Commit Graph

1707 Commits

Author SHA1 Message Date
beads/crew/jane
1676f0de45 Merge origin/main into db/fix-2 (resolve conflicts) 2026-01-20 19:49:12 -08:00
beads/crew/elinor
4b2d1791ee refactor(hooks): consolidate duplicate JSONL file lists into shared constant
- Add jsonlFilePaths constant to eliminate duplicate file list definitions
- Update all usages in hook.go and hooks.go to use the shared constant
- Include beads.jsonl for backwards compatibility with older installations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:15:18 -08:00
beads/crew/lizzy
2fe15e2328 feat(hooks): add jujutsu (jj) version control support
Add detection and hook support for jujutsu repositories:

- IsJujutsuRepo(): detects .jj directory
- IsColocatedJJGit(): detects colocated jj+git repos
- GetJujutsuRoot(): finds jj repo root

For colocated repos (jj git init --colocate):
- Install simplified hooks without staging (jj auto-commits working copy)
- Worktree handling preserved for git worktrees in colocated repos

For pure jj repos (no git):
- Print alias instructions since jj doesn't have native hooks yet

Closes: hq-ew1mbr.12

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:13:02 -08:00
beads/crew/wickham
e00f013bda feat(activity): use fsnotify for real-time feed (hq-ew1mbr.17)
Replace polling with filesystem watching for near-instant wake-up
(<50ms vs 250ms avg). Watches .beads/dolt/.dolt/noms for Dolt commits.
Falls back to polling if fsnotify unavailable.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:07:26 -08:00
beads/crew/wickham
a3ef7722f9 feat(cmd): add 'bd children <id>' command (bd-scbxh)
Convenience alias for 'bd list --parent <id>'. Lists all child beads
of a specified parent, supporting all standard list flags (--json,
--pretty, etc.).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:07:26 -08:00
beads/crew/emma
d72f37551b feat(rename): add bd rename command for renaming issue IDs
Add new `bd rename <old-id> <new-id>` command that:
- Updates the issue's primary ID
- Updates text references in other issues (title, description, etc.)
- Handles dependencies via storage layer's UpdateIssueID

