Implement BD_GUIDE.md generation for version-stamped documentation (bd-woro)

This implements the ability to separate bd-specific instructions from
project-specific instructions by generating a canonical BD_GUIDE.md file.

## Changes

1. Added `--output` flag to `bd onboard` command
   - Generates version-stamped BD_GUIDE.md at specified path
   - Includes both agentsContent and copilotInstructionsContent
   - Auto-generated header warns against manual editing

2. Version tracking integration
   - checkAndSuggestBDGuideUpdate() detects outdated BD_GUIDE.md
   - Suggests regeneration when bd version changes
   - Integrated with maybeShowUpgradeNotification()

3. Comprehensive test coverage
   - Tests for BD_GUIDE.md generation
   - Tests for version stamp validation
   - Tests for content inclusion

4. Documentation updates
   - Updated AGENTS.md with BD_GUIDE.md workflow
   - Added regeneration instructions to upgrade workflow

## Benefits

- Clear separation of concerns (bd vs project instructions)
- Deterministic updates (no LLM involved)
- Git-trackable diffs show exactly what changed
- Progressive disclosure (agents read when needed)

## Usage

\`\`\`bash
# Generate BD_GUIDE.md
bd onboard --output .beads/BD_GUIDE.md

# After upgrading bd
bd onboard --output .beads/BD_GUIDE.md  # Regenerate
\`\`\`

Closes bd-woro
This commit is contained in:
Steve Yegge
2025-11-23 21:16:09 -08:00
parent 71502b1b93
commit 9e16469b2e
6 changed files with 559 additions and 4 deletions

View File

@@ -114,9 +114,67 @@ func maybeShowUpgradeNotification() {
// Display notification
fmt.Printf("🔄 bd upgraded from v%s to v%s since last use\n", previousVersion, Version)
fmt.Println("💡 Run 'bd upgrade review' to see what changed")
// Check if BD_GUIDE.md exists and needs updating
checkAndSuggestBDGuideUpdate()
fmt.Println()
}
// checkAndSuggestBDGuideUpdate checks if .beads/BD_GUIDE.md exists and suggests regeneration if outdated.
// bd-woro: Auto-update BD_GUIDE.md on version changes
func checkAndSuggestBDGuideUpdate() {
beadsDir := beads.FindBeadsDir()
if beadsDir == "" {
return
}
guidePath := beadsDir + "/BD_GUIDE.md"
// Check if BD_GUIDE.md exists
if _, err := os.Stat(guidePath); os.IsNotExist(err) {
// File doesn't exist - no suggestion needed
return
}
// Read first few lines to check version stamp
content, err := os.ReadFile(guidePath)
if err != nil {
return // Silent failure
}
// Look for version in the first 200 bytes (should be in the header)
header := string(content)
if len(header) > 200 {
header = header[:200]
}
// Check if the file has the old version stamp
oldVersionStamp := fmt.Sprintf("bd v%s", previousVersion)
currentVersionStamp := fmt.Sprintf("bd v%s", Version)
if containsSubstring(header, oldVersionStamp) && !containsSubstring(header, currentVersionStamp) {
// BD_GUIDE.md is outdated
fmt.Printf("📄 BD_GUIDE.md is outdated (v%s → v%s)\n", previousVersion, Version)
fmt.Printf("💡 Run 'bd onboard --output .beads/BD_GUIDE.md' to regenerate\n")
}
}
// containsSubstring checks if haystack contains needle (case-sensitive)
func containsSubstring(haystack, needle string) bool {
return len(haystack) >= len(needle) && findSubstring(haystack, needle) >= 0
}
// findSubstring returns the index of needle in haystack, or -1 if not found
func findSubstring(haystack, needle string) int {
for i := 0; i <= len(haystack)-len(needle); i++ {
if haystack[i:i+len(needle)] == needle {
return i
}
}
return -1
}
// autoMigrateOnVersionBump automatically migrates the database when CLI version changes.
// This function is best-effort - failures are silent to avoid disrupting commands.
// Called from PersistentPreRun after daemon check but before opening DB for main operation.