Commit Graph

357 Commits

Author SHA1 Message Date
Steve Yegge
9dc0da9fdd docs: Document COALESCE/NULLIF clone-local field protection pattern
Expands the inline comment to serve as a reference for when to use the
COALESCE(NULLIF(?, zero), column) defensive idiom in JSONL imports.

Pattern protects clone-local state (pinned, gate fields) from being
overwritten when importing JSONL where omitempty causes zero values to
represent "field absent" rather than "field is zero".

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 00:45:59 -08:00
Steve Yegge
7fbc2766e2 fix(multirepo): Preserve gate await fields during upsert (bd-gr4q)
Apply COALESCE(NULLIF(...)) pattern to await_type, await_id, timeout_ns,
and waiters fields in upsertIssueInTx. This prevents gate await fields
from being cleared when importing issues from JSONL that don't have
these fields (since gates are wisps and aren't exported to JSONL.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
EOF
)
2025-12-25 23:21:03 -08:00
Aarya Reddy
bd5fc214c3 feat(ready,blocked): Add --parent flag for scoping by epic/bead desce… (#743)
* feat(ready,blocked): Add --parent flag for scoping by epic/bead descendants

Add --parent flag to `bd ready` and `bd blocked` CLI commands and MCP tools
to filter results to all descendants of a specific epic or bead.

## Backward Compatibility

- CLI: New optional --parent flag; existing usage unchanged
- RPC: New `blocked` operation added (was missing); existing operations unchanged
- MCP: New optional `parent` parameter; existing calls work as before
- Storage interface: GetBlockedIssues signature changed to accept WorkFilter
  - All callers updated to pass empty filter for existing behavior
  - Empty WorkFilter{} returns identical results to previous implementation

## Implementation Details

SQLite uses recursive CTE to traverse parent-child hierarchy:

    WITH RECURSIVE descendants AS (
        SELECT issue_id FROM dependencies
        WHERE type = 'parent-child' AND depends_on_id = ?
        UNION ALL
        SELECT d.issue_id FROM dependencies d
        JOIN descendants dt ON d.depends_on_id = dt.issue_id
        WHERE d.type = 'parent-child'
    )
    SELECT issue_id FROM descendants

MemoryStorage implements equivalent recursive traversal with visited-set
cycle protection via collectDescendants helper.

Parent filter composes with existing filters (priority, labels, assignee, etc.)
as an additional WHERE clause - all filters are AND'd together.

## RPC Blocked Support

MCP beads_blocked() existed but daemon client raised NotImplementedError.
Added OpBlocked and handleBlocked to enable daemon RPC path, which was
previously broken. Now both CLI and daemon clients work for blocked queries.

## Changes

- internal/types/types.go: Add ParentID *string to WorkFilter
- internal/storage/sqlite/ready.go: Add recursive CTE for parent filtering
- internal/storage/memory/memory.go: Add getAllDescendants/collectDescendants
- internal/storage/storage.go: Update GetBlockedIssues interface signature
- cmd/bd/ready.go: Add --parent flag to ready and blocked commands
- internal/rpc/protocol.go: Add OpBlocked constant and BlockedArgs type
- internal/rpc/server_issues_epics.go: Add handleBlocked RPC handler
- internal/rpc/client.go: Add Blocked client method
- integrations/beads-mcp/: Add BlockedParams model and parent parameter

## Usage

  bd ready --parent bd-abc              # All ready descendants
  bd ready --parent bd-abc --priority 1 # Combined with other filters
  bd blocked --parent bd-abc            # All blocked descendants

## Testing

Added 4 test cases for parent filtering:
- TestParentIDFilterDescendants: Verifies recursive traversal (grandchildren)
- TestParentIDWithOtherFilters: Verifies composition with priority filter
- TestParentIDWithBlockedDescendants: Verifies blocked issues excluded from ready
- TestParentIDEmptyParent: Verifies empty result for childless parent

* fix: Correct blockedCmd indentation and suppress gosec false positive

- Fix syntax error from incorrect indentation in blockedCmd Run function
- Add nolint:gosec comment for GetBlockedIssues SQL formatting (G201)
  The filterSQL variable contains only parameterized WHERE clauses with
  ? placeholders, not user input
2025-12-25 21:11:58 -08:00
Steve Yegge
f3a5e02a35 feat(close): Add --suggest-next flag to show newly unblocked issues (GH#679)
When closing an issue, the new --suggest-next flag returns a list of
issues that became unblocked (ready to work on) as a result of the close.

This helps agents and users quickly identify what work is now available
after completing a blocker.

Example:
  $ bd close bd-5 --suggest-next
  ✓ Closed bd-5: Completed

  Newly unblocked:
    • bd-7 "Implement feature X" (P1)
    • bd-8 "Write tests for X" (P2)

Implementation:
- Added GetNewlyUnblockedByClose to storage interface
- Implemented efficient single-query for SQLite using blocked_issues_cache
- Added SuggestNext field to CloseArgs in RPC protocol
- Added CloseResult type for structured response
- CLI handles both daemon and direct modes

Thanks to @kraitsura for the detailed feature request and design.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 20:05:04 -08:00
Steve Yegge
9c1bf7d4ea fix: Combine db prefix with type prefix for mol/wisp IDs (bd-hobo)
Changed prefix logic to combine the database prefix with the type prefix:
- bd-wisp-xxx (was: wisp-xxx)
- bd-mol-xxx (was: mol-xxx)

This ensures IDs like hq-wisp-xxx at town level and gt-mol-xxx for gastown,
maintaining database namespace while adding type recognition.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 02:10:08 -08:00
Steve Yegge
f78fe883d0 feat: Distinct prefixes for protos, molecules, wisps (bd-hobo)
Added type-specific ID prefixes for better visual recognition:
- `bd pour` now generates IDs with "mol-" prefix
- `bd wisp create` now generates IDs with "wisp-" prefix
- Regular issues continue using the configured prefix

Implementation:
- Added IDPrefix field to types.Issue (internal, not exported to JSONL)
- Added Prefix field to CloneOptions for spawning operations
- Added IDPrefix to RPC CreateArgs for daemon communication
- Updated storage layer to use issue.IDPrefix when generating IDs
- Updated pour.go and wisp.go to pass appropriate prefixes

This enables instant visual recognition of entity types and prevents
accidental modification of templates.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 02:05:25 -08:00
Steve Yegge
c28defb710 fix(sqlite): handle dots in prefix for extractParentChain (GH#664)
extractParentChain was using strings.Split(id, ".") which incorrectly
parsed prefixes containing dots (like "alicealexandra.com"). This caused
--parent to fail with "parent does not exist" even when the parent was
present in the database.

The fix uses IsHierarchicalID to walk up the hierarchy correctly, only
splitting on dots followed by numeric suffixes (the actual hierarchy
delimiter).

Example:
- "test.example-abc.1" now correctly returns ["test.example-abc"]
- Previously it incorrectly returned ["test", "test.example-abc"]

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 14:39:30 -08:00
Steve Yegge
1e7c7f5e54 fix(sqlite): update child_counters when explicit child IDs are created (GH#728)
When creating issues with explicit hierarchical IDs (e.g., bd-test.1, bd-test.2
via --id flag or import), the child_counters table was not being updated.
This caused GetNextChildID to return colliding IDs when later called with
--parent.

Changes:
- Add ensureChildCounterUpdatedWithConn() to update counter on explicit child creation
- Add ParseHierarchicalID() to extract parent and child number from IDs
- Update CreateIssue to call counter update after hierarchical ID validation
- Update EnsureIDs to call counter update when parent exists
- Add post-insert phase in batch operations to update counters after FK
  constraint can be satisfied
- Update tests to reflect new behavior where counter is properly initialized

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 13:22:55 -08:00
Steve Yegge
9743b45c6d fix(import): preserve comment created_at timestamps during import (#735)
Comment timestamps were being overwritten with CURRENT_TIMESTAMP during
import, causing infinite sync loops between hosts as each import would
update timestamps.

Added ImportIssueComment() method that accepts and preserves the original
timestamp from JSONL, and updated importComments() to use it.

Closes #735
2025-12-24 12:45:20 -08:00
Steve Yegge
5cabb0f3d7 test(storage): add interface conformance tests for storage package (bd-a15d)
Add storage_test.go with:
- Compile-time interface conformance checks for Storage and Transaction
- Mock implementations for interface testing
- Config struct tests for sqlite and postgres configurations
- Interface documentation tests that verify all method groups exist

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 00:10:42 -08:00
Steve Yegge
e67f27c092 bd sync: 2025-12-23 23:38:57 2025-12-24 00:06:41 -08:00
Steve Yegge
2de1695615 bd sync: 2025-12-23 22:33:32 2025-12-23 22:33:33 -08:00
Steve Yegge
cf9e5a597b bd sync: 2025-12-23 20:50:50 2025-12-23 20:50:50 -08:00
Steve Yegge
9c8761abc9 bd sync: 2025-12-23 20:45:19 2025-12-23 20:45:19 -08:00
Steve Yegge
f777093386 feat(rpc): add GetMoleculeProgress endpoint (bd-0oqz)
New RPC endpoint to get detailed progress for a molecule (parent issue
with child steps). Returns moleculeID, title, assignee, and list of
steps with their status (done/current/ready/blocked) and timestamps.

Used when user expands a worker in the activity feed TUI.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 18:27:35 -08:00
Steve Yegge
fe2ac97597 fix: Exclude workflow types from bd ready by default (gt-7xtn)
merge-request, gate, molecule, and message types are internal workflow
items processed by Refinery/Deacon, not work for polecats to claim.
These are now excluded from bd ready unless explicitly requested via
--type flag.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 15:05:51 -08:00
Steve Yegge
7b671662aa bd sync: 2025-12-23 13:49:07 2025-12-23 14:39:07 -08:00
Steve Yegge
0d31e4209d fix: preserve pinned field during JSONL import (bd-phtv)
Fixed two code paths where pinned=false from JSONL would overwrite
existing pinned=true in database:
- importer.go: Only update pinned if explicitly true in JSONL
- multirepo.go: Use COALESCE to preserve existing pinned value

Added tests for pinned field preservation.

Note: Bug may have additional code path - investigation ongoing.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 13:49:22 -08:00
Steve Yegge
ec0c710718 Split queries.go into focused modules (bd-rgyd)
Split internal/storage/sqlite/queries.go (1586 lines) into logical modules:

- queries.go (650 lines) - Core CRUD: CreateIssue, GetIssue, UpdateIssue, CloseIssue
- queries_search.go (429 lines) - Search/filter: SearchIssues, GetIssueByExternalRef,
  GetCloseReason, GetCloseReasonsForIssues
- queries_delete.go (464 lines) - Delete operations: CreateTombstone, DeleteIssue,
  DeleteIssues and cascade logic
- queries_rename.go (149 lines) - ID/prefix operations: UpdateIssueID,
  RenameDependencyPrefix, RenameCounterPrefix, ResetCounter
- queries_helpers.go (50 lines) - Utilities: parseNullableTimeString,
  parseJSONStringArray, formatJSONStringArray

All tests pass. No functional changes.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 13:41:24 -08:00
Steve Yegge
f2db0a1d42 fix: exclude external deps from orphan check in migration invariants (bd-ucgz)
External dependencies (external:<project>:<capability>) reference issues in
other projects and are expected to not exist in the local issues table.
The orphan check now excludes these with: AND d.depends_on_id NOT LIKE 'external:%'

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 12:42:13 -08:00
Steve Yegge
47b86b35d8 feat: add gate issue type and CLI commands for async coordination (bd-udsi)
Add async gates - coordination primitives for agents to wait on external events
like CI completion, PR merges, timers, or human approval.

Changes:
- Add 'gate' issue type to types.go with gate-specific fields:
  - AwaitType: condition type (gh:run, gh:pr, timer, human, mail)
  - AwaitID: condition identifier
  - Timeout: max wait duration
  - Waiters: mail addresses to notify when gate clears
- Add SQLite migration 027_gate_columns for new fields
- Update all SQLite storage queries to handle gate fields
- Add bd gate commands: create, show, list, close, wait
- All commands support --json output and --no-daemon mode

Closes: bd-2v0f, bd-lz49, bd-u66e

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 12:06:42 -08:00
Steve Yegge
117bdd637e fix: add nolint:misspell for SQL query with British spelling 2025-12-23 05:14:01 -08:00
Steve Yegge
8b49d8f079 fix: resolve golangci-lint errors
- Add _ = prefix for ignored Close/Remove return values
- Fix unused cmd parameter in runMoleculeReady
- Add nolint:misspell for intentional British "cancelled" spelling
- Update comments to use US spelling where not intentional

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 05:10:38 -08:00
Steve Yegge
fa9a88e2a3 feat: add waits-for dependency type for fanout gates (bd-xo1o.2)
Adds 'waits-for' dependency type for dynamic molecule bonding:
- DepWaitsFor blocks an issue until spawner's children are closed
- Two gate types: all-children (wait for all) or any-children (first)
- Updated blocked_cache.go CTE to handle waits-for dependencies
- Added --waits-for and --waits-for-gate flags to bd create command
- Added WaitsForMeta struct for gate metadata storage
- Full test coverage for all gate types and dynamic child scenarios

This enables patrol molecules to wait for dynamically-bonded arms to
complete before proceeding (Christmas Ornament pattern).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 04:00:00 -08:00
Steve Yegge
14e1f5a2e0 feat: add --parent flag to bd list command (bd-yqhh)
Filters issues by parent issue ID using parent-child dependencies.

Example: bd list --parent=bd-xyz --status=open

Changes:
- Add ParentID field to IssueFilter type
- Add --parent flag to list command
- Forward parent filter through RPC
- Implement filtering in SQLite and memory storage

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 02:10:42 -08:00
Steve Yegge
7fb92ff78c feat: implement conditional bond type for mol bond (bd-kzda)
Conditional bonds now work as documented: "B runs only if A fails".

Implementation:
- Add DepConditionalBlocks dependency type to types.go
- Add IsFailureClose() helper to detect failure keywords in close_reason
- Update blocked cache to handle conditional-blocks:
  - B is blocked while A is open
  - B stays blocked if A closes with success
  - B becomes unblocked if A closes with failure

Failure keywords: failed, rejected, wontfix, cancelled, abandoned,
blocked, error, timeout, aborted (case-insensitive)

Updated bondProtoProto, bondProtoMol, bondMolMol to use
DepConditionalBlocks for conditional bond type.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 01:32:31 -08:00
Steve Yegge
cfe823da61 refactor: add testEnv helpers, reduce SQLite test file sizes (bd-4opy)
- Add testEnv struct with common test helper methods to test_helpers.go
- Methods include CreateIssue, CreateEpic, AddDep, AddParentChild, Close,
  GetReadyWork, AssertReady, AssertBlocked
- Migrate 12+ tests in ready_test.go to use new helpers (-252 lines)
- Migrate 3 tests in dependencies_test.go to use new helpers (-34 lines)
- Total reduction: ~286 lines from test files

The testEnv pattern makes tests more readable and maintainable by:
- Eliminating boilerplate setup (store, cleanup, ctx)
- Providing semantic helper methods (AddDep vs manual AddDependency)
- Using t.Cleanup for automatic resource management

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 01:30:06 -08:00
Steve Yegge
d677554ef3 fix: prevent parallel execution migration race conditions (GH#720)
When multiple bd commands are run in parallel, they can race during database
migrations, causing "duplicate column name" errors. This happens because:

1. Process A checks if column exists → false
2. Process B checks if column exists → false
3. Process A adds column → succeeds
4. Process B adds column → FAILS (duplicate column)

Changes:
- Wrap RunMigrations in BEGIN EXCLUSIVE transaction to serialize migrations
- Disable foreign keys BEFORE the transaction (PRAGMA must be called outside tx)
- Convert nested BEGIN/COMMIT in migrations 010, 022, 025 to use SAVEPOINTs
  (SQLite does not support nested transactions)
- Remove redundant PRAGMA foreign_keys calls from individual migrations

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 00:55:05 -08:00
Steve Yegge
f795f61108 feat: add performance optimization indexes (bd-bha9, bd-a9y3, bd-jke6, bd-8x3w, bd-lk39)
Migration 026_additional_indexes adds 5 indexes identified during schema review (bd-h0we):

- idx_issues_updated_at: For GetStaleIssues date filtering
- idx_issues_status_priority: For common list query patterns
- idx_labels_label_issue: Covering index for label lookups
- idx_dependencies_issue_type: For blocked issues queries
- idx_events_issue_type: For close reason queries

These indexes improve query performance for common operations,
particularly at scale (10K+ issues).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 23:16:08 -08:00
Steve Yegge
ad02b80330 feat: display external deps in bd dep tree (bd-vks2, bd-mv6h, bd-d9mu)
External dependencies (external:project:capability) are now visible in
the dependency tree output. Previously they were invisible because the
recursive CTE only JOINed against the issues table.

Changes:
- GetDependencyTree now fetches external deps and adds them as synthetic
  leaf nodes with resolution status (satisfied/blocked)
- formatTreeNode displays external deps with special formatting
- Added helper parseExternalRefParts for parsing external refs

Test coverage added for:
- External deps appearing in dependency tree
- Cycle detection ignoring external refs
- CheckExternalDep when target has no .beads directory
- Various invalid external ref format variations

Closes: bd-vks2, bd-mv6h, bd-d9mu
2025-12-22 22:34:18 -08:00
Steve Yegge
340417f393 fix: filter satisfied external deps from GetBlockedIssues (bd-396j)
GetBlockedIssues was showing external deps as blocking even when they
were satisfied (had a closed issue with provides:capability label).

Added filterBlockedByExternalDeps() which:
- Collects all external refs from blocked issues
- Checks each with CheckExternalDeps() in batch
- Filters satisfied refs from BlockedBy lists
- Updates BlockedByCount accordingly
- Removes issues with no remaining blockers (unless status=blocked/deferred)

This matches the behavior of GetReadyWork which already filters by
external deps correctly.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 21:48:55 -08:00
Steve Yegge
62bbae9c78 feat(types): add HOP entity tracking types (bd-7pwh)
- Add EntityRef type for structured entity references with URI support
- Add Creator field to Issue for tracking who created work
- Add Validation type and Validations field for proof-of-stake approvals
- Fix RemoveDependency FK violation on external deps (bd-a3sj)
- Include all new fields in content hash computation
- Full test coverage for all new types

🤝 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 20:10:09 -08:00
Charles P. Cross
e360a74b61 fix: resolve all golangci-lint errors (#699)
Fix 12 linting issues that were causing CI failures:

errcheck (8 fixes):
- cmd/bd/mol_burn.go: wrap wispStore.Close() in defer func
- cmd/bd/mol_burn.go: handle fmt.Scanln() return value
- cmd/bd/mol_squash.go: wrap wispStore.Close() in defer func (2 locations)
- cmd/bd/wisp.go: wrap wispStore.Close() in defer func (3 locations)
- internal/beads/beads.go: wrap mainStore.Close() and wispStore.Close()

gosec G104 (2 fixes):
- internal/storage/sqlite/multirepo.go: handle rows.Close() errors

misspell (1 fix):
- cmd/bd/mol_burn.go: change "Cancelled" to "Canceled"

unparam (1 fix):
- cmd/bd/mol_squash.go: use blank identifier for unused cmd parameter

All fixes follow existing patterns in the codebase:
- defer func() { _ = store.Close() }() for deferred closes
- _ = rows.Close() for explicit closes with ignored errors
- _, _ = fmt.Scanln() for ignored return values

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-22 14:06:45 -08:00
Steve Yegge
8f8e9516df fix: bd repo commands write to YAML and cleanup on remove (#683)
- bd repo add/remove now writes to .beads/config.yaml instead of database
- bd repo remove deletes hydrated issues from the removed repo
- Added internal/config/repos.go for YAML config manipulation
- Added DeleteIssuesBySourceRepo for cleanup on remove

Fixes config disconnect where bd repo add wrote to DB but hydration read from YAML.

Breaking change: bd repo add no longer accepts optional alias argument.

Co-authored-by: Dylan Conlin <dylan.conlin@gmail.com>

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 01:26:45 -08:00
Ryan
a11b20960a fix(doctor): UX improvements for diagnostics and daemon (#687)
* fix(doctor): UX improvements for diagnostics and daemon

- Add Repo Fingerprint check to detect when database belongs to a
  different repository (copied .beads dir or git remote URL change)
- Add interactive fix for repo fingerprint with options: update repo ID,
  reinitialize database, or skip
- Add visible warning when daemon takes >5s to start, recommending
  'bd doctor' for diagnosis
- Detect install method (Homebrew vs script) and show only relevant
  upgrade command
- Improve WARNINGS section:
  - Add icons (⚠ or ✖) next to each item
  - Color numbers by severity (yellow for warnings, red for errors)
  - Render entire error lines in red
  - Sort by severity (errors first)
  - Fix alignment with checkmarks above
- Use heavier fail icon (✖) for better visibility
- Add integration and validation tests for doctor fixes

* fix(lint): address errcheck and gosec warnings

- mol_bond.go: explicitly ignore ephStore.Close() error
- beads.go: add nosec for .gitignore file permissions (0644 is standard)
2025-12-22 01:25:23 -08:00
Steve Yegge
1cfb23487b feat: bd ready filters by external dep satisfaction (bd-zmmy)
GetReadyWork now lazily resolves external dependencies at query time:
- External refs (external:project:capability) checked against target DB
- Issues with unsatisfied external deps are filtered from ready list
- Satisfaction = closed issue with provides:<capability> label in target

Key changes:
- Remove FK constraint on depends_on_id to allow external refs
- Add migration 025 to drop FK and recreate views
- Filter external deps in GetReadyWork, not in blocked_issues_cache
- Add application-level validation for orphaned local deps
- Comprehensive tests for external dep resolution

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:41:44 -08:00
Steve Yegge
a9bfce7f6e wip: external dep resolution helper (bd-zmmy) 2025-12-21 23:13:50 -08:00
Steve Yegge
e7f09660c0 feat: add cross-project dependency support - config and external: prefix (bd-66w1, bd-om4a)
Config (bd-66w1):
- Add external_projects config for mapping project names to paths
- Add GetExternalProjects() and ResolveExternalProjectPath() functions
- Add config documentation and tests

External deps (bd-om4a):
- bd dep add accepts external:project:capability syntax
- External refs stored as-is in dependencies table
- GetBlockedIssues includes external deps in blocked_by list
- blocked_issues_cache includes external dependencies
- Add validation and parsing helpers for external refs

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:08:00 -08:00
Steve Yegge
240a4e2dbc feat: add bd doctor check for orphaned issues (bd-5hrq)
- Add CheckOrphanedIssues to detect issues referenced in commits but still open
- Pattern matches (prefix-xxx) in git log against open issues in database
- Reports warning with issue IDs and commit hashes
- Add 8 comprehensive tests for the new check

Also:
- Add tests for mol spawn --attach functionality (bd-f7p1)
- Document commit message convention in AGENT_INSTRUCTIONS.md
- Fix CheckpointWAL to use wrapDBError for consistency

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 22:05:14 -08:00
Steve Yegge
358d076fde refactor: rename Ephemeral → Wisp (Steam Engine metaphor)
Wisp = ephemeral vapor produced by the Steam Engine (Gas Town).
This aligns with the metaphor:
- Claude = Fire
- Claude Code = Steam
- Gas Town = Steam Engine
- Wisps = ephemeral vapor it produces

Changes:
- types.Issue.Ephemeral → types.Issue.Wisp
- types.IssueFilter.Ephemeral → types.IssueFilter.Wisp
- JSON field: "ephemeral" → "wisp"
- CLI flag: --ephemeral → --wisp (bd cleanup)
- All tests updated

Note: SQLite column remains "ephemeral" (no migration needed).
This is a breaking change for JSON consumers using 0.33.0.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 15:22:45 -08:00
Steve Yegge
39f8461914 feat(mol): filter ephemeral issues from JSONL export (bd-687g)
Ephemeral issues should never be exported to issues.jsonl. They exist only
in SQLite and are shared via .beads/redirect pointers. This prevents
"zombie" issues from resurrecting after mol squash deletes them.

Changes:
- Filter ephemeral issues in autoflush, export, and multirepo_export
- Add --summary flag to bd mol squash for agent-provided summaries
- Fix DeleteIssue to also remove comments (missing cascade)
- Add tests for ephemeral filtering and comment deletion

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 14:37:22 -08:00
Steve Yegge
acba84ef7f fix(memory): exclude pinned issues from GetReadyWork
SQLite storage already excluded pinned issues from ready work
(bd-92u), but memory storage was missing this check. Pinned
issues are context markers, not actionable work items.

Closes bd-o9o.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 11:30:58 -08:00
Steve Yegge
5d2daf2e1e fix(pin): add 'pinned' field to allowed update fields (gt-zr0a)
The 'bd pin' command was failing with "invalid field for update: pinned"
because the pinned field was missing from allowedUpdateFields.

Fixes:
- Add 'pinned' to allowedUpdateFields in queries.go
- Update importer to include pinned field in updates during import
- Add equalBool comparator for IssueDataChanged to detect pinned changes
- Fix stats query to count pinned=1 instead of status='pinned'
- Fix pinIndicator in list.go to check issue.Pinned instead of status

This unblocks gt mail --pinned functionality.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 19:57:16 -08:00
Steve Yegge
e778b3f648 feat(status): add deferred status for icebox issues (bd-4jr)
Add 'deferred' as a valid issue status for issues that are deliberately
put on ice - not blocked by dependencies, just postponed for later.

Changes:
- Add StatusDeferred constant and update IsValid() validation
- Add DeferredIssues to Statistics struct with counting in both SQLite
  and memory storage
- Add 'bd defer' command to set status to deferred
- Add 'bd undefer' command to restore status to open
- Update help text across list, search, count, dep, stale, and config
- Update MCP server models and tools to accept deferred status
- Add deferred to blocker status checks (schema, cache, ready, compact)
- Add StatusDeferred to public API exports (beads.go, internal/beads)
- Add snowflake styling for deferred in dep tree and graph views

Semantics:
- deferred vs blocked: deferred is a choice, blocked is forced
- deferred vs closed: deferred will be revisited, closed is done
- Deferred issues excluded from 'bd ready' (already works since
  default filter only includes open/in_progress)
- Deferred issues still block dependents (they are not done!)
- Deferred issues visible in 'bd list' and 'bd stale'

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 14:24:48 -08:00
Steve Yegge
844e9ffc02 fix(deps): exclude relates-to from cycle detection (fixes #661)
relates-to dependencies are intentionally bidirectional ("see also" links)
and should not be reported as cycles by bd dep cycles. This matches the
existing behavior in AddDependency which already skips cycle prevention
for relates-to.

Changes:
- Filter relates-to edges in DetectCycles SQL query
- Add tests for relates-to exclusion from cycle detection
- Update existing test to reflect correct behavior

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:33:15 -08:00
Steve Yegge
52135d0370 feat(types): add template molecules infrastructure for beads-1ra
Add support for template molecules (is_template field and TypeMolecule type):

- Add IsTemplate field to Issue type with JSON support
- Add TypeMolecule constant to IssueType constants
- Add IsTemplate filter to IssueFilter for querying
- Update all SQL queries to include is_template column
- Add migration 024 for is_template column
- Add FindMoleculesJSONLInDir helper for molecules.jsonl path detection

This enables treating certain issues as read-only templates that can be
instantiated to create work items. The template flag allows separating
template molecules from regular work items in queries and exports.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 22:03:22 -08:00
Steve Yegge
567dd0a0c6 fix(schema): add pinned column to schema compatibility checks
The schema_probe.go and doctor/database.go had different column lists
for validating database schemas. Neither included the pinned column
added in migration 023, causing:
- Doctor to report "All required tables and columns present" on
  databases missing the pinned column
- Potential failures when using `gt mail send` on databases without
  the pinned column

Changes:
- Add pinned, sender, ephemeral to doctor's criticalChecks
- Add metadata, thread_id to dependencies check
- Add all missing columns to schema_probe.go's expectedSchema:
  source_repo, close_reason, deleted_at, deleted_by, delete_reason,
  original_type, sender, ephemeral, pinned

Fixes: beads-9yc

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 19:57:14 -08:00
Justin Williams
df5ceb5d82 feat: Linear Integration (#655)
* Add Linear integration CLI with sync and status commands

- Add `bd linear sync` for bidirectional issue sync with Linear
- Add `bd linear status` to show configuration and sync state
- Stub pull/push functions pending GraphQL client (bd-b6b.2)

* Implement Linear GraphQL client with full sync support

- Add LinearClient with auth, fetch, create, update methods
- Implement pull/push operations with Beads type mapping
- Clean up redundant comments and remove unused code

* Add configurable data mapping and dependency sync for Linear

- Add LinearMappingConfig with configurable priority/state/label/relation maps
- Import parent-child and issue relations as Beads dependencies
- Support custom workflow states via linear.state_map.* config

* Add incremental sync support for Linear integration

- Add FetchIssuesSince() method using updatedAt filter in GraphQL
- Check linear.last_sync config to enable incremental pulls
- Track sync mode (incremental vs full) in LinearPullStats

* feat(linear): implement push updates for existing Linear issues

Add FetchIssueByIdentifier method to retrieve single issues by identifier
(e.g., "TEAM-123") for timestamp comparison during push.

Update doPushToLinear to:
- Fetch Linear issue to get internal ID and UpdatedAt timestamp
- Compare timestamps: only update if local is newer
- Build update payload with title, description, priority, and state
- Call UpdateIssue for issues where local has newer changes

Closes bd-b6b.5

* Implement Linear conflict resolution strategies

- Add true conflict detection by fetching Linear timestamps via API
- Implement --prefer-linear resolution (re-import from Linear)
- Implement timestamp-based resolution (newer wins as default)
- Fix linter issues: handle resp.Body.Close() and remove unused error return

* Add Linear integration tests and documentation

- Add comprehensive unit tests for Linear mapping (priority, state, labels, relations)
- Update docs/CONFIG.md with Linear configuration reference
- Add examples/linear-workflow guide for bidirectional sync
- Remove AI section header comments from tests

* Fix Linear GraphQL filter construction and improve test coverage

- Refactor filter handling to combine team ID into main filter object
- Add test for duplicate issue relation mapping
- Add HTTP round-trip helper for testing request payload validation

* Refactor Linear queries to use shared constant and add UUID validation

- Extract linearIssuesQuery to deduplicate FetchIssues/FetchIssuesSince
- Add linearMaxPageSize constant and UUID validation with regex
- Expand test coverage for new functionality

* Refactor Linear integration into internal/linear package

- Extract types, client, and mapping logic from cmd/bd/linear.go
- Create internal/linear/ package for better code organization
- Update tests to work with new package structure

* Add linear teams command to list available teams

- Add FetchTeams GraphQL query to Linear client
- Refactor config reading to support daemon mode
- Add tests for teams listing functionality

* Refactor Linear config to use getLinearConfig helper

- Consolidate config/env var lookup using getLinearConfig function
- Add LINEAR_TEAM_ID environment variable support
- Update error messages to include env var configuration options

* Add hash ID generation and improve Linear conflict detection

- Add configurable hash ID mode for Linear imports (matches bd/Jira)
- Improve conflict detection with content hash comparison
- Enhance conflict resolution with skip/force update tracking

* Fix test for updated doPushToLinear signature

- Add missing skipUpdateIDs parameter to test call
2025-12-19 17:58:24 -08:00
Charles P. Cross
a82f393e49 fix(storage): implement RenameDependencyPrefix to preserve dependencies (#642)
* fix(storage): implement RenameDependencyPrefix to update dependency records

RenameDependencyPrefix was previously a no-op that returned nil without
updating any records. This caused dependencies to break after using
bd rename-prefix, as the issue_id and depends_on_id columns in the
dependencies table still referenced the old prefix.

The fix updates both columns in the dependencies table to use the new
prefix, ensuring all dependency relationships are preserved.

Fixes #630

* test(storage): add regression tests for RenameDependencyPrefix

Add tests verifying that RenameDependencyPrefix:
- Executes without error when no dependencies exist
- Can be called with various prefix combinations

These tests ensure the fix for GH#630 doesn't regress.

---------

Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
2025-12-19 17:52:44 -08:00
Steve Yegge
c84a2404b7 feat(ready): add --type flag for filtering by issue type (gt-ktf3)
Enables bd ready --type=merge-request for MQ integration.
The Engineer can now query for ready merge-requests.

Files changed:
- cmd/bd/ready.go: Add -t/--type flag
- internal/types/types.go: Add Type field to WorkFilter
- internal/rpc/protocol.go: Add Type to ReadyArgs
- internal/storage/sqlite/ready.go: Filter by issue_type column
2025-12-19 15:09:30 -08:00