Created internal/storage/sqlite/errors.go with:
- Sentinel errors: ErrNotFound, ErrInvalidID, ErrConflict, ErrCycle
- wrapDBError helpers that auto-convert sql.ErrNoRows to ErrNotFound
- Type-safe error checking with errors.Is() compatibility
Updated error handling across storage layer:
- dirty.go: Added context to error returns, converted sql.ErrNoRows checks
- util.go: Updated withTx to use wrapDBError
- batch_ops.go: Added context wrapping to batch operations
- dependencies.go: Wrapped errors from markIssuesDirtyTx calls
- ids.go: Added error wrapping for ID validation
Also restored sqlite.go that was accidentally deleted in previous commit.
All tests pass. Provides consistent error wrapping with operation context
for better debugging.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Created internal/validation package for centralized validation logic
- Created cmd/bd/flags.go for shared flag registration
- Updated create and update commands to use shared logic
- Added support for 'P1' style priority to update command
- Added tests for validation logic
Amp-Thread-ID: https://ampcode.com/threads/T-c8d369a3-32f0-42a0-96d1-fd589e89bd6b
Co-authored-by: Amp <amp@ampcode.com>
Fixes `isHashID` checks for hyphenated application names
When a user calls bd init inside an application that has a "-" for
example my-first-application without any options than ids will follow a
pattern of my-first-application-{ID}. When using SplitN on the "-"
separator it would result in the split parts returning as [my,
first-application-{ID}] which is incorrectly pulling out the {ID}
resulting in the `isHashID` returning false when it could be a hash id.
Instead of using SplitN, this changes to find the last index of the
separator resulting in the suffix becoming the actual {ID}.
* fix: address critical resource leaks and error handling issues
Fixes 5 critical and high-priority issues identified in codebase analysis:
1. bd-vavh: Fix row iterator resource leak in recursive dependency queries
- Move defer rows.Close() to execute on all code paths
- Previously leaked connections on scan errors
- Location: internal/storage/sqlite/sqlite.go:1121-1145
2. bd-qhws: Configure database connection pool limits for daemon mode
- Set MaxOpenConns to runtime.NumCPU() + 1 for file-based databases
- Prevents connection exhaustion under concurrent RPC load
- Only affects daemon mode (long-running server)
- Location: internal/storage/sqlite/sqlite.go:108-125
3. bd-jo38: Add WaitGroup tracking to FileWatcher goroutines
- Track goroutines with sync.WaitGroup for graceful shutdown
- Wait for goroutines to finish before cleanup in Close()
- Prevents race condition on debouncer access during shutdown
- Location: cmd/bd/daemon_watcher.go (Start, startPolling, Close)
4. bd-2d5r: Fix silent error handling in RPC response writing
- writeResponse now returns errors instead of ignoring them
- Prevents sending partial JSON and client hangs
- Closes connection on marshal/write errors
- Location: internal/rpc/server_lifecycle_conn.go:227-246
5. bd-zqmb: Fix goroutine leak in daemon restart
- Add 10-second timeout to daemon Wait() goroutine
- Kill process if it doesn't fork within timeout
- Prevents goroutine accumulation on restart failures
- Location: cmd/bd/daemons.go:250-268
All changes follow Go best practices and maintain backward compatibility.
* Add feature request for .beads/README.md generation during init
Created bd-m7ge to automatically generate a promotional/documentation
README in the .beads directory when running 'bd init'. This will help
advertise Beads in open source repositories and provide quick reference
documentation for developers using AI coding agents.
The README will include:
- Brief explanation of Beads (AI-native issue tracking)
- Link to steveyegge/beads repository
- Quick reference of essential commands
- Compelling messaging to encourage adoption
monitor-webui fails to connect to the bd daemon because it calculates the socket path incorrectly. It expects beads.db.sock in a nested .beads directory, whereas the daemon listens on bd.sock in the .beads directory.
Updated `getSocketPath` function to:
- Check if dbPath directory is already .beads.
- Use bd.sock as the socket name instead of [dbName].sock.
- Handle both nested and non-nested cases correctly.
- Add fast path for exact ID matches in ResolvePartialID
- Properly unmarshal ResolveID RPC responses used by `bd show`
Summary:
--------
Fixes regression introduced after v0.23.1 where `bd show <issue_id>`,
`bd update <issue_id>`, and `bd close <issue_id>` commands failed with
"operation failed: issue not found" errors even when the issue existed
in the database.
Root Cause:
-----------
The daemon's ResolveID RPC handler (handleResolveID in
internal/rpc/server_issues_epics.go) returns a JSON-encoded string
containing the resolved issue ID. For example, when resolving "ao-izl",
the RPC response contains the JSON string: "ao-izl" (with quotes).
After v0.23.1, the show/update/close commands in cmd/bd/show.go were
changed to use string(resp.Data) to extract the resolved ID, which
treats the raw bytes as a string without decoding the JSON. This caused
the resolved ID to literally be "ao-izl" (including the quotes),
which then failed to match the actual issue ID ao-izl (without quotes)
when passed to subsequent Show/Update/Close RPC calls.
In v0.23.1 (commit 77dcf55), the code correctly unmarshaled the JSON:
var resolvedID string
if err := json.Unmarshal(resp.Data, &resolvedID); err != nil {
// handle error
}
This unmarshal step was removed in later commits, causing the regression.
Fix:
----
Restored the JSON unmarshaling step in three places in cmd/bd/show.go:
1. showCmd - line 37-42
2. updateCmd - line 400-405
3. closeCmd - line 723-728
Each now properly decodes the JSON string response before using the
resolved ID in subsequent RPC calls.
Testing:
--------
- Verified `bd show <issue-id-with-prefix>` works correctly in both daemon and direct modes
- Tested with newly created issues to ensure the fix works for all IDs
- All Go tests pass (go test ./... -short)
- Confirmed behavior matches v0.23.1 working binary
The fix ensures that issue ID resolution works correctly regardless of
whether the ID prefix matches the configured issue_prefix.
After daemon auto-export, JSONL mtime could be newer than database mtime
due to SQLite WAL mode not updating beads.db until checkpoint. This caused
validatePreExport to incorrectly block subsequent exports with "JSONL is
newer than database" error, leading to daemon shutdown.
Solution: Call TouchDatabaseFile after all export operations to ensure
database mtime >= JSONL mtime. This prevents false positives in validation