Commit Graph

4102 Commits

Author SHA1 Message Date
Steve Yegge
6a9e68630b chore: bump version to v0.37.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 01:29:30 -08:00
Steve Yegge
efe8180078 docs: Add 0.37.0 release notes
- Gate commands: bd gate create/eval/approve for async coordination
- New features: --suggest-next, --parent flag, TOML formulas, fork detection
- Fixes: gate await fields, tombstone timestamps, git caching, Windows support
2025-12-26 01:29:30 -08:00
Steve Yegge
1fdd3538d2 bd sync: 2025-12-26 01:12:48 2025-12-26 01:12:48 -08:00
Steve Yegge
cc858b8273 bd sync: 2025-12-26 01:10:54 2025-12-26 01:11:03 -08:00
Steve Yegge
8fa3a21a8a bd sync: 2025-12-26 00:58:07 2025-12-26 01:11:03 -08:00
Steve Yegge
a975cdecd9 bd sync: 2025-12-26 00:57:19 2025-12-26 01:11:03 -08:00
Steve Yegge
64d2f372a3 fix: Allow tombstones to retain closed_at timestamp
Previously, tombstones could not have a closed_at timestamp due to:
1. Go validation: `if status != closed && closed_at != nil` failed
2. SQL CHECK constraint: `(status = 'closed') = (closed_at IS NOT NULL)`

This caused import failures for tombstones that were closed before being
deleted - a valid scenario where we want to preserve the historical
closed_at timestamp for audit purposes.

Changes:
- internal/types/types.go: Updated validation to allow tombstones with
  closed_at (line 253)
- internal/storage/sqlite/schema.go: Updated CHECK constraint to allow
  closed AND tombstone statuses to have closed_at
- internal/storage/sqlite/migrations/028_tombstone_closed_at.go: Migration
  to update existing databases with the new constraint
- .beads/issues.jsonl: Fixed bd-6s61 status from 'closed' to 'tombstone'

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 00:57:59 -08:00
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
53921d75c8 chore: Move beads-release formula to gastown
Formulas are Gas Town orchestration workflows, not beads primitives.
The release workflow now lives in gastown/mayor/rig/.beads/formulas/

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 23:47:32 -08:00
Steve Yegge
e0403c2d31 Add mail gate evaluation in bd gate eval (gt-twjr5.4)
Mail gates check for messages matching the pattern (await_id):
- Case-insensitive substring match on message subjects
- If waiters specified, only matches messages to those recipients
- Closes gate when matching message found

Note: Full testing blocked by bd-70c4 (await fields being cleared).
The code is correct but gate fields get corrupted by auto-import.

Also adds context and storage imports for mail gate function.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 23:42:05 -08:00
Steve Yegge
a0e4267aa0 Add bd gate approve command for human gates (gt-twjr5.4)
Human gates now have proper workflow:
- Create with: bd gate create --await human:approve-deploy
- Approve with: bd gate approve <gate-id> [--comment "reason"]
- bd gate eval now reports human gates as "awaiting approval"
- Rejects non-human gates with clear error message

Also added mail gate placeholder in eval (awaiting mail: ...).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 23:35:35 -08:00
Steve Yegge
c366d538a1 bd sync: Filed bd-70c4 (gate await fields bug) 2025-12-25 23:32:44 -08:00
Steve Yegge
3b0630ba0e chore(formula): Convert beads-release to TOML format
Align with Gas Town formula format change from JSON to TOML.
Same content, cleaner syntax.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 23:31:32 -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
Steve Yegge
5788f90aa1 bd sync: 2025-12-25 23:20:35 2025-12-25 23:20:35 -08:00
Steve Yegge
9a508240d9 fix(gate): Use correct gh pr field name (mergedAt, not merged)
The merged field does not exist in gh pr view output. The actual
fields are:
- state: OPEN, CLOSED, or MERGED
- mergedAt: timestamp string (empty if not merged)

Also simplified the switch statement since state already distinguishes
merged vs closed-without-merge PRs.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 23:10:00 -08:00
Steve Yegge
1c95ac9ae2 bd sync: 2025-12-25 22:57:05 2025-12-25 22:58:10 -08:00
Steve Yegge
92e6ccb88d bd sync: 2025-12-25 22:45:49 2025-12-25 22:58:10 -08:00
Steve Yegge
e22cdc2f58 bd sync: 2025-12-25 22:34:55 2025-12-25 22:58:10 -08:00
Steve Yegge
e581188c80 bd sync: 2025-12-25 22:27:01 2025-12-25 22:58:10 -08:00
Steve Yegge
acc7168931 bd sync: 2025-12-25 22:04:46 2025-12-25 22:58:10 -08:00
Steve Yegge
3d83226d93 bd sync: 2025-12-25 20:20:55 2025-12-25 22:58:10 -08:00
Steve Yegge
07181560a7 feat(gate): Add GitHub gate evaluation (gh:run, gh:pr)
Implements evaluation for GitHub-related gate types:

