feat(config): add directory-aware label scoping for monorepos (fixes #541)

Adds automatic label filtering based on current working directory:
- New config option: directory.labels (maps directory patterns to labels)
- bd ready and bd list auto-apply label filtering when in matching directory
- Uses --label-any semantics (shows issues with any of the matching labels)

Config example:
```yaml
directory:
  labels:
    packages/maverick: maverick
    packages/agency: agency
```

When running `bd ready` from `packages/maverick/`, issues labeled
"maverick" are automatically shown first, without needing --label-any.

Closes #541

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-20 03:41:09 -08:00
parent 5892a826fc
commit 244ba1471b
4 changed files with 71 additions and 1 deletions

View File

@@ -116,6 +116,10 @@ func Initialize() error {
v.SetDefault("git.author", "") // Override commit author (e.g., "beads-bot <beads@example.com>")
v.SetDefault("git.no-gpg-sign", false) // Disable GPG signing for beads commits
// Directory-aware label scoping (GH#541)
// Maps directory patterns to labels for automatic filtering in monorepos
v.SetDefault("directory.labels", map[string]string{})
// Read config file if it was found
if configFileSet {
if err := v.ReadInConfig(); err != nil {
@@ -196,6 +200,44 @@ func GetStringSlice(key string) []string {
return v.GetStringSlice(key)
}
// GetStringMapString retrieves a map[string]string configuration value
func GetStringMapString(key string) map[string]string {
if v == nil {
return map[string]string{}
}
return v.GetStringMapString(key)
}
// GetDirectoryLabels returns labels for the current working directory based on config.
// It checks directory.labels config for matching patterns.
// Returns nil if no labels are configured for the current directory.
func GetDirectoryLabels() []string {
cwd, err := os.Getwd()
if err != nil {
return nil
}
dirLabels := GetStringMapString("directory.labels")
if len(dirLabels) == 0 {
return nil
}
// Check each configured directory pattern
for pattern, label := range dirLabels {
// Support both exact match and suffix match
// e.g., "packages/maverick" matches "/path/to/repo/packages/maverick"
if strings.HasSuffix(cwd, pattern) || strings.HasSuffix(cwd, filepath.Clean(pattern)) {
return []string{label}
}
// Also try as a path prefix (user might be in a subdirectory)
if strings.Contains(cwd, "/"+pattern+"/") || strings.Contains(cwd, "/"+pattern) {
return []string{label}
}
}
return nil
}
// MultiRepoConfig contains configuration for multi-repo support
type MultiRepoConfig struct {
Primary string // Primary repo path (where canonical issues live)