feat(daemon): unify auto-sync config for simpler agent workflows (#904)
* feat(daemon): unify auto-sync config for simpler agent workflows ## Problem Agents running `bd sync` at session end caused delays in the Claude Code "event loop", slowing development. The daemon was already auto-exporting DB→JSONL instantly, but auto-commit and auto-push weren't enabled by default when sync-branch was configured - requiring manual `bd sync`. Additionally, having three separate config options (auto-commit, auto-push, auto-pull) was confusing and could get out of sync. ## Solution Simplify to two intuitive sync modes: 1. **Read/Write Mode** (`daemon.auto-sync: true` or `BEADS_AUTO_SYNC=true`) - Enables auto-commit + auto-push + auto-pull - Full bidirectional sync - eliminates need for manual `bd sync` - Default when sync-branch is configured 2. **Read-Only Mode** (`daemon.auto-pull: true` or `BEADS_AUTO_PULL=true`) - Only receives updates from team - Does NOT auto-publish changes - Useful for experimental work or manual review before sharing ## Benefits - **Faster agent workflows**: No more `bd sync` delays at session end - **Simpler config**: Two modes instead of three separate toggles - **Backward compatible**: Legacy auto_commit/auto_push settings still work (treated as auto-sync=true) - **Adaptive `bd prime`**: Session close protocol adapts when daemon is auto-syncing (shows simplified 4-step git workflow, no `bd sync`) - **Doctor warnings**: `bd doctor` warns about deprecated legacy config ## Changes - cmd/bd/daemon.go: Add loadDaemonAutoSettings() with unified config logic - cmd/bd/doctor.go: Add CheckLegacyDaemonConfig call - cmd/bd/doctor/daemon.go: Add CheckDaemonAutoSync, CheckLegacyDaemonConfig - cmd/bd/init_team.go: Use daemon.auto-sync in team wizard - cmd/bd/prime.go: Detect daemon auto-sync, adapt session close protocol - cmd/bd/prime_test.go: Add stubIsDaemonAutoSyncing for testing * docs: add comprehensive daemon technical analysis Add daemon-summary.md documenting the beads daemon architecture, memory analysis (explaining the 30-35MB footprint), platform support comparison, historical problems and fixes, and architectural guidance for other projects implementing similar daemon patterns. Key sections: - Architecture deep dive with component diagrams - Memory breakdown (SQLite WASM runtime is the main contributor) - Platform support matrix (macOS/Linux full, Windows partial) - Historical bugs and their fixes with reusable patterns - Analysis of daemon usefulness without database (verdict: low value) - Expert-reviewed improvement proposals (3 recommended, 3 skipped) - Technical design patterns for other implementations * feat: add cross-platform CI matrix and dual-mode test framework Cross-Platform CI: - Add Windows, macOS, Linux matrix to catch platform-specific bugs - Linux: full tests with race detector and coverage - macOS: full tests with race detector - Windows: full tests without race detector (performance) - Catches bugs like GH#880 (macOS path casing) and GH#387 (Windows daemon) Dual-Mode Test Framework (cmd/bd/dual_mode_test.go): - Runs tests in both direct mode and daemon mode - Prevents recurring bug pattern (GH#719, GH#751, bd-fu83) - Provides DualModeTestEnv with helper methods for common operations - Includes 5 example tests demonstrating the pattern Documentation: - Add dual-mode testing section to CONTRIBUTING.md - Document RunDualModeTest API and available helpers Test Fixes: - Fix sync_local_only_test.go gitPull/gitPush calls - Add gate_no_daemon_test.go for beads-70c4 investigation * fix(test): isolate TestFindBeadsDir tests with BEADS_DIR env var The tests were finding the real project's .beads directory instead of the temp directory because FindBeadsDir() walks up the directory tree. Using BEADS_DIR env var provides proper test isolation. * fix(test): stop daemon before running test suite guard The test suite guard checks that tests don't modify the real repo's .beads directory. However, a background daemon running auto-sync would touch issues.jsonl during test execution, causing false positives. Changes: - Set BEADS_NO_DAEMON=1 to prevent daemon auto-start from tests - Stop any running daemon for the repo before taking the "before" snapshot - Uses exec to call `bd daemon --stop` to avoid import cycle issues * chore: revert .beads/issues.jsonl to upstream/main Per CONTRIBUTING.md, .beads/issues.jsonl should not be modified in PRs.
This commit is contained in:
79
.github/workflows/ci.yml
vendored
79
.github/workflows/ci.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Check for .beads/issues.jsonl changes
|
||||
run: |
|
||||
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "^\.beads/issues\.jsonl$"; then
|
||||
echo "❌ This PR includes changes to .beads/issues.jsonl"
|
||||
echo "This PR includes changes to .beads/issues.jsonl"
|
||||
echo ""
|
||||
echo "This file is the project's issue database and should not be modified in PRs."
|
||||
echo ""
|
||||
@@ -41,11 +41,30 @@ jobs:
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ No .beads/issues.jsonl changes detected"
|
||||
echo "No .beads/issues.jsonl changes detected"
|
||||
|
||||
# Cross-platform test matrix
|
||||
# Catches platform-specific bugs like GH#880 (macOS path casing) and GH#387 (Windows daemon)
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
name: Test (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
include:
|
||||
# Linux: full test suite with coverage
|
||||
- os: ubuntu-latest
|
||||
coverage: true
|
||||
test-flags: '-v -race -short -coverprofile=coverage.out'
|
||||
# macOS: full test suite, no coverage (faster)
|
||||
- os: macos-latest
|
||||
coverage: false
|
||||
test-flags: '-v -race -short'
|
||||
# Windows: full test suite, no race detector (slower on Windows)
|
||||
- os: windows-latest
|
||||
coverage: false
|
||||
test-flags: '-v -short'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
@@ -63,66 +82,31 @@ jobs:
|
||||
run: go build -v ./cmd/bd
|
||||
|
||||
- name: Test
|
||||
run: go test -v -race -short -coverprofile=coverage.out ./...
|
||||
run: go test ${{ matrix.test-flags }} ./...
|
||||
|
||||
- name: Check coverage threshold
|
||||
if: matrix.coverage
|
||||
run: |
|
||||
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
|
||||
MIN_COVERAGE=42
|
||||
WARN_COVERAGE=55
|
||||
echo "Coverage: $COVERAGE%"
|
||||
if (( $(echo "$COVERAGE < $MIN_COVERAGE" | bc -l) )); then
|
||||
echo "❌ Coverage is below ${MIN_COVERAGE}% threshold"
|
||||
echo "Coverage is below ${MIN_COVERAGE}% threshold"
|
||||
exit 1
|
||||
elif (( $(echo "$COVERAGE < $WARN_COVERAGE" | bc -l) )); then
|
||||
echo "⚠️ Coverage is below ${WARN_COVERAGE}% (warning threshold)"
|
||||
echo "Coverage is below ${WARN_COVERAGE}% (warning threshold)"
|
||||
else
|
||||
echo "✅ Coverage meets threshold"
|
||||
echo "Coverage meets threshold"
|
||||
fi
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
if: success()
|
||||
if: matrix.coverage && success()
|
||||
with:
|
||||
file: ./coverage.out
|
||||
fail_ci_if_error: false
|
||||
|
||||
# Windows smoke tests only - full test suite times out (see bd-bmev)
|
||||
# Linux runs comprehensive tests; Windows just verifies binary works
|
||||
test-windows:
|
||||
name: Test (Windows - smoke)
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.24'
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.name "CI Bot"
|
||||
git config --global user.email "ci@beads.test"
|
||||
|
||||
- name: Build
|
||||
run: go build -v -o bd.exe ./cmd/bd
|
||||
|
||||
- name: Smoke test - version
|
||||
run: ./bd.exe version
|
||||
|
||||
- name: Smoke test - init and CRUD
|
||||
run: |
|
||||
./bd.exe init --quiet --prefix smoke
|
||||
$output = ./bd.exe create --title "Windows smoke test" --type task
|
||||
$id = ($output | Select-String -Pattern "smoke-\w+").Matches.Value
|
||||
echo "Created issue: $id"
|
||||
./bd.exe list
|
||||
./bd.exe show $id
|
||||
./bd.exe update $id --status in_progress
|
||||
./bd.exe close $id
|
||||
echo "All smoke tests passed!"
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
@@ -139,6 +123,7 @@ jobs:
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=5m
|
||||
|
||||
test-nix:
|
||||
name: Test Nix Flake
|
||||
runs-on: ubuntu-latest
|
||||
@@ -159,9 +144,9 @@ jobs:
|
||||
FIRST_LINE=$(head -n 1 help.txt)
|
||||
EXPECTED="Issues chained together like beads. A lightweight issue tracker with first-class dependency support."
|
||||
if [ "$FIRST_LINE" != "$EXPECTED" ]; then
|
||||
echo "❌ First line of help.txt doesn't match expected output"
|
||||
echo "First line of help.txt doesn't match expected output"
|
||||
echo "Expected: $EXPECTED"
|
||||
echo "Got: $FIRST_LINE"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Help text first line is correct"
|
||||
echo "Help text first line is correct"
|
||||
|
||||
Reference in New Issue
Block a user