Also fix sync.go build error where hasSyncBranchConfig/syncBranchName
were referenced but not defined - should use sbc.IsConfigured()/sbc.Branch.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 18:49:44 -08:00
Dustin Brown
d3ccd5cfba Fix Dolt backend init/daemon/doctor; prevent accidental SQLite artifacts; add integration tests; clean up lint (#1218)
* /{cmd,internal}: get dolt backend init working and allow issue creation

* /{website,internal,docs,cmd}: integration tests and more split backend fixes

* /{cmd,internal}: fix lint issues

* /cmd/bd/doctor/integrity.go: fix unable to query issues bug with dolt backend

* /cmd/bd/daemon.go: remove debug logging
2026-01-20 17:34:00 -08:00
Test
7ed6849d19 /{cmd,docs,internal,website}: make dolt backend explicitly single process 2026-01-20 16:51:14 -08:00
coffeegoddd☕️✨
47a31a3e6e /cmd/bd/daemon.go: remove debug logging 2026-01-20 14:08:58 -08:00
Roland Tritsch
c1ac69da3e feat(mol): add 'bd mol seed --patrol' command (#1149)
* Fix doctor DB-JSONL sync check to exclude ephemeral wisps

The DB-JSONL Sync check was showing a false positive warning when wisps
(ephemeral issues) existed in the database. Wisps are intentionally
excluded from JSONL exports, so they shouldn't be counted when comparing
database and JSONL issue counts.

Changes:
- Updated CheckDatabaseJSONLSync to exclude ephemeral issues from count
  using 'WHERE ephemeral = 0 OR ephemeral IS NULL'
- Added 'ephemeral' column to test database schema
- Added test case to verify ephemeral issues are excluded from count
- Updated TestCheckDatabaseJSONLSync_MoleculePrefix to include ephemeral column

This prevents false warnings like 'database has 92 issues, JSONL has 30'
when the difference is entirely due to wisps that should not be exported.

* feat(mol): add 'bd mol seed --patrol' command

Adds `bd mol seed` command to verify formula accessibility before
patrols attempt to spawn work.

## Problem

Gas Town's `gt rig add` calls `bd mol seed --patrol` but this command
didn't exist in beads, causing the call to always fail and fall back
to creating non-functional placeholder beads.

## Solution

Implemented `bd mol seed` with two modes:

1. **With --patrol flag**: Verifies all three patrol formulas are accessible
   - mol-deacon-patrol
   - mol-witness-patrol
   - mol-refinery-patrol

2. **Without --patrol**: Verifies a specific formula is accessible

## Implementation

The command uses `resolveAndCookFormulaWithVars` to verify formulas:
- Checks formula search paths (.beads/formulas/, ~/.beads/formulas/, $GT_ROOT/.beads/formulas/)
- Validates formula syntax and resolution
- Confirms formula can be cooked to subgraph

## Usage

```bash
bd mol seed --patrol                    # Verify all patrol formulas
bd mol seed mol-feature                 # Verify specific formula
bd mol seed mol-review --var name=test  # With variable substitution
```

## Testing

-  Command compiles without errors
-  Help text displays correctly
-  `--patrol` succeeds when formulas accessible (town level)
-  `--patrol` fails with clear error when formulas missing (rig level)
-  Follows existing beads command patterns (cobra, flags, error handling)

## Impact

- Enables Gas Town's intended patrol formula verification flow
- Eliminates creation of unnecessary placeholder beads
- Provides health check command for formula accessibility
- Foundation for future seed commands (data initialization, etc.)

Fixes the missing command referenced in steveyegge/gastown#715

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Roland Tritsch <roland@ailtir.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-20 14:06:57 -08:00
Roland Tritsch
09355eee8c Add --gastown flag to bd doctor for gastown-specific checks (#1162)
When running in gastown multi-workspace mode, two checks produce false
positives that are expected behavior:

1. routes.jsonl is a valid configuration file (maps issue prefixes to
   rig directories), not a duplicate JSONL file
2. Duplicate issues are expected (ephemeral wisps from patrol cycles)
   and normal up to ~1000, with GC cleaning them up automatically

This commit adds flags to bd doctor for gastown-specific checks:
- --gastown: Skip routes.jsonl warning and enable duplicate threshold
- --gastown-duplicates-threshold=N: Set duplicate tolerance (default 1000)

Fixes false positive warnings:
  Multiple JSONL files found: issues.jsonl, routes.jsonl
  70 duplicate issue(s) in 30 group(s)

Changes:
- Add --gastown flag to bd doctor command
- Add --gastown-duplicates-threshold flag (default: 1000)
- Update CheckLegacyJSONLFilename to skip routes.jsonl when gastown mode active
- Update CheckDuplicateIssues to use configurable threshold when gastown mode active
- Add test cases for gastown mode behavior with various thresholds

Co-authored-by: Roland Tritsch <roland@ailtir.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-20 14:06:53 -08:00
John Zila
f336e669e9 fix(sync): use sync-branch worktree for --full --no-pull (#1183)
* fix(sync): use sync-branch worktree for --full --no-pull (#1173)

Bug 1: PullFromSyncBranch was copying uncommitted worktree changes to
main repo when remoteAhead==0. This corrupted the 3-way merge because
local changes appeared as remote changes. Fixed by copying only the
committed state from HEAD instead of the working directory.

Bug 2: doExportOnlySync was checking main repo for changes via
gitHasBeadsChanges, but when sync-branch is configured, changes go to
the worktree, not main. Fixed by detecting sync-branch config and using
CommitToSyncBranch which operates on the worktree.

Fixes #1173

* refactor(sync): consolidate sync-branch detection and commit/push logic

Extract repeated patterns into reusable helpers:

- SyncBranchContext struct: holds branch name and repo root
- getSyncBranchContext(): detects sync-branch config from store
- commitAndPushBeads(): handles both sync-branch and regular git workflows

This eliminates duplicated sync-branch detection code (was in 3 places)
and the duplicated commit/push conditional logic (was in 2 places).

Net reduction of ~20 lines while improving maintainability.

* fix: remove unused bool return from commitAndPushBeads
2026-01-20 14:06:22 -08:00
Oliver Jägle
d929c8f974 feat: add hierarchical tree display for --tree --parent combination (#1211)
Motivation:
The existing --parent flag only shows direct children in a flat list,
but users often need to see the complete hierarchy including grandchildren
and deeper levels. This limitation made it difficult to understand the
full scope of work under an epic or parent issue.

Key changes:
- Enhanced list command to detect --tree --parent combination
- Implemented recursive parent filtering instead of GetDependencyTree
- Added DRY refactoring with withStorage() and getHierarchicalChildren() helpers
- Eliminated duplication between daemon and direct modes
- Added comprehensive test coverage with TestHierarchicalChildren
- Fixed cross-repository compatibility issues

Side-effects:
- No breaking changes: existing --parent behavior unchanged
- --tree --parent now shows hierarchical tree instead of flat list
- Parent issue is included as root of the displayed tree
- Works consistently across all repositories and storage modes
- Improved code maintainability with DRY architecture
- Better test coverage ensures reliability and prevents regressions
2026-01-20 14:06:17 -08:00
Zachary Piazza
ee44498659 feat(linear): add --type and --exclude-type flags for sync filtering (#1205)
* feat(linear): add --type and --exclude-type flags for sync filtering

Add type filtering support to `bd linear sync --push` to allow users to
control which issue types are synced to Linear.

New flags:
- --type: Only sync issues matching these types (e.g., --type=task,feature)
- --exclude-type: Exclude issues of these types (e.g., --exclude-type=wisp)

Use cases:
- Sync only work items (tasks, features, bugs) while excluding internal
  telemetry (wisps, messages)
- Push only specific issue types to Linear

Fixes #1204

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(linear): update test to match new doPushToLinear signature

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 14:05:48 -08:00
Eugene Sukhodolin
4ccdd7a2df fix(routing): close original store before replacing with target store (#1215)
* fix(routing): close original store before replacing with target store

Fix "database is closed" error during auto-flush when contributor routing
redirects issue creation to a different repository (e.g., ~/.beads-planning).

When a user is detected as a contributor (based on git remote URL pattern),
the default configuration routes new issues to ~/.beads-planning instead of
the current repository. This routing caused auto-flush to fail with:

  Warning: auto-flush failed: failed to get stored JSONL hash:
  failed to get jsonl_file_hash: sql: database is closed

In create.go, when switching to the planning repo:
1. targetStore was opened for the planning database
2. A defer was set to close targetStore at function end
3. store = targetStore replaced the global store pointer
4. Issue was created successfully
5. Command Run ended → defer closed targetStore
6. PersistentPostRun tried to flush using the global store → error!

The bug: the defer closed targetStore, but the global `store` variable
pointed to the same object. When PersistentPostRun called flushManager.Shutdown(),
it tried to use the already-closed store for the flush operation.

- Remove the defer that prematurely closed targetStore
- Explicitly close the ORIGINAL store before replacing it (it won't be used)
- Let PersistentPostRun close whatever store is current at exit time

This ensures proper store lifecycle:
- Original store: closed when replaced (no longer needed)
- Target store: closed by PersistentPostRun after flush completes

1. Have a git repo with a remote URL that doesn't match maintainer patterns
   (e.g., github-a:org/repo.git instead of git@github.com:org/repo.git)
2. Have ~/.beads-planning directory with beads initialized
3. Run: cd /path/to/repo && bd create "Test issue"
4. Observe: Issue created successfully, but followed by:
   Warning: auto-flush failed: ... sql: database is closed

Added debug prints to SQLiteStorage.Close() and GetJSONLFileHash() which
revealed two different databases were involved:
- /path/to/repo/.beads/beads.db (closed first, unexpectedly)
- ~/.beads-planning/.beads/beads.db (used for flush after being closed)

* fix(test): resolve race condition in TestAutoFlushOnExit

Not directly related to the previous routing fix, but exposed by CI timing.

Root cause: The test had a latent race condition between two channel operations:
1. markDirtyAndScheduleFlush() sends event to markDirtyCh
2. Shutdown() sends request to shutdownCh

Without any delay, Go's scheduler might process the shutdown event first.
Since isDirty was still false (markDirty event not yet processed), the
FlushManager would skip the flush entirely, causing the test to fail with
"Expected JSONL file to be created on exit".

The race was always present but only manifested in CI environments with
different timing characteristics (CPU contention, virtualization, scheduler
behavior).

Fix: Add a 10ms sleep after markDirtyAndScheduleFlush() to allow the
FlushManager's background goroutine to process the event before shutdown.
This mimics real-world behavior where there's always some time between
CRUD operations and process exit.
2026-01-20 14:05:40 -08:00
Perttu Landström
9ed74ca233 fix(types): show custom types when daemon is running (#1216)
The `bd types` command only checked `if store != nil` to fetch custom
types. In daemon mode, `store` is nil (daemonClient handles RPC instead),
so custom types were never displayed even when configured.

This caused a mismatch where `bd config get types.custom` showed the
correct values but `bd types` showed none.

Fix by calling ensureDirectMode() at the start of the command, matching
the pattern used by `bd config get`. This falls back from daemon mode
to direct storage access when needed.

Co-authored-by: Perttulands <perttu.landstrom@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 14:05:03 -08:00
Wilhelm Uschtrin
f7134954b9 fix(worktree): correct redirect path computation in bd worktree create (#1217)
Computes the relative path from the worktree root instead of the .beads directory. This ensures that FollowRedirect resolves paths correctly relative to the parent of .beads.
2026-01-20 14:04:51 -08:00
coffeegoddd☕️✨
4e386c8adf /cmd/bd/doctor/integrity.go: fix unable to query issues bug with dolt backend 2026-01-20 14:00:37 -08:00
coffeegoddd☕️✨
a097fc546b /{cmd,internal}: fix lint issues 2026-01-20 13:46:57 -08:00
coffeegoddd☕️✨
422bc838ed /{website,internal,docs,cmd}: integration tests and more split backend fixes 2026-01-20 13:39:04 -08:00
coffeegoddd☕️✨
ba432847e0 /{cmd,internal}: get dolt backend init working and allow issue creation 2026-01-20 12:24:14 -08:00
collins
521239cfdc refactor(config): improve sync config with warnings toggle and dedup
Code review improvements to internal/config/sync.go:

1. Warning suppression toggle
   - Add ConfigWarnings bool to enable/disable warnings
   - Add ConfigWarningWriter io.Writer for testable output

2. Consolidate sync mode constants
   - cmd/bd/sync_mode.go now imports from internal/config
   - Single source of truth for mode values
   - Uses shared IsValidSyncMode() for validation

3. Fix empty sovereignty semantics
   - Empty now returns SovereigntyNone (no restriction)
   - Only non-empty invalid values fall back to T1 with warning

4. Export validation helpers
   - IsValidSyncMode(), IsValidConflictStrategy(), IsValidSovereignty()
   - ValidSyncModes(), ValidConflictStrategies(), ValidSovereigntyTiers()
   - String() methods on all typed values

5. Logger interface
   - ConfigWarningWriter allows custom logging destinations
   - Tests can capture warnings without os.Stderr manipulation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 11:49:44 -08:00
jane
80cd1f35c0 fix(sync): address code review issues in manual conflict resolution
Fixes from code review:
- Fix duplicate check in merge logic (use else clause)
- Handle io.EOF gracefully (treat as quit)
- Add quit (q) option to abort resolution early
- Add accept-all (a) option to auto-merge remaining conflicts
- Fix skipped conflicts to keep local version (not auto-merge)
- Handle json.MarshalIndent errors properly
- Fix truncateText to use rune count for UTF-8 safety
- Update help text with new options
- Add UTF-8 and emoji test cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 11:44:24 -08:00
lydia
5d68e6b61a refactor(hook): simplify export state logic, add tests
Code review fixes:
- Renamed misleading exportIncrementalDolt to hasDoltChanges (now just checks for changes)
- Extracted stageJSONLFiles() helper to eliminate duplication
- Extracted runJSONLExport() helper
- Removed unused Actor field from ExportState (add back when implementing filtering)
- Consolidated hookPreCommitDoltFallback into doExportAndSaveState
- Added updateExportStateCommit for no-change fast path

Net reduction: 44 lines (-116/+72)

Added tests for:
- getWorktreeHash
- Export state paths
- Save/load export state
- JSON serialization with omitempty
- updateExportStateCommit
- computeJSONLHashForHook

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 11:44:08 -08:00
lizzy
38af99f300 fix(config): improve cross-platform path handling and regex efficiency
Code review fixes for bd config validate:
- Use filepath.Join instead of string concatenation for paths
- Use filepath.Dir instead of strings.LastIndex for parent directory
- Move gitSSHRemotePattern regex to package-level var (compile once)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 11:42:09 -08:00
collins
0335067e34 fix(config): restore sync.go with warning implementations
Commit 356ab92b deleted internal/config/sync.go while adding
cmd/bd/sync_mode.go, but config.go still references the types and
functions from sync.go, causing build failures.

These serve different purposes:
- internal/config/sync.go: viper-based (config.yaml), has warnings
- cmd/bd/sync_mode.go: storage-based (database), no warnings

Both should coexist. This restores sync.go and sync_test.go from
e82e15a8, and fixes type conversion in sync.go:805.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 11:18:14 -08:00
Bo
6a4a6170e7 fix(sync): add --sparse flag to git add for worktree compatibility (#1143)
Fixes #1076.

When git worktrees have sparse-checkout enabled, git add operations can
fail with 'outside of sparse-checkout cone' errors. Adding the --sparse
flag allows git to stage files outside the sparse-checkout cone.

Changes:
- Add --sparse flag to git add in daemon_sync_branch.go (line 165)
- Add --sparse flag to git add in migrate_sync.go (line 343)
- Add --sparse flag to git add in sync_branch.go (line 308)
- Add --sparse flag to git add in worktree.go (line 732)

All changes include comments referencing #1076 for traceability.
2026-01-19 10:21:12 -08:00
Roland Tritsch
34b741d2e0 Fix doctor DB-JSONL sync check to exclude ephemeral wisps (#1144)
The DB-JSONL Sync check was showing a false positive warning when wisps
(ephemeral issues) existed in the database. Wisps are intentionally
excluded from JSONL exports, so they shouldn't be counted when comparing
database and JSONL issue counts.

Changes:
- Updated CheckDatabaseJSONLSync to exclude ephemeral issues from count
  using 'WHERE ephemeral = 0 OR ephemeral IS NULL'
- Added 'ephemeral' column to test database schema
- Added test case to verify ephemeral issues are excluded from count
- Updated TestCheckDatabaseJSONLSync_MoleculePrefix to include ephemeral column

This prevents false warnings like 'database has 92 issues, JSONL has 30'
when the difference is entirely due to wisps that should not be exported.

Co-authored-by: Roland Tritsch <roland@ailtir.com>
2026-01-19 10:11:23 -08:00
Bobby Johnson
aa3b318939 Fix issue-prefix config fallback to config.yaml (GH#1145) (#1146)
The config.yaml file uses "issue-prefix" (with hyphen) but this setting
was only read during bd init. After initialization, all code read from
the database's "issue_prefix" key, so subsequent changes to config.yaml
were silently ignored.

This fix adds a fallback to config.yaml's "issue-prefix" in the key
locations where the prefix is retrieved from the database:

1. autoflush.go: Auto-import now checks config.yaml before falling back
   to auto-detection from JSONL or directory name

2. autoflush.go: filterByMultiRepoPrefix now checks config.yaml as fallback

3. create.go: Direct mode prefix validation now checks config.yaml as fallback

Priority order is preserved:
1. Database issue_prefix (if set)
2. Config.yaml issue-prefix (new fallback)
3. Auto-detection from JSONL/directory (existing fallback)

Fixes #1145

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:11:19 -08:00
Damir Vandic
b09aee377f fix: set git index flags on init when sync-branch is configured (#1158)
Fresh clones with sync-branch configured in .beads/config.yaml would show
.beads/issues.jsonl as modified in git status because the git index flags
(skip-worktree, assume-unchanged) are local-only and don't transfer via clone.

This fix ensures bd init sets these flags in two scenarios:
1. `bd init --branch <name>` - when user explicitly sets sync branch
2. `bd init` on cloned repo - when sync-branch already exists in config.yaml

Added SetSyncBranchGitignoreFlags() helper and two tests for coverage.
2026-01-19 10:11:16 -08:00
Subhrajit Makur
065ca3d6af fix(config): remove duplicate declarations and fix test failures (#1160)
* fix(config): remove duplicate declarations between config.go and sync.go

Commit e82e15a8 created sync.go with typed constants (SyncMode,
ConflictStrategy, Sovereignty) but didn't remove the original untyped
constants from config.go that were added in 16f8c3d3. This caused
redeclaration errors preventing the project from building.

Changes:
- Remove duplicate SyncMode, ConflictStrategy, Sovereignty constants
  from config.go (keep typed versions in sync.go)
- Remove duplicate GetSyncMode, GetConflictStrategy, GetSovereignty
  functions from config.go (keep sync.go versions with warnings)
- Update SyncConfig, ConflictConfig, FederationConfig structs to use
  typed fields instead of string
- Add IsSyncModeValid, IsConflictStrategyValid, IsSovereigntyValid
  wrapper functions that use sync.go's validation maps
- Update cmd/bd/sync.go to use typed ConflictStrategy parameter
- Update tests to work with typed constants

* fix(dolt): handle Merge return values in concurrent test

* fix(test): add --repo flag to show_test.go to bypass auto-routing

The tests were failing because the create command was routing issues
to ~/.beads-planning instead of the test's temp directory. Adding
--repo . overrides auto-routing and creates issues in the test dir.
2026-01-19 10:11:14 -08:00
Peter Chanthamynavong
2cbf3a5497 fix: Validate sync-branch at config-time and runtime (closes #1166) (#1168)
* fix(config): validate sync-branch at config time

Add sync-branch validation to validateYamlConfigValue() to reject
main/master at config time, preventing the validation bypass in GH#1166.

- Add case for sync-branch and sync.branch keys
- Inline validation logic to avoid import cycle (config <-> syncbranch)
- Add unit tests for rejection (main/master) and acceptance (valid names)

Part of: #1166

* fix(sync): add runtime guard for sync-branch == current-branch

Add dynamic runtime check before worktree operations to catch cases
where sync-branch matches the current branch. This provides defense
in depth for manual YAML edits, pre-fix configs, or non-main/master
branch names (trunk, develop, production, etc.).

- Check IsSyncBranchSameAsCurrent() after hasSyncBranchConfig is set
- Position check BEFORE worktree entry (CWD changes inside worktree)
- Add integration test TestSync_FailsWhenOnSyncBranch

Part of: #1166

* docs: note main/master restriction in sync-branch FAQ

Clarifies that git worktrees cannot checkout the same branch in
multiple locations, so main/master cannot be used as sync branch.
2026-01-19 10:11:06 -08:00
Peter Chanthamynavong
460d2bf113 fix(doctor): improve diagnostic fix message output (#1187)
Problem:
- Diagnostic fix messages were restricted to single lines
- Inconsistent file path formatting in database sync issues
- Outdated cleanup command suggested in maintenance fixes

Solution:
- Implement multiline support for doctor fix messages
- Standardize issue file paths across database diagnostics
- Update maintenance fix instructions to use 'bd admin cleanup'

Impact:
- Clearer and more accurate recovery instructions for users
- Better readability of complex diagnostic output

Fixes: GH#1170, GH#1171, GH#1172
2026-01-19 10:10:57 -08:00
Steven Syrek
73d4d5ecb2 fix(create): validate explicit IDs against allowed_prefixes using starts-with matching (#1137)
When creating issues with explicit IDs like `bd create --id hq-cv-test`,
the prefix validation was failing even when `hq-cv` was in `allowed_prefixes`.

Root cause: `ExtractIssuePrefix("hq-cv-test")` returns `"hq"` (not `"hq-cv"`)
because "test" looks like an English word, causing the algorithm to fall back
to the first hyphen. The validation then checked if `"hq"` was in the allowed
list containing `"hq-cv"` - which failed.

The fix adds `ValidateIDPrefixAllowed()` which validates the full ID using
"starts with" matching (the same approach the importer uses successfully).
This correctly handles multi-hyphen prefixes like `hq-cv-` regardless of
what the suffix looks like.

Fixes #1135

Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:08:56 -08:00
Steven Syrek
8e40018701 fix(daemon): Fix double-unlock risk in debouncer on action panic (#1140)
The debouncer's timer callback used a pattern that could cause a
double-unlock panic if the action function panicked:

  d.mu.Lock()
  defer d.mu.Unlock()
  if d.seq == currentSeq {
      d.mu.Unlock()  // Manual unlock
      d.action()     // If this panics...
      d.mu.Lock()    // ...this never runs
  }                  // ...but defer still tries to unlock

Fix: Remove the defer and manually manage lock state. Now if the
action panics, the lock is already released, preventing a
double-unlock panic that would mask the original panic.

Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:08:53 -08:00
Steven Syrek
ba832c4f37 fix(daemon): Eliminate race condition in sync state load-modify-save (#1139)
The RecordSyncFailure and ResetBackoffOnDaemonStart functions had a
TOCTOU (time-of-check-time-of-use) race condition. They called
LoadSyncState (which locks, reads, unlocks) then modified the state,
then called SaveSyncState (which locks, writes, unlocks).

Between LoadSyncState returning and SaveSyncState being called, another
goroutine could load the old state, modify it, and save it - then this
goroutine's save would overwrite those changes.

Fix: Create internal unlocked helper functions (loadSyncStateUnlocked,
saveSyncStateUnlocked) and have RecordSyncFailure and
ResetBackoffOnDaemonStart hold the lock for the entire load-modify-save
operation.

Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:08:41 -08:00
beads/crew/emma
4bc0b698a8 fix(staleness): skip auto-import when store is read-only (GH#1089)
Track whether the store was actually opened read-only (vs just requested)
since the fallback logic may change opts.ReadOnly. Use this to skip
auto-import in staleness checks - importing would fail anyway if the
store is read-only.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 18:25:50 -08:00
beads/crew/emma
356ab92b78 feat(sync): wire up sync.mode config to change sync behavior
Implements hq-ew1mbr.27: The sync.mode config now actually changes how
bd sync operates:

- git-portable (default): JSONL exported on push, imported on pull
- realtime: JSONL exported on every change (placeholder for daemon hook)
- dolt-native: Uses Dolt Push/Pull, skips JSONL workflow entirely
- belt-and-suspenders: Both Dolt remotes AND JSONL for redundancy

Changes:
- Add sync_mode.go with mode constants, Get/Set functions, and helpers
- Update bd sync --status to show actual mode from config
- Add --set-mode flag to bd sync for configuring the mode
- Modify doExportSync to respect mode (Dolt push for dolt-native)
- Modify doPullFirstSync to use Dolt pull for dolt-native mode
- Add RemoteStorage interface for Push/Pull operations
- Add comprehensive tests for sync mode functionality

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 10:36:20 -08:00
jane
c99bd00ca7 feat(sync): implement interactive conflict resolution for manual strategy
Adds interactive manual conflict resolution for `bd sync --resolve --manual`:
- Shows field-by-field diff between local and remote versions
- Prompts user to choose: local (l), remote (r), merge (m), skip (s)
- Supports viewing full JSON diff with 'd' option
- Skipped conflicts remain in conflict state for later resolution
- Integrates with existing 3-way merge infrastructure

New files:
- cmd/bd/sync_manual.go: Interactive conflict resolution logic
- cmd/bd/sync_manual_test.go: Unit tests for helper functions

Closes hq-ew1mbr.28

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 14:02:47 -08:00
lizzy
9ddd7a2620 feat(config): add validate command for sync config
Add `bd config validate` command to validate sync-related configuration:

- sync.mode: validates values (local, git-branch, external)
- conflict.strategy: validates values (lww, manual, ours, theirs)
- federation.sovereignty: validates values (none, isolated, federated)
- federation.remote: ensures set when sync.mode is 'external'
- Remote URL format: validates dolthub://, gs://, s3://, file://, etc.

Also validates existing config via doctor.CheckConfigValues (sync.branch,
routing.mode, etc.)

Closes: hq-ew1mbr.29

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 14:02:28 -08:00
darcy
16f8c3d3ae feat(sync): add sync mode configuration (hq-ew1mbr.3)
Add configurable sync modes for Dolt storage integration:

Sync modes:
- git-portable (default): Export JSONL on push, import on pull
- realtime: Export JSONL on every database change
- dolt-native: Use Dolt remotes directly (no JSONL)
- belt-and-suspenders: Both Dolt remote AND JSONL backup

Configuration options in .beads/config.yaml:
- sync.mode: Select sync mode
- sync.export_on: push (default) or change
- sync.import_on: pull (default) or change
- conflict.strategy: newest (default), ours, theirs, manual
- federation.remote: Dolt remote URL for dolt-native mode
- federation.sovereignty: T1-T4 data sovereignty tier

The sync command now displays configuration in `bd sync --status`
and uses configured conflict strategy for resolution.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 10:52:29 -08:00
lydia
ba0e754dc8 feat(hook): implement per-worktree export state tracking (Design Part 21)
Updates ExportState to track Dolt commits (not git commits) for accurate
change detection. This prevents polecats sharing a Dolt DB from exporting
each others uncommitted work.

Changes:
- ExportState now tracks Dolt commit hash via VersionedStorage.GetCurrentCommit()
- Added WorktreeHash and Actor fields for debugging and future filtering
- hookPreCommitDolt uses Diff() to detect changes since last export
- Added hookPreCommitDoltFallback for graceful degradation
- Added exportIncrementalDolt and exportFullDolt helper functions
- Removed unused exportToJSONLFromStore function

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 10:46:44 -08:00
beads/crew/emma
4f0f5744a6 feat(types): remove Gas Town types from core built-in types
Core beads built-in types now only include work types:
- bug, feature, task, epic, chore

Gas Town types (molecule, gate, convoy, merge-request, slot, agent,
role, rig, event, message) are now "well-known custom types":
- Constants still exist for code convenience
- Require types.custom configuration for validation
- bd types command shows core types and configured custom types

Changes:
- types.go: Separate core work types from well-known custom types
- IsValid(): Only accepts core work types
- bd types: Updated to show core types and custom types from config
- memory.go: Use ValidateWithCustom for custom type support
- multirepo.go: Only check core types as built-in
- Updated all tests to configure custom types

This allows Gas Town (and other projects) to define their own types
via config while keeping beads core focused on work tracking.

Closes: bd-find4

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 05:07:11 -08:00
emma
88a6438c80 chore(release): bump version to 0.48.0
Release highlights:
- VersionedStorage interface for pluggable backends
- bd types command and enhancement type alias
- bd close -m flag (git commit convention)
- RepoContext API for centralized git operations
- Dolt backend improvements (WIP)
- Many bug fixes for doctor, sync, hooks, worktrees

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 04:36:41 -08:00
emma
10bdc94294 feat(close): add -m as alias for --reason
Adds -m/--message as a hidden alias for --reason, following the git
commit convention where -m specifies a message. This makes the command
more intuitive for users familiar with git workflows.

Usage: bd close <id> -m "reason for closing"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 03:48:51 -08:00
lydia
feed888b57 fix(duplicates): use combined weight (dependents + dependencies) for merge target selection (GH#1022)
When choosing which duplicate to keep, the merge target now considers
both dependentCount (children/blocked-by) AND dependsOnCount (dependencies).
This ensures issues with ANY structural connections are preferred over
empty shells, rather than only considering children.

- Updated chooseMergeTarget to calculate weight = dependentCount + dependsOnCount
- Updated display output to show weight instead of just dependents
- Updated JSON output to include dependencies and weight fields
- Added tests for dependsOnCount inclusion and combined weight calculation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 03:44:13 -08:00
jane
251ded73be fix(merge-slot): use daemon RPC to get issue_prefix in daemon mode
When running in daemon mode, getMergeSlotID() was not using the daemon
RPC to retrieve the configured issue_prefix, causing it to fall back
to the hardcoded "bd" default. This fix adds the missing daemon path
that uses daemonClient.GetConfig() to properly retrieve the prefix,
matching the pattern used in create.go.

Fixes #1096

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 03:44:02 -08:00
emma
a21a29c283 fix(doctor): remove destructive sync branch health check (GH#1062)
The "Sync Branch Health" check incorrectly warned when the sync branch
differed from main on source files. Since the sync branch only tracks
.beads/ data, source file differences are expected behavior.

The associated --fix action (reset sync branch to main and force push)
was destructive and destroyed legitimate sync branch history.

Removed Check 2 entirely - only Check 1 (detecting divergence from remote
after force-push) remains, which is a legitimate issue.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 03:42:35 -08:00
elinor
f06e742273 fix(daemon): apply git.author config to sync branch commits
The daemon's gitCommitInWorktree function was building git commit
commands directly without checking the git.author and git.no-gpg-sign
config options. This caused daemon sync commits to use the local git
user config instead of the configured beads-specific author.

Now gitCommitInWorktree applies the same config-based author and
signing options that buildCommitArgs uses for regular commits.

Fixes #1051
2026-01-17 03:40:28 -08:00
emma
e60e8f1823 chore: remove placeholder comment in test
Remove `// See: https://github.com/steveyegge/beads/issues/XXX`
placeholder that was left in the regression test from PR #1131.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 02:51:06 -08:00