brainclaw 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -260
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +182 -14
- package/dist/commands/mcp.js +18 -4
- package/dist/core/agent-registry.js +51 -3
- package/dist/core/claims.js +18 -0
- package/dist/core/facade-schema.js +12 -0
- package/dist/core/federation-cloud.js +142 -11
- package/dist/core/federation-outbox.js +292 -0
- package/dist/core/federation-signing.js +115 -0
- package/dist/core/io.js +6 -0
- package/dist/core/schema.js +11 -0
- package/dist/core/worktree.js +25 -4
- package/dist/facts.js +5 -5
- package/dist/facts.json +4 -4
- package/docs/mcp-schema-changelog.md +18 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -429,266 +429,12 @@ npm run test:coverage # with coverage report
|
|
|
429
429
|
|
|
430
430
|
## Changelog
|
|
431
431
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
- **Coordination hygiene v1** (pln#602) — family-level TTL sweep (park-don't-delete, `config.hygiene`-overridable), lazy at the `bclaw_work` read path (zero extra reads on a healthy store) + full at session-start, K-times aging of stale warnings/hints into one actionable aggregate, and `brainclaw doctor --hygiene`.
|
|
439
|
-
- **Worktree creation for in-tree projects** (pln#614) — `bclaw_coordinate(assign|review)` on a project dir that isn't the git root (app inside a monorepo) now resolves the real toplevel (`resolveGitToplevel` with a parent-walk past an invalid nested `.git`), so it spawns instead of failing with "not a git repository". Standalone projects unchanged; validated E2E on the reporting monorepo.
|
|
440
|
-
- **Dispatch-supervisor round-3 spec** (pln#545, docs) — `docs/concepts/dispatch-supervisor.md`: honest worker-liveness attribution (Node supervisor + `run_id`-keyed sentinels), A0→B hard dependency, Windows Job Object FAIL-CLOSED, complete behavior matrix. Implementation lands later as A0-first increments.
|
|
441
|
-
|
|
442
|
-
### v1.13.0
|
|
443
|
-
|
|
444
|
-
Operator-maturity batch from two days of heavy multi-agent dogfooding — dispatch/worktree lifecycle, claim parity, write-path auto-repair, model routing, benchmark gate, 2× faster context reads:
|
|
445
|
-
|
|
446
|
-
- **Model selection for codex and copilot spawns** (pln#606) — `dispatch run --model <m>` now reaches codex (`exec -m`) and copilot argv, verified on the installed binaries. The codex `--add-dir` writable-roots spike closed negative on Windows: file-first stays the codex transport.
|
|
447
|
-
- **Auto-repair identity & session on canonical writes** (pln#608) — `bclaw_create`/`update`/`remove`/`transition` auto-register + auto-session instead of throwing "Start a session first", with an explicit `session auto-created` warning; the trust boundary for unknown identities is unchanged.
|
|
448
|
-
- **Time-to-first-value benchmark with blocking CI budgets** (pln#604) — seeded synthetic stores, three scenarios (cold_onboard / warm_work / first_edit), budgets versioned in `bench-budgets.json`.
|
|
449
|
-
- **Claim lifecycle parity** (trp#928) — `bclaw_transition(entity='claim')` wired, `coordinator_override` (trusted+) on release/transition, cascade release with per-claim logging on plan-done / loop close / assignment-completed / harvest, entity-scoped `bclaw_find` filter rejections.
|
|
450
|
-
- **Squash-aware worktree GC + junction-safe removal** (trp#926) — squash-merged lanes are finally collected (content-based detection), and the Windows `node_modules`-junction wipe class is closed for good; `dispatch_status` compares against the worktree's creation ref.
|
|
451
|
-
- **VS Code extension** — Backlog pagination (recent plans were invisible, trp#925) and probe/spawn parity with classified, actionable resolver failures (trp#927).
|
|
452
|
-
- **Context read 2× faster on large stores** (pln#578) — 3 of the 4 full-store read passes per context build eliminated (disabled-reputation sweep ×2, estimation reload, triple candidate scan): 23.9 s → 11.9 s, 196 MB → 49 MB parsed, byte-identical output.
|
|
453
|
-
|
|
454
|
-
### v1.12.0
|
|
455
|
-
|
|
456
|
-
Auto-localized execution writes for multi-project workspaces (pln#597), from DGX-Spark dogfooding:
|
|
457
|
-
|
|
458
|
-
- **Execution writes auto-localize into a workspace sibling named by `project=X`** — `bclaw_create`/`bclaw_transition` (plan & claim), `bclaw_claim`, the step tools and `bclaw_delete_plan` open a session + sticky switch into a workspace store-chain child instead of rejecting with "limited to signaling entities", echoing `auto_switched`. The signaling-vs-execution boundary is re-scoped to federation (`cross_project_links`): federated links and unknown names stay blocked.
|
|
459
|
-
|
|
460
|
-
### v1.11.1
|
|
461
|
-
|
|
462
|
-
Agent-identity & session-hook resilience, from a fresh-CLI dogfood on a monorepo:
|
|
463
|
-
|
|
464
|
-
- **Session hooks no longer spam `UserPromptSubmit hook error` on every prompt.** Root cause was an agent-identity error whose own remediation (`register-agent --set-current`) the resolver ignored, swallowed by `2>/dev/null`. Now: the error hint points at what actually works (`--agent` / `$BRAINCLAW_AGENT_NAME`), a **single registered agent auto-resolves** with no env signal, and `session-start`/`context-diff`/`session-end` run with `--hook` so they degrade to exit 0 + `~/.brainclaw/hook.log` instead of erroring the prompt loop. Multi-agent safety (pln#562) is unchanged.
|
|
465
|
-
- **`brainclaw doctor --fix-hooks`** purges stale/broken/duplicate brainclaw hooks across all Claude Code settings scopes (user + cwd) and rewrites the canonical ones — for the broken hooks that accumulate where `setup`'s git-repo discovery never reached.
|
|
466
|
-
- **`setup` repo discovery recurses** (bounded, skipping `node_modules`/build dirs) so repos nested deep in a workspace are found instead of silently missed, and it registers the detected agent so the hooks it installs can resolve an identity.
|
|
467
|
-
|
|
468
|
-
### v1.11.0
|
|
469
|
-
|
|
470
|
-
Monorepo project-resolution + Code Map, cross-project relocation, and dispatch-worktree hygiene — from a multi-project (monorepo) dogfood:
|
|
471
|
-
|
|
472
|
-
- **`bclaw_switch` to the monorepo root now works, and a switch is honored everywhere.** An agent inside a child project could not switch *up* to the workspace-root project, and a session-scoped switch was silently lost (sessions are stored per-cwd, but the resolver read them only at the workspace anchor). The resolver now matches the root project by `project_name`/`project_id` and probes the anchor / physical cwd / workspace root for the session, so `bclaw_switch` is authoritative for every subsequent call — including Code Map — without `--cwd`.
|
|
473
|
-
- **`code-map refresh --cascade`** — monorepo-native, per-project indexing: one command at the root refreshes **every** nested project into its own store plus a child-scoped root store, with **zero double-indexing** (even under nesting). `code-map status --cascade` adds a per-child recap. Opt-in; single-project repos are unchanged.
|
|
474
|
-
- **`brainclaw move <entity> <id> --to <project>` / `bclaw_move`** — id-preserving cross-project relocation, closing the gap the switch bug exposed (items created in the wrong store). Execution-local entities (claim/assignment/agent_run/session) stay put; refuses id collisions and active-claim moves; audits both stores.
|
|
475
|
-
- **Sub-agent worktrees auto-clean on loop close** — a completed review/dispatch loop garbage-collects its worktrees (junction-safe; keeps any that are alive, un-harvested, or carry unmerged commits). Opt out with `BRAINCLAW_NO_WORKTREE_GC=1`.
|
|
476
|
-
|
|
477
|
-
### v1.10.2
|
|
478
|
-
|
|
479
|
-
Dispatch worktree-creation hardening (parallel-lane dispatch on a large repo): the claim-scope branch slug is length-capped *before* its trailing-dot strip (a scope ending in `…Page.astro` no longer truncates to an invalid `feat/…Page.` ref), and `git worktree add` gets a dedicated timeout (120s default; override `BRAINCLAW_WORKTREE_ADD_TIMEOUT_MS`) so a several-hundred-file checkout isn't SIGTERM-killed mid-materialize.
|
|
480
|
-
|
|
481
|
-
### v1.10.1
|
|
482
|
-
|
|
483
|
-
Code Map fast-follows from the 1.10.0 dogfood, plus a lint cleanup:
|
|
484
|
-
|
|
485
|
-
- A git branch switch now flags the index stale (new `stale_git_head` freshness reason); `refresh` honors `.gitignore` (gitignored output dirs no longer indexed); `brief("<path>")` resolves the exact file instead of token-flooding; and the freshness badge distinguishes index freshness from a call's spot-check (`index_status`).
|
|
486
|
-
- The `brainclaw-session` skill + agent instruction surface now point agents at `bclaw_code_find` / `bclaw_code_brief` before grep. Lint baseline cleared to zero (stylistic rules ratcheted to `error`); README doc links clickable; `docs/code-map.md` lists JS / TS / JSX / TSX · Python · PHP · Java.
|
|
487
|
-
|
|
488
|
-
### v1.10.0
|
|
489
|
-
|
|
490
|
-
- **Code Map** — a new per-project [Tree-sitter](docs/code-map.md) symbol + import
|
|
491
|
-
index for **JS / TS / TSX, Python, PHP, and Java**. Ask *"where is X / what should I
|
|
492
|
-
read first"* before editing: `bclaw_code_find`, `bclaw_code_brief`,
|
|
493
|
-
`bclaw_code_status`, `bclaw_code_refresh` (CLI: `brainclaw code-map …`). Pull-based
|
|
494
|
-
freshness with a per-response badge; never blocks `bclaw_work`; monorepo-aware. See
|
|
495
|
-
[code map](docs/code-map.md).
|
|
496
|
-
- **Monorepo multi-project safety** — agents working in different child projects of a
|
|
497
|
-
monorepo are now genuinely independent:
|
|
498
|
-
- an anchored agent working *inside* a child project resolves **that** child, not the
|
|
499
|
-
repo root — no more "plans / index target the repo root";
|
|
500
|
-
- CLI `brainclaw switch` is **session-scoped by default** (two agents no longer clobber
|
|
501
|
-
a shared pointer); the new `--global` flag is the only path that sets the shared
|
|
502
|
-
workspace default; `switch --list` / show are session-aware;
|
|
503
|
-
- a session-less agent physically inside a child project beats a stale shared global
|
|
504
|
-
pointer (resolves the child it is in);
|
|
505
|
-
- dispatched / CoDev workers spawn with a **clean identity** — the coordinator's
|
|
506
|
-
session / project / agent env no longer leaks into a worker.
|
|
507
|
-
- Internal — MCP public surface fingerprint re-pinned for the Code Map tools (additive;
|
|
508
|
-
no tool removed or renamed).
|
|
509
|
-
|
|
510
|
-
### v1.9.1
|
|
511
|
-
|
|
512
|
-
- **Multi-project scoping fixes for monorepos** — MCP reads/writes resolve the
|
|
513
|
-
effective project from an explicit arg, the MCP session, `BRAINCLAW_CWD`, or
|
|
514
|
-
the global active project (in that order), so commands target the right store
|
|
515
|
-
inside a monorepo; `bclaw_find` legacy-filter diagnostics report how many
|
|
516
|
-
`provenance.kind="legacy"` records the default filter excluded.
|
|
517
|
-
- **Case-insensitive agent names** — `targetAgents=["Codex"]` (any casing) now
|
|
518
|
-
resolves like `codex`; dispatch/coordinate no longer silently drop a reviewer
|
|
519
|
-
over a capital letter, and an unresolved name reports a distinct `unknown_agent`
|
|
520
|
-
reason instead of the misleading "no CLI spawn template (IDE-only?)".
|
|
521
|
-
- **Docs** — revamped Loop Engine, Git Worktrees, Cross-Project Signals, and the
|
|
522
|
-
Orchestration Playbook, corrected against actual behavior (`bclaw_work` =
|
|
523
|
-
session + context + claim, not worktree provisioning; worktrees come from
|
|
524
|
-
dispatch/coordinate; plans via `bclaw_create(entity="plan")`).
|
|
525
|
-
|
|
526
|
-
### v1.9.0
|
|
527
|
-
|
|
528
|
-
- **Release hardening for npm publishing + agent-surface coherence** (pln#571).
|
|
529
|
-
A dedicated CI **Release Package Check** builds the CLI, builds the optional
|
|
530
|
-
VS Code extension, runs the extension tests, and verifies the published tarball
|
|
531
|
-
contents; `version --publish-local`/`prepublishOnly` now run `build:release` +
|
|
532
|
-
`pack:check` before `npm pack`. The `.vsix` ships as an *optional* IDE
|
|
533
|
-
companion (local CLI builds skip it; release builds stay strict). Generated
|
|
534
|
-
agent surfaces no longer pin the npm semver (stable `Managed by brainclaw`
|
|
535
|
-
banner), and `.brainclaw/project.md` is documented as a legacy derived view —
|
|
536
|
-
root `PROJECT.md` is the durable project vision; live claims/plans/handoffs
|
|
537
|
-
live in `agent-board` / MCP context.
|
|
538
|
-
- **Coordination & safety fixes** — strict claim isolation (a duplicate active
|
|
539
|
-
claim on the same scope now fails inside the mutation lock instead of warning),
|
|
540
|
-
`JsonStore` entity-id validation to prevent path traversal (pln#571), and
|
|
541
|
-
`reflect --batch` no longer swallows identity/security errors so a strict
|
|
542
|
-
import can never silently skip sensitive content (pln#572).
|
|
543
|
-
- **Concurrency & CI robustness** — the journal append waits fairly under
|
|
544
|
-
contention so a multi-process kill-9 storm converges without seq reuse
|
|
545
|
-
(pln#573/#574), and `merge-risk` reconciles Windows 8.3 short-name worktree
|
|
546
|
-
paths so a claim matches its lane on Windows runners (pln#576).
|
|
547
|
-
- **Docs** — Roo, Continue, Windsurf, Copilot, OpenClaw, quickstart, and the
|
|
548
|
-
agent-integration docs now match the current export formats and setup behavior
|
|
549
|
-
(pln#571/#575).
|
|
550
|
-
|
|
551
|
-
### v1.8.0
|
|
552
|
-
|
|
553
|
-
- **Multi-agent dispatch convergence — "worktree-as-contract"** (from a real
|
|
554
|
-
cross-project field session where a sandboxed worker could neither commit nor
|
|
555
|
-
reach MCP). The worker's contract shrinks to "edit files in this worktree +
|
|
556
|
-
drop `LANE-RESULT.json`": `brainclaw harvest --integrate` commits the worktree
|
|
557
|
-
diff on behalf of a worker that can't self-commit (hard-guarded to the linked
|
|
558
|
-
worktree, never the main repo), then completes the assignment and releases the
|
|
559
|
-
claim with plan cascade. A `LANE-RESULT.json` is now the #1 verdict signal in
|
|
560
|
-
`bclaw_dispatch_status` (worker FINISHED, even without self-update); the
|
|
561
|
-
dispatcher refuses to spawn without an isolated worktree; `open_loop` reviews
|
|
562
|
-
pre-flight each reviewer agent with a trivial validation spawn (clear
|
|
563
|
-
boot-failure reason instead of a generic loop timeout); and decisions/traps
|
|
564
|
-
gain `verified_at`/`verify_cmd` so perishable facts can be flagged stale.
|
|
565
|
-
Additive + opt-in throughout. (pln#530, pln#531, pln#532, pln#533, pln#534, trp#468)
|
|
566
|
-
|
|
567
|
-
### v1.7.5
|
|
568
|
-
|
|
569
|
-
- **Security patch (recommended upgrade)** — fixes a git command-injection / RCE
|
|
570
|
-
vector flagged by Socket AI: several commands interpolated a git ref (notably
|
|
571
|
-
one derived from the persisted session `git_sha`) into `execSync` shell
|
|
572
|
-
strings. All git calls now use `execFileSync` (no shell) and `git_sha` is
|
|
573
|
-
validated as a hex SHA. No functional change. (session-end, release-claims,
|
|
574
|
-
release-notes, sync)
|
|
575
|
-
|
|
576
|
-
### v1.7.4
|
|
577
|
-
|
|
578
|
-
- **Dispatch observability + worker DX hardening** (from a real cross-project
|
|
579
|
-
field session) — `bclaw_dispatch_status` and the reconciler now derive liveness
|
|
580
|
-
from filesystem activity (log + worktree mtime), so a worker actively editing
|
|
581
|
-
files is no longer falsely flagged `stalled`, and known codex boot-failure
|
|
582
|
-
stderr signatures get a targeted diagnosis; briefs are transport-aware (a
|
|
583
|
-
sandboxed agent without MCP/commit gets the file protocol, not instructions it
|
|
584
|
-
can't follow), backed by a derived capability matrix
|
|
585
|
-
(`dispatchHasMcp`/`dispatchCanCommit`); `bclaw_claim` gains an advisory
|
|
586
|
-
(no-worktree) mode; `bclaw_find` payloads are size-bounded with pagination
|
|
587
|
-
metadata; an opt-in per-worktree `tsc --noEmit` pre-commit gate; gated ready
|
|
588
|
-
lanes carry a code-propagation advisory; the reconciler auto-releases the claim
|
|
589
|
-
of a run it infers failed; and `plan.related_paths` is now updatable.
|
|
590
|
-
(pln#479, pln#491, pln#527, pln#528, pln#529, trp#291, trp#431, trp#433, trp#434)
|
|
591
|
-
|
|
592
|
-
### v1.7.3
|
|
593
|
-
|
|
594
|
-
- **Multi-agent dispatch hardening for JS/TS monorepos** — dispatched worktrees
|
|
595
|
-
junction-link per-package `node_modules` (npm / yarn / pnpm workspaces), not
|
|
596
|
-
just the root, and surface failed links instead of swallowing them; `brainclaw worktree clean` now garbage-collects merged worktrees past birth-noise instead
|
|
597
|
-
of skipping them all; the agent inventory reports an agent `spawnable` when its
|
|
598
|
-
binary is on PATH even if `--version` is slow to start; dispatch-verification
|
|
599
|
-
guidance leads with `bclaw_dispatch_status` (not the untrustworthy Windows
|
|
600
|
-
wrapper pid); and a new `LANE-RESULT.json` convention + `brainclaw harvest <assignment_id>` give workers a standard, MCP-free result channel. The dispatch
|
|
601
|
-
dirty-guard also ignores `.claude/`, `.cursor/`, and `.codex/` agent-local
|
|
602
|
-
config. (pln#523, pln#524, pln#525, pln#526, trp#371, trp#427, trp#428)
|
|
603
|
-
|
|
604
|
-
### v1.7.2
|
|
605
|
-
|
|
606
|
-
- **Sequence MCP tools are agent-first by default** — sequence creation,
|
|
607
|
-
listing, update, and deletion tools are now in the default MCP catalog, with
|
|
608
|
-
explicit lane item schemas (`planId`, optional `stepId`, `rank`,
|
|
609
|
-
dependencies, lane metadata) and matching canonical CRUD validation for
|
|
610
|
-
`entity="sequence"`.
|
|
611
|
-
|
|
612
|
-
### v1.7.1
|
|
613
|
-
|
|
614
|
-
- **MCP project context isolation fix** — `bclaw_switch` now keeps MCP switches
|
|
615
|
-
session-scoped even when the agent session has to be resolved or created on
|
|
616
|
-
the fly. Session lookup honors explicit session IDs, avoids adopting another
|
|
617
|
-
live process's session, detects Codex via native `CODEX_*` runtime variables,
|
|
618
|
-
and `bclaw_switch(list=true)` reports the session active project with
|
|
619
|
-
`active_source`.
|
|
620
|
-
|
|
621
|
-
### v1.7.0
|
|
622
|
-
|
|
623
|
-
- **Dispatch reliability + scope-aware dirty guard** — evidence-first
|
|
624
|
-
`agent_run` reconciliation avoids false terminal states, `bclaw_coordinate`
|
|
625
|
-
accepts pinned refs and a scope-aware `allow_dirty` guard, and the Hermes
|
|
626
|
-
agent integration joins the supported surfaces.
|
|
627
|
-
|
|
628
|
-
### v1.6.0
|
|
629
|
-
|
|
630
|
-
- **Bootstrap loop + cross-project agent workflow** — the bootstrap ideation
|
|
631
|
-
preset can materialize `PROJECT.md`, `bclaw_init_project` initializes and links
|
|
632
|
-
arbitrary project paths, and `project=` routing reaches `bclaw_work` /
|
|
633
|
-
`bclaw_loop` for linked-project operations.
|
|
634
|
-
|
|
635
|
-
### v1.5.3
|
|
636
|
-
|
|
637
|
-
- **Cross-project canonical grammar + CLI parity** (pln#359, all phases) — the canonical grammar (`bclaw_find / get / create / update / remove / transition`), `bclaw_context`, and `bclaw_coordinate` now accept an optional `project: <name>` argument that routes the operation to a linked project. Two link kinds are recognised: `cross_project_links` (sibling/peer projects in `config.yaml`, `brainclaw link list`) and workspace store-chain children. Arbitrary directory paths are rejected — adoption requires an explicit link, which gives the user a single point of control over what an agent can reach. Identity is sourced from the caller's home registry; entity writes + audit log entries land in the target. Unknown project names throw `validation_error` with a hint listing the configured links — no silent fallback. Cross-project `bclaw_coordinate` is **inbox-only**: claim/assignment/message all land in the target, the target agent picks the brief up async via its own `bclaw_work`, and auto-spawn from the source process is force-disabled because the spawn cwd / worktree are tied to the target's git repo (a warning surfaces in `FacadeResponse.warnings`). The CLI exposes the same as a global `--project <name>` flag, mutually exclusive with `--cwd`. Refs: helper `resolveProjectCwd` in `src/core/cross-project.ts`, MCP write/read handler dispatch in `src/commands/mcp.ts` and `src/commands/mcp-read-handlers.ts`, `--project` plumbing in `src/cli.ts` preAction, surface advertisement in `src/core/instruction-templates.ts`, plus tests in `tests/unit/cross-project.test.ts` (10 unit cases on the helper), `tests/unit/bclaw-coordinate.test.ts` (4 cross-project routing cases), and `tests/cli-cross-project.test.ts` (5 e2e cases). Closes the `--cwd` workaround pattern that had been the day-to-day shape of multi-project sessions.
|
|
638
|
-
- **Site facts contract** (umbrella `pln_7fdfd70d` sprint 0) — new `scripts/emit-site-facts.mjs` emits `dist/facts.{js,json}` from `MCP_TOOL_NAMES` + `ENTITY_NAMES` so the brainclaw-site (and any consumer) can pull live tool/entity counts at build time without forking the values into a hand-maintained config. The package `files` list ships `dist/facts.json`; build:cli runs the emitter as part of the chain.
|
|
639
|
-
|
|
640
|
-
### v1.5.2
|
|
641
|
-
|
|
642
|
-
- **Grammar fix: `bclaw_update` no longer silently drops patches** (trp#187, pln#500) — the canonical CRUD surface promised that `EntityRegistry.updatable` listed every patchable field, but the legacy impls behind the dispatch (`updatePlan`, `updateMemoryItem`) only handled a typed subset. A `as UpdatePlanInput` cast in `entity-operations.ts` masked the gap from TypeScript: callers passed `{text, tags, severity, …}`, validation accepted them, and the function bodies never read them. Empirically reproduced this session on `pln#359` (text+tags drop) and `trp#187` itself (severity drop). Fix adds a generic-patch escape-hatch (`patch?: Partial<…>`) on `UpdatePlanInput` and `UpdateMemoryInput`, applied via `Object.assign` after the typed fields so legacy CLI callers keep their behaviour. The dispatch in `entity-operations.ts` now passes the full patch through that escape-hatch for plan/decision/constraint/trap. `runtime_note`, `candidate`, and `cross_project_link` were already correct. New `tests/unit/entity-update-coverage.test.ts` is parametric: for every `(entity, field)` pair in `EntityRegistry.updatable`, create + patch + get + assert the field actually persisted (29 cases). Adding a new updatable field will require adding a coverage row, so the contract stays honest.
|
|
643
|
-
|
|
644
|
-
### v1.5.1
|
|
645
|
-
|
|
646
|
-
- **Cross-project link CLI + grammar parity** (pln#454 step 2) — new `brainclaw link add/list/remove` subcommands and a stateless `cross_project_link` entity wired into the canonical CRUD verbs (`bclaw_create / find / get / update / remove`). The pain point was small (config.yaml is hand-editable) but the asymmetry — runtime cross-project signaling shipped, management UX did not — meant federation peers had no first-class affordance. Storage stays in `config.cross_project_links`; the entity is intentionally stateless (no transitions). Refs: `src/commands/link.ts`, `src/core/cross-project.ts` (new `addCrossProjectLink` / `removeCrossProjectLink`), `src/core/entity-registry.ts` (new `xpl` prefix), `src/core/entity-operations.ts` dispatch cases, `tests/unit/link.test.ts` + `tests/unit/cross-project-link-grammar.test.ts` (26 new cases).
|
|
647
|
-
- **Agent registry pruned** (pln#454 step 1) — 8 synthetic profiles (antigravity, copilot-vscode, claude-opus, copilot-identity, copilot, claude-sonnet, visionnaire, copilot-codev) and 11 abandoned sessions archived under `.brainclaw/archive/agents/2026-05-07/`. The whitelist that survives matches `feedback_allowed_dispatch_agents.md`: `claude-code`, `codex`, `github-copilot`, plus `jberdah` (curator). Auto-re-registration in `detectAiAgent` is intentionally preserved — if a real surface starts a session, the registry auto-rebuilds for it. Pure store cleanup, no code change.
|
|
648
|
-
- **Inbox + assignment lifecycle reconciliation** (housekeeping) — 89 stale inbox messages and 7 orphan offered-assignments closed with retroactive lifecycle updates. The plans they backed (pln#478 mcp self-heal, pln#480 multi-stack worktree, pln#483 bclaw_work compact, pln#471 tier-B live companions) had all merged weeks earlier without the dispatch path calling `bclaw_assignment_update`. Captured as `feedback_dispatch_test_inbox_debris` so future drift is mass-acked instead of triaged per-message.
|
|
649
|
-
|
|
650
|
-
### v1.5.0
|
|
651
|
-
|
|
652
|
-
- **Ideation loop MVP** (pln#492) — new `bclaw_coordinate(intent='ideate')` opens a memory-confrontation loop: critic reads only adversarial categories (traps + feedback + runtime_notes + critique_history) and gets a BM25-ranked, context-filtered, 12k-token-capped brief assembled from project memory. Single-agent (champion drives manually) or multi-agent (auto-dispatch a turn per critic). Iteration block (cycle, max_iterations, exit_when), phase-advance gate (≥3 critique artifacts before leaving critique), system events (`phase_advance_blocked`, `max_iterations_reached`). Full design: [docs/concepts/ideation-loop.md](docs/concepts/ideation-loop.md).
|
|
653
|
-
- **Reliable dispatch + autonomy contract** (pln#496) — codex / sandboxed task-based agents now emit the full lifecycle (accepted → started → progress → completed). `briefMode` resolution corrected: `task-based && hasMcp → 'full'` (not 'compact', which silently dropped the protocol section). Lazy reconciliation pattern: `agentrun-reconciler` runs at every read path (`bclaw_assignment_events`, `bclaw_loop intent='get'`, `doctor --dispatch`) instead of a daemon; first run auto-recovered 9 historical orphan agent_runs in <1s. New autonomy contract section in instruction surfaces — agents execute protocol-defined transitions instead of pausing to ask. New `buildClaimEnvPrefix` consolidates cross-shell env injection (Windows defaults to cmd, POSIX uses unquoted bytes per PATH conventions). New `brainclaw doctor --dispatch` for operator-facing dispatch health.
|
|
654
|
-
- **Worktree junction wipe fix** (pln#498) — `detachWorktreeJunctions` runs before `git worktree remove` on Windows so git's recursive rm cannot follow the `node_modules` junction back into the main repo. Closes the recurring post-merge wipe trap; validated empirically on multiple back-to-back merges in the v1.5.0 session.
|
|
655
|
-
- **Methodological lessons** captured as user auto-memory feedback memos: bisect historical state before bisecting code (regression vs. always-broken-but-hidden), lazy reconcile at read paths beats daemon polling, codex briefs MUST include the Protocol section (implicit instructions don't propagate to sandboxed CLIs).
|
|
656
|
-
|
|
657
|
-
### v1.2.0
|
|
658
|
-
|
|
659
|
-
- **zod 3 → 4 migration** (pln#486) — schemas are semantically equivalent but the JSON Schema emitted by `tools/list` shifted shape; downstream MCP clients that snapshot schemas should re-pin. See `docs/mcp-schema-changelog.md` for the public surface fingerprint.
|
|
660
|
-
|
|
661
|
-
### v1.1.0
|
|
662
|
-
|
|
663
|
-
- **Node 20+ baseline** (pln#485) — `engines.node` is now `>=20.0.0` (Node 18 reached EOL in April 2025). CI matrix runs Node 22 and 24 on Linux; Windows on Node 24. Node 20 remains the minimum installable runtime but is no longer CI-verified.
|
|
664
|
-
- **commander 13 → 14** (requires Node 20+).
|
|
665
|
-
- **@types/node 22 → 24** (LTS-aligned).
|
|
666
|
-
|
|
667
|
-
### v1.0.15
|
|
668
|
-
|
|
669
|
-
- **TypeScript 5.8 → 6.0** (pln#484) — migration to `module: "nodenext"` (`Node16` is deprecated in TS 6, scheduled for removal in TS 7); explicit `types: ["node"]` since TS 6 changed the default to `[]`.
|
|
670
|
-
|
|
671
|
-
### v1.0.14
|
|
672
|
-
|
|
673
|
-
- **`bclaw_work` compact payload by default** (pln#483) — avoids exceeding the ~25k MCP token cap on projects with substantial memory. Pass `compact: false` for the full payload, or call `bclaw_context(kind="memory")` after.
|
|
674
|
-
- **MCP runtime self-heal + `doctor --repair`** (pln#478) — when `dist/mcp-worker.js` is missing, the server logs an actionable repair pointer and read-only handlers keep serving in-process. `brainclaw doctor --repair` rebuilds dist in one step.
|
|
675
|
-
- **Tier B/C native live companions** (pln#471) — `.cursor/live.md`, `.clinerules/live.md`, `.windsurf/rules/live.md`, `.github/copilot-instructions.live.md`, `.continue/live.md`, `GEMINI.live.md` regenerated on session-end and handoff. Opt-in via `brainclaw export --include-live --write`.
|
|
676
|
-
|
|
677
|
-
### v1.0.13
|
|
678
|
-
|
|
679
|
-
- **Worktree GC scope hardening** (pln#477) — `safeRemoveWorktreeDir` no longer follows symlinks/junctions during cleanup. Closes a class of post-merge wipes that previously destroyed `node_modules` and other neighboring directories on Windows.
|
|
680
|
-
|
|
681
|
-
### v1.0.10–v1.0.12
|
|
682
|
-
|
|
683
|
-
- **GitHub Copilot CLI is spawnable** (pln#440) — Copilot CLI 1.0.35+ supports `-p "<prompt>" --allow-all --no-ask-user`; tier promoted to A.
|
|
684
|
-
- **Codex spawn on Windows: stdin pipe + 30s handshake TTL** (pln#475) — fixes embedded backticks/`#`/multi-line content getting mis-parsed by `cmd.exe` when a prompt is passed as an inline argument.
|
|
685
|
-
- **Brief-ack file handshake** (pln#476) — `.brainclaw/coordination/runtime/ack/<assignmentId>.ack` proves a spawned worker started, decoupling the handshake from MCP availability inside the worker (important for Codex in `--sandbox workspace-write`).
|
|
686
|
-
- **`bclaw_loop(intent="open")` orphan-gate** (pln#461) — refuses to open a loop without dispatch unless `allow_orphan: true` is explicit. Use `bclaw_coordinate(intent="review", open_loop: true)` instead.
|
|
687
|
-
- **Kilocode** — Tier B integration with native MCP config and live companion (pln#464).
|
|
688
|
-
|
|
689
|
-
### v1.0.0
|
|
690
|
-
|
|
691
|
-
- **Canonical grammar promoted to standard tier** — `bclaw_find` / `bclaw_get` / `bclaw_create` / `bclaw_update` / `bclaw_remove` / `bclaw_transition`, plus the entry facades `bclaw_work` and `bclaw_context`, the multi-agent facades `bclaw_coordinate` and `bclaw_dispatch`, and the loop facade `bclaw_loop`. Legacy per-entity tools removed from the discoverable surface (still callable as a migration escape hatch). See `docs/concepts/mcp-governance.md` for tier rules and the deprecation policy.
|
|
432
|
+
Full version history lives in **[CHANGELOG.md](CHANGELOG.md)** (Keep a Changelog
|
|
433
|
+
format, Semantic Versioning). MCP protocol / schema changes and the public surface
|
|
434
|
+
fingerprint are tracked separately in
|
|
435
|
+
**[docs/mcp-schema-changelog.md](docs/mcp-schema-changelog.md)**. For releases
|
|
436
|
+
predating the changelog file, `git log` on `master` is the source of truth — each
|
|
437
|
+
release commit follows the `chore(release): bump version to <semver>` convention.
|
|
692
438
|
|
|
693
439
|
---
|
|
694
440
|
|
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -1957,7 +1957,14 @@ federationCmd
|
|
|
1957
1957
|
const msg = createFederationMessage({
|
|
1958
1958
|
version: 1,
|
|
1959
1959
|
from: { project_name: config.project_name, project_path: process.cwd(), agent_name: agent },
|
|
1960
|
-
to: {
|
|
1960
|
+
to: {
|
|
1961
|
+
project_name: options.toProject ?? 'broadcast',
|
|
1962
|
+
project_path: '',
|
|
1963
|
+
// Wire --to-agent into the message (was declared but dropped, so every
|
|
1964
|
+
// push went out as a broadcast with to_agent NULL — found during the
|
|
1965
|
+
// cross-machine E2E, pln#365). Omitted → undefined → broadcast, as before.
|
|
1966
|
+
...(options.toAgent ? { agent_name: options.toAgent } : {}),
|
|
1967
|
+
},
|
|
1961
1968
|
type: options.type,
|
|
1962
1969
|
payload: { text: message },
|
|
1963
1970
|
});
|
|
@@ -2002,23 +2009,184 @@ federationCmd
|
|
|
2002
2009
|
});
|
|
2003
2010
|
federationCmd
|
|
2004
2011
|
.command('status')
|
|
2005
|
-
.description('
|
|
2012
|
+
.description('Diagnose cloud federation: config, health, signing identity, approved agent')
|
|
2006
2013
|
.action(async () => {
|
|
2007
|
-
const {
|
|
2008
|
-
const
|
|
2009
|
-
|
|
2010
|
-
console.log(`
|
|
2011
|
-
console.log(`
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2014
|
+
const { diagnoseCloudBridge } = await import('./core/federation-cloud.js');
|
|
2015
|
+
const d = await diagnoseCloudBridge();
|
|
2016
|
+
const yn = (b) => (b ? 'yes' : 'no');
|
|
2017
|
+
console.log(`Cloud URL: ${d.apiUrl}`);
|
|
2018
|
+
console.log(`API Key: ${process.env.BRAINCLAW_CLOUD_API_KEY ? '***configured***' : (d.configured ? 'from config' : 'NOT SET')}`);
|
|
2019
|
+
console.log(`Configured: ${yn(d.configured)}`);
|
|
2020
|
+
console.log(`Opted-in: ${yn(d.enabled)}`);
|
|
2021
|
+
console.log(`Project: ${d.projectId ?? '(none)'}`);
|
|
2022
|
+
console.log(`Require signed writes: ${yn(d.requireSigned)}`);
|
|
2023
|
+
if (d.health) {
|
|
2024
|
+
console.log(d.health.ok
|
|
2025
|
+
? `Cloud status: ${d.health.status} (v${d.health.version})`
|
|
2026
|
+
: `Cloud unreachable: ${d.health.error ?? 'unknown error'}`);
|
|
2027
|
+
}
|
|
2028
|
+
if (d.signing.available) {
|
|
2029
|
+
console.log('\nSigning identity:');
|
|
2030
|
+
console.log(` Agent: ${d.signing.agentName} [${d.signing.cloudAgentId}]`);
|
|
2031
|
+
console.log(` Key present: yes`);
|
|
2032
|
+
console.log(` Fingerprint: ${d.signing.fingerprint.slice(0, 16)}…`);
|
|
2033
|
+
}
|
|
2034
|
+
else {
|
|
2035
|
+
console.log(`\nSigning identity: unavailable — ${d.signing.reason}`);
|
|
2036
|
+
}
|
|
2037
|
+
if (d.approvedAgent) {
|
|
2038
|
+
console.log('\nApproved agent (cloud):');
|
|
2039
|
+
if (d.approvedAgent.found) {
|
|
2040
|
+
console.log(` Status: ${d.approvedAgent.status ?? '(unknown)'}`);
|
|
2041
|
+
console.log(` Trust: ${d.approvedAgent.trustLevel ?? '(unknown)'}`);
|
|
2042
|
+
console.log(` Key match: ${d.approvedAgent.fingerprintMatch ? 'yes ✔' : 'NO ✗ (local key does not match the registered key)'}`);
|
|
2043
|
+
}
|
|
2044
|
+
else {
|
|
2045
|
+
console.log(` Not found${d.approvedAgent.error ? ` — ${d.approvedAgent.error}` : ''}`);
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
if (d.requireSigned && !d.signing.available) {
|
|
2049
|
+
console.log('\n⚠ require_signed is set but no signing identity is available — the bridge will refuse to push (fail-closed).');
|
|
2050
|
+
}
|
|
2051
|
+
});
|
|
2052
|
+
federationCmd
|
|
2053
|
+
.command('identity')
|
|
2054
|
+
.description('Show this agent\'s federation signing identity (public key to approve in the cloud UI)')
|
|
2055
|
+
.option('--agent <name>', 'Agent name (defaults to the current agent)')
|
|
2056
|
+
.option('--json', 'Output as JSON')
|
|
2057
|
+
.action(async (options) => {
|
|
2058
|
+
const { resolveOrAutoRegisterAgentIdentity, ensureAgentSigningKey, resolveCurrentAgentName } = await import('./core/agent-registry.js');
|
|
2059
|
+
const agentName = options.agent ?? resolveCurrentAgentName();
|
|
2060
|
+
const { identity } = resolveOrAutoRegisterAgentIdentity({ agentName, cwd: process.cwd() });
|
|
2061
|
+
const key = ensureAgentSigningKey(identity.agent_id);
|
|
2062
|
+
if (options.json) {
|
|
2063
|
+
console.log(JSON.stringify({
|
|
2064
|
+
agent_name: identity.agent_name,
|
|
2065
|
+
local_agent_id: identity.agent_id,
|
|
2066
|
+
fingerprint: key.fingerprint,
|
|
2067
|
+
public_key_pem: key.publicKeyPem,
|
|
2068
|
+
}, null, 2));
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
console.log(`Agent name: ${identity.agent_name}`);
|
|
2072
|
+
console.log(`Local agent id: ${identity.agent_id}`);
|
|
2073
|
+
console.log(`Fingerprint: ${key.fingerprint}`);
|
|
2074
|
+
console.log('\nPublic key — paste into the cloud UI (project → Agents → Register / approve an agent):\n');
|
|
2075
|
+
console.log(key.publicKeyPem.trim());
|
|
2076
|
+
console.log('\nThen, on this machine, configure the bridge with the cloud agent id shown after approval:');
|
|
2077
|
+
console.log(` export BRAINCLAW_AGENT_NAME=${identity.agent_name}`);
|
|
2078
|
+
console.log(' export BRAINCLAW_CLOUD_AGENT_ID=<agt_... returned by the UI>');
|
|
2079
|
+
console.log(' (plus BRAINCLAW_CLOUD_API_KEY, BRAINCLAW_PROJECT_ID) — then run `brainclaw federation status`.');
|
|
2080
|
+
});
|
|
2081
|
+
federationCmd
|
|
2082
|
+
.command('sync')
|
|
2083
|
+
.description('Drain the federation outbox — push signed claim upserts to the cloud')
|
|
2084
|
+
.option('--entity <type>', 'Entity type to sync (increment 1: claim)', 'claim')
|
|
2085
|
+
.option('--limit <n>', 'Max records to push this run')
|
|
2086
|
+
.option('--dry-run', 'Reconcile + list pending records without any network calls')
|
|
2087
|
+
.option('--json', 'Output as JSON')
|
|
2088
|
+
.action(async (options) => {
|
|
2089
|
+
const outbox = await import('./core/federation-outbox.js');
|
|
2090
|
+
const { pushClaimToCloud, isCloudConfigured } = await import('./core/federation-cloud.js');
|
|
2091
|
+
const cwd = process.cwd();
|
|
2092
|
+
const PARK_AFTER = 5;
|
|
2093
|
+
const reconciled = outbox.reconcileOutbox(cwd);
|
|
2094
|
+
let records = outbox.listOutboxRecords(cwd);
|
|
2095
|
+
if (options.limit)
|
|
2096
|
+
records = records.slice(0, parseInt(options.limit, 10));
|
|
2097
|
+
const counts = { synced: 0, superseded: 0, parked: reconciled.parked, dropped: reconciled.dropped, retry: 0 };
|
|
2098
|
+
const lines = [];
|
|
2099
|
+
const emit = (line) => { lines.push(line); if (!options.json)
|
|
2100
|
+
console.log(line); };
|
|
2101
|
+
if (options.dryRun) {
|
|
2102
|
+
for (const r of records)
|
|
2103
|
+
emit(`pending ${r.record.entity_type} ${r.record.entity_id} r${r.record.rev} (${r.record.to_status})`);
|
|
2104
|
+
const out = { dry_run: true, reconciled, pending: records.length, records: lines };
|
|
2105
|
+
if (options.json)
|
|
2106
|
+
console.log(JSON.stringify(out, null, 2));
|
|
2107
|
+
else
|
|
2108
|
+
console.log(`\npending=${records.length} reconciled_dropped=${reconciled.dropped} reconciled_parked=${reconciled.parked}`);
|
|
2109
|
+
return;
|
|
2110
|
+
}
|
|
2111
|
+
if (!isCloudConfigured(cwd)) {
|
|
2112
|
+
console.error('Error: cloud not configured (set BRAINCLAW_CLOUD_API_KEY or cloud_sync). Records left in outbox.');
|
|
2113
|
+
process.exit(3);
|
|
2114
|
+
}
|
|
2115
|
+
let failClosed = false;
|
|
2116
|
+
for (const r of records) {
|
|
2117
|
+
const res = await pushClaimToCloud(r.record.payload, cwd);
|
|
2118
|
+
const tag = `${r.record.entity_id} r${r.record.rev}`;
|
|
2119
|
+
if (res.kind === 'not_configured' || res.kind === 'fail_closed') {
|
|
2120
|
+
failClosed = true;
|
|
2121
|
+
emit(`fail-closed ${tag} (${res.kind}) — not sent`);
|
|
2122
|
+
break; // same config for all remaining records
|
|
2017
2123
|
}
|
|
2018
|
-
|
|
2019
|
-
|
|
2124
|
+
if (res.kind === 'network_error') {
|
|
2125
|
+
const attempts = r.record.attempts + 1;
|
|
2126
|
+
if (attempts >= PARK_AFTER) {
|
|
2127
|
+
outbox.parkRecord(r, `network error x${attempts}: ${res.error}`, cwd);
|
|
2128
|
+
counts.parked++;
|
|
2129
|
+
emit(`park ${tag} (network x${attempts}: ${res.error})`);
|
|
2130
|
+
}
|
|
2131
|
+
else {
|
|
2132
|
+
outbox.recordAttempt(r, { http_status: null, error: res.error }, cwd);
|
|
2133
|
+
counts.retry++;
|
|
2134
|
+
emit(`retry ${tag} (network: ${res.error})`);
|
|
2135
|
+
}
|
|
2136
|
+
continue;
|
|
2137
|
+
}
|
|
2138
|
+
const { httpStatus, code } = res;
|
|
2139
|
+
if (httpStatus === 200 || httpStatus === 201) {
|
|
2140
|
+
outbox.archiveToSent(r, { http_status: httpStatus }, cwd);
|
|
2141
|
+
counts.synced++;
|
|
2142
|
+
emit(`pushed ${tag} → ${httpStatus}`);
|
|
2143
|
+
}
|
|
2144
|
+
else if (httpStatus === 409 && (code === 'STALE' || code === 'stale_version')) {
|
|
2145
|
+
outbox.archiveToSent(r, { http_status: httpStatus }, cwd);
|
|
2146
|
+
counts.superseded++;
|
|
2147
|
+
emit(`superseded ${tag} → 409 ${code} (cloud has a newer rev)`);
|
|
2148
|
+
}
|
|
2149
|
+
else if (httpStatus === 409) {
|
|
2150
|
+
outbox.parkRecord(r, `409 ${code ?? 'conflict'}`, cwd);
|
|
2151
|
+
counts.parked++;
|
|
2152
|
+
emit(`PARK ${tag} → 409 ${code ?? 'conflict'} (divergence — inspect)`);
|
|
2153
|
+
}
|
|
2154
|
+
else if (httpStatus === 403) {
|
|
2155
|
+
outbox.parkRecord(r, `403 ${code ?? 'forbidden'}`, cwd);
|
|
2156
|
+
counts.parked++;
|
|
2157
|
+
emit(`PARK ${tag} → 403 ${code ?? 'forbidden'}`);
|
|
2158
|
+
}
|
|
2159
|
+
else if (httpStatus >= 500) {
|
|
2160
|
+
const attempts = r.record.attempts + 1;
|
|
2161
|
+
if (attempts >= PARK_AFTER) {
|
|
2162
|
+
outbox.parkRecord(r, `5xx x${attempts} (last ${httpStatus})`, cwd);
|
|
2163
|
+
counts.parked++;
|
|
2164
|
+
emit(`park ${tag} → ${httpStatus} (x${attempts})`);
|
|
2165
|
+
}
|
|
2166
|
+
else {
|
|
2167
|
+
outbox.recordAttempt(r, { http_status: httpStatus, error: null }, cwd);
|
|
2168
|
+
counts.retry++;
|
|
2169
|
+
emit(`retry ${tag} → ${httpStatus}`);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
else {
|
|
2173
|
+
outbox.parkRecord(r, `${httpStatus} ${code ?? 'client error'}`, cwd);
|
|
2174
|
+
counts.parked++;
|
|
2175
|
+
emit(`PARK ${tag} → ${httpStatus} ${code ?? ''}`.trim());
|
|
2020
2176
|
}
|
|
2021
2177
|
}
|
|
2178
|
+
const summary = `synced=${counts.synced} superseded=${counts.superseded} retry=${counts.retry} parked=${counts.parked} dropped=${counts.dropped}`;
|
|
2179
|
+
if (options.json)
|
|
2180
|
+
console.log(JSON.stringify({ ...counts, fail_closed: failClosed, records: lines }, null, 2));
|
|
2181
|
+
else
|
|
2182
|
+
console.log(`\n${summary}`);
|
|
2183
|
+
if (failClosed)
|
|
2184
|
+
process.exit(3);
|
|
2185
|
+
if (counts.parked > 0)
|
|
2186
|
+
process.exit(2);
|
|
2187
|
+
if (counts.retry > 0)
|
|
2188
|
+
process.exit(1);
|
|
2189
|
+
// exit 0
|
|
2022
2190
|
});
|
|
2023
2191
|
// --- codev (legacy experimental) ---
|
|
2024
2192
|
if (isCodevEnabled()) {
|
package/dist/commands/mcp.js
CHANGED
|
@@ -27,7 +27,7 @@ import { ENTITY_REGISTRY } from '../core/entity-registry.js';
|
|
|
27
27
|
import { generateClaimId, listClaims, loadClaim, saveClaim, createCoordinatorClaim, adoptClaimSession, attachAssignmentMessageToClaim, linkClaimToAssignment, releaseClaimWithCascade } from '../core/claims.js';
|
|
28
28
|
import { createSequence, updateSequence, deleteSequence } from '../core/sequence.js';
|
|
29
29
|
import { assertCrossProjectBoundary, checkPolicy } from '../core/policy.js';
|
|
30
|
-
import { createWorktree as coreCreateWorktree } from '../core/worktree.js';
|
|
30
|
+
import { createWorktree as coreCreateWorktree, sanitizeBranchComponent } from '../core/worktree.js';
|
|
31
31
|
import { createRuntimeNote } from './runtime-note.js';
|
|
32
32
|
import { createCandidateFromInput } from './reflect.js';
|
|
33
33
|
import { acceptCandidate } from './accept.js';
|
|
@@ -56,7 +56,7 @@ import { deleteMemoryItem, updateMemoryItem } from '../core/operations/memory-mu
|
|
|
56
56
|
import { assessMemoryPressure, buildCompactionTemplate, applyCompaction } from '../core/gc-semantic.js';
|
|
57
57
|
import { WorkRequestSchema, CoordinateRequestSchema } from '../core/facade-schema.js';
|
|
58
58
|
import { codeMapWorkSection, codeMapRefreshNextActions } from '../core/code-map/work-section.js';
|
|
59
|
-
import { getSpawnableAgents, getCapabilityProfile, buildInvokeCommand, validateAgentForDispatch } from '../core/agent-capability.js';
|
|
59
|
+
import { getSpawnableAgents, getCapabilityProfile, buildInvokeCommand, validateAgentForDispatch, resolveModel } from '../core/agent-capability.js';
|
|
60
60
|
import { attemptExecution } from '../core/execution.js';
|
|
61
61
|
import { createAgentRun, transitionAgentRun } from '../core/agentruns.js';
|
|
62
62
|
import { sweepDeadPidRunningAgentRunsAtRead } from '../core/agentrun-reconciler.js';
|
|
@@ -520,6 +520,7 @@ const MCP_WRITE_TOOLS = [
|
|
|
520
520
|
agents: { type: 'array', items: { type: 'string' }, description: 'Only dispatch to these agents. Default: all available.' },
|
|
521
521
|
lanes: { type: 'array', items: { type: 'string' }, description: 'Only dispatch items in these lanes. Also used by intent=analysis.' },
|
|
522
522
|
maxAssignments: { type: 'number', description: 'Max assignments to make (default: all ready). intent=execute only.' },
|
|
523
|
+
model: { type: 'string', description: 'Model to run on spawned workers, decoupled from agent identity (e.g. "sonnet", "gpt-5-codex"). Injected as `<model_flag> <model>` for agents that declare one (claude-code/codex/copilot); no-op for template-pinned identities. Mirrors the CLI `brainclaw dispatch run --model`. intent=execute only.' },
|
|
523
524
|
dryRun: { type: 'boolean', description: 'Preview without sending. Accepted by all intents.' },
|
|
524
525
|
autoExecute: { type: 'boolean', description: 'Attempt to spawn agents after delivery (default: true). intent=execute only.' },
|
|
525
526
|
// intent=review args (forwarded to bclaw_dispatch_review)
|
|
@@ -1051,6 +1052,7 @@ const MCP_WRITE_TOOLS = [
|
|
|
1051
1052
|
project: { type: 'string', description: 'Optional (pln#359 phase 1b): name of a linked project to dispatch into. When set, claim/assignment/message all land in the target project — the target agent picks the brief up async via its own bclaw_work. Auto-spawn is disabled in cross-project mode. Accepts cross_project_links and workspace store-chain children (see `brainclaw link list`).' },
|
|
1052
1053
|
allow_dirty: { type: 'boolean', description: 'Override the scope-aware dirty-working-tree guard (trp#371 Tier 2). The guard runs only for worktree-spawning intents (assign/review/reroute) and blocks only when uncommitted files overlap — or cannot be proven disjoint from — the dispatch scope (the worker spawns from HEAD and will not see them). `.brainclaw/` and `.git/` are always excluded. Set true to proceed anyway (the block is downgraded to a warning that lists the overlapping files). Boolean; the string "true"/"false" are also coerced.' },
|
|
1053
1054
|
ref: { type: 'string', description: 'Optional git ref (commit/branch/tag) for assign/review/reroute: the dispatched worker builds its worktree from this ref instead of HEAD. When set, uncommitted working-tree changes are intentionally out of scope and the dirty guard allows the dispatch. Ignored by consult/ideate/summarize (no worktree).' },
|
|
1055
|
+
model: { type: 'string', description: 'Model to run on the spawned worker, decoupled from agent identity (e.g. "sonnet", "gpt-5-codex", "gpt-5.4"). Injected as `<model_flag> <model>` into the invoke command for agents that declare one (claude-code/codex/github-copilot); no-op for template-pinned pseudo-identities (e.g. claude-sonnet) or agents without a model_flag. Highest-priority link in the model resolution chain (override > lane > identity > default). Applies to intents that spawn a worker (assign/consult/review/reroute/ideate); ignored by summarize.' },
|
|
1054
1056
|
},
|
|
1055
1057
|
required: ['intent', 'task'],
|
|
1056
1058
|
},
|
|
@@ -3542,7 +3544,9 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
3542
3544
|
// worktree:false) for an advisory-only lock with no worktree.
|
|
3543
3545
|
const advisoryClaim = args.advisory === true || args.worktree === false;
|
|
3544
3546
|
if (!advisoryClaim) {
|
|
3545
|
-
|
|
3547
|
+
// Shared slug logic (trp#950): collision-resistant when the scope
|
|
3548
|
+
// exceeds the branch-component cap, and identical to createCoordinatorClaim.
|
|
3549
|
+
const branchSlug = sanitizeBranchComponent(claimScope);
|
|
3546
3550
|
const worktreeBranch = args.worktreeBranch?.trim() || `feat/${branchSlug}`;
|
|
3547
3551
|
try {
|
|
3548
3552
|
worktreePath = coreCreateWorktree(claimCwd, worktreeBranch, {
|
|
@@ -3608,7 +3612,7 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
3608
3612
|
const { execSync } = await import('node:child_process');
|
|
3609
3613
|
const branch = execSync('git branch --show-current', { cwd: claimCwd, encoding: 'utf-8' }).trim();
|
|
3610
3614
|
if (branch === 'master' || branch === 'main') {
|
|
3611
|
-
const branchSlug = claimScope
|
|
3615
|
+
const branchSlug = sanitizeBranchComponent(claimScope);
|
|
3612
3616
|
branchWarn = `\n⚠️ You are on ${branch}. Create a feature branch before editing: git checkout -b feat/${branchSlug}`;
|
|
3613
3617
|
}
|
|
3614
3618
|
}
|
|
@@ -4048,6 +4052,7 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
4048
4052
|
dispatcherAgentId: resolved.identity.agent_id,
|
|
4049
4053
|
sessionId: connectionSessionId,
|
|
4050
4054
|
autoExecute: args.autoExecute,
|
|
4055
|
+
model: args.model,
|
|
4051
4056
|
}, cwd);
|
|
4052
4057
|
if (!result) {
|
|
4053
4058
|
return { response: createToolErrorResponse('operation_error', 'No active sequence found. Create a sequence first.') };
|
|
@@ -5627,6 +5632,15 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
5627
5632
|
side_effects.push({ action: 'create', entity: 'message', id: msgResult.id });
|
|
5628
5633
|
const invoke = buildInvokeCommand(input.agent, input.text, {
|
|
5629
5634
|
mode: input.commandMode ?? 'worker',
|
|
5635
|
+
// pln#520/#606 — decouple model from agent identity. req.model is the
|
|
5636
|
+
// override link; when unset, resolveModel intentionally falls back to
|
|
5637
|
+
// the profile's default_model (the documented last link in the chain),
|
|
5638
|
+
// mirroring the dispatcher's resolveModel usage (dispatcher.ts) so
|
|
5639
|
+
// coordinate and dispatch spawn with the same model. No profile ships
|
|
5640
|
+
// a default_model today, so omitting model stays a no-op in practice
|
|
5641
|
+
// (gpt-5.6-luna review). Flows to both the manual commandHint and the
|
|
5642
|
+
// auto-spawn path (runCoordinateExecution reuses this invoke).
|
|
5643
|
+
model: resolveModel(input.agent, { override: req.model }),
|
|
5630
5644
|
});
|
|
5631
5645
|
// Build env prefix for claim routing — centralised in
|
|
5632
5646
|
// execution-profile.ts:buildClaimEnvPrefix as of pln#496 step
|