From 3df138445aa86bb474b511c63bcb664dfe11ad0a Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 30 Nov 2025 21:17:42 -0800 Subject: [PATCH] fix(init): allow fresh clones with JSONL to run bd init (bd-4h9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, bd init blocked when JSONL existed with issues but no database, telling users to run 'bd doctor --fix'. But doctor --fix just ran bd migrate which requires an existing database - creating a circular dependency. Now: - bd init allows fresh clones (JSONL exists, no database) to proceed - bd init creates the database and imports from JSONL automatically - bd doctor --fix runs bd init (not migrate) when there's no database 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .beads/deletions.jsonl | 1 + cmd/bd/doctor/fix/migrate.go | 24 ++++++++++++++++-- cmd/bd/init.go | 48 ++++++++---------------------------- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/.beads/deletions.jsonl b/.beads/deletions.jsonl index 93e1c3c6..316b42c4 100644 --- a/.beads/deletions.jsonl +++ b/.beads/deletions.jsonl @@ -94,3 +94,4 @@ {"id":"bd-tjn","ts":"2025-12-01T05:13:13.738456Z","by":"git-history-backfill","reason":"recovered from git history (pruned from manifest)"} {"id":"bd-qvj","ts":"2025-12-01T05:13:13.743949Z","by":"git-history-backfill","reason":"recovered from git history (pruned from manifest)"} {"id":"bd-clg","ts":"2025-12-01T05:13:13.748995Z","by":"git-history-backfill","reason":"recovered from git history (pruned from manifest)"} +{"id":"bd-4h9","ts":"2025-12-01T05:18:00.744362Z","by":"git-history-backfill","reason":"recovered from git history (pruned from manifest)"} diff --git a/cmd/bd/doctor/fix/migrate.go b/cmd/bd/doctor/fix/migrate.go index 0cdfe7bb..67f1122f 100644 --- a/cmd/bd/doctor/fix/migrate.go +++ b/cmd/bd/doctor/fix/migrate.go @@ -4,9 +4,11 @@ import ( "fmt" "os" "os/exec" + "path/filepath" ) -// DatabaseVersion fixes database version mismatches by running bd migrate +// DatabaseVersion fixes database version mismatches by running bd migrate, +// or creates the database from JSONL by running bd init for fresh clones (bd-4h9). func DatabaseVersion(path string) error { // Validate workspace if err := validateBeadsWorkspace(path); err != nil { @@ -19,7 +21,25 @@ func DatabaseVersion(path string) error { return err } - // Run bd migrate + // Check if database exists - if not, run init instead of migrate (bd-4h9) + beadsDir := filepath.Join(path, ".beads") + dbPath := filepath.Join(beadsDir, "beads.db") + + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + // No database - this is a fresh clone, run bd init + fmt.Println("→ No database found, running 'bd init' to hydrate from JSONL...") + cmd := exec.Command(bdBinary, "init") // #nosec G204 -- bdBinary from validated executable path + cmd.Dir = path + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to initialize database: %w", err) + } + return nil + } + + // Database exists - run bd migrate cmd := exec.Command(bdBinary, "migrate") // #nosec G204 -- bdBinary from validated executable path cmd.Dir = path // Set working directory without changing process dir cmd.Stdout = os.Stdout diff --git a/cmd/bd/init.go b/cmd/bd/init.go index b0cc7977..8665c20a 100644 --- a/cmd/bd/init.go +++ b/cmd/bd/init.go @@ -1338,8 +1338,12 @@ func setupGlobalGitIgnore(homeDir string, verbose bool) error { return nil } -// checkExistingBeadsData checks for existing JSONL or database files +// checkExistingBeadsData checks for existing database files // and returns an error if found (safety guard for bd-emg) +// +// Note: This only blocks when a database already exists (workspace is initialized). +// Fresh clones with JSONL but no database are allowed - init will create the database +// and import from JSONL automatically (bd-4h9: fixes circular dependency with doctor --fix). func checkExistingBeadsData(prefix string) error { cwd, err := os.Getwd() if err != nil { @@ -1373,44 +1377,12 @@ To completely reinitialize (data loss warning): Aborting.`, yellow("⚠"), dbPath, cyan("bd list"), prefix) } - // Check for existing JSONL files with issues - jsonlCandidates := []string{ - filepath.Join(beadsDir, "issues.jsonl"), - filepath.Join(beadsDir, "beads.jsonl"), - } + // Fresh clones (JSONL exists but no database) are allowed - init will + // create the database and import from JSONL automatically. + // This fixes the circular dependency where init told users to run + // "bd doctor --fix" but doctor couldn't create a database (bd-4h9). - for _, jsonlPath := range jsonlCandidates { - if _, err := os.Stat(jsonlPath); err == nil { - // JSONL exists, count issues - issueCount := countIssuesInJSONLFile(jsonlPath) - - if issueCount > 0 { - yellow := color.New(color.FgYellow).SprintFunc() - cyan := color.New(color.FgCyan).SprintFunc() - - prefixHint := prefix - if prefixHint == "" { - prefixHint = "" - } - - return fmt.Errorf(` -%s Found existing %s with %d issues. - -This appears to be a fresh clone, not a new project. - -To hydrate the database from existing JSONL: - %s - -To force re-initialization (may cause data loss): - bd init --prefix %s --force - -Aborting.`, yellow("⚠"), filepath.Base(jsonlPath), issueCount, cyan("bd doctor --fix"), prefixHint) - } - // Empty JSONL (0 issues) is OK - likely a new project - } - } - - return nil // No existing data found, safe to init + return nil // No database found, safe to init }