Commit Graph

32 Commits

Author SHA1 Message Date
Peter Chanthamynavong
1561374c04 feat(sync): pull-first sync with 3-way merge (#918)
* feat(sync): implement pull-first synchronization strategy

- Add --pull-first flag and logic to sync command
- Introduce 3-way merge stub for issue synchronization
- Add concurrent edit tests for the pull-first flow

Ensures local changes are reconciled with remote updates before pushing to prevent data loss.

* feat(sync): implement 3-way merge and state tracking

- Implement 3-way merge algorithm for issue synchronization
- Add base state storage to track changes between syncs
- Add comprehensive tests for merge logic and persistence

Ensures data consistency and prevents data loss during concurrent
issue updates.

* feat(sync): implement field-level conflict merging

- Implement field-level merge logic for issue conflicts
- Add unit tests for field-level merge strategies

Reduces manual intervention by automatically resolving overlapping updates at the field level.

* refactor(sync): simplify sync flow by removing ZFC checks

The previous sync implementation relied on Zero-False-Convergence (ZFC)
staleness checks which are redundant following the transition to
structural 3-way merging. This legacy logic added complexity and
maintenance overhead without providing additional safety.

This commit introduces a streamlined sync pipeline:
- Remove ZFC staleness validation from primary sync flow
- Update safety documentation to reflect current merge strategy
- Eliminate deprecated unit tests associated with ZFC logic

These changes reduce codebase complexity while maintaining data
integrity through the robust structural 3-way merge implementation.

* feat(sync): default to pull-first sync workflow

- Set pull-first as the primary synchronization workflow
- Refactor core sync logic for better maintainability
- Update concurrent edit tests to validate 3-way merge logic

Reduces merge conflicts by ensuring local state is current before pushing changes.

* refactor(sync): clean up lint issues in merge code

- Remove unused error return from MergeIssues (never returned error)
- Use _ prefix for unused _base parameter in mergeFieldLevel
- Update callers to not expect error from MergeIssues
- Keep nolint:gosec for trusted internal file path

* test(sync): add mode compatibility and upgrade safety tests

Add tests addressing Steve's PR #918 review concerns:

- TestSyncBranchModeWithPullFirst: Verifies sync-branch config
  storage and git branch creation work with pull-first
- TestExternalBeadsDirWithPullFirst: Verifies external BEADS_DIR
  detection and pullFromExternalBeadsRepo
- TestUpgradeFromOldSync: Validates upgrade safety when
  sync_base.jsonl doesn't exist (first sync after upgrade)
- TestMergeIssuesWithBaseState: Comprehensive 3-way merge cases
- TestLabelUnionMerge: Verifies labels use union (no data loss)

Key upgrade behavior validated:
- base=nil (no sync_base.jsonl) safely handles all cases
- Local-only issues kept (StrategyLocal)
- Remote-only issues kept (StrategyRemote)
- Overlapping issues merged (LWW scalars, union labels)

* fix(sync): report line numbers for malformed JSON

Problem:
- JSON decoding errors when loading sync base state lacked line numbers
- Difficult to identify location of syntax errors in large state files

Solution:
- Include line number reporting in JSON decoder errors during state loading
- Add regression tests for malformed sync base file scenarios

Impact:
- Users receive actionable feedback for corrupted state files
- Faster troubleshooting of manual configuration errors

* fix(sync): warn on large clock skew during sync

Problem:
- Unsynchronized clocks between systems could lead to silent merge errors
- No mechanism existed to alert users of significant timestamp drift

Solution:
- Implement clock skew detection during sync merge
- Log a warning when large timestamp differences are found
- Add comprehensive unit tests for skew reporting

Impact:
- Users are alerted to potential synchronization risks
- Easier debugging of time-related merge issues

* fix(sync): defer state update until remote push succeeds

Problem:
- Base state updated before confirming remote push completion
- Failed pushes resulted in inconsistent local state tracking

Solution:
- Defer base state update until after the remote push succeeds

Impact:
- Ensures local state accurately reflects remote repository status
- Prevents state desynchronization during network or push failures

* fix(sync): prevent concurrent sync operations

Problem:
- Multiple sync processes could run simultaneously
- Overlapping operations risk data corruption and race conditions

Solution:
- Implement file-based locking using gofrs/flock
- Add integration tests to verify locking behavior

Impact:
- Guarantees execution of a single sync process at a time
- Eliminates potential for data inconsistency during sync

* docs: document sync architecture and merge model

- Detail the 3-way merge model logic
- Describe the core synchronization architecture principles

* fix(lint): explicitly ignore lock.Unlock return value

errcheck linter flagged bare defer lock.Unlock() calls. Wrap in
anonymous function with explicit _ assignment to acknowledge
intentional ignore of unlock errors during cleanup.

* fix(lint): add sync_merge.go to G304 exclusions

The loadBaseState and saveBaseState functions use file paths derived
from trusted internal sources (beadsDir parameter from config). Add
to existing G304 exclusion list for safe JSONL file operations.

* feat(sync): integrate sync-branch into pull-first flow

When sync.branch is configured, doPullFirstSync now:
- Calls PullFromSyncBranch before merge
- Calls CommitToSyncBranch after export

This ensures sync-branch mode uses the correct branch for
pull/push operations.

* test(sync): add E2E tests for sync-branch and external BEADS_DIR

Adds comprehensive end-to-end tests:
- TestSyncBranchE2E: verifies pull→merge→commit flow with remote changes
- TestExternalBeadsDirE2E: verifies sync with separate beads repository
- TestExternalBeadsDirDetection: edge cases for repo detection
- TestCommitToExternalBeadsRepo: commit handling

* refactor(sync): remove unused rollbackJSONLFromGit

Function was defined but never called. Pull-first flow saves base
state after successful push, making this safety net unnecessary.

* test(sync): add export-only mode E2E test

Add TestExportOnlySync to cover --no-pull flag which was the only
untested sync mode. This completes full mode coverage:

- Normal (pull-first): sync_test.go, sync_merge_test.go
- Sync-branch: sync_modes_test.go:TestSyncBranchE2E (PR#918)
- External BEADS_DIR: sync_external_test.go (PR#918)
- From-main: sync_branch_priority_test.go
- Local-only: sync_local_only_test.go
- Export-only: sync_modes_test.go:TestExportOnlySync (this commit)

Refs: #911

* docs(sync): add sync modes reference section

Document all 6 sync modes with triggers, flows, and use cases.
Include mode selection decision tree and test coverage matrix.

Co-authored-by: Claude <noreply@anthropic.com>

* test(sync): upgrade sync-branch E2E tests to bare repo

- Replace mocked repository with real bare repo setup
- Implement multi-machine simulation in sync tests
- Refactor test logic to handle distributed states

Coverage: sync-branch end-to-end scenarios

* test(sync): add daemon sync-branch E2E tests

- Implement E2E tests for daemon sync-branch flow
- Add test cases for force-overwrite scenarios

Coverage: daemon sync-branch workflow in cmd/bd

* docs(sync): document sync-branch paths and E2E architecture

- Describe sync-branch CLI and Daemon execution flow
- Document the end-to-end test architecture

* build(nix): update vendorHash for gofrs/flock dependency

New dependency added for file-based sync locking changes the
Go module checksum.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-07 21:27:20 -08:00
Peter Chanthamynavong
d371baf2ca feat(dates): add --due and --defer timestamp options with natural language parsing (#847)
* feat(dates): add due date schema and --due flag

- Add due_at and defer_until columns to issues table via migration 035
- Implement --due flag on create command with ISO date parsing
- Extend RPC protocol and daemon to pass DueAt from CLI to storage
- Display DueAt and DeferUntil in show command output
- Update Issue type with new date fields

Users can now set due dates when creating issues, enabling deadline-based
task management.

* feat(dates): add compact duration parser (+6h, +1d, +2w)

- Create internal/timeparsing package with layered parser architecture
- Implement parseCompactDuration with regex pattern [+-]?\d+[hdwmy]
- Add comprehensive test suite (22 cases) for duration parsing
- Integrate into create.go with fallback to ISO format

Supports hours (h), days (d), weeks (w), months (m), and years (y).
Negative values allowed for past dates.

* feat(dates): add NLP parsing for natural language dates

Integrate olebedev/when library for natural language time expressions.
The layered parser now handles: compact duration → absolute formats → NLP.

Changes:
- Add olebedev/when dependency for NLP parsing
- Implement ParseNaturalLanguage and ParseRelativeTime functions
- Reorder layers: absolute formats before NLP to avoid misinterpretation
- Simplify create.go to use unified ParseRelativeTime
- Add comprehensive NLP test coverage (22 test cases)

Supports: tomorrow, next monday, in 3 days, 3 days ago

* feat(dates): add --defer flag to create/update/defer commands

Add time-based deferral support alongside existing status-based defer.
Issues can now be hidden from bd ready until a specific time.

Changes:
- Add --defer flag to bd create (sets defer_until on creation)
- Add --due and --defer flags to bd update (modify existing issues)
- Add --until flag to bd defer (combines status=deferred with defer_until)
- Add DueAt/DeferUntil fields to UpdateArgs in protocol.go

Supports: +1h, tomorrow, next monday, 2025-01-15

* feat(dates): add defer_until filtering to ready command

Add time-based deferral support to bd ready:

- Add --include-deferred flag to show issues with future defer_until
- Filter out issues where defer_until > now by default
- Update undefer to clear defer_until alongside status change
- Add IncludeDeferred to WorkFilter and RPC ReadyArgs

Part of GH#820: Relative Date Parsing (Phase 5)

* feat(dates): add polish and tests for relative date parsing

Add user-facing warnings when defer date is in the past to help catch
common mistakes. Expand help text with format examples and document
the olebedev/when September parsing quirk.

Tests:
- TestCreateSuite/WithDueAt, WithDeferUntil, WithBothDueAndDefer
- TestReadyWorkDeferUntil (ExcludesFutureDeferredByDefault, IncludeDeferredShowsAll)

Docs:
- CLAUDE.md quick reference updated with new flags
- Help text examples for --due, --defer on create/update

Closes: Phase 6 of beads-820-relative-dates spec

* feat(list): add time-based query filters for defer/due dates

Add --deferred, --defer-before, --defer-after, --due-before, --due-after,
and --overdue flags to bd list command. All date filters now support
relative time expressions (+6h, tomorrow, next monday) via the
timeparsing package.

Filters:
- --deferred: issues with defer_until set
- --defer-before/after: filter by defer_until date range
- --due-before/after: filter by due_at date range
- --overdue: due_at in past AND status != closed

Existing date filters (--created-after, etc.) now also support relative
time expressions through updated parseTimeFlag().

* build(nix): update vendorHash for olebedev/when dependency

The olebedev/when library was added for natural language date parsing
(GH#820). This changes go.sum, requiring an updated vendorHash in the
Nix flake configuration.
2026-01-01 20:06:13 -08:00
beads/crew/dave
82611834df feat: add version sync check to bd preflight --check (bd-lfak.5)
- Implement runVersionSyncCheck() to compare version.go and default.nix
- Reports version mismatch as hard failure
- Gracefully skips if default.nix is missing
- Fix version mismatch: update default.nix from 0.37.0 to 0.42.0

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

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

Executed-By: beads/crew/dave
Rig: beads
Role: crew
2025-12-31 00:08:40 -08:00
matt wilkie
d3fe6b0f32 fix: lint errors and update Nix vendorHash
- Add nolint:unparam for readOnly param in sqlite_open.go
- Handle cmd.Help() error in wisp.go
- Handle rows.Close() error in migration 028
- Handle targetStore.Close() error in create.go
- Update Nix vendorHash for current dependencies

Cherry-picked from PR #769
2025-12-27 17:29:36 -08:00
Steve Yegge
1611f16751 refactor: remove unused bd pin/unpin/hook commands (bd-x0zl)
Analysis found these commands are dead code:
- gt never calls `bd pin` - uses `bd update --status=pinned` instead
- Beads.Pin() wrapper exists but is never called
- bd hook functionality duplicated by gt mol status
- Code comment says "pinned field is cosmetic for bd hook visibility"

Removed:
- cmd/bd/pin.go
- cmd/bd/unpin.go
- cmd/bd/hook.go

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 16:02:15 -08:00
Steve Yegge
c8b912cbe6 bd sync: 2025-12-27 15:56:42 2025-12-27 15:56:42 -08:00
Steve Yegge
6862f6e35b chore(nix): Update version to 0.37.0 in default.nix (GH#749)
Version was stuck at 0.30.7. The vendorHash may need updating too -
if build fails with hash mismatch, use the "got:" value from the error.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 13:04:27 -08:00
Steve Yegge
6cc8926e59 chore(nix): update vendorHash for go-sqlite3 0.30.4 and wazero 1.11.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 14:12:33 -08:00
Ryan Snodgrass
e04785de60 fix(nix): update vendorHash after fatih/color removal 2025-12-20 17:33:00 -08:00
Ryan Snodgrass
acfdcebc0f fix: misc improvements and dependency updates
- Update nix vendorHash after fatih/color removal
- Bump version to 0.30.7
- Add GroupID to remaining commands for proper cobra grouping
- Apply semantic color rendering to list and stale commands
- Update pre-commit hook template
2025-12-20 17:09:50 -08:00
Doug Campos
c573f7d549 fix: update nix vendorHash for Go dependencies 2025-12-18 00:45:38 -05:00
Steve Yegge
d3b0cbb8b8 chore: bump version to 0.30.2
- Update version in version.go, default.nix, hook templates
- Add CHANGELOG.md entry for v0.30.2
- Add v0.30.1 and v0.30.2 to versionChanges in info.go
- Remove stale internal/deletions import from integration test
  (fixes CI failure from bd-fom refactor)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 16:47:43 -08:00
Steve Yegge
8e55b758aa chore(nix): update vendorHash for all Go dependency updates
Updated vendorHash after merging all Go dependency bumps:
- cobra 1.10.1 → 1.10.2
- x/term 0.37.0 → 0.38.0
- go-sqlite3 0.30.1 → 0.30.3
- anthropic-sdk 1.18.1 → 1.19.0

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 23:03:34 -08:00
Steve Yegge
c86a587880 chore(nix): recalculate vendorHash after more Go deps 2025-12-15 23:00:34 -08:00
Steve Yegge
ac8f5ca590 chore(nix): update vendorHash for Go dependency updates
Updated vendorHash after merging Go dependency bumps:
- cobra 1.10.1 → 1.10.2
- x/term 0.37.0 → 0.38.0

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 21:26:06 -08:00
Steve Yegge
c6c0e5f37d chore(nix): trigger vendorHash recalculation
Setting vendorHash to placeholder to trigger CI failure with correct hash.
Go dependencies were updated.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 21:23: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
980c4aae8f Merge branch 'main' of github.com:steveyegge/beads 2025-12-13 21:06:54 -08:00
Steve Yegge
38ecec08f6 fix(nix): update vendorHash for Go dependencies
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 21:06:11 -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
Aodhan Hayter
322f734010 fix(bump-version): update default.nix version (#502)
- Add missing support for scripted default.nix version update to
  bump-version.sh
2025-12-12 15:06:32 -08:00
Steve Yegge
97cfe30bd7 fix: update flake.nix vendorHash after dependency bumps (bd-gmf)
The Nix flake CI was failing due to stale vendorHash after dependabot
updates to go.mod/go.sum (wazero, anthropic-sdk-go, etc.).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 23:21:48 -08:00
Steve Yegge
10ec9fbd97 fix: update Nix flake version and vendorHash
- Update version from 0.9.9 to 0.24.4 (current release)
- Regenerate vendorHash after dependency updates

Fixes bd-870

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 22:34:22 -08:00
Steve Yegge
599c40c703 Fix Windows and Nix test failures
Windows test fixes (bd-web8):
- Add sanitizeMetadataKey() to replace colons with underscores
- Windows absolute paths (e.g., C:\...) contain colons that conflict with
  metadata key separator ':'
- Update tests to use sanitized keys when checking metadata
- Tests now pass on Windows by auto-sanitizing path-based keys

Nix flake fixes (bd-8y1a):
- Update vendorHash in default.nix to match current Go module dependencies
- Hash mismatch was causing Nix build failures in CI

Test improvements:
- Rename TestUpdateExportMetadataInvalidKeySuffix to reflect new behavior
- Test now verifies sanitization instead of rejection
- All tests pass locally

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 10:59:40 -08:00
Straffern
2f83815ddd Update vendorHash for Go module dependencies (#313) 2025-11-14 11:38:56 -08:00
Ben Lovell
b5e2ef4a59 Add script to automate Nix vendorHash updates (#235)
* Add script to automate Nix vendorHash updates

- Create update-nix-hash.sh to automate vendorHash calculation
- Update vendorHash (to be usedafter recent Go dependency changes)
- Script uses ed for OS agnostic in-place editing and extracts hash from nix output

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

* Fix Test Nix Flake CI job

* Revert CI change - bd outputs help by default without 'help' arg

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Steve Yegge <stevey@sourcegraph.com>
2025-11-06 10:30:19 -08:00
Zoe Gagnon
e49d5582e0 Skip tests in the nix build (#222)
The nix build is currently failing on tests around new git-enabled features.
Since ssh and certs are not available in the nix sandbox, all such tests will fail.
Rather than set up a sandbox for those things, skip the tests, with the assumption that
they are already done elsewhere
2025-11-04 10:26:56 -08:00
Steve Yegge
df6534de7f fix: Update Nix vendorHash after go.mod dependency updates
The Anthropic SDK update in PR #216 changed go.sum, requiring a new
vendorHash for the Nix flake build.

Updated hash from CI error output: sha256-m/2e3OxM4Ci4KoyH+leEt09C/CpD9SRrwPd39/cZQ9E=
2025-11-03 23:48:49 -08:00
Steve Yegge
68876dd98f fix: CI failures - performance thresholds, test eligibility, Nix hash, lint errors
- TestSyncBranchPerformance: Increase Windows threshold to 500ms (was 150ms)
  Windows git operations are ~3x slower than Unix
- TestCompactTier1: Fix eligibility by using 7-day minimum and 8-day closure
  Changed compact_tier1_days from 0 to 7 to properly test eligibility checks
- Nix flake: Update vendorHash for current go.mod dependencies
  sha256-cS2saiyKMgw4cXSc2INBHNJfJz5300ybI6Vxda1vLGk=
- Lint fixes:
  - Remove unused 'quiet' parameter from createConfigYaml
  - Change template file permissions from 0644 to 0600 (gosec G306)
  - Add nosec comment for sanitized file path (gosec G304)
2025-11-03 22:01:37 -08:00
Steve Yegge
20b21fda42 fix: Resolve import test failures and add git to Nix build
- Remove broken import special case that created vc.db instead of using found database
- Add git to nativeBuildInputs in default.nix for tests
- Fix path comparison bug (symlink resolution caused prefix mismatch)
2025-11-02 00:09:56 -07:00
Steve Yegge
622dec3b19 Fix CI: update golangci-lint to v1.64.1 and Nix vendorHash for Go 1.24 2025-10-23 23:55:49 -07:00
Zoe Gagnon
fb2881c47b Break out nix package definition into a default.nix (#105)
* Fix autostart test to work in nix sandbox

* Break out a default.nix to make consuming this package easier

The flake is great for local development, but creates overhead and
duplication when pulling it in on another machine. With the default.nix,
the flake continues to work as before, but consumers can callPackage directly
with their own nixpkgs.

* Break out a default.nix to make consuming this package easier

The flake is great for local development, but creates overhead and
duplication when pulling it in on another machine. With the default.nix,
the flake continues to work as before, but consumers can callPackage directly
with their own nixpkgs.
2025-10-22 11:30:57 -07:00