fix: Handle .beads/redirect files and limit verbose output in bd doctor --fix

- Add resolveBeadsDir helper to fix/common.go to follow redirect files
- Update OrphanedDependencies, ChildParentDependencies, and MergeArtifacts
  to use resolveBeadsDir instead of hardcoded .beads path
- Add --verbose/-v flag to bd doctor command
- Only print individual items if verbose or count < 20, always show summary

(bd-dq74, bd-v55y)

🤖 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-29 12:58:58 -08:00
parent cd942f136d
commit 24966bd1ce
5 changed files with 74 additions and 15 deletions

View File

@@ -6,6 +6,8 @@ import (
"os/exec"
"path/filepath"
"strings"
"github.com/steveyegge/beads/internal/beads"
)
// ErrTestBinary is returned when getBdBinary detects it's running as a test binary.
@@ -108,3 +110,43 @@ func isWithinWorkspace(root, candidate string) bool {
}
return rel == "." || (rel != ".." && !strings.HasPrefix(rel, ".."+string(os.PathSeparator)))
}
// resolveBeadsDir follows .beads/redirect files to find the actual beads directory.
// If no redirect exists, returns the original path unchanged.
func resolveBeadsDir(beadsDir string) string {
redirectFile := filepath.Join(beadsDir, beads.RedirectFileName)
data, err := os.ReadFile(redirectFile) //nolint:gosec // redirect file path is constructed from known beadsDir
if err != nil {
// No redirect file - use original path
return beadsDir
}
// Parse the redirect target
target := strings.TrimSpace(string(data))
if target == "" {
return beadsDir
}
// Skip comments
lines := strings.Split(target, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" && !strings.HasPrefix(line, "#") {
target = line
break
}
}
// Resolve relative paths from the parent of the .beads directory
if !filepath.IsAbs(target) {
projectRoot := filepath.Dir(beadsDir)
target = filepath.Join(projectRoot, target)
}
// Verify the target exists
if info, err := os.Stat(target); err != nil || !info.IsDir() {
return beadsDir
}
return target
}