Implement exclusive lock protocol for daemon/external tool coexistence

- Add ExclusiveLock struct with JSON marshaling and validation
- Implement IsProcessAlive() with EPERM fail-safe behavior
- Add ShouldSkipDatabase() with stale lock cleanup
- Integrate lock checking into daemon sync cycle
- Return holder name on stale removal for better logging
- Case-insensitive hostname comparison
- Comprehensive unit tests (89.3% coverage)
- Documentation updates (ADVANCED.md, AGENTS.md)
- Add .beads/.exclusive-lock to .gitignore

Closes bd-115, bd-116, bd-117, bd-118, bd-119, bd-120, bd-121, bd-122

Amp-Thread-ID: https://ampcode.com/threads/T-0b835739-0d79-4ef9-aa62-8446a368c42d
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-10-25 23:32:02 -07:00
parent e42868c8e5
commit 3a42ca252d
10 changed files with 620 additions and 0 deletions

View File

@@ -927,6 +927,21 @@ func createSyncFunc(ctx context.Context, store storage.Storage, autoCommit, auto
return
}
// Check for exclusive lock before processing database
beadsDir := filepath.Dir(jsonlPath)
skip, holder, err := types.ShouldSkipDatabase(beadsDir)
if skip {
if err != nil {
log.log("Skipping database (lock check failed: %v)", err)
} else {
log.log("Skipping database (locked by %s)", holder)
}
return
}
if holder != "" {
log.log("Removed stale lock (%s), proceeding with sync", holder)
}
if err := exportToJSONLWithStore(syncCtx, store, jsonlPath); err != nil {
log.log("Export failed: %v", err)
return