- gh:run: Checks if a GitHub Actions run has completed using
  `gh run view <id> --json status,conclusion`
- gh:pr: Checks if a PR has been merged/closed using
  `gh pr view <id> --json state,merged`

Both gate types require the gh CLI to be installed and authenticated.
If gh fails (not installed, network issues, invalid IDs), the gate is
skipped rather than erroneously closed.

Refactors the eval loop to use a switch statement for cleaner
gate type dispatch.

(gt-twjr5.3)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 22:57:39 -08:00
Steve Yegge
f6c739f75e feat(merge): Export Merge3WayWithTTL for configurable tombstone TTL (bd-6rl) 2025-12-25 22:45:44 -08:00
Steve Yegge
19a182a26a docs(git): Add thread-safety warning to ResetCaches() (bd-43xj) 2025-12-25 22:45:44 -08:00
Steve Yegge
1d3a7f98df Add bd gate eval command for timer gate evaluation (gt-twjr5.2)
- New `bd gate eval` command evaluates all open gates and closes elapsed ones
- Timer gates: closes when elapsed time exceeds timeout duration
- For timer gates, parse duration from await_id if --timeout not explicitly set
- Supports --dry-run and --json output modes
- Idempotent and safe to run repeatedly (e.g., in Deacon patrol)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 22:29:05 -08:00
Steve Yegge
32c803dd16 fix(worktree): Cache git detection results to eliminate slowness (bd-7di)
In git worktrees, any bd command was slow with a 2-3s pause because:
- git.IsWorktree() was called 4+ times per command
- Each call spawned 2 git processes (git-dir and git-common-dir)
- git.GetRepoRoot() and git.GetMainRepoRoot() also called multiple times

Fix: Cache results using sync.Once since these values do not change during
a single command execution:
- IsWorktree() - caches worktree detection
- GetRepoRoot() - caches repo root path
- GetMainRepoRoot() - caches main repo root for worktrees

