Commit Graph

546 Commits

Author SHA1 Message Date
Steve Yegge
2e9b5a5870 Merge bd-xoyh-morsov: GH#517 2025-12-16 01:17:18 -08:00
Steve Yegge
60ae6586e7 Merge bd-zbyb-gusher: GH#509 worktrees 2025-12-16 01:16:46 -08:00
Steve Yegge
a518581a86 Merge bd-6xfz-furiosa: GH#405 prefix parsing 2025-12-16 01:16:26 -08:00
Steve Yegge
40c6893f33 Merge bd-er7r-derrick: GH#444 status naming 2025-12-16 01:15:36 -08:00
Steve Yegge
11c3bb4fdb Merge bd-0yzm-ace: GH#522 --type flag for bd update 2025-12-16 01:15:11 -08:00
Steve Yegge
77aeb50d27 fix(utils): parse multi-hyphen prefixes correctly (GH#405)
The ExtractIssuePrefix function was falling back to first-hyphen
extraction when the suffix didn't look like a hash (e.g., 4+ char
words without digits). This broke prefixes like 'hacker-news' where
an issue ID 'hacker-news-test' would incorrectly extract 'hacker'.

Fix: Always use last-hyphen extraction for alphanumeric suffixes.
Only fall back to first-hyphen for non-alphanumeric suffixes.

