Merge branch 'main' of github.com:steveyegge/beads
This commit is contained in:
@@ -48,6 +48,7 @@
|
|||||||
{"id":"bd-3b7f","content_hash":"7eeed8397b2a1da442ee4126f4ed2a97f0c1ff3ef7360df0ef0fc00446ca24d1","title":"Add tests for extracted modules","description":"Create tests for migrations.go, hash_ids.go, batch_ops.go, and validators.go","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-01T19:28:54.88933-07:00","updated_at":"2025-11-01T19:54:52.925978-07:00","closed_at":"2025-11-01T19:54:52.925978-07:00"}
|
{"id":"bd-3b7f","content_hash":"7eeed8397b2a1da442ee4126f4ed2a97f0c1ff3ef7360df0ef0fc00446ca24d1","title":"Add tests for extracted modules","description":"Create tests for migrations.go, hash_ids.go, batch_ops.go, and validators.go","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-01T19:28:54.88933-07:00","updated_at":"2025-11-01T19:54:52.925978-07:00","closed_at":"2025-11-01T19:54:52.925978-07:00"}
|
||||||
{"id":"bd-3d844c58","content_hash":"92be620ba7d89a256decb33cefd8ba8a12f40413a27e4d92dca9b6189b48665b","title":"Implement content-hash based collision resolution for deterministic convergence","description":"The current collision resolution uses creation timestamps to decide which issue to keep vs. remap. This is non-deterministic when two clones create issues at nearly the same time.\n\nRoot cause of bd-71107098:\n- Clone A creates test-1=\"Issue from clone A\" at T0\n- Clone B creates test-1=\"Issue from clone B\" at T0+30ms\n- Clone B syncs first, remaps Clone A's to test-2\n- Clone A syncs second, sees collision, remaps Clone B's to test-2\n- Result: titles are swapped between clones\n\nSolution:\n- Use content-based hashing (title + description + priority + type)\n- Deterministic winner: always keep issue with lower hash\n- Same collision on different clones produces same result (idempotent)\n\nImplementation:\n- Modify ScoreCollisions in internal/storage/sqlite/collision.go\n- Replace timestamp-based scoring with content hash comparison\n- Ensure hash function is stable across platforms","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-28T17:04:06.145646-07:00","updated_at":"2025-10-30T17:12:58.225476-07:00","closed_at":"2025-10-28T19:20:09.943023-07:00","dependencies":[{"issue_id":"bd-3d844c58","depends_on_id":"bd-71107098","type":"blocks","created_at":"2025-10-31T19:38:09.203365-07:00","created_by":"stevey"}]}
|
{"id":"bd-3d844c58","content_hash":"92be620ba7d89a256decb33cefd8ba8a12f40413a27e4d92dca9b6189b48665b","title":"Implement content-hash based collision resolution for deterministic convergence","description":"The current collision resolution uses creation timestamps to decide which issue to keep vs. remap. This is non-deterministic when two clones create issues at nearly the same time.\n\nRoot cause of bd-71107098:\n- Clone A creates test-1=\"Issue from clone A\" at T0\n- Clone B creates test-1=\"Issue from clone B\" at T0+30ms\n- Clone B syncs first, remaps Clone A's to test-2\n- Clone A syncs second, sees collision, remaps Clone B's to test-2\n- Result: titles are swapped between clones\n\nSolution:\n- Use content-based hashing (title + description + priority + type)\n- Deterministic winner: always keep issue with lower hash\n- Same collision on different clones produces same result (idempotent)\n\nImplementation:\n- Modify ScoreCollisions in internal/storage/sqlite/collision.go\n- Replace timestamp-based scoring with content hash comparison\n- Ensure hash function is stable across platforms","status":"closed","priority":0,"issue_type":"task","created_at":"2025-10-28T17:04:06.145646-07:00","updated_at":"2025-10-30T17:12:58.225476-07:00","closed_at":"2025-10-28T19:20:09.943023-07:00","dependencies":[{"issue_id":"bd-3d844c58","depends_on_id":"bd-71107098","type":"blocks","created_at":"2025-10-31T19:38:09.203365-07:00","created_by":"stevey"}]}
|
||||||
{"id":"bd-3e307cd4","content_hash":"2d95ea3b6835139e1fd266bbdcd0f683b5b4d26a1041516c4883beeb37b11ede","title":"File change test issue","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T19:11:28.425601-07:00","updated_at":"2025-10-31T12:00:43.176605-07:00","closed_at":"2025-10-31T12:00:43.176605-07:00"}
|
{"id":"bd-3e307cd4","content_hash":"2d95ea3b6835139e1fd266bbdcd0f683b5b4d26a1041516c4883beeb37b11ede","title":"File change test issue","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T19:11:28.425601-07:00","updated_at":"2025-10-31T12:00:43.176605-07:00","closed_at":"2025-10-31T12:00:43.176605-07:00"}
|
||||||
|
{"id":"bd-3e3b","content_hash":"db612c737d8f330bb1ff1bbda043835d1318bb806970677ed768a69e15287653","title":"Add circular dependency detection to bd doctor","description":"Added cycle detection as Check #10 in bd doctor command. Uses same recursive CTE query as DetectCycles() to find circular dependencies. Reports error status with count and fix suggestion if cycles found.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-11-01T20:18:23.416056-07:00","updated_at":"2025-11-01T20:18:26.76113-07:00","closed_at":"2025-11-01T20:18:26.76113-07:00"}
|
||||||
{"id":"bd-3e9ddc31","content_hash":"4e03660281dbe2c069617fc8d723d546d6e5eb386142c0359b862747867a1b90","title":"Replace getStorageForRequest with Direct Access","description":"Replace all getStorageForRequest(req) calls with s.storage","acceptance_criteria":"- No references to getStorageForRequest() in codebase (except in deleted file)\n- All handlers use s.storage directly\n- Code compiles without errors\n\nFiles to update:\n- internal/rpc/server_issues_epics.go (~8 calls)\n- internal/rpc/server_labels_deps_comments.go (~4 calls)\n- internal/rpc/server_compact.go (~2 calls)\n- internal/rpc/server_export_import_auto.go (~2 calls)\n- internal/rpc/server_routing_validation_diagnostics.go (~1 call)\n\nPattern: store, err := s.getStorageForRequest(req) → store := s.storage","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:20:10.393759-07:00","updated_at":"2025-10-30T17:12:58.21613-07:00","closed_at":"2025-10-28T14:08:38.06721-07:00"}
|
{"id":"bd-3e9ddc31","content_hash":"4e03660281dbe2c069617fc8d723d546d6e5eb386142c0359b862747867a1b90","title":"Replace getStorageForRequest with Direct Access","description":"Replace all getStorageForRequest(req) calls with s.storage","acceptance_criteria":"- No references to getStorageForRequest() in codebase (except in deleted file)\n- All handlers use s.storage directly\n- Code compiles without errors\n\nFiles to update:\n- internal/rpc/server_issues_epics.go (~8 calls)\n- internal/rpc/server_labels_deps_comments.go (~4 calls)\n- internal/rpc/server_compact.go (~2 calls)\n- internal/rpc/server_export_import_auto.go (~2 calls)\n- internal/rpc/server_routing_validation_diagnostics.go (~1 call)\n\nPattern: store, err := s.getStorageForRequest(req) → store := s.storage","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:20:10.393759-07:00","updated_at":"2025-10-30T17:12:58.21613-07:00","closed_at":"2025-10-28T14:08:38.06721-07:00"}
|
||||||
{"id":"bd-3ee2c7e9","content_hash":"a1a26c30e2d2d791d3dd5b3fe3a917304cb001b1d024e4627e46fd93c98bcf86","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-26T16:53:40.970042-07:00","updated_at":"2025-10-31T20:41:33.915811-07:00"}
|
{"id":"bd-3ee2c7e9","content_hash":"a1a26c30e2d2d791d3dd5b3fe3a917304cb001b1d024e4627e46fd93c98bcf86","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-26T16:53:40.970042-07:00","updated_at":"2025-10-31T20:41:33.915811-07:00"}
|
||||||
{"id":"bd-3f80d9e0","title":"Improve internal/daemon test coverage (currently 22.5%)","description":"Daemon functionality needs better coverage:\n- Auto-start behavior\n- Lock file management\n- Discovery mechanisms\n- Connection handling\n- Error recovery","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:30.832728-07:00","updated_at":"2025-10-30T17:12:58.186077-07:00"}
|
{"id":"bd-3f80d9e0","title":"Improve internal/daemon test coverage (currently 22.5%)","description":"Daemon functionality needs better coverage:\n- Auto-start behavior\n- Lock file management\n- Discovery mechanisms\n- Connection handling\n- Error recovery","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:30.832728-07:00","updated_at":"2025-10-30T17:12:58.186077-07:00"}
|
||||||
|
|||||||
30
AGENTS.md
30
AGENTS.md
@@ -717,6 +717,36 @@ rm .beads/.exclusive-lock
|
|||||||
- Hash IDs eliminate collisions - same ID with different content is a normal update
|
- Hash IDs eliminate collisions - same ID with different content is a normal update
|
||||||
- Use `--id` flag with `bd create` to partition ID space for parallel workers (e.g., `worker1-100`, `worker2-500`)
|
- Use `--id` flag with `bd create` to partition ID space for parallel workers (e.g., `worker1-100`, `worker2-500`)
|
||||||
|
|
||||||
|
### Checking GitHub Issues and PRs
|
||||||
|
|
||||||
|
**IMPORTANT**: When asked to check GitHub issues or PRs, use command-line tools like `gh` instead of browser/playwright tools.
|
||||||
|
|
||||||
|
**Preferred approach:**
|
||||||
|
```bash
|
||||||
|
# List open issues with details
|
||||||
|
gh issue list --limit 30
|
||||||
|
|
||||||
|
# List open PRs
|
||||||
|
gh pr list --limit 30
|
||||||
|
|
||||||
|
# View specific issue
|
||||||
|
gh issue view 201
|
||||||
|
```
|
||||||
|
|
||||||
|
**Then provide an in-conversation summary** highlighting:
|
||||||
|
- Urgent/critical issues (regressions, bugs, broken builds)
|
||||||
|
- Common themes or patterns
|
||||||
|
- Feature requests with high engagement
|
||||||
|
- Items that need immediate attention
|
||||||
|
|
||||||
|
**Why this matters:**
|
||||||
|
- Browser tools consume more tokens and are slower
|
||||||
|
- CLI summaries are easier to scan and discuss
|
||||||
|
- Keeps the conversation focused and efficient
|
||||||
|
- Better for quick triage and prioritization
|
||||||
|
|
||||||
|
**Do NOT use:** `browser_navigate`, `browser_snapshot`, or other playwright tools for GitHub PR/issue reviews unless specifically requested by the user.
|
||||||
|
|
||||||
## Building and Testing
|
## Building and Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
102
cmd/bd/doctor.go
102
cmd/bd/doctor.go
@@ -56,6 +56,7 @@ This command checks:
|
|||||||
- Daemon health (version mismatches, stale processes)
|
- Daemon health (version mismatches, stale processes)
|
||||||
- Database-JSONL sync status
|
- Database-JSONL sync status
|
||||||
- File permissions
|
- File permissions
|
||||||
|
- Circular dependencies
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
bd doctor # Check current directory
|
bd doctor # Check current directory
|
||||||
@@ -165,6 +166,13 @@ func runDiagnostics(path string) doctorResult {
|
|||||||
result.OverallOK = false
|
result.OverallOK = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check 10: Dependency cycles
|
||||||
|
cycleCheck := checkDependencyCycles(path)
|
||||||
|
result.Checks = append(result.Checks, cycleCheck)
|
||||||
|
if cycleCheck.Status == statusError || cycleCheck.Status == statusWarning {
|
||||||
|
result.OverallOK = false
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,6 +863,100 @@ func checkPermissions(path string) doctorCheck {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkDependencyCycles(path string) doctorCheck {
|
||||||
|
beadsDir := filepath.Join(path, ".beads")
|
||||||
|
dbPath := filepath.Join(beadsDir, beads.CanonicalDatabaseName)
|
||||||
|
|
||||||
|
// If no database, skip this check
|
||||||
|
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
|
||||||
|
return doctorCheck{
|
||||||
|
Name: "Dependency Cycles",
|
||||||
|
Status: statusOK,
|
||||||
|
Message: "N/A (no database)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open database to check for cycles
|
||||||
|
db, err := sql.Open("sqlite", dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return doctorCheck{
|
||||||
|
Name: "Dependency Cycles",
|
||||||
|
Status: statusWarning,
|
||||||
|
Message: "Unable to open database",
|
||||||
|
Detail: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Query for cycles using simplified SQL
|
||||||
|
query := `
|
||||||
|
WITH RECURSIVE paths AS (
|
||||||
|
SELECT
|
||||||
|
issue_id,
|
||||||
|
depends_on_id,
|
||||||
|
issue_id as start_id,
|
||||||
|
issue_id || '→' || depends_on_id as path,
|
||||||
|
0 as depth
|
||||||
|
FROM dependencies
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
d.issue_id,
|
||||||
|
d.depends_on_id,
|
||||||
|
p.start_id,
|
||||||
|
p.path || '→' || d.depends_on_id,
|
||||||
|
p.depth + 1
|
||||||
|
FROM dependencies d
|
||||||
|
JOIN paths p ON d.issue_id = p.depends_on_id
|
||||||
|
WHERE p.depth < 100
|
||||||
|
AND p.path NOT LIKE '%' || d.depends_on_id || '→%'
|
||||||
|
)
|
||||||
|
SELECT DISTINCT start_id
|
||||||
|
FROM paths
|
||||||
|
WHERE depends_on_id = start_id`
|
||||||
|
|
||||||
|
rows, err := db.Query(query)
|
||||||
|
if err != nil {
|
||||||
|
return doctorCheck{
|
||||||
|
Name: "Dependency Cycles",
|
||||||
|
Status: statusWarning,
|
||||||
|
Message: "Unable to check for cycles",
|
||||||
|
Detail: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
cycleCount := 0
|
||||||
|
var firstCycle string
|
||||||
|
for rows.Next() {
|
||||||
|
var startID string
|
||||||
|
if err := rows.Scan(&startID); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cycleCount++
|
||||||
|
if cycleCount == 1 {
|
||||||
|
firstCycle = startID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cycleCount == 0 {
|
||||||
|
return doctorCheck{
|
||||||
|
Name: "Dependency Cycles",
|
||||||
|
Status: statusOK,
|
||||||
|
Message: "No circular dependencies detected",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return doctorCheck{
|
||||||
|
Name: "Dependency Cycles",
|
||||||
|
Status: statusError,
|
||||||
|
Message: fmt.Sprintf("Found %d circular dependency cycle(s)", cycleCount),
|
||||||
|
Detail: fmt.Sprintf("First cycle involves: %s", firstCycle),
|
||||||
|
Fix: "Run 'bd dep cycles' to see full cycle paths, then 'bd dep remove' to break cycles",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
doctorCmd.Flags().Bool("json", false, "Output JSON format")
|
doctorCmd.Flags().Bool("json", false, "Output JSON format")
|
||||||
rootCmd.AddCommand(doctorCmd)
|
rootCmd.AddCommand(doctorCmd)
|
||||||
|
|||||||
Reference in New Issue
Block a user