Added ResetCaches() for test cleanup between subtests that change directories.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 22:04:40 -08:00
Steve Yegge
df5d4b384c Add TOML support for formulas (gt-xmyha)
- Add TOML parsing using BurntSushi/toml
- Update formula loader to try .toml first, fall back to .json
- Add `bd formula convert` command for JSON→TOML migration
- Multi-line string support for readable descriptions
- Cache git worktree/reporoot checks for performance

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 21:59:19 -08:00
Steve Yegge
5c3a40156c feat(init): Auto-detect fork repos and offer to configure .git/info/exclude (GH#742)
When bd init runs in a forked repo (detected via upstream remote), prompt
the user to configure .git/info/exclude to keep beads files local.

- Add --setup-exclude flag for manual trigger
- Add fork detection to init flow (reuses detectForkSetup)
- Add setupForkExclude() to configure .git/info/exclude with:
  .beads/, **/RECOVERY*.md, **/SESSION*.md
- Add promptForkExclude() with Y/n prompt (default yes)
- Add containsExactPattern() helper for precise pattern matching

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 21:38:20 -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
4ffbab5311 docs(worktrees): Add 'Fully Separate Beads Repository' section (GH#195)
Document the BEADS_DIR workflow for storing beads in a completely
separate git repository from your code. This feature was added in
PR #533 by @dand-oss but wasn't documented.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 20:48:59 -08:00
Steve Yegge
e91f0de8d1 feat(formula): Add inline step expansion (gt-8tmz.35)
Steps can now declare their own expansion using the Expand field:

  steps:
    - id: design
      expand: rule-of-five
      expand_vars:
        iterations: 3

This is more convenient than compose.expand for single-step expansions.
The step is replaced by the expansion template with variables substituted.

Reuses existing expandStep() and mergeVars() from gt-8tmz.34.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 20:46:12 -08:00
Steve Yegge
f82c75c39e feat(formula): Validate expanded step IDs are unique (gt-8tmz.36) 2025-12-25 20:19:55 -08:00
Steve Yegge
e8458935f9 feat(formula): Implement expansion var overrides (gt-8tmz.34)
- Add vars parameter to expandStep for {varname} substitution
- Add mergeVars to combine formula defaults with rule overrides
- Update ApplyExpansions to merge and pass vars for expand/map rules
- Apply var substitution to step ID, title, description, assignee,
  labels, and dependencies
- Add comprehensive tests for var overrides functionality

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 20:07:29 -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
35ab0d7a7f bd sync: 2025-12-25 20:01:27 2025-12-25 20:01:27 -08:00
Steve Yegge
76c1e08a9b bd sync: 2025-12-25 20:01:13 2025-12-25 20:01:13 -08:00
Steve Yegge
46b7f162cf bd sync: 2025-12-25 19:55:25 2025-12-25 19:55:25 -08:00
Steve Yegge
488ec56938 fix(mcp): Graceful fallback on Windows for daemon mode (GH#387)
- Skip daemon mode on Windows (sys.platform == win32)
- Falls back to CLI mode which works on all platforms
- Avoids asyncio.open_unix_connection which does not exist on Windows

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 19:50:55 -08:00
Steve Yegge
c64ad028b7 fix(npm): Windows postinstall file locking issue (GH#670)
- Move write stream creation after redirect handling to avoid orphan
  streams that keep file handles open
- Add 100ms delay after file.close() on Windows to ensure handle release
- Fixes "The process cannot access the file" error during extraction

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 19:47:22 -08:00
Steve Yegge
bbe1980b6c bd sync: 2025-12-25 19:43:27 2025-12-25 19:43:27 -08:00
Steve Yegge
3e7628348a bd sync: 2025-12-25 19:40:08 2025-12-25 19:40:08 -08:00
Steve Yegge
8050e7b5fa bd sync: 2025-12-25 19:38:08 2025-12-25 19:38:08 -08:00
Steve Yegge
fbd2371200 bd sync: 2025-12-25 19:32:24 2025-12-25 19:32:24 -08:00
Steve Yegge
ae2a0b2503 bd sync: merge divergent histories (content-level recovery) 2025-12-25 19:30:40 -08:00
Steve Yegge
b21b318588 feat: Improve bd mol distill command
- Update help text to clarify mol/wisp/epic support (not just epics)
- Add daemon support (no longer requires --no-daemon)
- Add -o shorthand for --output flag
- Update use cases to match new architecture

Part of bd-1dez.1

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 18:54:33 -08:00
Steve Yegge
cfecadc8a5 docs: Clarify formulas are JSON, add distillation and sharing docs
- Fix YAML → JSON references in formula.go and types.go
- Update MOLECULES.md with ephemeral proto architecture
- Add Distillation section: extract formulas from completed work
- Add Sharing section: Mol Mall formula marketplace
- Update Layer Cake diagram to show ephemeral proto flow

Related: bd-1dez (Mol Mall epic)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 18:43:08 -08:00
Steve Yegge
abf672243c feat: Compile-time vs runtime cooking (gt-8tmz.23)
Add --mode flag (compile/runtime) and --var flag to bd cook command.

Compile-time mode (default):
- Keeps {{variable}} placeholders intact
- Use for: modeling, estimation, contractor handoff

Runtime mode (triggered by --var or --mode=runtime):
- Substitutes variables with provided values
- Validates all required variables have values
- Use for: final validation before pour

Also updates --dry-run output to clearly show which mode is active
and display substituted values in runtime mode.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 18:40:15 -08:00
Steve Yegge
ea9f1d2760 Add edge case tests for expression evaluator (code review)
Test cases for:
- Unary minus in expression: 3*-2 -> -6
- Parenthesized negative: (-5) -> -5
- Unary minus after power: 2^-1 -> 0 (truncated)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 17:55:42 -08:00
Steve Yegge
030838cfde Implement computed range expansion for loops (gt-8tmz.27)
Add support for for-each expansion over computed ranges:

  loop:
    range: "1..2^{disks}-1"  # Evaluated at cook time
    var: move_num
    body: [...]

Features:
- Range field in LoopSpec for computed iterations
- Var field to expose iteration value to body steps
- Expression evaluator supporting + - * / ^ and parentheses
- Variable substitution in range expressions using {name} syntax
- Title/description variable substitution in expanded steps

Example use case: Towers of Hanoi formula where step count is 2^n-1

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 17:48:35 -08:00