Examples:
- 'hacker-news-test' -> 'hacker-news' (was: 'hacker')
- 'me-py-toolkit-abc' -> 'me-py-toolkit' (was: 'me')
- 'vc-baseline-hello' -> 'vc-baseline' (was: 'vc')

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 01:13:15 -08:00
Steve Yegge
7d35ced5ae feat(update): add --type flag to bd update command (GH#522)
Allow changing an issue type (bug, feature, task, epic, chore) via the
bd update command. The storage layer already supported issue_type in
allowedUpdateFields, this just exposes it through the CLI.

Changes:
- Add --type/-t flag to updateCmd in show.go
- Add IssueType field to UpdateArgs in protocol.go
- Handle issue_type in updatesFromArgs in server_issues_epics.go
- Add validation using ParseIssueType before update

Example usage:
  bd update ab-xyz --type epic

Fixes: #522
2025-12-16 01:08:11 -08:00
Steve Yegge
0c9e78f42e fix: improve priority format documentation and error message (GH#517)
Claude was using word-based priorities like "medium" instead of numeric
values (0-4 or P0-P4), causing bd create commands to fail in a loop.

Changes:
- Update bd prime output to clearly document priority format with example
- Add explicit note: NOT "high"/"medium"/"low"
- Improve error message to mention that words are not valid

Closes #517

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 01:07:55 -08:00
Steve Yegge
de75e5181c feat(sync): improve divergence recovery UX (bd-vckm)
When sync branch diverges significantly from remote, provide clear
recovery options instead of a confusing rebase conflict error.

- Add CheckDivergence() to detect and report sync branch divergence
- Add ResetToRemote() to reset local sync branch to remote state
- Add --reset-remote and --force-push flags for recovery
- Improve error message when rebase fails to include recovery steps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 01:07:34 -08:00
Steve Yegge
39e09449cc fix: orphan detection false positive with dots in directory name
Only treat issue IDs as hierarchical (parent.child) when the dot appears
AFTER the first hyphen. This prevents false positives when the project
directory name contains a dot (e.g., "my.project-abc123" was incorrectly
being treated as having parent "my").

Fixes GH#508

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 01:06:14 -08:00
Steve Yegge
2c86404d65 fix: resolve P2 sync noise and cleanup issues
- bd-6pni: Auto-filter tombstoned issues with mismatched prefixes during
  import instead of failing. Tombstones from contributor PRs with different
  test prefixes are pollution and safe to ignore.

- bd-ffr9: Stop recreating deletions.jsonl after tombstone migration.
  Added IsTombstoneMigrationComplete() check to all code paths that write
  to the legacy deletions manifest.

- bd-admx: Fix perpetual "JSONL file hash mismatch" warning. Now clears
  both export_hashes AND jsonl_file_hash when mismatch detected, so the
  warning doesn't repeat.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 00:56:06 -08:00
Steve Yegge
8c45069228 fix(doctor,sync): clean up deletions manifest and reduce sync noise
- bd-8v5o: When doctor --fix hydrates issues from git history, also
  remove them from the deletions manifest to prevent perpetual skip
  warnings during sync

- bd-wsqt: Remove verbose per-issue "Skipping bd-xxx" messages during
  sync. Caller already shows summary of skipped issues.

Added RemoveDeletions() function to deletions package with tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 00:42:36 -08:00
Steve Yegge
171f7de250 Merge pull request #584 from rsnodgrass/repair-hashes
fix(rename-prefix): use hash IDs instead of sequential in --repair mode
2025-12-16 00:42:32 -08:00
Steve Yegge
4657ec7640 Merge pull request #569 from crcatala/feature/daemon-status-config
feat(daemon): show configuration in `bd daemon --status` output
2025-12-16 00:35:07 -08:00
Steve Yegge
07fc9bf094 Merge pull request #564 from deblasis/fix-daemon-stale-cache
fix(daemon): detect external db file replacement
2025-12-16 00:34:57 -08:00
Ryan Snodgrass
627ac1afb8 fix(import): skip cross-prefix content matches instead of triggering rename
When importing issues, if an incoming issue has the same content hash as an
existing issue but a DIFFERENT prefix, this should not be treated as a rename.
Cross-prefix content matches occur when importing issues from other projects
that happen to have identical content.

Previously, the importer would call handleRename which tries to create an issue
with the incoming prefix, failing prefix validation ("does not match configured
prefix" error).

The fix checks if prefixes differ before calling handleRename:
- Same prefix, different ID suffix → true rename, call handleRename
- Different prefix → skip incoming issue, keep existing unchanged

Added test: TestImportCrossPrefixContentMatch reproduces the bug scenario
where alpha-* issues exist but beta-* issues are imported with same content.
2025-12-16 00:29:19 -08:00
Ryan Snodgrass
421d41dfa0 docs: add detailed comments explaining ID formats and merge deletion logic
Document the intent and nuances of recent fixes:

internal/importer/utils.go:
- RenameImportedIssuePrefixes: explain the three ID formats (sequential,
  hash-based, hierarchical) and how prefix renaming preserves identity
- isValidIDSuffix: document why dots are allowed (hierarchical parent-child
  relationships) and what characters are rejected

cmd/bd/deletion_tracking.go:
- isIssueNotFoundError: explain why "not found" is success during merge
  (issue may be tombstoned, never existed locally, or manually deleted)
- Deletion loop: document what "accepted deletions" means and why we
  tolerate missing issues during the pruning phase
2025-12-16 00:17:40 -08:00
Ryan Snodgrass
c7b45a8a40 fix(import): support hierarchical hash IDs in --rename-on-import
The isNumeric function was rejecting valid hierarchical hash IDs like
'6we.2' that contain dots for parent.child notation. This caused
`bd import --rename-on-import` to fail with "non-numeric suffix" errors.

Changes:
- Rename isNumeric to isValidIDSuffix for clarity
- Accept dots (.) in addition to alphanumeric for hierarchical IDs
- Update test cases to cover hierarchical ID formats
2025-12-16 00:12:10 -08:00
Charles P. Cross
a69e94a958 Auto-disable daemon in git worktrees for safety (#567)
* feat: auto-disable daemon in git worktrees for safety

Implement worktree daemon compatibility as proposed in the analysis.
The daemon is now automatically disabled when running in a git worktree
unless sync-branch is configured.

Git worktrees share the same .beads directory, and the daemon commits
to whatever branch its working directory has checked out. This causes
commits to go to the wrong branch when using daemon in worktrees.

- Add shouldDisableDaemonForWorktree() helper that checks:
  1. If current directory is a git worktree (via git rev-parse)
  2. If sync-branch is configured (env var or config.yaml)
- Modify shouldAutoStartDaemon() to call the helper
- Modify daemon connection logic in main.go to skip connection
- Add FallbackWorktreeSafety constant for daemon status reporting
- Update warnWorktreeDaemon() to skip warning when sync-branch configured

- In worktree WITHOUT sync-branch: daemon auto-disabled, direct mode used
- In worktree WITH sync-branch: daemon enabled (commits go to dedicated branch)
- In regular repo: no change (daemon works as before)

- Added comprehensive unit tests for shouldDisableDaemonForWorktree()
- Added integration tests for shouldAutoStartDaemon() in worktree contexts
- Manual E2E testing verified correct behavior

- Updated WORKTREES.md with new automatic safety behavior
- Updated DAEMON.md with Git Worktrees section

* feat: check database config for sync-branch in worktree safety logic

Previously, the worktree daemon safety check only looked at:
- BEADS_SYNC_BRANCH environment variable
- sync-branch in config.yaml

This meant users who configured sync-branch via `bd config set sync-branch`
(which stores in the database) would still have daemon disabled in worktrees.

Now the check also reads sync.branch from the database config table,
making daemon work in worktrees when sync-branch is configured via any method.

Changes:
- Add IsConfiguredWithDB() function that checks env, config.yaml, AND database
- Add findBeadsDB() to locate database (worktree-aware via git-common-dir)
- Add getMainRepoRoot() helper using git rev-parse
- Add getConfigFromDB() for lightweight database reads
- Update shouldDisableDaemonForWorktree() to use IsConfiguredWithDB()
- Update warnWorktreeDaemon() to use IsConfiguredWithDB()
- Add test case for database config path

* refactor: use existing beads.FindDatabasePath() instead of duplicating code

Remove duplicate getMainRepoRoot() and findBeadsDB() functions from
syncbranch.go and use the existing beads.FindDatabasePath() which is
already worktree-aware.

Changes:
- Replace custom findBeadsDB() with beads.FindDatabasePath()
- Remove duplicate getMainRepoRoot() (git.GetMainRepoRoot() exists)
- Remove unused imports (exec, strings, filepath)
- Clean up debug logging in tests

---------

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-16 00:06:19 -08:00
Alessandro De Blasis
78c248a17a fix(daemon): detect external db file replacement
When git merge replaces the .beads/beads.db file, the daemon's
SQLite connection becomes stale (still reading deleted inode).
This adds FreshnessChecker that detects file replacement via
inode/mtime comparison and triggers automatic reconnection.

Implementation:
- freshness.go: monitors db file for replacement
- store.go: adds EnableFreshnessChecking() and reconnect()
- queries.go: calls checkFreshness() on GetIssue/SearchIssues
- daemon.go: enables freshness checking at startup
- freshness_test.go: comprehensive tests including merge scenario

Code quality (per review):
- Extract configureConnectionPool() helper to reduce duplication
- Handle Close() error in reconnect() (log but continue)
- Use t.Cleanup() pattern in tests per project conventions
- Rename setupFreshnessTest() per naming conventions

Overhead: ~2.6μs per read op (~0.8% of total query time)

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 06:29:59 +01:00
matt wilkie
cd3b0e30be bd-ckej: fix orphan skip count mismatch on fresh import (#572)
* bd-ckej: fix orphan skip count mismatch on fresh import

When OrphanSkip mode is used during import and a child issue's parent doesn't
exist, the issue ID was cleared to '' but then regenerated anyway in
GenerateBatchIssueIDs, causing it to be created in the database. This resulted
in a count mismatch: JSONL had 824 issues but only 823 were in the database (one
orphan was counted but not created).

Fix: Filter out orphaned issues with empty IDs before batch creation and track
them in result.Skipped so the count stays accurate.

* test: add TestImportOrphanSkip_CountMismatch for bd-ckej

Adds comprehensive test that verifies orphaned issues are properly skipped
during import when orphan_handling=OrphanSkip and parent doesn't exist.

Also improves the fix to pre-filter orphaned issues before batch creation,
ensuring they're not inserted then have IDs cleared (preventing count
mismatches).

---------

Co-authored-by: Amp <amp@example.com>
2025-12-15 21:17:32 -08:00
cc-vps
4e87ae18e5 feat: show daemon config in 'bd daemon --status' output
Add auto-commit, auto-push, local mode, sync interval, and daemon mode
to the status output when querying a running daemon.

This helps users understand the current daemon configuration without
having to check logs or remember what flags were used at startup.

Changes:
- Add config fields to StatusResponse in protocol.go
- Add SetConfig() method to Server for daemon to set its config
- Update handleStatus() to include config in response
- Update showDaemonStatus() to query and display config via RPC
- Add comprehensive test coverage for new functionality

Co-authored-by: Christian Catalan <crcatala@gmail.com>
2025-12-15 09:03:20 -08:00
Steve Yegge
8e58c306a7 fix(sync,blocked): add safety guards for issue deletion and include status=blocked in bd blocked
GH#464: Add safety guards to prevent deletion of open/in_progress issues during sync:
- Safety guard in git-history-backfill (importer.go)
- Safety guard in deletions manifest processing
- Warning when uncommitted changes detected before pull (daemon_sync.go)
- Enhanced repo ID mismatch error message

GH#545: Fix bd blocked to show status=blocked issues (sqlite/ready.go):
- Changed from INNER JOIN to LEFT JOIN to include issues without dependencies
- Added WHERE clause to include both status=blocked AND dependency-blocked issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 23:07:54 -08:00
Steve Yegge
7535dc88d2 fix(lint): resolve all golangci-lint errors
- Mark unused ctx parameter with underscore in getRepoRootForWorktree
- Replace exec.Command("test", "-d") with os.Stat for directory check
- Handle file.Close() errors properly in compact.go and migrate_tombstones.go
- Explicitly ignore cleanup errors with _ assignment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 22:36:51 -08:00
Steve Yegge
f83a8f5a38 fix(ci): update nix vendorHash and fix integration test compilation
- Update default.nix vendorHash to match current go.mod dependencies
- Fix NewSQLiteStorage calls to include required context.Context parameter
- Rename duplicate runCmd to runGitCmd in routing_integration_test.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 22:18:10 -08:00
Steve Yegge
fb20e43f5f fix(orphan): handle prefixes with dots in orphan detection (GH#508)
The orphan detection was incorrectly flagging issues with dots in their
prefix (e.g., "my.project-abc123") as orphans because it was looking for
any dot in the ID, treating everything before the first dot as the
parent ID.

The fix:
- Add IsHierarchicalID() helper that correctly detects hierarchical IDs
  by checking if the ID ends with .{digits} (e.g., "bd-abc.1")
- Update SQL query in orphan detection migration to use GLOB patterns
  that only match IDs ending with numeric suffixes
- Update all Go code that checks for hierarchical IDs to use the new
  helper function

Test cases added:
- Unit tests for IsHierarchicalID covering normal, dotted prefix, and
  edge cases
- Integration test verifying dotted prefixes do not trigger false
  positives

Fixes: #508
2025-12-14 17:23:46 -08:00
Steve Yegge
82dc06eb84 feat(update): add --type flag to bd update command
Allows changing issue type (task/epic/bug/feature/chore) via bd update --type.
Storage layer already supported it, this adds CLI and RPC support.

Fixes GH#522.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 17:22:42 -08:00
Steve Yegge
17389d0eb4 fix(sync): handle sync.branch == current branch (GH#519)
When sync.branch is configured to the same branch as the current branch,
git worktree creation fails because the same branch cannot be checked out
in multiple locations.

This fix detects when sync.branch equals the current branch and falls back
to direct commits on the current branch instead of using the worktree-based
approach.

Changes:
- Add IsSyncBranchSameAsCurrent() helper in syncbranch package
- Add GetCurrentBranch() helper function
- Update sync.go to detect this case and skip worktree operations
- Add unit tests for the new functionality

Closes #519

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 17:20:47 -08:00
Steve Yegge
69d14e21d8 fix(git): find .beads from nested worktrees (GH#509)
When worktrees are nested under the main repo (e.g.,
/project/.worktrees/feature/), bd now correctly finds .beads/ in the
parent repo.

The fix simplifies GetMainRepoRoot() to use `git rev-parse --git-common-dir`
which always returns the main repo's .git directory, regardless of whether
we're in a regular repo, a worktree, or a nested worktree.

- Simplified GetMainRepoRoot() implementation
- Added tests for nested worktree scenarios
- Updated CHANGELOG.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 17:20:46 -08:00
Steve Yegge
6f3309b304 test(lockfile): improve coverage from 42% to 98%
- Add TestTryDaemonLock with 6 test cases for lock detection scenarios
- Add TestFlockFunctions for blocking/non-blocking lock operations
- Add TestIsProcessRunning for process detection edge cases
- Fix TestCheckPIDFile/current_process_is_running (was using invalid PID encoding)

Closes bd-9w3s
2025-12-14 15:21:29 -08:00
Steve Yegge
a60972cd6a Merge remote-tracking branch 'origin/main' into performance-fix 2025-12-14 14:53:30 -08:00
cbro
2651620a4c fix(storage): persist close_reason to issues table on close (#551)
CloseIssue was storing the reason only in the events table, not in the
issues.close_reason column. This caused `bd show --json` to return an
empty close_reason even when one was provided.

- Update CloseIssue in queries.go and transaction.go to set close_reason
- Clear close_reason when reopening issues (in manageClosedAt)
- Add tests for close_reason in storage and CLI JSON output
- Document the dual-storage of close_reason (issues + events tables)
2025-12-14 14:18:01 -08:00
Ryan Snodgrass
f88a0d015b feat(cli): add 'bd thanks' command to thank contributors
Adds a new command that displays a thank you page listing all human
contributors to the beads project. Features:

- Static list of contributors (compiled into binary)
- Top 20 featured contributors displayed in columns
- Additional contributors in wrapped list
- Styled output using lipgloss (colored box, sections)
- Dynamic width based on content
- JSON output support (--json flag)
- Excludes bots and AI agents by email pattern
2025-12-14 12:40:32 -08:00
Steve Yegge
a61ca252ae fix(cleanup): resolve CHECK constraint failure and add tombstone pruning
- Fix bd-tnsq: executeDelete now sets closed_at=NULL when creating
  tombstones, satisfying the CHECK constraint that requires
  closed_at IS NULL when status != 'closed'

- Fix bd-08ea: cleanup command now also prunes expired tombstones
  (older than 30 days) after converting closed issues to tombstones

- Add regression test for batch deletion of closed issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 00:37:54 -08:00
Steve Yegge
9db756f8b6 fix(memory): implement GetReadyWork/GetBlockedIssues + child counters
Fixes #543, #544, #545, #546 (no-db mode regressions)

Memory backend fixes:
- GetReadyWork now properly excludes issues with open blocks dependencies
- GetBlockedIssues now includes issues with status=blocked (even with 0 blockers)
- LoadFromIssues initializes hierarchical child counters from existing IDs
  so repeated --parent creates bd-xxx.1, bd-xxx.2, etc.

JSONL path discovery:
- findJSONLPath works in no-db mode when dbPath is empty
- Honors BEADS_JSONL environment variable override
- Falls back to locating .beads directory

Based on PR #547 by @joelklabo - cherry-picked core fixes.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-13 23:22:10 -08:00
Steve Yegge
e7991b9334 fix: add retry with rebase for concurrent push conflicts
When multiple polecats run bd sync simultaneously, they race to push to
the shared beads-sync branch. Previously this caused non-fast-forward
errors that blocked all polecats.

Now pushFromWorktree:
- Detects non-fast-forward errors from git push output
- On conflict: fetches remote, rebases local commits on top, retries
- Uses exponential backoff for transient failures (up to 5 retries)
- Aborts rebase cleanly if it fails to leave worktree in good state

Fixes gt-zqor.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 20:42:45 -08:00
Steve Yegge
fc23dca7fb feat(cli): add --lock-timeout flag for SQLite busy_timeout control (#536)
Implements single-shot mode improvements for Windows and Docker scenarios:

- Add --lock-timeout global flag (default 30s, 0 = fail immediately)
- Add config file support: lock-timeout: 100ms
- Parameterize SQLite busy_timeout via NewWithTimeout() function
- In --sandbox mode: default lock-timeout to 100ms
- In --sandbox mode: skip FlushManager creation (no background goroutines)

This addresses bd.exe hanging on Windows and locking conflicts when
using beads across host + Docker containers.

Closes: bd-59er, bd-r4od, bd-dh8a

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 18:07:49 -08:00
matt wilkie
e01b7412d9 feat: add Git worktree compatibility (PR #478)
Adds comprehensive Git worktree support for beads issue tracking:

Core changes:
- New internal/git/gitdir.go package for worktree detection
- GetGitDir() returns proper .git location (main repo, not worktree)
- Updated all hooks to use git.GetGitDir() instead of local helper
- BeadsDir() now prioritizes main repository's .beads directory

Features:
- Hooks auto-install in main repo when run from worktree
- Shared .beads directory across all worktrees
- Config option no-install-hooks to disable auto-install
- New bd worktree subcommand for diagnostics

Documentation:
- New docs/WORKTREES.md with setup instructions
- Updated CHANGELOG.md and AGENT_INSTRUCTIONS.md

Testing:
- Updated tests to use exported git.GetGitDir()
- Added worktree detection tests

Co-authored-by: Claude <noreply@anthropic.com>
Closes: #478
2025-12-13 12:50:33 -08:00
Charles P. Cross
eb988fcb21 Fix daemon auto-sync delete mutation not reflected in sync branch (#537)
Fix daemon auto-sync delete mutation not reflected in sync branch

When deleting an issue with `bd delete <id> --force`, the daemon auto-sync now properly removes the deleted issue from the sync branch.

**Problem:** The merge logic saw fewer local issues (due to deletion) and would re-add the deleted issue.

**Solution:** Add `ForceOverwrite` option to bypass merge logic when mutations occur. Mutation-triggered exports are authoritative and should overwrite, not merge.

Reviewed-by: stevey
2025-12-13 10:53:09 -08:00
Steve Yegge
a612c575f9 fix(sync): include tombstones when building ID map during import
The importer was not seeing tombstones when building the dbByID map,
causing it to treat tombstone IDs as "new" issues. This led to UNIQUE
constraint violations during INSERT.

- Include tombstones in SearchIssues call (IncludeTombstones: true)
- Skip tombstones when matching by ID instead of trying to update them

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 10:20:22 -08:00
Steve Yegge
2c6748fd59 fix(tombstone): clear closed_at when converting closed issue to tombstone
When CreateTombstone was called on a closed issue, the CHECK constraint
(status = closed) = (closed_at IS NOT NULL) was violated because
closed_at was not cleared. Now setting closed_at = NULL in the UPDATE.

Added regression test for creating tombstone from closed issue.

Fixes: bd-fi05

Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 07:31:16 -08:00
Steve Yegge
18b1eb2e07 fix(sqlite): handle deleted_at TEXT column scanning properly
The deleted_at column was defined as TEXT in the schema but code was
trying to scan into sql.NullTime. The ncruces/go-sqlite3 driver only
auto-converts TEXT to time.Time for columns declared as DATETIME/DATE/
TIME/TIMESTAMP. For TEXT columns, it returns raw strings which
sql.NullTime.Scan() cannot handle.

Added parseNullableTimeString() helper that manually parses time strings
and changed all deletedAt variables from sql.NullTime to sql.NullString.

Fixes import failure: "sql: Scan error on column index 22, name
deleted_at: unsupported Scan, storing driver.Value type string into
type *time.Time"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 07:13:40 -08:00
Ryan
335887e000 perf: fix stale startlock delay and add comprehensive benchmarks (#484)
* fix(daemon): check for stale startlock before waiting 5 seconds

When a previous daemon startup left behind a bd.sock.startlock file
(e.g., from a crashed process), the code was waiting 5 seconds before
checking if the lock was stale. This caused unnecessary delays on
every bd command when the daemon wasn't running.

Now checks if the PID in the startlock file is alive BEFORE waiting.
If the PID is dead or unreadable, the stale lock is cleaned up
immediately and lock acquisition is retried.

Fixes ~5s delay when startlock file exists from crashed process.

* perf: add benchmarks for large descriptions, bulk operations, and sync merge

Added three new performance benchmarks to identify bottlenecks in common operations:

1. BenchmarkLargeDescription - Tests handling of 100KB+ issue descriptions
   - Measures string allocation/parsing overhead
   - Result: 3.3ms/op, 874KB/op allocation

2. BenchmarkBulkCloseIssues - Tests closing 100 issues sequentially
   - Measures batch write performance
   - Result: 1.9s total, shows write amplification

3. BenchmarkSyncMerge - Tests JSONL merge cycle with creates/updates
   - Simulates real sync operations (10 creates + 10 updates per iteration)
   - Result: 29ms/op, identifies sync bottlenecks

Added BENCHMARKS.md documentation describing:
- How to run benchmarks with various options
- All available benchmark categories
- Performance targets on M2 Pro hardware
- Dataset caching strategy
- CPU profiling integration
- Optimization workflow

This completes performance testing coverage for previously unmeasured scenarios.

* docs: clarify daemon lock acquisition logic in comments

Improve comments to clarify that acquireStartLock does both:
1. Immediately check for stale locks from crashed processes (avoids 5s delay)
2. If PID is alive, properly wait for legitimate daemon startup (5s timeout)

No code changes - only clarified comment documentation for maintainability.

---------

Co-authored-by: Steve Yegge <steve.yegge@gmail.com>
2025-12-13 06:57:11 -08:00
Ryan Stortz
4254c3f2f5 feat(config): add BD_NO_INSTALL_HOOKS environment variable to disable git hook installation (#500)
* feat(config): add no-install-hooks config to disable git hook installation

Add `no-install-hooks` boolean config that prevents git hook installation
during `bd init`. This can be set via:
- Environment variable: BD_NO_INSTALL_HOOKS=1
- Global config: ~/.config/bd/config.yaml with `no-install-hooks: true`
- Local config: .beads/config.yaml with `no-install-hooks: true`

The existing `--skip-hooks` flag continues to work and takes precedence.
Default behavior unchanged: hooks install by default.

* docs: add no-install-hooks to configuration documentation

- Add no-install-hooks to Supported Settings table in CONFIG.md
- Add example in config file section
- Add "Disabling Hook Installation" section to GIT_INTEGRATION.md
  with examples for flag, env var, and config file methods
2025-12-13 06:38:26 -08:00
Steve Yegge
2fd1d1fb87 fix: resolve golangci-lint warnings
- Handle ignored errors with explicit _ assignment (errcheck)
- Add #nosec comments for false positive G304/G204 warnings (gosec)
- Fix misspelling: cancelled -> canceled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 10:07:36 +11:00
Steve Yegge
88153f224f feat(reset): implement bd reset CLI command with unit tests
Implements the bd reset command for GitHub issue #479:
- CLI command with flags: --hard, --force, --backup, --dry-run, --skip-init, --verbose
- Impact summary showing issues/tombstones to be deleted
- Confirmation prompt (skippable with --force)
- Colored output for better UX
- Unit tests for reset.go and git.go
- Fix: use --force flag in git rm to handle staged files

Part of epic bd-aydr.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 10:00:47 +11:00
Steve Yegge
ca9d306ef0 feat(reset): implement core reset package for bd reset command
Phase 1 implementation of bd reset (GitHub #479):

- internal/reset/reset.go: Core reset logic with ResetOptions, ResetResult,
  ImpactSummary structs. Handles daemon killing, backup, file removal,
  git operations, and re-initialization.

- internal/reset/backup.go: CreateBackup() for timestamped .beads/ backups
  with permission preservation.

- internal/reset/git.go: Git state detection and operations for --hard mode.
  CheckGitState(), GitRemoveBeads(), GitCommitReset(), GitAddAndCommit().

- cmd/bd/doctor/gitignore.go: Add .beads-backup-*/ to gitignore template.

Code review fixes applied:
- Git rm now runs BEFORE file deletion (was backwards)
- Removed stderr output from core package (CLI-agnostic)
- IsDirty now checks only .beads/ changes, not entire repo
- GitCommitReset handles nothing to commit gracefully
2025-12-13 09:47:26 +11:00
Rod Davenport
6985ea94e5 fix(sync): protect local issues from git-history-backfill during sync (#485)
Fix sync bug where newly created issues were incorrectly tombstoned during bd sync.

The root cause was git-history-backfill finding issues in local commits on the sync branch, then tombstoning them when they weren't in the merged JSONL. The fix protects issues from the left snapshot (local export) from git-history-backfill.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-12-12 13:28:48 -08:00
Charles P. Cross
8af08460a7 Enable daemon RPC support for delete operations to trigger auto-sync, Fix for issue #527 (#528)
Enable daemon RPC support for delete operations to trigger auto-sync.

This PR adds delete operation support to the RPC daemon, ensuring that delete operations emit mutation events and trigger auto-sync like other mutating operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-12-12 13:19:31 -08:00
Steve Yegge
08d8353619 feat(tombstones): add migrate-tombstones command and compact pruning
- Add bd migrate-tombstones command (bd-8f9) to convert legacy
  deletions.jsonl entries to inline tombstones in issues.jsonl
  - Supports --dry-run to preview changes
  - Supports --verbose for detailed progress
  - Archives deletions.jsonl with .migrated suffix after migration

- Update bd compact to prune expired tombstones (bd-okh)
  - All compact modes now prune tombstones older than 30-day TTL
  - Reports count of pruned tombstones in output

- Add resurrection merge test (bd-bob)
  - Tests scenario where base is tombstone but both left/right resurrect

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:34:35 +11:00