Merge GH#532

This commit is contained in:
Steve Yegge
2025-12-16 01:19:14 -08:00
7 changed files with 9777 additions and 32 deletions

View File

@@ -25,6 +25,12 @@ if [ ! -d .beads ]; then
exit 0
fi
# Skip if bd sync is already in progress (GH#532: prevents circular error)
# bd sync sets this env var when pushing from worktree
if [ -n "$BD_SYNC_IN_PROGRESS" ]; then
exit 0
fi
# Optionally flush pending bd changes so they surface in JSONL
# This prevents the race where a debounced flush lands after the check
if command -v bd >/dev/null 2>&1; then

File diff suppressed because it is too large Load Diff

View File

@@ -423,6 +423,15 @@ With --stealth: configures global git settings for invisible beads usage:
}
}
// Add "landing the plane" instructions to AGENTS.md and @AGENTS.md
// Skip in stealth mode (user wants invisible setup) and quiet mode (suppress all output)
if !stealth {
if err := addLandingThePlaneInstructions(!quiet); err != nil && !quiet {
yellow := color.New(color.FgYellow).SprintFunc()
fmt.Fprintf(os.Stderr, "%s Failed to add landing-the-plane instructions: %v\n", yellow("⚠"), err)
}
}
// Skip output if quiet mode
if quiet {
return
@@ -1550,6 +1559,114 @@ Aborting.`, yellow("⚠"), dbPath, cyan("bd list"), prefix)
}
// landingThePlaneSection is the "landing the plane" instructions for AI agents
// This gets appended to AGENTS.md and @AGENTS.md during bd init
const landingThePlaneSection = `
## Landing the Plane (Session Completion)
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until ` + "`git push`" + ` succeeds.
**MANDATORY WORKFLOW:**
1. **File issues for remaining work** - Create issues for anything that needs follow-up
2. **Run quality gates** (if code changed) - Tests, linters, builds
3. **Update issue status** - Close finished work, update in-progress items
4. **PUSH TO REMOTE** - This is MANDATORY:
` + "```bash" + `
git pull --rebase
bd sync
git push
git status # MUST show "up to date with origin"
` + "```" + `
5. **Clean up** - Clear stashes, prune remote branches
6. **Verify** - All changes committed AND pushed
7. **Hand off** - Provide context for next session
**CRITICAL RULES:**
- Work is NOT complete until ` + "`git push`" + ` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
`
// addLandingThePlaneInstructions adds "landing the plane" instructions to AGENTS.md and @AGENTS.md
func addLandingThePlaneInstructions(verbose bool) error {
// Files to update (AGENTS.md and @AGENTS.md for web Claude)
agentFiles := []string{"AGENTS.md", "@AGENTS.md"}
for _, filename := range agentFiles {
if err := updateAgentFile(filename, verbose); err != nil {
// Non-fatal - continue with other files
if verbose {
fmt.Fprintf(os.Stderr, "Warning: failed to update %s: %v\n", filename, err)
}
}
}
return nil
}
// updateAgentFile creates or updates an agent instructions file with landing the plane section
func updateAgentFile(filename string, verbose bool) error {
// Check if file exists
content, err := os.ReadFile(filename)
if os.IsNotExist(err) {
// File doesn't exist - create it with basic structure
newContent := fmt.Sprintf(`# Agent Instructions
This project uses **bd** (beads) for issue tracking. Run ` + "`bd onboard`" + ` to get started.
## Quick Reference
` + "```bash" + `
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --status in_progress # Claim work
bd close <id> # Complete work
bd sync # Sync with git
` + "```" + `
%s
`, landingThePlaneSection)
// #nosec G306 - markdown needs to be readable
if err := os.WriteFile(filename, []byte(newContent), 0644); err != nil {
return fmt.Errorf("failed to create %s: %w", filename, err)
}
if verbose {
green := color.New(color.FgGreen).SprintFunc()
fmt.Printf(" %s Created %s with landing-the-plane instructions\n", green("✓"), filename)
}
return nil
} else if err != nil {
return fmt.Errorf("failed to read %s: %w", filename, err)
}
// File exists - check if it already has landing the plane section
if strings.Contains(string(content), "Landing the Plane") {
if verbose {
fmt.Printf(" %s already has landing-the-plane instructions\n", filename)
}
return nil
}
// Append the landing the plane section
newContent := string(content)
if !strings.HasSuffix(newContent, "\n") {
newContent += "\n"
}
newContent += landingThePlaneSection
// #nosec G306 - markdown needs to be readable
if err := os.WriteFile(filename, []byte(newContent), 0644); err != nil {
return fmt.Errorf("failed to update %s: %w", filename, err)
}
if verbose {
green := color.New(color.FgGreen).SprintFunc()
fmt.Printf(" %s Added landing-the-plane instructions to %s\n", green("✓"), filename)
}
return nil
}
// setupClaudeSettings creates or updates .claude/settings.local.json with onboard instruction
func setupClaudeSettings(verbose bool) error {
claudeDir := ".claude"

View File

@@ -23,20 +23,12 @@ if ! command -v bd >/dev/null 2>&1; then
exit 0
fi
# Check if we're in a bd workspace with an actual database
# Just having a .beads directory isn't enough - it must be properly initialized
# Check if we're in a bd workspace
if [ ! -d .beads ]; then
# Not a bd workspace, nothing to do
exit 0
fi
# Verify beads is actually initialized (has database or config)
# This handles the case where .beads was removed from git but directory lingers
if [ ! -f .beads/beads.db ] && [ ! -f .beads/config.yaml ] && [ ! -f .beads/issues.jsonl ]; then
# Directory exists but beads not initialized, nothing to do
exit 0
fi
# Check if sync-branch is configured in config.yaml or env var
# If so, .beads changes go to a separate branch via worktree, not the current branch
SYNC_BRANCH="${BEADS_SYNC_BRANCH:-}"
@@ -54,36 +46,18 @@ fi
# Flush pending changes to JSONL
# Use --flush-only to skip git operations (we're already in a git hook)
# Suppress output unless there's an error
<<<<<<< HEAD
# Note: We don't block commits on flush failure - beads issues shouldn't prevent code commits
if ! bd sync --flush-only >/dev/null 2>&1; then
echo "Warning: Failed to flush bd changes to JSONL" >&2
echo "Run 'bd sync --flush-only' manually to diagnose" >&2
# Continue with commit - don't block code changes due to beads issues
=======
# Note: We warn but don't fail - this allows commits to proceed even if
# beads has issues (e.g., user removed .beads from their branch)
if ! bd sync --flush-only >/dev/null 2>&1; then
echo "Warning: Failed to flush bd changes to JSONL" >&2
echo "Run 'bd sync --flush-only' manually to diagnose" >&2
# Don't block the commit - user may have removed beads or have other issues
>>>>>>> origin/bd-l0pg-slit
fi
# Stage all tracked JSONL files (issues.jsonl is canonical, beads.jsonl for backward compat, deletions.jsonl for deletion propagation)
# For worktrees, .beads is in the main repo's working tree, not the worktree,
# so we can't use git add. Skip staging for worktrees.
if [ "$(git rev-parse --git-dir)" = "$(git rev-parse --git-common-dir)" ]; then
# Regular repo: files are in the working tree, safe to add
# git add is harmless if file doesn't exist
for f in .beads/beads.jsonl .beads/issues.jsonl .beads/deletions.jsonl; do
[ -f "$f" ] && git add "$f" 2>/dev/null || true
done
else
# Worktree: .beads is in the main repo's working tree, not this worktree
# Git rejects adding files outside the worktree, so we skip it.
# The main repo will see the changes on the next pull/sync.
: # do nothing
fi
# Stage all tracked JSONL files (beads.jsonl, issues.jsonl for backward compat, deletions.jsonl for deletion propagation)
# git add is harmless if file doesn't exist
for f in .beads/beads.jsonl .beads/issues.jsonl .beads/deletions.jsonl; do
[ -f "$f" ] && git add "$f" 2>/dev/null || true
done
exit 0

View File

@@ -28,6 +28,12 @@ if [ ! -d .beads ]; then
exit 0
fi
# Skip if bd sync is already in progress (GH#532: prevents circular error)
# bd sync sets this env var when pushing from worktree
if [ -n "$BD_SYNC_IN_PROGRESS" ]; then
exit 0
fi
# Check if sync-branch is configured in config.yaml or env var
# If so, .beads changes go to a separate branch via worktree, not the current branch
SYNC_BRANCH="${BEADS_SYNC_BRANCH:-}"

View File

@@ -28,6 +28,12 @@ if [ ! -d .beads ]; then
exit 0
fi
# Skip if bd sync is already in progress (GH#532: prevents circular error)
# bd sync sets this env var when pushing from worktree
if [ -n "$BD_SYNC_IN_PROGRESS" ]; then
exit 0
fi
# Check if sync-branch is configured in config.yaml or env var
# If so, .beads changes go to a separate branch via worktree, not the current branch
SYNC_BRANCH="${BEADS_SYNC_BRANCH:-}"

View File

@@ -855,6 +855,9 @@ func pushFromWorktree(ctx context.Context, worktreePath, branch string) error {
for attempt := 0; attempt < maxRetries; attempt++ {
// Push with explicit remote and branch, set upstream if not set
cmd := exec.CommandContext(ctx, "git", "-C", worktreePath, "push", "--set-upstream", remote, branch)
// Set BD_SYNC_IN_PROGRESS so pre-push hook knows to skip checks (GH#532)
// This prevents circular error where hook suggests running bd sync
cmd.Env = append(os.Environ(), "BD_SYNC_IN_PROGRESS=1")
output, err := cmd.CombinedOutput()
if err == nil {