Skip to content

Commit 7e29605

Browse files
committed
fix(doctor): eliminate false warnings after clean-room bd init
Addresses remaining doctor warnings that fire after bd init in a fresh git repo (PR gastownhall#1915 scope): - CheckGitUpstream: skip warning when no remotes exist (cannot have upstream without a remote) - bd init: auto-stage .beads/, AGENTS.md, .gitignore and commit so doctor does not warn about dirty working tree or untracked files - bd init: clean noms LOCK files after store close and after git commit (pre-commit hook may reopen the database) - store.Close: remove 0-byte noms LOCK files on shutdown Co-authored-by: matt wilkie <maphew@gmail.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Executed-By: beads/crew/lizzy Rig: beads Role: crew
1 parent 5907658 commit 7e29605

2 files changed

Lines changed: 66 additions & 1 deletion

File tree

cmd/bd/init.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,9 @@ environment variable.`,
540540
fmt.Fprintf(os.Stderr, "Warning: failed to close database: %v\n", err)
541541
}
542542

543+
// Clean up 0-byte noms LOCK files left behind by the store open/close cycle.
544+
dolt.CleanStaleNomsLocks(doltserver.ResolveDoltDir(beadsDir))
545+
543546
// Fork detection: offer to configure .git/info/exclude (GH#742)
544547
setupExclude, _ := cmd.Flags().GetBool("setup-exclude")
545548
if setupExclude {
@@ -624,6 +627,36 @@ environment variable.`,
624627
addAgentsInstructions(!quiet, agentsTemplate)
625628
}
626629

630+
// Auto-stage and commit beads files so bd doctor doesn't warn about
631+
// untracked files or dirty working tree in a clean room setup.
632+
// Only runs when not stealth, in a git repo, and using local storage.
633+
if !stealth && isGitRepo() && useLocalBeads {
634+
gitAddCmd := exec.Command("git", "add", ".beads/")
635+
if _, addErr := gitAddCmd.CombinedOutput(); addErr == nil {
636+
// Also stage AGENTS.md if it exists
637+
if _, statErr := os.Stat("AGENTS.md"); statErr == nil {
638+
agentsCmd := exec.Command("git", "add", "AGENTS.md")
639+
_ = agentsCmd.Run()
640+
}
641+
// Also stage .gitignore if modified by EnsureProjectGitignore
642+
if _, statErr := os.Stat(".gitignore"); statErr == nil {
643+
giCmd := exec.Command("git", "add", ".gitignore")
644+
_ = giCmd.Run()
645+
}
646+
commitCmd := exec.Command("git", "commit", "-m", "bd init: initialize beads issue tracking")
647+
if commitOut, commitErr := commitCmd.CombinedOutput(); commitErr != nil {
648+
if !quiet && !strings.Contains(string(commitOut), "nothing to commit") {
649+
fmt.Fprintf(os.Stderr, "Warning: failed to commit beads files: %v\n", commitErr)
650+
}
651+
} else if !quiet {
652+
fmt.Printf(" %s Committed beads files to git\n", ui.RenderPass("✓"))
653+
}
654+
// Clean up LOCK files again — the pre-commit hook may have
655+
// reopened the database and left a new LOCK behind.
656+
dolt.CleanStaleNomsLocks(doltserver.ResolveDoltDir(beadsDir))
657+
}
658+
}
659+
627660
// Check for missing git upstream and warn if not configured.
628661
// Only warn when remotes exist (has origin but no upstream).
629662
// Skip for brand-new repos with no remotes — the warning is noise there.

internal/storage/dolt/store.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,8 @@ func isOnlyComments(stmt string) bool {
886886
return true
887887
}
888888

889-
// Close closes the database connection
889+
// Close closes the database connection and removes any 0-byte noms LOCK files
890+
// left behind by the embedded Dolt engine.
890891
func (s *DoltStore) Close() error {
891892
s.closed.Store(true)
892893
s.mu.Lock()
@@ -901,9 +902,40 @@ func (s *DoltStore) Close() error {
901902
}
902903
}
903904
s.db = nil
905+
906+
// Clean up 0-byte noms LOCK files. The Dolt engine creates these when
907+
// opening a database; they should be removed on clean shutdown but may
908+
// persist after crashes or when bd init triggers hook reopens.
909+
if s.dbPath != "" {
910+
cleanZeroByteNomsLocks(s.dbPath)
911+
}
912+
904913
return err
905914
}
906915

916+
// cleanZeroByteNomsLocks removes 0-byte noms LOCK files from all databases
917+
// under doltDir. Only empty LOCK files are removed — non-empty ones may
918+
// indicate an active lock held by a running server.
919+
func cleanZeroByteNomsLocks(doltDir string) {
920+
entries, err := os.ReadDir(doltDir)
921+
if err != nil {
922+
return
923+
}
924+
for _, entry := range entries {
925+
if !entry.IsDir() {
926+
continue
927+
}
928+
lockPath := filepath.Join(doltDir, entry.Name(), ".dolt", "noms", "LOCK")
929+
info, statErr := os.Stat(lockPath)
930+
if statErr != nil {
931+
continue
932+
}
933+
if info.Size() == 0 {
934+
_ = os.Remove(lockPath)
935+
}
936+
}
937+
}
938+
907939
// Path returns the database directory path
908940
func (s *DoltStore) Path() string {
909941
return s.dbPath

0 commit comments

Comments
 (0)