brainclaw 1.9.1 → 1.10.1
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 +78 -25
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +18 -1
- package/dist/commands/code-map.js +129 -0
- package/dist/commands/codev.js +7 -0
- package/dist/commands/dispatch-watch.js +1 -1
- package/dist/commands/doctor.js +3 -5
- package/dist/commands/loops-handlers.js +4 -1
- package/dist/commands/mcp-read-handlers.js +8 -0
- package/dist/commands/mcp.js +121 -1
- package/dist/commands/metrics.js +0 -1
- package/dist/commands/release-claims.js +1 -1
- package/dist/commands/run-profile.js +3 -2
- package/dist/commands/sequence.js +1 -1
- package/dist/commands/switch.js +100 -89
- package/dist/commands/sync.js +1 -1
- package/dist/commands/upgrade.js +0 -7
- package/dist/core/agent-context.js +1 -1
- package/dist/core/agent-files.js +13 -2
- package/dist/core/agent-integrations.js +3 -3
- package/dist/core/agent-registry.js +2 -2
- package/dist/core/assignments.js +12 -0
- package/dist/core/brainclaw-version.js +2 -2
- package/dist/core/code-map/backend.js +176 -0
- package/dist/core/code-map/core.js +81 -0
- package/dist/core/code-map/drafts.js +2 -0
- package/dist/core/code-map/extractor.js +29 -0
- package/dist/core/code-map/finalizer.js +191 -0
- package/dist/core/code-map/freshness.js +144 -0
- package/dist/core/code-map/ids.js +0 -0
- package/dist/core/code-map/importable.js +35 -0
- package/dist/core/code-map/indexes.js +197 -0
- package/dist/core/code-map/lang/java/imports.scm +17 -0
- package/dist/core/code-map/lang/java/index.js +254 -0
- package/dist/core/code-map/lang/java/tags.scm +48 -0
- package/dist/core/code-map/lang/php/imports.scm +21 -0
- package/dist/core/code-map/lang/php/index.js +251 -0
- package/dist/core/code-map/lang/php/tags.scm +44 -0
- package/dist/core/code-map/lang/provider.js +9 -0
- package/dist/core/code-map/lang/providers.js +24 -0
- package/dist/core/code-map/lang/python/imports.scm +90 -0
- package/dist/core/code-map/lang/python/index.js +364 -0
- package/dist/core/code-map/lang/python/tags.scm +81 -0
- package/dist/core/code-map/lang/query-runtime.js +374 -0
- package/dist/core/code-map/lang/registry.js +125 -0
- package/dist/core/code-map/lang/typescript/imports.scm +90 -0
- package/dist/core/code-map/lang/typescript/index.js +306 -0
- package/dist/core/code-map/lang/typescript/tags.js.scm +106 -0
- package/dist/core/code-map/lang/typescript/tags.scm +151 -0
- package/dist/core/code-map/lock.js +210 -0
- package/dist/core/code-map/materialized.js +51 -0
- package/dist/core/code-map/memory-reader.js +59 -0
- package/dist/core/code-map/paths.js +53 -0
- package/dist/core/code-map/query.js +599 -0
- package/dist/core/code-map/refresh.js +0 -0
- package/dist/core/code-map/resolve.js +177 -0
- package/dist/core/code-map/store.js +206 -0
- package/dist/core/code-map/types.js +293 -0
- package/dist/core/code-map/vocabulary.js +57 -0
- package/dist/core/code-map/wasm-loader.js +294 -0
- package/dist/core/code-map/work-section.js +206 -0
- package/dist/core/codev-rounds.js +4 -0
- package/dist/core/context.js +1 -1
- package/dist/core/cross-project.js +1 -1
- package/dist/core/dispatcher.js +0 -2
- package/dist/core/entity-operations.js +0 -3
- package/dist/core/execution-adapters.js +11 -10
- package/dist/core/execution-profile.js +58 -0
- package/dist/core/facade-schema.js +9 -0
- package/dist/core/ids.js +1 -1
- package/dist/core/instruction-templates.js +2 -0
- package/dist/core/instructions.js +0 -1
- package/dist/core/loops/lock.js +0 -3
- package/dist/core/mcp-command-resolution.js +3 -1
- package/dist/core/protocol-skills.js +5 -3
- package/dist/core/security-detectors.js +2 -2
- package/dist/core/security-extract.js +2 -2
- package/dist/core/store-resolution.js +41 -4
- package/dist/facts.js +9 -5
- package/dist/facts.json +8 -4
- package/dist/vendor/web-tree-sitter/tree-sitter.js +3980 -0
- package/dist/vendor/web-tree-sitter/tree-sitter.wasm +0 -0
- package/dist/wasm/tree-sitter-java.wasm +0 -0
- package/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/wasm/tree-sitter-php.wasm +0 -0
- package/dist/wasm/tree-sitter-python.wasm +0 -0
- package/dist/wasm/tree-sitter-tsx.wasm +0 -0
- package/dist/wasm/tree-sitter-typescript.wasm +0 -0
- package/dist/wasm/tree-sitter.wasm +0 -0
- package/docs/cli.md +46 -8
- package/docs/code-map.md +209 -0
- package/docs/integrations/mcp.md +13 -6
- package/docs/mcp-schema-changelog.md +7 -3
- package/docs/quickstart.md +1 -1
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -6,6 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center"><strong>Local-first coordination and shared memory for coding agents.</strong></p>
|
|
8
8
|
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/jberdah/brainclaw/actions/workflows/ci.yml"><img src="https://github.com/jberdah/brainclaw/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/brainclaw"><img src="https://img.shields.io/npm/v/brainclaw?logo=npm" alt="npm version"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/brainclaw"><img src="https://img.shields.io/npm/dm/brainclaw" alt="npm downloads"></a>
|
|
13
|
+
<img src="https://img.shields.io/node/v/brainclaw" alt="node version">
|
|
14
|
+
<a href="./LICENSE"><img src="https://img.shields.io/npm/l/brainclaw" alt="MIT license"></a>
|
|
15
|
+
<img src="https://img.shields.io/badge/MCP-stdio-blue" alt="MCP">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
9
18
|
---
|
|
10
19
|
|
|
11
20
|
If you've ever:
|
|
@@ -35,6 +44,7 @@ It sits alongside your coding agents and gives them a shared state layer they ca
|
|
|
35
44
|
| **Project memory** | constraints, decisions, traps, handoffs, and layered instructions agents can resume from |
|
|
36
45
|
| **Coordination state** | shared plans, file claims (dispatched work isolated in Git Worktrees), runtime notes, and board views for active work |
|
|
37
46
|
| **Agent-ready context** | compact, prompt-sized context built from real workspace state instead of stale instructions |
|
|
47
|
+
| **Code Map** | a Tree-sitter symbol + import index (JS/TS, Python, PHP, Java) so agents ask "where is X / what should I read first" before editing, with related decisions/traps attached — `bclaw_code_find` / `bclaw_code_brief`, see [code map](docs/code-map.md) |
|
|
38
48
|
| **Native agent files** | auto-writes `CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.cursor/rules/`, `.windsurfrules`, and similar local guidance |
|
|
39
49
|
| **Multi-turn loops** | review and ideation loops with structured phases, iteration semantics, and per-phase memory filters — see[loop engine](docs/concepts/loop-engine.md) and [ideation loop](docs/concepts/ideation-loop.md) |
|
|
40
50
|
| **Machine AI surface discovery** | detects local coding agents plus desktop AI work surfaces such as ChatGPT Desktop and Gemini CLI |
|
|
@@ -43,6 +53,19 @@ It sits alongside your coding agents and gives them a shared state layer they ca
|
|
|
43
53
|
|
|
44
54
|
---
|
|
45
55
|
|
|
56
|
+
## Code Map
|
|
57
|
+
|
|
58
|
+
When an agent (or you) is about to edit unfamiliar code, the first question is *"where is this, and what should I read first?"* Code Map answers it without grepping: a per-project [Tree-sitter](https://tree-sitter.github.io/) index of the symbols each file defines (functions, classes, types, React components/hooks), what it imports/exports, and how files relate — across **JS / TS / TSX, Python, PHP, and Java**.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
brainclaw code-map find useAuth # locate a symbol / component / hook by name
|
|
62
|
+
brainclaw code-map brief src/App.tsx # ranked "read these first" list + related decisions/traps
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Capable agents use the MCP equivalents `bclaw_code_find` / `bclaw_code_brief`, each carrying a freshness badge. Code Map is a **discovery aid, not a build artifact**: it never changes your code, never blocks `bclaw_work`, and degrades gracefully — a stale or missing index says so instead of answering wrong. Pull-based (no daemon) and monorepo-aware. Full guide: **[Code Map](docs/code-map.md)**.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
46
69
|
## Agent Surfaces
|
|
47
70
|
|
|
48
71
|
brainclaw exposes the same collaboration state through three surfaces, but they do not have the same role in an agent-first workflow.
|
|
@@ -97,7 +120,7 @@ brainclaw is most effective today when one agent works at a time in a given chec
|
|
|
97
120
|
|
|
98
121
|
## Platform Support
|
|
99
122
|
|
|
100
|
-
brainclaw
|
|
123
|
+
brainclaw requires Node.js 22.12+ (`engines.node = ">=22.12.0"`). CI exercises Node 22 (Active LTS) and Node 24 (current LTS) on Linux; Windows runs on Node 24. Node 20 reached EOL in April 2026 and is no longer supported — the commander 15 upgrade requires Node ≥22.12. The recommended runtime is Node 22 LTS or Node 24 LTS.
|
|
101
124
|
|
|
102
125
|
| Logo | Platform | Status today | Notes |
|
|
103
126
|
| ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -346,33 +369,34 @@ The same surface is available through the canonical grammar for agents: `bclaw_c
|
|
|
346
369
|
|
|
347
370
|
## Documentation
|
|
348
371
|
|
|
349
|
-
The
|
|
372
|
+
The Markdown docs below ship in the npm package under `docs/` and are versioned in the repo. The links resolve on GitHub and are rewritten to the package repo on the npm page.
|
|
350
373
|
|
|
351
374
|
If you are integrating Brainclaw into an agent workflow, start with the agent-facing docs first:
|
|
352
375
|
|
|
353
|
-
|
|
|
354
|
-
|
|
|
355
|
-
|
|
|
356
|
-
|
|
|
357
|
-
|
|
|
358
|
-
|
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
|
|
|
365
|
-
|
|
|
366
|
-
|
|
|
367
|
-
|
|
|
368
|
-
|
|
|
369
|
-
|
|
|
370
|
-
|
|
|
371
|
-
|
|
|
372
|
-
|
|
|
373
|
-
|
|
|
374
|
-
|
|
|
375
|
-
|
|
|
376
|
+
| Doc | What it covers |
|
|
377
|
+
| --- | --- |
|
|
378
|
+
| [docs/index.md](docs/index.md) | Documentation index grouped by getting started, guides, reference, and design |
|
|
379
|
+
| [docs/integrations/overview.md](docs/integrations/overview.md) | Start here for agent integrations |
|
|
380
|
+
| [docs/integrations/mcp.md](docs/integrations/mcp.md) | MCP runtime path for capable agents |
|
|
381
|
+
| [docs/quickstart.md](docs/quickstart.md) | First-time setup on a new project (greenfield) |
|
|
382
|
+
| [docs/quickstart-existing-project.md](docs/quickstart-existing-project.md) | Joining a project that already has `.brainclaw/` |
|
|
383
|
+
| [docs/server-operations.md](docs/server-operations.md) | Operator and remote-server workflow guide |
|
|
384
|
+
| [docs/cli.md](docs/cli.md) | CLI reference for operators, scripts, and fallback use |
|
|
385
|
+
| [docs/code-map.md](docs/code-map.md) | Code Map — symbol/import index, freshness model, monorepo behavior |
|
|
386
|
+
| [docs/concepts/memory.md](docs/concepts/memory.md) | What "memory" means in brainclaw |
|
|
387
|
+
| [docs/concepts/plans-and-claims.md](docs/concepts/plans-and-claims.md) | Coordination layer |
|
|
388
|
+
| [docs/concepts/runtime-notes.md](docs/concepts/runtime-notes.md) | Ephemeral observations |
|
|
389
|
+
| [docs/concepts/multi-agent-workflows.md](docs/concepts/multi-agent-workflows.md) | The four common scenarios — orchestration, agent switching, project recovery, team async |
|
|
390
|
+
| [docs/concepts/troubleshooting.md](docs/concepts/troubleshooting.md) | Runbook for degraded coordination state — stale claims, missing dist, octopus failures, etc. |
|
|
391
|
+
| [docs/integrations/cursor.md](docs/integrations/cursor.md) | Cursor |
|
|
392
|
+
| [docs/integrations/claude-code.md](docs/integrations/claude-code.md) | Claude Code |
|
|
393
|
+
| [docs/integrations/copilot.md](docs/integrations/copilot.md) | GitHub Copilot |
|
|
394
|
+
| [docs/integrations/codex.md](docs/integrations/codex.md) | Codex |
|
|
395
|
+
| [docs/storage.md](docs/storage.md) | Storage model |
|
|
396
|
+
| [docs/security.md](docs/security.md) | Security model |
|
|
397
|
+
| [docs/review.md](docs/review.md) | Reflective review |
|
|
398
|
+
| [docs/reputation.md](docs/reputation.md) | Reputation signals |
|
|
399
|
+
| [docs/playbooks/](docs/playbooks/) | Audience design constraints for brainclaw development |
|
|
376
400
|
|
|
377
401
|
---
|
|
378
402
|
|
|
@@ -393,6 +417,35 @@ npm run test:coverage # with coverage report
|
|
|
393
417
|
|
|
394
418
|
For older releases (v0.x and the early v1.0 launch series), `git log` on `master` is the source of truth — every release commit follows the `chore(release): bump version to <semver>` convention, and the matching feature/fix commits reference their plan id (e.g. `feat(mcp): self-heal ... (pln#478)`).
|
|
395
419
|
|
|
420
|
+
### v1.10.1
|
|
421
|
+
|
|
422
|
+
Code Map fast-follows from the 1.10.0 dogfood, plus a lint cleanup:
|
|
423
|
+
|
|
424
|
+
- 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`).
|
|
425
|
+
- 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.
|
|
426
|
+
|
|
427
|
+
### v1.10.0
|
|
428
|
+
|
|
429
|
+
- **Code Map** — a new per-project [Tree-sitter](docs/code-map.md) symbol + import
|
|
430
|
+
index for **JS / TS / TSX, Python, PHP, and Java**. Ask *"where is X / what should I
|
|
431
|
+
read first"* before editing: `bclaw_code_find`, `bclaw_code_brief`,
|
|
432
|
+
`bclaw_code_status`, `bclaw_code_refresh` (CLI: `brainclaw code-map …`). Pull-based
|
|
433
|
+
freshness with a per-response badge; never blocks `bclaw_work`; monorepo-aware. See
|
|
434
|
+
[code map](docs/code-map.md).
|
|
435
|
+
- **Monorepo multi-project safety** — agents working in different child projects of a
|
|
436
|
+
monorepo are now genuinely independent:
|
|
437
|
+
- an anchored agent working *inside* a child project resolves **that** child, not the
|
|
438
|
+
repo root — no more "plans / index target the repo root";
|
|
439
|
+
- CLI `brainclaw switch` is **session-scoped by default** (two agents no longer clobber
|
|
440
|
+
a shared pointer); the new `--global` flag is the only path that sets the shared
|
|
441
|
+
workspace default; `switch --list` / show are session-aware;
|
|
442
|
+
- a session-less agent physically inside a child project beats a stale shared global
|
|
443
|
+
pointer (resolves the child it is in);
|
|
444
|
+
- dispatched / CoDev workers spawn with a **clean identity** — the coordinator's
|
|
445
|
+
session / project / agent env no longer leaks into a worker.
|
|
446
|
+
- Internal — MCP public surface fingerprint re-pinned for the Code Map tools (additive;
|
|
447
|
+
no tool removed or renamed).
|
|
448
|
+
|
|
396
449
|
### v1.9.1
|
|
397
450
|
|
|
398
451
|
- **Multi-project scoping fixes for monorepos** — MCP reads/writes resolve the
|
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -19,6 +19,7 @@ import { runListPlans } from './commands/list-plans.js';
|
|
|
19
19
|
import { runUpdatePlan } from './commands/update-plan.js';
|
|
20
20
|
import { runDeletePlan } from './commands/delete-plan.js';
|
|
21
21
|
import { runPlanResource } from './commands/plan-resource.js';
|
|
22
|
+
import { runCodeMap } from './commands/code-map.js';
|
|
22
23
|
import { runSequenceResource } from './commands/sequence.js';
|
|
23
24
|
import { runAddStep } from './commands/add-step.js';
|
|
24
25
|
import { runDeleteStep } from './commands/delete-step.js';
|
|
@@ -598,6 +599,20 @@ program
|
|
|
598
599
|
.action((subcommand, args, options) => {
|
|
599
600
|
runPlanResource(subcommand, args, { ...options, actualEffort: options.actualEffort, localOnly: options.localOnly });
|
|
600
601
|
});
|
|
602
|
+
// --- code-map ---
|
|
603
|
+
program
|
|
604
|
+
.command('code-map <subcommand> [args...]')
|
|
605
|
+
.description('Query the per-project Code Map (status, refresh, find, brief)')
|
|
606
|
+
.option('--json', 'Output as JSON')
|
|
607
|
+
.option('--all', 'For refresh: enumerate all supported files (full refresh)')
|
|
608
|
+
.option('--changed', 'For refresh: only changed files (default)')
|
|
609
|
+
.option('--limit <n>', 'Max results for find/brief', (v) => parseInt(v, 10))
|
|
610
|
+
.action((subcommand, args, options) => {
|
|
611
|
+
void runCodeMap(subcommand, args, options).catch((err) => {
|
|
612
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
613
|
+
process.exit(1);
|
|
614
|
+
});
|
|
615
|
+
});
|
|
601
616
|
// --- list-plans ---
|
|
602
617
|
program
|
|
603
618
|
.command('list-plans')
|
|
@@ -1806,15 +1821,17 @@ program
|
|
|
1806
1821
|
});
|
|
1807
1822
|
program
|
|
1808
1823
|
.command('switch [project]')
|
|
1809
|
-
.description('Set the active project for subsequent commands')
|
|
1824
|
+
.description('Set the active project for subsequent commands (session-scoped by default)')
|
|
1810
1825
|
.option('--list', 'List available projects in the workspace')
|
|
1811
1826
|
.option('--clear', 'Clear the active project (revert to cwd)')
|
|
1827
|
+
.option('--global', 'Set/clear the SHARED workspace default for ALL agents (writes active-project.json). Without it, switch is session-scoped and isolated.')
|
|
1812
1828
|
.option('--json', 'Output as JSON')
|
|
1813
1829
|
.action((project, options) => {
|
|
1814
1830
|
const globalOpts = options.parent?.parent ? program.opts() : {};
|
|
1815
1831
|
runSwitch(project, {
|
|
1816
1832
|
list: options.list,
|
|
1817
1833
|
clear: options.clear,
|
|
1834
|
+
global: options.global,
|
|
1818
1835
|
json: options.json,
|
|
1819
1836
|
cwd: globalOpts.cwd,
|
|
1820
1837
|
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `brainclaw code-map <subcommand>` — CLI surface over the Code Map backend
|
|
3
|
+
* (spec §9). Mirrors plan-resource.ts: a switch over the subcommand delegating
|
|
4
|
+
* to a JsonlBackend (status | refresh | find | brief). The backend owns all
|
|
5
|
+
* query logic; this file only adapts it to argv + stdout (text or --json), and
|
|
6
|
+
* every output carries the freshness_badge.
|
|
7
|
+
*/
|
|
8
|
+
import { JsonlBackend } from '../core/code-map/backend.js';
|
|
9
|
+
const KNOWN_SUBCOMMANDS = new Set(['status', 'refresh', 'find', 'brief']);
|
|
10
|
+
function backend() {
|
|
11
|
+
return new JsonlBackend();
|
|
12
|
+
}
|
|
13
|
+
function badgeLine(badge) {
|
|
14
|
+
const detailKeys = Object.keys(badge.details ?? {}).filter((k) => badge.details[k] !== null && badge.details[k] !== undefined);
|
|
15
|
+
const detail = detailKeys.length
|
|
16
|
+
? ` (${detailKeys.map((k) => `${k}=${JSON.stringify(badge.details[k])}`).join(', ')})`
|
|
17
|
+
: '';
|
|
18
|
+
return `Freshness: ${badge.status}${detail}`;
|
|
19
|
+
}
|
|
20
|
+
export async function runCodeMap(subcommand, args, options = {}) {
|
|
21
|
+
const normalized = (subcommand ?? '').trim().toLowerCase();
|
|
22
|
+
const be = backend();
|
|
23
|
+
const cwd = options.cwd;
|
|
24
|
+
if (normalized === 'status') {
|
|
25
|
+
const status = await be.status({ cwd });
|
|
26
|
+
printStatus(status, options);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (normalized === 'refresh') {
|
|
30
|
+
const scope = options.all ? 'all' : 'changed';
|
|
31
|
+
const result = await be.refresh({ scope, cwd });
|
|
32
|
+
printRefresh(result, options);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (normalized === 'find') {
|
|
36
|
+
const query = args.join(' ').trim();
|
|
37
|
+
if (!query) {
|
|
38
|
+
console.error('Error: code-map find requires <query>.');
|
|
39
|
+
console.error(' Usage: brainclaw code-map find <query>');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const result = await be.find({ query, limit: options.limit, cwd });
|
|
43
|
+
printFind(result, options);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (normalized === 'brief') {
|
|
47
|
+
const target = args.join(' ').trim();
|
|
48
|
+
if (!target) {
|
|
49
|
+
console.error('Error: code-map brief requires <symbol-or-path>.');
|
|
50
|
+
console.error(' Usage: brainclaw code-map brief <symbol-or-path>');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const result = await be.brief({ target, limit: options.limit, cwd });
|
|
54
|
+
printBrief(result, options);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
console.error(`Error: unknown code-map subcommand "${subcommand}".`);
|
|
58
|
+
console.error(` Available: ${[...KNOWN_SUBCOMMANDS].join(', ')}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
function printStatus(status, options) {
|
|
62
|
+
if (options.json) {
|
|
63
|
+
console.log(JSON.stringify(status, null, 2));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log('Code Map status');
|
|
67
|
+
console.log(` Store: ${status.store_exists ? 'present' : 'absent'}`);
|
|
68
|
+
console.log(` ${badgeLine(status.freshness_badge)}`);
|
|
69
|
+
if (status.stats) {
|
|
70
|
+
console.log(` Files: ${status.stats.files_indexed}`);
|
|
71
|
+
console.log(` Nodes: ${status.stats.nodes}`);
|
|
72
|
+
console.log(` Edges: ${status.stats.edges}`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.log(' Stats: (none — index not built)');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function printRefresh(result, options) {
|
|
79
|
+
if (options.json) {
|
|
80
|
+
console.log(JSON.stringify(result, null, 2));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log(`Code Map refresh [${result.scope}]`);
|
|
84
|
+
console.log(` Ran: ${result.ran}`);
|
|
85
|
+
console.log(` Lock: ${result.lock_acquired ? 'acquired' : 'not acquired'}`);
|
|
86
|
+
if (result.lock_status)
|
|
87
|
+
console.log(` Status: ${result.lock_status}`);
|
|
88
|
+
console.log(` ${badgeLine(result.freshness_badge)}`);
|
|
89
|
+
}
|
|
90
|
+
function printFind(result, options) {
|
|
91
|
+
if (options.json) {
|
|
92
|
+
console.log(JSON.stringify(result, null, 2));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
console.log(`Code Map find: "${result.query}"`);
|
|
96
|
+
console.log(` ${badgeLine(result.freshness_badge)}`);
|
|
97
|
+
if (result.matches.length === 0) {
|
|
98
|
+
console.log(' (no matches)');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
for (const m of result.matches) {
|
|
102
|
+
const sub = m.subtype ? ` ${m.subtype}` : '';
|
|
103
|
+
console.log(` [${m.score.toFixed(1)}] ${m.name}${sub} — ${m.path}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function printBrief(result, options) {
|
|
107
|
+
if (options.json) {
|
|
108
|
+
console.log(JSON.stringify(result, null, 2));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
console.log(`Code Map brief: "${result.target}"`);
|
|
112
|
+
console.log(` ${badgeLine(result.freshness_badge)}`);
|
|
113
|
+
if (result.suggested_files_to_read.length === 0) {
|
|
114
|
+
console.log(' Suggested files: (none)');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.log(' Suggested files to read:');
|
|
118
|
+
for (const f of result.suggested_files_to_read) {
|
|
119
|
+
console.log(` [${f.score.toFixed(1)}] ${f.path} — ${f.reason}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (result.related_memory.length > 0) {
|
|
123
|
+
console.log(' Related memory:');
|
|
124
|
+
for (const mem of result.related_memory) {
|
|
125
|
+
console.log(` ${mem.id} (${mem.kind}): ${mem.text.slice(0, 80)}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=code-map.js.map
|
package/dist/commands/codev.js
CHANGED
|
@@ -26,6 +26,7 @@ import { buildContext } from '../core/context.js';
|
|
|
26
26
|
import { buildCoordinationSnapshot } from '../core/coordination.js';
|
|
27
27
|
import { getDefaultInvokeTemplate, getSpawnableAgents } from '../core/agent-capability.js';
|
|
28
28
|
import { executeRound } from '../core/codev-rounds.js';
|
|
29
|
+
import { buildWorkerIdentityEnv } from '../core/execution-profile.js';
|
|
29
30
|
import { loadIdeationRound } from '../core/ideation.js';
|
|
30
31
|
import { summarizeMetrics, summarizeMetricsByRound } from '../core/codev-metrics.js';
|
|
31
32
|
import { generatePlansFromConvergence, generateSummaryNote } from '../core/codev-plan-gen.js';
|
|
@@ -422,12 +423,16 @@ function spawnConsultant(brief, threadId, personaName, cwd, agent) {
|
|
|
422
423
|
console.warn(` ⚠ Spawn error for ${agentName}/${personaName}: ${err.message}`);
|
|
423
424
|
});
|
|
424
425
|
};
|
|
426
|
+
// F7 (trp_0e5150d3): scrub coordinator identity so a consultant worker is an
|
|
427
|
+
// independent agent — these spawns previously inherited the full parent env.
|
|
428
|
+
const workerEnv = buildWorkerIdentityEnv(process.env, { agent: agentName });
|
|
425
429
|
if (agentName === 'codex') {
|
|
426
430
|
// Codex: use temp file via shell to avoid Windows .cmd ENOENT issues
|
|
427
431
|
const child = spawn('sh', ['-c', `cat "${briefFile}" | "${binaryPath}" exec --full-auto - ; rm -f "${briefFile}"`], {
|
|
428
432
|
detached: true,
|
|
429
433
|
stdio: 'ignore',
|
|
430
434
|
cwd,
|
|
435
|
+
env: workerEnv,
|
|
431
436
|
});
|
|
432
437
|
attachErrorHandler(child);
|
|
433
438
|
child.unref();
|
|
@@ -438,6 +443,7 @@ function spawnConsultant(brief, threadId, personaName, cwd, agent) {
|
|
|
438
443
|
detached: true,
|
|
439
444
|
stdio: 'ignore',
|
|
440
445
|
cwd,
|
|
446
|
+
env: workerEnv,
|
|
441
447
|
});
|
|
442
448
|
attachErrorHandler(child);
|
|
443
449
|
child.unref();
|
|
@@ -448,6 +454,7 @@ function spawnConsultant(brief, threadId, personaName, cwd, agent) {
|
|
|
448
454
|
detached: true,
|
|
449
455
|
stdio: 'ignore',
|
|
450
456
|
cwd,
|
|
457
|
+
env: workerEnv,
|
|
451
458
|
});
|
|
452
459
|
attachErrorHandler(child);
|
|
453
460
|
child.unref();
|
package/dist/commands/doctor.js
CHANGED
|
@@ -747,7 +747,6 @@ export function runDoctor(options = {}) {
|
|
|
747
747
|
const msg = e instanceof Error ? e.message : String(e);
|
|
748
748
|
checks.push({ name: 'config', status: 'error', message: `config.yaml is invalid: ${msg}` });
|
|
749
749
|
console.error(`✗ config.yaml is invalid: ${msg}`);
|
|
750
|
-
hasIssues = true;
|
|
751
750
|
if (options.json) {
|
|
752
751
|
console.log(JSON.stringify({ ok: false, checks, metrics: {} }, null, 2));
|
|
753
752
|
}
|
|
@@ -807,7 +806,6 @@ export function runDoctor(options = {}) {
|
|
|
807
806
|
const msg = e instanceof Error ? e.message : String(e);
|
|
808
807
|
checks.push({ name: 'state', status: 'error', message: `state is invalid: ${msg}` });
|
|
809
808
|
console.error(`✗ state is invalid: ${msg}`);
|
|
810
|
-
hasIssues = true;
|
|
811
809
|
if (options.json) {
|
|
812
810
|
console.log(JSON.stringify({ ok: false, checks, metrics: {} }, null, 2));
|
|
813
811
|
}
|
|
@@ -2202,7 +2200,7 @@ export function runDoctor(options = {}) {
|
|
|
2202
2200
|
}
|
|
2203
2201
|
// Find duplicates (same text at different levels)
|
|
2204
2202
|
const duplicates = [];
|
|
2205
|
-
allConstraints.forEach((items,
|
|
2203
|
+
allConstraints.forEach((items, _key) => {
|
|
2206
2204
|
if (items.length > 1 && new Set(items.map((i) => i.store)).size > 1) {
|
|
2207
2205
|
duplicates.push({
|
|
2208
2206
|
type: 'constraint',
|
|
@@ -2211,7 +2209,7 @@ export function runDoctor(options = {}) {
|
|
|
2211
2209
|
});
|
|
2212
2210
|
}
|
|
2213
2211
|
});
|
|
2214
|
-
allDecisions.forEach((items,
|
|
2212
|
+
allDecisions.forEach((items, _key) => {
|
|
2215
2213
|
if (items.length > 1 && new Set(items.map((i) => i.store)).size > 1) {
|
|
2216
2214
|
duplicates.push({
|
|
2217
2215
|
type: 'decision',
|
|
@@ -2220,7 +2218,7 @@ export function runDoctor(options = {}) {
|
|
|
2220
2218
|
});
|
|
2221
2219
|
}
|
|
2222
2220
|
});
|
|
2223
|
-
allTraps.forEach((items,
|
|
2221
|
+
allTraps.forEach((items, _key) => {
|
|
2224
2222
|
if (items.length > 1 && new Set(items.map((i) => i.store)).size > 1) {
|
|
2225
2223
|
duplicates.push({
|
|
2226
2224
|
type: 'trap',
|
|
@@ -84,7 +84,10 @@ function validateSemanticRequest(req) {
|
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
86
|
function requestPayload(req) {
|
|
87
|
-
const
|
|
87
|
+
const rest = { ...req };
|
|
88
|
+
delete rest.agent;
|
|
89
|
+
delete rest.agentId;
|
|
90
|
+
delete rest.client_request_id;
|
|
88
91
|
return rest;
|
|
89
92
|
}
|
|
90
93
|
function currentLoopVersion(loopId, cwd) {
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP read-only tool handlers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from mcp.ts to reduce file size. These handlers do not mutate
|
|
5
|
+
* state — they build context, list items, search, and inspect.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
1
9
|
import { applyBootstrapImport, renderBootstrapInterview, renderBootstrapSummary, runBootstrapProfile, uninstallBootstrapImport } from '../core/bootstrap.js';
|
|
2
10
|
import { buildAgentToolingContext, renderAgentToolingSummary } from '../core/agent-context.js';
|
|
3
11
|
import { buildCoordinationSnapshot, buildCrossProjectSnapshot } from '../core/coordination.js';
|
package/dist/commands/mcp.js
CHANGED
|
@@ -48,6 +48,7 @@ import { dispatch, dispatchReview, generateDispatchBrief } from '../core/dispatc
|
|
|
48
48
|
import { deleteMemoryItem, updateMemoryItem } from '../core/operations/memory-mutation.js';
|
|
49
49
|
import { assessMemoryPressure, buildCompactionTemplate, applyCompaction } from '../core/gc-semantic.js';
|
|
50
50
|
import { WorkRequestSchema, CoordinateRequestSchema } from '../core/facade-schema.js';
|
|
51
|
+
import { codeMapWorkSection, codeMapRefreshNextActions } from '../core/code-map/work-section.js';
|
|
51
52
|
import { getSpawnableAgents, getCapabilityProfile, buildInvokeCommand, validateAgentForDispatch } from '../core/agent-capability.js';
|
|
52
53
|
import { attemptExecution } from '../core/execution.js';
|
|
53
54
|
import { createAgentRun, transitionAgentRun } from '../core/agentruns.js';
|
|
@@ -449,8 +450,54 @@ export const MCP_READ_TOOLS = [
|
|
|
449
450
|
required: ['target_id'],
|
|
450
451
|
},
|
|
451
452
|
},
|
|
453
|
+
{
|
|
454
|
+
name: 'bclaw_code_status',
|
|
455
|
+
description: 'Code Map status for this project: store presence, freshness badge (fresh / stale_changed_files / stale_extractor / stale_grammar / stale_git_head / partial / missing_index), and index stats (files, nodes, edges). Read-only; never refreshes. Pair with bclaw_code_refresh when freshness is missing_index or stale.',
|
|
456
|
+
annotations: { tier: 'standard', category: 'discovery', headlessApproval: 'auto' },
|
|
457
|
+
inputSchema: {
|
|
458
|
+
type: 'object',
|
|
459
|
+
properties: {},
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
name: 'bclaw_code_find',
|
|
464
|
+
description: 'Search the Code Map symbol index for a query (function/class/component/hook/type names). Returns ranked matches with path + score, plus a freshness_badge from the lazy read-path check. Read-only; never refreshes — a missing_index badge means run bclaw_code_refresh first.',
|
|
465
|
+
annotations: { tier: 'standard', category: 'discovery', headlessApproval: 'auto' },
|
|
466
|
+
inputSchema: {
|
|
467
|
+
type: 'object',
|
|
468
|
+
properties: {
|
|
469
|
+
query: { type: 'string', description: 'Symbol or token to search for (e.g. "App", "useAuth", "dispatch").' },
|
|
470
|
+
limit: { type: 'number', description: 'Max matches to return.' },
|
|
471
|
+
},
|
|
472
|
+
required: ['query'],
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
name: 'bclaw_code_brief',
|
|
477
|
+
description: 'Before editing, ask Code Map what to read: returns a ranked suggested_files_to_read list (cap 12) for a symbol or path, related brainclaw memory (cap 5), and a freshness_badge. Read-only; never refreshes.',
|
|
478
|
+
annotations: { tier: 'standard', category: 'discovery', headlessApproval: 'auto' },
|
|
479
|
+
inputSchema: {
|
|
480
|
+
type: 'object',
|
|
481
|
+
properties: {
|
|
482
|
+
target: { type: 'string', description: 'Symbol name or file path to build a reading brief for.' },
|
|
483
|
+
limit: { type: 'number', description: 'Max suggested files (hard-capped at 12 by the spec).' },
|
|
484
|
+
},
|
|
485
|
+
required: ['target'],
|
|
486
|
+
},
|
|
487
|
+
},
|
|
452
488
|
];
|
|
453
489
|
const MCP_WRITE_TOOLS = [
|
|
490
|
+
{
|
|
491
|
+
name: 'bclaw_code_refresh',
|
|
492
|
+
description: 'Rebuild the Code Map index for this project (Tree-sitter parse + shards + indexes, behind the per-project lock). scope="changed" (default) reparses changed files; scope="all" does a full refresh + compaction. A live competing lock fails fast with a clear status — refresh never blocks. Returns the resulting freshness_badge.',
|
|
493
|
+
annotations: { tier: 'standard', category: 'discovery', headlessApproval: 'prompt' },
|
|
494
|
+
inputSchema: {
|
|
495
|
+
type: 'object',
|
|
496
|
+
properties: {
|
|
497
|
+
scope: { type: 'string', enum: ['changed', 'all'], description: 'changed (default) reparses changed files only; all does a full refresh with orphan compaction.' },
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
},
|
|
454
501
|
{
|
|
455
502
|
name: 'bclaw_dispatch',
|
|
456
503
|
description: 'Unified dispatch entry for sequence-lane parallelization (parallelize plans across lanes). To open a NEW review of a commit/branch, use `bclaw_coordinate(intent="review", open_loop=true, targetAgents=[…])` instead — bclaw_dispatch is for sequence-driven execution, NOT for opening new reviews. `intent` discriminator: analysis (sequence lane status, read-only), execute (default — analyze + generate briefs + send to agents), review (routes an EXISTING already-reflected handoff to a reviewer — only for handoffs produced by `session-end --reflect-handoff` or similar). Consolidates the legacy bclaw_dispatch_analysis / bclaw_dispatch / bclaw_dispatch_review. Returns FacadeResponse; for verification semantics see the same response-validation guidance documented on `bclaw_coordinate`.',
|
|
@@ -2599,6 +2646,59 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
2599
2646
|
const { handleCheckSecurity } = await import('./check-security-mcp.js');
|
|
2600
2647
|
return { response: toolResponse(await handleCheckSecurity(args, cwd)) };
|
|
2601
2648
|
}
|
|
2649
|
+
// Code Map tools (spec §9). These delegate to the async JsonlBackend, so
|
|
2650
|
+
// they are handled here rather than via the synchronous read-tool path.
|
|
2651
|
+
// status/find/brief are reads; refresh is a write (prompt approval).
|
|
2652
|
+
if (name === 'bclaw_code_status' || name === 'bclaw_code_find' || name === 'bclaw_code_brief' || name === 'bclaw_code_refresh') {
|
|
2653
|
+
const { JsonlBackend } = await import('../core/code-map/backend.js');
|
|
2654
|
+
const be = new JsonlBackend();
|
|
2655
|
+
if (name === 'bclaw_code_status') {
|
|
2656
|
+
const status = await be.status({ cwd });
|
|
2657
|
+
return {
|
|
2658
|
+
response: toolResponse({
|
|
2659
|
+
content: [{ type: 'text', text: `Code Map: ${status.store_exists ? 'store present' : 'no store'} — freshness=${status.freshness_badge.status}` }],
|
|
2660
|
+
structuredContent: { ...status, freshness_badge: status.freshness_badge },
|
|
2661
|
+
}),
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
if (name === 'bclaw_code_refresh') {
|
|
2665
|
+
const scope = args.scope === 'all' ? 'all' : 'changed';
|
|
2666
|
+
const result = await be.refresh({ scope, cwd });
|
|
2667
|
+
return {
|
|
2668
|
+
response: toolResponse({
|
|
2669
|
+
content: [{ type: 'text', text: `Code Map refresh [${result.scope}]: ran=${result.ran} freshness=${result.freshness_badge.status}${result.lock_status ? ` (${result.lock_status})` : ''}` }],
|
|
2670
|
+
structuredContent: { ...result, freshness_badge: result.freshness_badge },
|
|
2671
|
+
}),
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
if (name === 'bclaw_code_find') {
|
|
2675
|
+
const query = typeof args.query === 'string' ? args.query : '';
|
|
2676
|
+
if (!query.trim()) {
|
|
2677
|
+
return { response: createToolErrorResponse('validation_error', 'bclaw_code_find requires a non-empty query.') };
|
|
2678
|
+
}
|
|
2679
|
+
const limit = typeof args.limit === 'number' ? args.limit : undefined;
|
|
2680
|
+
const result = await be.find({ query, limit, cwd });
|
|
2681
|
+
return {
|
|
2682
|
+
response: toolResponse({
|
|
2683
|
+
content: [{ type: 'text', text: `Code Map find "${result.query}": ${result.matches.length} match(es), freshness=${result.freshness_badge.status}` }],
|
|
2684
|
+
structuredContent: { ...result, freshness_badge: result.freshness_badge },
|
|
2685
|
+
}),
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
// bclaw_code_brief
|
|
2689
|
+
const target = typeof args.target === 'string' ? args.target : '';
|
|
2690
|
+
if (!target.trim()) {
|
|
2691
|
+
return { response: createToolErrorResponse('validation_error', 'bclaw_code_brief requires a non-empty target.') };
|
|
2692
|
+
}
|
|
2693
|
+
const limit = typeof args.limit === 'number' ? args.limit : undefined;
|
|
2694
|
+
const result = await be.brief({ target, limit, cwd });
|
|
2695
|
+
return {
|
|
2696
|
+
response: toolResponse({
|
|
2697
|
+
content: [{ type: 'text', text: `Code Map brief "${result.target}": ${result.suggested_files_to_read.length} file(s) to read, freshness=${result.freshness_badge.status}` }],
|
|
2698
|
+
structuredContent: { ...result, freshness_badge: result.freshness_badge },
|
|
2699
|
+
}),
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2602
2702
|
if (MCP_READ_TOOLS.some((tool) => tool.name === name) || LEGACY_READ_TOOL_HANDLERS.has(name)) {
|
|
2603
2703
|
return {
|
|
2604
2704
|
response: appendLegacyMcpToolWarning(toolResponse(handleMcpReadToolCall(name, args, { cwd, connectionSessionId, effectiveScope: scopeInfo })), name),
|
|
@@ -4854,6 +4954,26 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
4854
4954
|
nextActions.push({ tool: 'bclaw_context', args: { kind: 'memory' }, when: 'to read the full changed items behind context_diff' });
|
|
4855
4955
|
}
|
|
4856
4956
|
nextActions.push({ tool: 'bclaw_quick_capture', args: { text: '<finding>', type: '<decision|trap|constraint|note>' }, when: 'capture decisions/traps as you work' });
|
|
4957
|
+
// Code Map opt-in section (spec §10). Single live seam: returns null
|
|
4958
|
+
// (and does no work) unless the project's Code Map manifest carries
|
|
4959
|
+
// code_map_enabled:true. Never refreshes; bounded ≤2500ms on an active
|
|
4960
|
+
// lock; surfaces a missing_index hint or stale results with the badge.
|
|
4961
|
+
let codeMapSection = null;
|
|
4962
|
+
try {
|
|
4963
|
+
codeMapSection = await codeMapWorkSection(targetCwd, {
|
|
4964
|
+
query: workReq.scope ?? workReq.contextTarget,
|
|
4965
|
+
});
|
|
4966
|
+
}
|
|
4967
|
+
catch {
|
|
4968
|
+
// Best-effort: Code Map must never break or block bclaw_work.
|
|
4969
|
+
}
|
|
4970
|
+
// Code Map onboarding/freshness nudge (pln#588): promote the actionable
|
|
4971
|
+
// refresh to a first-class next_action so a fresh or stale project's first
|
|
4972
|
+
// bclaw_work TELLS the agent to build/update the index — the passive
|
|
4973
|
+
// missing_index hint alone was easy to skip. Still never refreshes here.
|
|
4974
|
+
for (const action of codeMapRefreshNextActions(codeMapSection)) {
|
|
4975
|
+
nextActions.push(action);
|
|
4976
|
+
}
|
|
4857
4977
|
const facadeResponse = {
|
|
4858
4978
|
status: 'ok',
|
|
4859
4979
|
intent: workReq.intent,
|
|
@@ -4868,6 +4988,7 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
4868
4988
|
bootstrap_verdict: bootstrapVerdict,
|
|
4869
4989
|
next_action: nextAction,
|
|
4870
4990
|
next_actions: nextActions,
|
|
4991
|
+
...(codeMapSection ? { code_map: codeMapSection } : {}),
|
|
4871
4992
|
};
|
|
4872
4993
|
const summaryParts = [`✔ bclaw_work [${workReq.intent}] session=${sessionResult.session_id}`];
|
|
4873
4994
|
if (claimId)
|
|
@@ -5239,7 +5360,6 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
5239
5360
|
}));
|
|
5240
5361
|
continue;
|
|
5241
5362
|
}
|
|
5242
|
-
const profile = check.profile;
|
|
5243
5363
|
// Ensure target agent is registered before creating claims/messages
|
|
5244
5364
|
ensureAgentRegisteredForDispatch(agentName, dispatchCwd);
|
|
5245
5365
|
const assignScope = req.scope ?? req.task;
|
package/dist/commands/metrics.js
CHANGED
|
@@ -12,7 +12,6 @@ export function runMetrics(options = {}) {
|
|
|
12
12
|
}
|
|
13
13
|
const config = loadConfig();
|
|
14
14
|
const slaHours = config.governance?.review_sla_hours ?? 24;
|
|
15
|
-
const now = new Date();
|
|
16
15
|
const report = buildMetricsReport(slaHours, options.since);
|
|
17
16
|
if (options.json) {
|
|
18
17
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -39,7 +39,7 @@ export function runReleaseClaims(options = {}) {
|
|
|
39
39
|
process.exit(0);
|
|
40
40
|
let released = 0;
|
|
41
41
|
mutate({ cwd: options.cwd }, () => {
|
|
42
|
-
let state
|
|
42
|
+
let state;
|
|
43
43
|
for (const claim of toRelease) {
|
|
44
44
|
try {
|
|
45
45
|
releaseClaim(claim.id, options.cwd);
|