From 4de9f015d624fd6dab246d7b696e56884655189c Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 9 Nov 2025 16:16:45 -0800 Subject: [PATCH 1/3] Support local-only git repos without remote origin (bd-biwp) - Add hasGitRemote() helper to detect if any remote exists - Gracefully skip git pull/push when no remote configured - Daemon now works in local-only mode (RPC, auto-flush, JSONL export) - Add comprehensive test coverage for local-only workflows - Fixes GH#279: daemon crash on repos without origin remote Amp-Thread-ID: https://ampcode.com/threads/T-5dad0ca8-ac77-4ae0-8de6-208b23ea47af Co-authored-by: Amp --- .beads/beads.jsonl | 1 + cmd/bd/daemon_sync_branch.go | 10 +++ cmd/bd/sync.go | 22 ++++++ cmd/bd/sync_local_only_test.go | 133 +++++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 cmd/bd/sync_local_only_test.go diff --git a/.beads/beads.jsonl b/.beads/beads.jsonl index 0565ddad..cce66b50 100644 --- a/.beads/beads.jsonl +++ b/.beads/beads.jsonl @@ -279,6 +279,7 @@ {"id":"bd-bdhn","content_hash":"ddbc003327e0492285b53fd765e90a816b9cea1e4cf9fc8797e8a465a1e834bd","title":"bd message: Add input validation for --importance flag","description":"The --importance flag accepts any string without validation, leading to confusing server errors.\n\n**Location:** cmd/bd/message.go:256-258\n\n**Fix:**\n- Add flag validation for: low, normal, high, urgent\n- Add shell completion support\n- Validate in runMessageSend before sending\n\n**Impact:** Better UX, prevents confusing errors","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-08T12:54:26.43027-08:00","updated_at":"2025-11-08T12:57:59.65367-08:00","closed_at":"2025-11-08T12:57:59.65367-08:00","source_repo":".","dependencies":[{"issue_id":"bd-bdhn","depends_on_id":"bd-6uix","type":"parent-child","created_at":"2025-11-08T12:55:54.910841-08:00","created_by":"daemon"}]} {"id":"bd-be7a","content_hash":"d9043a7a49f8e42dc88c3c01aaa178c1560b67c1637c3373b39c387272e8b725","title":"Create npm package structure with package.json","description":"Set up initial npm package structure for @beads/bd:\n\n## Files to create\n- npm/package.json - Package metadata, dependencies, scripts\n- npm/bin/bd - CLI wrapper script that invokes native binary\n- npm/.gitignore - Ignore downloaded binaries\n- npm/README.md - Installation and usage instructions\n\n## package.json structure\n- Name: @beads/bd (scoped package)\n- Main: index.js (exports binary path)\n- Bin: bin/bd (CLI entry point)\n- Scripts: postinstall (download binary)\n- Keywords: issue-tracker, cli, beads, bd\n- License: MIT\n\n## Bin wrapper\nSimple Node.js script that:\n- Spawns native binary with child_process.spawn\n- Passes through all arguments and stdio\n- Exits with binary's exit code","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T23:39:47.416779-08:00","updated_at":"2025-11-03T10:31:45.381258-08:00","closed_at":"2025-11-03T10:31:45.381258-08:00","source_repo":".","dependencies":[{"issue_id":"bd-be7a","depends_on_id":"bd-febc","type":"parent-child","created_at":"2025-11-02T23:40:32.923859-08:00","created_by":"daemon"}]} {"id":"bd-bgca","content_hash":"c617d03baef137f2425cea14eb5346012e556b35e9048f0601fe8d719b5b705f","title":"Latency test manual","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-08T00:04:25.028223-08:00","updated_at":"2025-11-08T00:06:46.169654-08:00","closed_at":"2025-11-08T00:06:46.169654-08:00","source_repo":"."} +{"id":"bd-biwp","content_hash":"ece37e742d401489872e2735084fc94510f9308c3acff2659b233ab19440ebb4","title":"Support local-only git repos without remote origin","description":"Daemon crashes when working with local git repos that don't have origin remote configured. Should gracefully degrade to local-only mode: skip git pull/push operations but maintain daemon features (RPC server, auto-flush, JSONL export).","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2025-11-09T16:09:50.677769-08:00","updated_at":"2025-11-09T16:13:21.970934-08:00","external_ref":"gh#279","source_repo":"."} {"id":"bd-buol","content_hash":"020dc9dbbd7f3e2b40c35f01bf8a65cf32ab419c188081493ea4e541bad1442e","title":"Invert control for compact: provide tools for agent-driven compaction","description":"Currently compact requires Anthropic API key because bd calls the AI directly. This is backwards - we should provide tools (like all other bd commands) that let an AI agent perform the compaction. The agent decides what to keep/merge, not bd. Related to GH #243 complaint about API key requirement.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-07T00:27:28.498069-08:00","updated_at":"2025-11-08T01:49:23.46152-08:00","closed_at":"2025-11-07T23:08:51.67473-08:00","source_repo":"."} {"id":"bd-by3x","content_hash":"80149be1ddf4ef26d5d56c444895be01ec8b59492c258c2365fa1c2619061bbd","title":"Windows binaries lack SQLite support (GH #253)","description":"Windows users installing via install.ps1 get \"sql: unknown driver sqlite\" error. Root cause: GoReleaser was building with CGO_ENABLED=0, which excludes SQLite driver.\n\nFixed by:\n1. Enabling CGO in .goreleaser.yml\n2. Installing MinGW cross-compiler in release workflow\n3. Splitting builds per platform to set correct CC for Windows\n\nNeeds new release to fix for users.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-07T15:54:13.134815-08:00","updated_at":"2025-11-07T15:55:07.024156-08:00","closed_at":"2025-11-07T15:55:07.024156-08:00","source_repo":"."} {"id":"bd-bzfy","content_hash":"90bbde4d90d68728a9377d5d966682dc836740f1be43a0cf80d3cc69002a560b","title":"Integrate beads-merge tool by @neongreen","description":"**Context**: @neongreen built a production-ready 3-way merge tool for JSONL files that works with both Git and Jujutsu. This is superior to our planned bd resolve-conflicts because it prevents conflicts proactively instead of resolving them after the fact.\n\n**Tool**: https://github.com/neongreen/mono/tree/main/beads-merge\n\n**What it does**:\n- 3-way merge of JSONL files (base, left, right)\n- Field-level merging (titles, status, priority, etc.)\n- Smart dependency merging (union + dedup)\n- Conflict markers for unresolvable conflicts\n- Exit code 1 for conflicts (standard)\n\n**Integration options**:\n\n1. **Recommend (minimal effort)** - Document in AGENTS.md + TROUBLESHOOTING.md\n2. **Bundle binary** - Include in releases (cross-platform builds)\n3. **Port to Go** - Reimplement in bd codebase\n4. **Auto-install hook** - During bd init, offer to install merge driver\n\n**Recommendation**: Start with option 1 (document), then option 2 (bundle) once proven.\n\n**Related**: bd-5f483051 (bd resolve-conflicts - can close as superseded)","notes":"Created GitHub issue to discuss integration approach with @neongreen: https://github.com/neongreen/mono/issues/240\n\nAwaiting their preference on:\n1. Vendor with attribution (fastest)\n2. Extract as importable module (best long-term)\n3. Keep as separate tool (current state)\n\nNext: Wait for response before proceeding with integration.\n\nUPDATE 2025-11-06: @neongreen gave permission to vendor! Quote: \"I switched from beads to my own thing (tk) so I'm very happy to give beads-merge away — feel free to move it into the beads repo and I will point mono's readme to beads\"\n\nNext: Vendor beads-merge with full attribution","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-11-05T11:31:44.906652-08:00","updated_at":"2025-11-06T18:19:16.233387-08:00","closed_at":"2025-11-06T15:38:37.052274-08:00","source_repo":"."} diff --git a/cmd/bd/daemon_sync_branch.go b/cmd/bd/daemon_sync_branch.go index a090cda3..dec2330a 100644 --- a/cmd/bd/daemon_sync_branch.go +++ b/cmd/bd/daemon_sync_branch.go @@ -16,6 +16,11 @@ import ( // syncBranchCommitAndPush commits JSONL to the sync branch using a worktree // Returns true if changes were committed, false if no changes or sync.branch not configured func syncBranchCommitAndPush(ctx context.Context, store storage.Storage, autoPush bool, log daemonLogger) (bool, error) { + // Check if any remote exists (bd-biwp: support local-only repos) + if !hasGitRemote(ctx) { + return true, nil // Skip sync branch commit/push in local-only mode + } + // Get sync.branch config syncBranch, err := store.GetConfig(ctx, "sync.branch") if err != nil { @@ -169,6 +174,11 @@ func gitPushFromWorktree(ctx context.Context, worktreePath, branch string) error // syncBranchPull pulls changes from the sync branch into the worktree // Returns true if pull was performed, false if sync.branch not configured func syncBranchPull(ctx context.Context, store storage.Storage, log daemonLogger) (bool, error) { + // Check if any remote exists (bd-biwp: support local-only repos) + if !hasGitRemote(ctx) { + return true, nil // Skip sync branch pull in local-only mode + } + // Get sync.branch config syncBranch, err := store.GetConfig(ctx, "sync.branch") if err != nil { diff --git a/cmd/bd/sync.go b/cmd/bd/sync.go index 4298cbcb..9aba0fdf 100644 --- a/cmd/bd/sync.go +++ b/cmd/bd/sync.go @@ -385,8 +385,24 @@ func gitCommit(ctx context.Context, filePath string, message string) error { return nil } +// hasGitRemote checks if a git remote exists in the repository +func hasGitRemote(ctx context.Context) bool { + cmd := exec.CommandContext(ctx, "git", "remote") + output, err := cmd.Output() + if err != nil { + return false + } + return len(strings.TrimSpace(string(output))) > 0 +} + // gitPull pulls from the current branch's upstream +// Returns nil if no remote configured (local-only mode) func gitPull(ctx context.Context) error { + // Check if any remote exists (bd-biwp: support local-only repos) + if !hasGitRemote(ctx) { + return nil // Gracefully skip - local-only mode + } + // Get current branch name branchCmd := exec.CommandContext(ctx, "git", "rev-parse", "--abbrev-ref", "HEAD") branchOutput, err := branchCmd.Output() @@ -414,7 +430,13 @@ func gitPull(ctx context.Context) error { } // gitPush pushes to the current branch's upstream +// Returns nil if no remote configured (local-only mode) func gitPush(ctx context.Context) error { + // Check if any remote exists (bd-biwp: support local-only repos) + if !hasGitRemote(ctx) { + return nil // Gracefully skip - local-only mode + } + cmd := exec.CommandContext(ctx, "git", "push") output, err := cmd.CombinedOutput() if err != nil { diff --git a/cmd/bd/sync_local_only_test.go b/cmd/bd/sync_local_only_test.go new file mode 100644 index 00000000..63f35d67 --- /dev/null +++ b/cmd/bd/sync_local_only_test.go @@ -0,0 +1,133 @@ +package main + +import ( + "context" + "os" + "os/exec" + "path/filepath" + "testing" +) + +// TestLocalOnlyMode tests that daemon works with local git repos (no remote) +func TestLocalOnlyMode(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test in short mode") + } + + // Create temp directory for local-only repo + tempDir := t.TempDir() + + // Initialize local git repo without remote + runGitCmd(t, tempDir, "init") + runGitCmd(t, tempDir, "config", "user.email", "test@example.com") + runGitCmd(t, tempDir, "config", "user.name", "Test User") + + // Change to temp directory so git commands run in the test repo + oldDir, err := os.Getwd() + if err != nil { + t.Fatalf("Failed to get working dir: %v", err) + } + defer os.Chdir(oldDir) + + if err := os.Chdir(tempDir); err != nil { + t.Fatalf("Failed to change to temp dir: %v", err) + } + + // Verify no remote exists + cmd := exec.Command("git", "remote") + output, err := cmd.Output() + if err != nil { + t.Fatalf("Failed to check git remotes: %v", err) + } + if len(output) > 0 { + t.Fatalf("Expected no remotes, got: %s", output) + } + + ctx := context.Background() + + // Test hasGitRemote returns false + if hasGitRemote(ctx) { + t.Error("Expected hasGitRemote to return false for local-only repo") + } + + // Test gitPull returns nil (no error) + if err := gitPull(ctx); err != nil { + t.Errorf("gitPull should gracefully skip when no remote, got error: %v", err) + } + + // Test gitPush returns nil (no error) + if err := gitPush(ctx); err != nil { + t.Errorf("gitPush should gracefully skip when no remote, got error: %v", err) + } + + // Create a dummy JSONL file to commit + beadsDir := filepath.Join(tempDir, ".beads") + if err := os.MkdirAll(beadsDir, 0750); err != nil { + t.Fatalf("Failed to create .beads dir: %v", err) + } + + jsonlPath := filepath.Join(beadsDir, "issues.jsonl") + if err := os.WriteFile(jsonlPath, []byte(`{"id":"test-1","title":"Test"}`+"\n"), 0644); err != nil { + t.Fatalf("Failed to write JSONL: %v", err) + } + + // Test gitCommit works (local commits should work fine) + runGitCmd(t, tempDir, "add", ".beads") + if err := gitCommit(ctx, jsonlPath, "Test commit"); err != nil { + t.Errorf("gitCommit should work in local-only mode, got error: %v", err) + } + + // Verify commit was created + cmd = exec.Command("git", "log", "--oneline") + output, err = cmd.Output() + if err != nil { + t.Fatalf("Failed to check git log: %v", err) + } + if len(output) == 0 { + t.Error("Expected at least one commit in git log") + } +} + +// TestWithRemote verifies hasGitRemote detects remotes correctly +func TestWithRemote(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test in short mode") + } + + // Create temp directories + tempDir := t.TempDir() + remoteDir := filepath.Join(tempDir, "remote") + cloneDir := filepath.Join(tempDir, "clone") + + // Create bare remote + if err := os.MkdirAll(remoteDir, 0750); err != nil { + t.Fatalf("Failed to create remote dir: %v", err) + } + runGitCmd(t, remoteDir, "init", "--bare") + + // Clone it + runGitCmd(t, tempDir, "clone", remoteDir, cloneDir) + + // Change to clone directory + oldDir, err := os.Getwd() + if err != nil { + t.Fatalf("Failed to get working dir: %v", err) + } + defer os.Chdir(oldDir) + + if err := os.Chdir(cloneDir); err != nil { + t.Fatalf("Failed to change to clone dir: %v", err) + } + + ctx := context.Background() + + // Test hasGitRemote returns true + if !hasGitRemote(ctx) { + t.Error("Expected hasGitRemote to return true when origin exists") + } + + // Verify git pull doesn't error (even with empty remote) + // Note: pull might fail with "couldn't find remote ref", but that's different + // from the fatal "'origin' does not appear to be a git repository" error + gitPull(ctx) // Just verify it doesn't panic +} From deaa463d2917a18d5d60985c05f2773b4e0f8147 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 9 Nov 2025 16:17:08 -0800 Subject: [PATCH 2/3] Update bd JSONL Amp-Thread-ID: https://ampcode.com/threads/T-5dad0ca8-ac77-4ae0-8de6-208b23ea47af Co-authored-by: Amp --- .beads/beads.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/beads.jsonl b/.beads/beads.jsonl index cce66b50..cd9a930e 100644 --- a/.beads/beads.jsonl +++ b/.beads/beads.jsonl @@ -279,7 +279,7 @@ {"id":"bd-bdhn","content_hash":"ddbc003327e0492285b53fd765e90a816b9cea1e4cf9fc8797e8a465a1e834bd","title":"bd message: Add input validation for --importance flag","description":"The --importance flag accepts any string without validation, leading to confusing server errors.\n\n**Location:** cmd/bd/message.go:256-258\n\n**Fix:**\n- Add flag validation for: low, normal, high, urgent\n- Add shell completion support\n- Validate in runMessageSend before sending\n\n**Impact:** Better UX, prevents confusing errors","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-08T12:54:26.43027-08:00","updated_at":"2025-11-08T12:57:59.65367-08:00","closed_at":"2025-11-08T12:57:59.65367-08:00","source_repo":".","dependencies":[{"issue_id":"bd-bdhn","depends_on_id":"bd-6uix","type":"parent-child","created_at":"2025-11-08T12:55:54.910841-08:00","created_by":"daemon"}]} {"id":"bd-be7a","content_hash":"d9043a7a49f8e42dc88c3c01aaa178c1560b67c1637c3373b39c387272e8b725","title":"Create npm package structure with package.json","description":"Set up initial npm package structure for @beads/bd:\n\n## Files to create\n- npm/package.json - Package metadata, dependencies, scripts\n- npm/bin/bd - CLI wrapper script that invokes native binary\n- npm/.gitignore - Ignore downloaded binaries\n- npm/README.md - Installation and usage instructions\n\n## package.json structure\n- Name: @beads/bd (scoped package)\n- Main: index.js (exports binary path)\n- Bin: bin/bd (CLI entry point)\n- Scripts: postinstall (download binary)\n- Keywords: issue-tracker, cli, beads, bd\n- License: MIT\n\n## Bin wrapper\nSimple Node.js script that:\n- Spawns native binary with child_process.spawn\n- Passes through all arguments and stdio\n- Exits with binary's exit code","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T23:39:47.416779-08:00","updated_at":"2025-11-03T10:31:45.381258-08:00","closed_at":"2025-11-03T10:31:45.381258-08:00","source_repo":".","dependencies":[{"issue_id":"bd-be7a","depends_on_id":"bd-febc","type":"parent-child","created_at":"2025-11-02T23:40:32.923859-08:00","created_by":"daemon"}]} {"id":"bd-bgca","content_hash":"c617d03baef137f2425cea14eb5346012e556b35e9048f0601fe8d719b5b705f","title":"Latency test manual","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-08T00:04:25.028223-08:00","updated_at":"2025-11-08T00:06:46.169654-08:00","closed_at":"2025-11-08T00:06:46.169654-08:00","source_repo":"."} -{"id":"bd-biwp","content_hash":"ece37e742d401489872e2735084fc94510f9308c3acff2659b233ab19440ebb4","title":"Support local-only git repos without remote origin","description":"Daemon crashes when working with local git repos that don't have origin remote configured. Should gracefully degrade to local-only mode: skip git pull/push operations but maintain daemon features (RPC server, auto-flush, JSONL export).","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2025-11-09T16:09:50.677769-08:00","updated_at":"2025-11-09T16:13:21.970934-08:00","external_ref":"gh#279","source_repo":"."} +{"id":"bd-biwp","content_hash":"ece37e742d401489872e2735084fc94510f9308c3acff2659b233ab19440ebb4","title":"Support local-only git repos without remote origin","description":"Daemon crashes when working with local git repos that don't have origin remote configured. Should gracefully degrade to local-only mode: skip git pull/push operations but maintain daemon features (RPC server, auto-flush, JSONL export).","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-09T16:09:50.677769-08:00","updated_at":"2025-11-09T16:16:56.588548-08:00","closed_at":"2025-11-09T16:16:56.588548-08:00","external_ref":"gh#279","source_repo":"."} {"id":"bd-buol","content_hash":"020dc9dbbd7f3e2b40c35f01bf8a65cf32ab419c188081493ea4e541bad1442e","title":"Invert control for compact: provide tools for agent-driven compaction","description":"Currently compact requires Anthropic API key because bd calls the AI directly. This is backwards - we should provide tools (like all other bd commands) that let an AI agent perform the compaction. The agent decides what to keep/merge, not bd. Related to GH #243 complaint about API key requirement.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-07T00:27:28.498069-08:00","updated_at":"2025-11-08T01:49:23.46152-08:00","closed_at":"2025-11-07T23:08:51.67473-08:00","source_repo":"."} {"id":"bd-by3x","content_hash":"80149be1ddf4ef26d5d56c444895be01ec8b59492c258c2365fa1c2619061bbd","title":"Windows binaries lack SQLite support (GH #253)","description":"Windows users installing via install.ps1 get \"sql: unknown driver sqlite\" error. Root cause: GoReleaser was building with CGO_ENABLED=0, which excludes SQLite driver.\n\nFixed by:\n1. Enabling CGO in .goreleaser.yml\n2. Installing MinGW cross-compiler in release workflow\n3. Splitting builds per platform to set correct CC for Windows\n\nNeeds new release to fix for users.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-07T15:54:13.134815-08:00","updated_at":"2025-11-07T15:55:07.024156-08:00","closed_at":"2025-11-07T15:55:07.024156-08:00","source_repo":"."} {"id":"bd-bzfy","content_hash":"90bbde4d90d68728a9377d5d966682dc836740f1be43a0cf80d3cc69002a560b","title":"Integrate beads-merge tool by @neongreen","description":"**Context**: @neongreen built a production-ready 3-way merge tool for JSONL files that works with both Git and Jujutsu. This is superior to our planned bd resolve-conflicts because it prevents conflicts proactively instead of resolving them after the fact.\n\n**Tool**: https://github.com/neongreen/mono/tree/main/beads-merge\n\n**What it does**:\n- 3-way merge of JSONL files (base, left, right)\n- Field-level merging (titles, status, priority, etc.)\n- Smart dependency merging (union + dedup)\n- Conflict markers for unresolvable conflicts\n- Exit code 1 for conflicts (standard)\n\n**Integration options**:\n\n1. **Recommend (minimal effort)** - Document in AGENTS.md + TROUBLESHOOTING.md\n2. **Bundle binary** - Include in releases (cross-platform builds)\n3. **Port to Go** - Reimplement in bd codebase\n4. **Auto-install hook** - During bd init, offer to install merge driver\n\n**Recommendation**: Start with option 1 (document), then option 2 (bundle) once proven.\n\n**Related**: bd-5f483051 (bd resolve-conflicts - can close as superseded)","notes":"Created GitHub issue to discuss integration approach with @neongreen: https://github.com/neongreen/mono/issues/240\n\nAwaiting their preference on:\n1. Vendor with attribution (fastest)\n2. Extract as importable module (best long-term)\n3. Keep as separate tool (current state)\n\nNext: Wait for response before proceeding with integration.\n\nUPDATE 2025-11-06: @neongreen gave permission to vendor! Quote: \"I switched from beads to my own thing (tk) so I'm very happy to give beads-merge away — feel free to move it into the beads repo and I will point mono's readme to beads\"\n\nNext: Vendor beads-merge with full attribution","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-11-05T11:31:44.906652-08:00","updated_at":"2025-11-06T18:19:16.233387-08:00","closed_at":"2025-11-06T15:38:37.052274-08:00","source_repo":"."} From b49f9b730e0b6f57c02b6ce7c62a760e223d8e5e Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 9 Nov 2025 16:26:35 -0800 Subject: [PATCH 3/3] File bd-77gm: Import command reports misleading count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Misleading '0 created, 0 updated' message when actually importing all issues on fresh database. Discovered during VC database sync. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .beads/beads.jsonl | 1 + 1 file changed, 1 insertion(+) diff --git a/.beads/beads.jsonl b/.beads/beads.jsonl index cd9a930e..30d7d841 100644 --- a/.beads/beads.jsonl +++ b/.beads/beads.jsonl @@ -181,6 +181,7 @@ {"id":"bd-74ee","content_hash":"476deaacd64c91c96e5c9aca9ba0640dcf0f3854f9f11bbaa25a8ae80af3adf3","title":"Frontend task","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-03T19:11:59.358631-08:00","updated_at":"2025-11-05T00:25:06.457813-08:00","closed_at":"2025-11-05T00:25:06.457813-08:00","source_repo":".","labels":["frontend","week1"]} {"id":"bd-763c","content_hash":"31265106d3d8856bdda09f00708f6efdda862abc97a14f8e2bcacc8535870099","title":"~/src/beads daemon has 'sql: database is closed' errors - zombie daemon","description":"","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-31T21:08:03.388007-07:00","updated_at":"2025-10-31T21:52:04.214274-07:00","closed_at":"2025-10-31T21:52:04.214274-07:00","source_repo":".","dependencies":[{"issue_id":"bd-763c","depends_on_id":"bd-2752a7a2","type":"discovered-from","created_at":"2025-10-31T21:08:03.388716-07:00","created_by":"stevey"}]} {"id":"bd-76cu","content_hash":"2236f911e6f321a74aa61bdf702d24949e44a68ed511d12dd011aa4103c89230","title":"Issue 2","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-07T19:04:21.562329-08:00","updated_at":"2025-11-08T02:06:40.397755-08:00","closed_at":"2025-11-08T02:06:40.397755-08:00","source_repo":"."} +{"id":"bd-77gm","content_hash":"b227320f0cf0c889a1e0d617922c572a48eee563c9afb1662b44a22e183c0c80","title":"Import reports misleading '0 created, 0 updated' when actually importing all issues","description":"When running 'bd import' on a fresh database (no existing issues), the command reports 'Import complete: 0 created, 0 updated' even though it successfully imported all issues from the JSONL file.\n\n**Steps to reproduce:**\n1. Delete .beads/beads.db\n2. Run: bd import .beads/issues.jsonl\n3. Observe output: 'Import complete: 0 created, 0 updated'\n4. Run: bd list\n5. Confirm: All issues are actually present in the database\n\n**Expected behavior:**\nReport the actual number of issues imported, e.g., 'Import complete: 523 created, 0 updated'\n\n**Actual behavior:**\n'Import complete: 0 created, 0 updated' (misleading - makes user think import failed)\n\n**Impact:**\n- Users think import failed when it succeeded\n- Confusing during database sync operations (e.g., after git pull)\n- Makes debugging harder (can't tell if import actually worked)\n\n**Context:**\nDiscovered during VC session when syncing database after git pull. The misleading message caused confusion about whether the database was properly synced with the canonical JSONL file.","acceptance_criteria":"- Import command reports accurate count of created/updated issues\n- Fresh database import shows 'N created' where N is the actual number\n- Update operations show 'N updated' where N is the actual number changed\n- Message clearly indicates success vs failure","status":"open","priority":2,"issue_type":"bug","created_at":"2025-11-09T16:20:13.191156-08:00","updated_at":"2025-11-09T16:20:13.191156-08:00","source_repo":"."} {"id":"bd-78w","content_hash":"dd79ef79bf68b3a87f3a5b8d50fdfba9d6c6f7e6d728713e37dd34cf9fff835e","title":"Test Epic 2","description":"## Overview\n\n[Describe the high-level goal and scope of this epic]\n\n## Success Criteria\n\n- [ ] Criteria 1\n- [ ] Criteria 2\n- [ ] Criteria 3\n\n## Background\n\n[Provide context and motivation]\n\n## Scope\n\n**In Scope:**\n- Item 1\n- Item 2\n\n**Out of Scope:**\n- Item 1\n- Item 2\n","design":"## Architecture\n\n[Describe the overall architecture and approach]\n\n## Components\n\n- Component 1: [description]\n- Component 2: [description]\n\n## Dependencies\n\n[List external dependencies or constraints]\n","acceptance_criteria":"- [ ] All child issues are completed\n- [ ] Integration tests pass\n- [ ] Documentation is updated\n- [ ] Code review completed\n","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-11-03T20:15:03.878216-08:00","updated_at":"2025-11-05T00:25:06.566242-08:00","closed_at":"2025-11-05T00:25:06.566242-08:00","source_repo":".","labels":["epic"]} {"id":"bd-7a00c94e","content_hash":"5ea01765a9fdf5c4c75f485b1db26c942eaaa762f1cdcb497306a78c65132721","title":"Rapid 2","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-29T19:11:57.430725-07:00","updated_at":"2025-11-08T01:49:23.458912-08:00","closed_at":"2025-11-07T23:18:52.352188-08:00","source_repo":"."} {"id":"bd-7a2b58fc","content_hash":"02b9e5c0f7a58576876637f09cf67a97d180686a216d53b15351ca2c099c8e5f","title":"Implement clone-scoped ID allocation to prevent N-way collisions","description":"## Problem\nCurrent ID allocation uses per-clone atomic counters (issue_counters table) that sync based on local database state. In N-way collision scenarios:\n- Clone B sees {test-1} locally, allocates test-2\n- Clone D sees {test-1, test-2, test-3} locally, allocates test-4\n- When same content gets assigned test-2 and test-4, convergence fails\n\nRoot cause: Each clone independently allocates IDs without global coordination, leading to overlapping assignments for the same content.\n\n## Solution\nAdd clone UUID to ID allocation to make every ID globally unique:\n\n**Current format:** `test-1`, `test-2`, `test-3`\n**New format:** `test-1-a7b3`, `test-2-a7b3`, `test-3-c4d9`\n\nWhere suffix is first 4 chars of clone UUID.\n\n## Implementation\n\n### 1. Add clone_identity table\n```sql\nCREATE TABLE clone_identity (\n clone_uuid TEXT PRIMARY KEY,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n### 2. Modify getNextIDForPrefix()\n```go\nfunc (s *SQLiteStorage) getNextIDForPrefix(ctx context.Context, prefix string) (string, error) {\n cloneUUID := s.getOrCreateCloneUUID(ctx)\n shortUUID := cloneUUID[:4]\n \n nextNum := s.getNextCounterForPrefix(ctx, prefix)\n return fmt.Sprintf(\"%s-%d-%s\", prefix, nextNum, shortUUID), nil\n}\n```\n\n### 3. Update ID parsing logic\nAll places that parse IDs (utils.ExtractIssueNumber, etc.) need to handle new format.\n\n### 4. Migration strategy\n- Existing IDs remain unchanged (no suffix)\n- New IDs get clone suffix automatically\n- Display layer can hide suffix in UI: `bd-cb64c226.3-a7b3` → `#42`\n\n## Benefits\n- **Zero collision risk**: Same content in different clones gets different IDs\n- **Maintains readability**: Still sequential numbering within clone\n- **No coordination needed**: Works offline, no central authority\n- **Scales to 100+ clones**: 4-char hex = 65,536 unique clones\n\n## Concerns\n- ID format change may break existing integrations\n- Need migration path for existing databases\n- Display logic needs update to hide/show suffixes appropriately\n\n## Success Criteria\n- 10+ clone collision test passes without failures\n- Existing issues continue to work (backward compatibility)\n- Documentation updated with new ID format\n- Migration guide for v1.x → v2.x\n\n## Timeline\nMedium-term (v1.1-v1.2), 2-3 weeks implementation\n\n## References\n- Related to bd-0dcea000 (immediate fix)\n- See beads_nway_test.go for failing N-way tests","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-29T20:02:47.952447-07:00","updated_at":"2025-11-06T19:36:13.971527-08:00","closed_at":"2025-11-06T19:27:29.41629-08:00","source_repo":"."}