brainclaw 1.7.5 → 1.9.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 +28 -11
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +139 -13
- package/dist/commands/add-step.js +1 -1
- package/dist/commands/bootstrap.js +2 -26
- package/dist/commands/check-security-mcp.js +50 -33
- package/dist/commands/check-security.js +86 -43
- package/dist/commands/claim.js +22 -21
- package/dist/commands/confirm.js +26 -0
- package/dist/commands/context-diff.js +1 -1
- package/dist/commands/dispatch-watch.js +142 -0
- package/dist/commands/doctor.js +113 -2
- package/dist/commands/estimation-report.js +115 -16
- package/dist/commands/harvest.js +502 -16
- package/dist/commands/init.js +123 -21
- package/dist/commands/loops-handlers.js +4 -0
- package/dist/commands/mcp-read-handlers.js +198 -29
- package/dist/commands/mcp.js +615 -92
- package/dist/commands/memory.js +21 -17
- package/dist/commands/migrate.js +81 -17
- package/dist/commands/prune.js +78 -4
- package/dist/commands/reflect.js +26 -20
- package/dist/commands/register-agent.js +57 -1
- package/dist/commands/repair.js +20 -0
- package/dist/commands/session-end.js +15 -6
- package/dist/commands/session-start.js +18 -1
- package/dist/commands/setup-security.js +39 -18
- package/dist/commands/setup.js +26 -27
- package/dist/commands/stale.js +16 -2
- package/dist/commands/uninstall.js +126 -34
- package/dist/commands/update-step.js +6 -0
- package/dist/commands/worktree.js +60 -0
- package/dist/core/actions.js +12 -3
- package/dist/core/agent-capability.js +11 -13
- package/dist/core/agent-files.js +844 -547
- package/dist/core/agent-integrations.js +0 -3
- package/dist/core/agent-inventory.js +67 -0
- package/dist/core/agent-registry.js +163 -29
- package/dist/core/agentrun-reconciler.js +33 -2
- package/dist/core/agentruns.js +7 -1
- package/dist/core/ai-agent-detection.js +31 -44
- package/dist/core/archival.js +15 -9
- package/dist/core/assignment-reconciler.js +56 -0
- package/dist/core/assignment-sweeper.js +127 -4
- package/dist/core/assignments.js +69 -11
- package/dist/core/bootstrap.js +233 -67
- package/dist/core/brainclaw-version.js +22 -0
- package/dist/core/candidates.js +21 -1
- package/dist/core/claims.js +313 -150
- package/dist/core/config.js +6 -1
- package/dist/core/context-diff.js +148 -20
- package/dist/core/context.js +129 -8
- package/dist/core/coordination.js +22 -3
- package/dist/core/dispatch-status.js +109 -5
- package/dist/core/dispatcher.js +65 -11
- package/dist/core/entity-operations.js +45 -24
- package/dist/core/entity-registry.js +31 -5
- package/dist/core/event-log.js +138 -21
- package/dist/core/events/checkpoint.js +258 -0
- package/dist/core/events/genesis.js +220 -0
- package/dist/core/events/journal.js +507 -0
- package/dist/core/events/materialize.js +126 -0
- package/dist/core/events/registry-post-image.js +110 -0
- package/dist/core/events/verify.js +109 -0
- package/dist/core/execution-adapters.js +23 -0
- package/dist/core/execution.js +25 -0
- package/dist/core/facade-schema.js +48 -0
- package/dist/core/gc-semantic.js +130 -5
- package/dist/core/handoff-snapshot.js +68 -0
- package/dist/core/ids.js +19 -8
- package/dist/core/instruction-templates.js +34 -115
- package/dist/core/io.js +39 -3
- package/dist/core/json-store.js +10 -1
- package/dist/core/lock.js +153 -28
- package/dist/core/loops/bootstrap-acquire.js +25 -1
- package/dist/core/loops/facade-schema.js +2 -0
- package/dist/core/loops/hooks/survey-signals-baseline.js +36 -0
- package/dist/core/loops/index.js +1 -0
- package/dist/core/loops/presets/bootstrap.js +7 -0
- package/dist/core/loops/store.js +17 -0
- package/dist/core/loops/verbs.js +24 -1
- package/dist/core/markdown.js +8 -76
- package/dist/core/mcp-command-resolution.js +245 -0
- package/dist/core/memory-compactor.js +5 -3
- package/dist/core/memory-lifecycle.js +282 -0
- package/dist/core/merge-risk.js +150 -0
- package/dist/core/messaging.js +8 -1
- package/dist/core/migration.js +11 -1
- package/dist/core/observer-mode.js +26 -0
- package/dist/core/operations/memory-mutation.js +90 -65
- package/dist/core/operations/plan.js +27 -1
- package/dist/core/protocol-skills.js +210 -0
- package/dist/core/reflection-safety.js +6 -7
- package/dist/core/reputation.js +84 -2
- package/dist/core/runtime-signals.js +71 -9
- package/dist/core/runtime.js +84 -1
- package/dist/core/schema.js +125 -0
- package/dist/core/security-detectors.js +125 -0
- package/dist/core/security-extract.js +189 -0
- package/dist/core/security-guard.js +107 -29
- package/dist/core/security-packages.js +121 -0
- package/dist/core/security-scoring.js +76 -9
- package/dist/core/security.js +34 -2
- package/dist/core/sequence.js +11 -2
- package/dist/core/setup-flow.js +141 -13
- package/dist/core/spawn-check.js +110 -4
- package/dist/core/staleness.js +109 -1
- package/dist/core/state.js +250 -54
- package/dist/core/store-resolution.js +19 -5
- package/dist/core/worktree.js +169 -7
- package/dist/facts.js +8 -8
- package/dist/facts.json +7 -7
- package/docs/PROTOCOL.md +223 -0
- package/docs/cli.md +11 -10
- package/docs/concepts/coordinator-runbook.md +129 -0
- package/docs/concepts/dispatch-lifecycle.md +17 -0
- package/docs/concepts/event-log-store-critique-A.md +333 -0
- package/docs/concepts/event-log-store-critique-B.md +353 -0
- package/docs/concepts/event-log-store-phase0-measurements.md +58 -0
- package/docs/concepts/event-log-store-proposal-A.md +365 -0
- package/docs/concepts/event-log-store-proposal-B.md +404 -0
- package/docs/concepts/event-log-store.md +928 -0
- package/docs/concepts/identity-model-proposal.md +371 -0
- package/docs/concepts/memory.md +5 -4
- package/docs/concepts/observer-protocol.md +361 -0
- package/docs/concepts/parallel-merge-protocol.md +71 -0
- package/docs/concepts/plans-and-claims.md +43 -0
- package/docs/concepts/skills.md +78 -0
- package/docs/concepts/workspace-bootstrapping.md +61 -0
- package/docs/integrations/agents.md +4 -4
- package/docs/integrations/cline.md +10 -11
- package/docs/integrations/codex.md +2 -2
- package/docs/integrations/continue.md +5 -5
- package/docs/integrations/copilot.md +14 -12
- package/docs/integrations/openclaw.md +7 -6
- package/docs/integrations/overview.md +7 -7
- package/docs/integrations/roo.md +3 -3
- package/docs/integrations/windsurf.md +6 -6
- package/docs/mcp-schema-changelog.md +51 -20
- package/docs/quickstart.md +48 -47
- package/docs/security.md +174 -15
- package/docs/storage.md +4 -2
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -65,17 +65,17 @@ brainclaw is designed to sit alongside the coding agents teams are already using
|
|
|
65
65
|
| Logo | Agent | Tier | What brainclaw configures |
|
|
66
66
|
|---|---|---|---|
|
|
67
67
|
| [](https://github.com/anthropics/claude-code) | **[Claude Code](https://github.com/anthropics/claude-code)** | A | MCP + CLAUDE.md + hooks + auto-approve + permissions + /brainclaw skill |
|
|
68
|
-
| [](https://openai.com/codex/) | **[Codex](https://openai.com/codex/)** | A | MCP + AGENTS.md +
|
|
68
|
+
| [](https://openai.com/codex/) | **[Codex](https://openai.com/codex/)** | A | MCP + AGENTS.md + skills |
|
|
69
69
|
| [](https://cursor.com/en-US) | **[Cursor](https://cursor.com/en-US)** | A | MCP (machine) + .cursor/rules/ + hooks + skills |
|
|
70
|
-
| [](https://windsurf.com/) | **[Windsurf](https://windsurf.com/)** | A | MCP (machine) + .windsurfrules +
|
|
71
|
-
| [](https://github.com/cline/cline) | **[Cline](https://github.com/cline/cline)** | A | MCP + auto-approve + .clinerules/
|
|
70
|
+
| [](https://windsurf.com/) | **[Windsurf](https://windsurf.com/)** | A | MCP (machine) + .windsurfrules + .windsurf/rules/ |
|
|
71
|
+
| [](https://github.com/cline/cline) | **[Cline](https://github.com/cline/cline)** | A | MCP + auto-approve + .clinerules/ |
|
|
72
72
|
| [](https://github.com/features/copilot) | **[GitHub Copilot](https://github.com/features/copilot)** | A | MCP + copilot-instructions.md + hooks + skills |
|
|
73
73
|
| [](https://github.com/RooCodeInc/Roo-Code) | **[Roo](https://github.com/RooCodeInc/Roo-Code)** | B | MCP + auto-approve + .roo/rules/ |
|
|
74
74
|
| [](https://github.com/continuedev/continue) | **[Continue](https://github.com/continuedev/continue)** | B | MCP + .continue/rules/ |
|
|
75
75
|
| [](https://github.com/opencode-ai/opencode) | **[OpenCode](https://github.com/opencode-ai/opencode)** | B | MCP + AGENTS.md |
|
|
76
76
|
| [](https://github.com/google-gemini/gemini-cli) | **[Antigravity / Gemini CLI](https://github.com/google-gemini/gemini-cli)** | B | MCP + GEMINI.md |
|
|
77
77
|
|
|
78
|
-
**Tier A** =
|
|
78
|
+
**Tier A** = strongest supported integration for that agent family (usually MCP plus native files, and hooks/skills where the agent exposes them). **Tier B** = MCP/native-file integration with fewer automation surfaces. Tier can degrade at runtime if integration surfaces are missing.
|
|
79
79
|
|
|
80
80
|
### Autonomous Agents
|
|
81
81
|
|
|
@@ -96,11 +96,11 @@ brainclaw is most effective today when one agent works at a time in a given chec
|
|
|
96
96
|
|
|
97
97
|
## Platform Support
|
|
98
98
|
|
|
99
|
-
brainclaw declares support for Node.js 20+ in `package.json
|
|
99
|
+
brainclaw declares support for Node.js 20+ in `package.json` (`engines.node = ">=20.0.0"`). CI actively exercises Node 22 (Active LTS) and Node 24 (current LTS) on Linux; Windows runs on Node 24. Node 20 still works as a minimum runtime but is no longer CI-verified — it reached EOL in April 2026 and was removed from GitHub-hosted runners. The recommended runtime is Node 22 LTS or Node 24 LTS. Real-world support is still not perfectly even yet.
|
|
100
100
|
|
|
101
101
|
| Logo | Platform | Status today | Notes |
|
|
102
102
|
|---|---|---|---|
|
|
103
|
-
| [](https://www.kernel.org/) | **[Linux](https://www.kernel.org/)** | Recommended | best-supported environment today; GitHub CI runs on Ubuntu with Node
|
|
103
|
+
| [](https://www.kernel.org/) | **[Linux](https://www.kernel.org/)** | Recommended | best-supported environment today; GitHub CI runs on Ubuntu with Node 22 and 24 |
|
|
104
104
|
| [](https://www.apple.com/macos/) | **[macOS](https://www.apple.com/macos/)** | Likely supported | Unix-like path and shell model should map well, but it is less exercised than Linux |
|
|
105
105
|
| [](https://www.microsoft.com/windows/) | **[Windows](https://www.microsoft.com/windows/)** | Supported with caveats | native support exists, but PATH, npm, SSH, and PowerShell quoting still create more friction than on Unix systems |
|
|
106
106
|
| [](https://learn.microsoft.com/windows/wsl/) | **[Windows + WSL2](https://learn.microsoft.com/windows/wsl/)** | Important, still maturing | Brainclaw detects this setup explicitly, but setup/install/store parity across Windows and WSL is not fully seamless yet |
|
|
@@ -232,7 +232,7 @@ Still sharp:
|
|
|
232
232
|
1. **Same-checkout concurrent edits** — running two agents in the *same* working tree (no per-claim worktree) is still the wrong answer. Use the dispatch path (auto-worktree per claim) instead of raw concurrent CLI sessions.
|
|
233
233
|
2. **Cross-machine sync** — federation across machines is on the roadmap, not in v1.x. Today brainclaw's store is local and one-machine-per-project.
|
|
234
234
|
3. **Spawn-and-forget assumptions** — spawned workers don't always commit their work cleanly. The brief-ack file confirms the spawn started; in the worst case the coordinator harvests open changes.
|
|
235
|
-
4. **Live state for hook-less agents** —
|
|
235
|
+
4. **Live state for hook-less agents** — supported hook-less file surfaces such as Cline, Windsurf, Continue, Antigravity/Gemini CLI, and Mistral Vibe can get live context via `.live.md` companions regenerated on session-end and handoff, not via real-time push.
|
|
236
236
|
|
|
237
237
|
Recommended use today:
|
|
238
238
|
|
|
@@ -334,9 +334,10 @@ If you are integrating Brainclaw into an agent workflow, start with the agent-fa
|
|
|
334
334
|
Contributor note: the commands below are for developing Brainclaw itself, not for normal agent usage inside a target repo.
|
|
335
335
|
|
|
336
336
|
```bash
|
|
337
|
-
npm test # unit + smoke (fast path)
|
|
338
|
-
npm run test:e2e #
|
|
339
|
-
npm run test:
|
|
337
|
+
npm test # unit + smoke (fast path)
|
|
338
|
+
npm run test:e2e # end-to-end suite
|
|
339
|
+
npm run test:all # full suite
|
|
340
|
+
npm run test:coverage # with coverage report
|
|
340
341
|
```
|
|
341
342
|
|
|
342
343
|
---
|
|
@@ -345,6 +346,22 @@ npm run test:coverage # with coverage report
|
|
|
345
346
|
|
|
346
347
|
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)`).
|
|
347
348
|
|
|
349
|
+
### v1.8.0
|
|
350
|
+
|
|
351
|
+
- **Multi-agent dispatch convergence — "worktree-as-contract"** (from a real
|
|
352
|
+
cross-project field session where a sandboxed worker could neither commit nor
|
|
353
|
+
reach MCP). The worker's contract shrinks to "edit files in this worktree +
|
|
354
|
+
drop `LANE-RESULT.json`": `brainclaw harvest --integrate` commits the worktree
|
|
355
|
+
diff on behalf of a worker that can't self-commit (hard-guarded to the linked
|
|
356
|
+
worktree, never the main repo), then completes the assignment and releases the
|
|
357
|
+
claim with plan cascade. A `LANE-RESULT.json` is now the #1 verdict signal in
|
|
358
|
+
`bclaw_dispatch_status` (worker FINISHED, even without self-update); the
|
|
359
|
+
dispatcher refuses to spawn without an isolated worktree; `open_loop` reviews
|
|
360
|
+
pre-flight each reviewer agent with a trivial validation spawn (clear
|
|
361
|
+
boot-failure reason instead of a generic loop timeout); and decisions/traps
|
|
362
|
+
gain `verified_at`/`verify_cmd` so perishable facts can be flagged stale.
|
|
363
|
+
Additive + opt-in throughout. (pln#530, pln#531, pln#532, pln#533, pln#534, trp#468)
|
|
364
|
+
|
|
348
365
|
### v1.7.5
|
|
349
366
|
|
|
350
367
|
- **Security patch (recommended upgrade)** — fixes a git command-injection / RCE
|
|
@@ -443,7 +460,7 @@ For older releases (v0.x and the early v1.0 launch series), `git log` on `master
|
|
|
443
460
|
|
|
444
461
|
### v1.1.0
|
|
445
462
|
|
|
446
|
-
- **Node 20+ baseline** (pln#485) — `engines.node` is now `>=20.0.0` (Node 18 reached EOL in April 2025). CI matrix runs Node
|
|
463
|
+
- **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.
|
|
447
464
|
- **commander 13 → 14** (requires Node 20+).
|
|
448
465
|
- **@types/node 22 → 24** (LTS-aligned).
|
|
449
466
|
|
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -63,7 +63,7 @@ import { runCheckConstraints } from './commands/check-constraints.js';
|
|
|
63
63
|
import { runCheckPolicy } from './commands/check-policy.js';
|
|
64
64
|
import { runCheckSecurity } from './commands/check-security.js';
|
|
65
65
|
import { runSetupSecurity } from './commands/setup-security.js';
|
|
66
|
-
import { runRegisterAgent } from './commands/register-agent.js';
|
|
66
|
+
import { runRegisterAgent, runRemoveAgent } from './commands/register-agent.js';
|
|
67
67
|
import { runEnableAgent } from './commands/enable-agent.js';
|
|
68
68
|
import { runVersion } from './commands/version.js';
|
|
69
69
|
import { runReleaseNotes } from './commands/release-notes.js';
|
|
@@ -80,6 +80,7 @@ import { runExport, runRefresh } from './commands/export.js';
|
|
|
80
80
|
import { runHooks } from './commands/hooks.js';
|
|
81
81
|
import { runWatch } from './commands/watch.js';
|
|
82
82
|
import { runDispatchAnalysis, runDispatch, runDispatchReview } from './commands/dispatch.js';
|
|
83
|
+
import { runDispatchWatch } from './commands/dispatch-watch.js';
|
|
83
84
|
import { runInboxList, runInboxAck, runInboxArchive, runInboxSend, runInboxThread } from './commands/inbox.js';
|
|
84
85
|
import { runMetrics } from './commands/metrics.js';
|
|
85
86
|
import { runRollback } from './commands/rollback.js';
|
|
@@ -98,7 +99,7 @@ import { initLogLevel, logger } from './core/logger.js';
|
|
|
98
99
|
import { resolveEffectiveCwd } from './core/store-resolution.js';
|
|
99
100
|
import { resolveProjectCwd } from './core/cross-project.js';
|
|
100
101
|
import { runSwitch } from './commands/switch.js';
|
|
101
|
-
import { runWorktreeCreate, runWorktreeList, runWorktreeRemove, runWorktreePrune, runWorktreeClean, runWorktreeMerge } from './commands/worktree.js';
|
|
102
|
+
import { runWorktreeCreate, runWorktreeList, runWorktreeRemove, runWorktreePrune, runWorktreeClean, runWorktreeMerge, runWorktreeCheck } from './commands/worktree.js';
|
|
102
103
|
import { runCheckEvents } from './commands/check-events.js';
|
|
103
104
|
import { runDiscover } from './commands/discover.js';
|
|
104
105
|
import { runMigrate } from './commands/migrate.js';
|
|
@@ -148,11 +149,72 @@ function parseLeadingGlobalOptions(argv) {
|
|
|
148
149
|
}
|
|
149
150
|
return result;
|
|
150
151
|
}
|
|
152
|
+
function trailingGlobalOptionError(argv, actionCommand) {
|
|
153
|
+
let firstCommandIndex = -1;
|
|
154
|
+
for (let i = 0; i < argv.length; i++) {
|
|
155
|
+
const token = argv[i];
|
|
156
|
+
if (token === '--')
|
|
157
|
+
break;
|
|
158
|
+
if (!token.startsWith('-')) {
|
|
159
|
+
firstCommandIndex = i;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
if (token === '--cwd' || token === '--project')
|
|
163
|
+
i++;
|
|
164
|
+
}
|
|
165
|
+
if (firstCommandIndex < 0)
|
|
166
|
+
return undefined;
|
|
167
|
+
for (let i = firstCommandIndex + 1; i < argv.length; i++) {
|
|
168
|
+
const token = argv[i];
|
|
169
|
+
if (token === '--')
|
|
170
|
+
break;
|
|
171
|
+
const long = token.includes('=') ? token.slice(0, token.indexOf('=')) : token;
|
|
172
|
+
if (!['--cwd', '--project', '--verbose', '--debug'].includes(long))
|
|
173
|
+
continue;
|
|
174
|
+
const isLocalOption = actionCommand.options.some((option) => option.long === long);
|
|
175
|
+
if (!isLocalOption) {
|
|
176
|
+
const valueHint = token === long && (long === '--cwd' || long === '--project') ? ' <value>' : '';
|
|
177
|
+
return `Global option ${long} must appear before the subcommand. Use: brainclaw ${long}${valueHint} <command> ...`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolve the (possibly nested) subcommand named in argv without parsing.
|
|
184
|
+
* Used to run the trailing-global-option guard BEFORE Commander parses:
|
|
185
|
+
* with positional options enabled, Commander would otherwise reject a
|
|
186
|
+
* trailing --cwd/--project as "unknown option" before any hook runs.
|
|
187
|
+
*/
|
|
188
|
+
function findCommandFromArgv(argv) {
|
|
189
|
+
let current = program;
|
|
190
|
+
let found;
|
|
191
|
+
for (let i = 0; i < argv.length; i++) {
|
|
192
|
+
const token = argv[i];
|
|
193
|
+
if (token === '--')
|
|
194
|
+
break;
|
|
195
|
+
if (token.startsWith('-')) {
|
|
196
|
+
if (!found && (token === '--cwd' || token === '--project'))
|
|
197
|
+
i++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const sub = current.commands.find((c) => c.name() === token || c.aliases().includes(token));
|
|
201
|
+
if (!sub)
|
|
202
|
+
break;
|
|
203
|
+
found = sub;
|
|
204
|
+
current = sub;
|
|
205
|
+
}
|
|
206
|
+
return found;
|
|
207
|
+
}
|
|
151
208
|
function isCodevEnabled() {
|
|
152
209
|
return process.env.BRAINCLAW_ENABLE_CODEV === '1';
|
|
153
210
|
}
|
|
154
211
|
program
|
|
155
212
|
.name('brainclaw')
|
|
213
|
+
// Stop the program-level parser from consuming options that appear AFTER the
|
|
214
|
+
// subcommand: `instruction … --project auth` must reach the subcommand's own
|
|
215
|
+
// --project, not the global routing flag (which is leading-only by contract —
|
|
216
|
+
// see parseLeadingGlobalOptions + trailingGlobalOptionError).
|
|
217
|
+
.enablePositionalOptions()
|
|
156
218
|
.description('Shared project memory for humans and coding agents.')
|
|
157
219
|
.version(getInstalledBrainclawVersion())
|
|
158
220
|
.option('--verbose', 'Show info-level log messages on stderr')
|
|
@@ -570,8 +632,10 @@ program
|
|
|
570
632
|
.command('add-step <planId> <text>')
|
|
571
633
|
.description('Add an optional step to a plan item')
|
|
572
634
|
.option('--assign <assignee>', 'Assign this step to an agent or person')
|
|
635
|
+
.option('--estimate <minutes>', 'Step-level estimate (minutes, or a duration like "2h"/"30m")')
|
|
636
|
+
.option('--actual-effort <effort>', 'Step-level actual effort (e.g. "45m", "2h")')
|
|
573
637
|
.action((planId, text, options) => {
|
|
574
|
-
runAddStep(planId, text, { assignee: options.assign });
|
|
638
|
+
runAddStep(planId, text, { assignee: options.assign, estimatedEffort: options.estimate, actualEffort: options.actualEffort });
|
|
575
639
|
});
|
|
576
640
|
// --- complete-step ---
|
|
577
641
|
program
|
|
@@ -583,10 +647,12 @@ program
|
|
|
583
647
|
// --- update-step ---
|
|
584
648
|
program
|
|
585
649
|
.command('update-step <planId> <stepId>')
|
|
586
|
-
.description('Update a plan step (status, text, assignee)')
|
|
650
|
+
.description('Update a plan step (status, text, assignee, effort)')
|
|
587
651
|
.option('--status <status>', 'New status: todo, in_progress, testing, done, blocked')
|
|
588
652
|
.option('--text <text>', 'Replace step description')
|
|
589
653
|
.option('--assign <assignee>', 'Assign the step (empty string to unassign)')
|
|
654
|
+
.option('--estimate <minutes>', 'Step-level estimate (minutes, or a duration like "2h"/"30m")')
|
|
655
|
+
.option('--actual-effort <effort>', 'Step-level actual effort (e.g. "45m", "2h")')
|
|
590
656
|
.action((planId, stepId, options) => {
|
|
591
657
|
runUpdateStep(planId, stepId, options);
|
|
592
658
|
});
|
|
@@ -603,8 +669,13 @@ program
|
|
|
603
669
|
.description('Show estimation accuracy report for completed plans')
|
|
604
670
|
.option('--agent <name>', 'Filter by agent/author name')
|
|
605
671
|
.option('--json', 'Output as JSON')
|
|
672
|
+
.option('--outlier-threshold <minutes>', 'Drop plan-wallclock actuals over N minutes from the stats (default 1440 = 24h; 0 disables)')
|
|
606
673
|
.action((options) => {
|
|
607
|
-
runEstimationReport(
|
|
674
|
+
runEstimationReport({
|
|
675
|
+
agent: options.agent,
|
|
676
|
+
json: options.json,
|
|
677
|
+
outlierThresholdMinutes: options.outlierThreshold !== undefined ? Number(options.outlierThreshold) : undefined,
|
|
678
|
+
});
|
|
608
679
|
});
|
|
609
680
|
// --- update-plan ---
|
|
610
681
|
program
|
|
@@ -681,6 +752,7 @@ program
|
|
|
681
752
|
.option('--repair', 'Rebuild dist/ when the MCP runtime is missing or stale')
|
|
682
753
|
.option('--after-migration', 'Run the v1.0 post-migration health check only (exits non-zero on any failure)')
|
|
683
754
|
.option('--dispatch', 'Run dispatch-health diagnostic only: reconcile open agent_runs and report stuck/unverified/silent failures (pln#496 step stp_8c072d75)')
|
|
755
|
+
.option('--verify-journal', 'Phase-2 cutover gate (pln#565): rebuild state from the event journal and diff vs live projections; exits non-zero on any drift')
|
|
684
756
|
.option('--spawn-check', 'Real spawn round-trip per installed agent before dispatch (pln#520 step 2): validates delivery + handshake on this host, exits non-zero on any installed-agent failure')
|
|
685
757
|
.option('--spawn-check-timeout <ms>', 'Per-agent timeout for --spawn-check (default 15000)', parseInt)
|
|
686
758
|
.action(async (options) => {
|
|
@@ -688,7 +760,7 @@ program
|
|
|
688
760
|
await runDoctorSpawnCheck({ cwd: options.cwd, json: options.json, timeoutMs: options.spawnCheckTimeout });
|
|
689
761
|
return;
|
|
690
762
|
}
|
|
691
|
-
runDoctor({ ...options, afterMigration: options.afterMigration, dispatch: options.dispatch });
|
|
763
|
+
runDoctor({ ...options, afterMigration: options.afterMigration, dispatch: options.dispatch, verifyJournal: options.verifyJournal });
|
|
692
764
|
});
|
|
693
765
|
// --- repair (Phase 4 Sprint 2 Lane C / pln#397) ---
|
|
694
766
|
program
|
|
@@ -901,8 +973,14 @@ program
|
|
|
901
973
|
.option('--generate-fingerprint', 'Generate or rotate a local public identity fingerprint for this agent')
|
|
902
974
|
.option('--set-current', 'Set this identity as the current agent in config')
|
|
903
975
|
.option('--curator', 'Register this agent as a curator (project owner with direct-write access)')
|
|
976
|
+
.option('--remove', 'Remove this identity instead of registering (guarded: debris identities only unless --force)')
|
|
977
|
+
.option('--force', 'With --remove: allow removing a non-debris identity')
|
|
904
978
|
.option('--json', 'Output as JSON')
|
|
905
979
|
.action((name, options) => {
|
|
980
|
+
if (options.remove) {
|
|
981
|
+
runRemoveAgent(name, { force: options.force, json: options.json });
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
906
984
|
runRegisterAgent(name, options);
|
|
907
985
|
});
|
|
908
986
|
// --- enable-agent ---
|
|
@@ -1014,6 +1092,9 @@ program
|
|
|
1014
1092
|
.command('harvest [assignment_id]')
|
|
1015
1093
|
.description('Harvest a worker LANE-RESULT.json from its worktree into the project (pass an assignment id, or --all)')
|
|
1016
1094
|
.option('--all', 'Harvest every lane result found across worktrees')
|
|
1095
|
+
.option('--integrate', 'Worktree-as-contract (pln#534): commit the worktree diff on behalf of a sandboxed worker, lifecycle the assignment, and release the claim')
|
|
1096
|
+
.option('--orphaned', 'Recover a dead worker that left NO lane-result (pln#554): typecheck + commit the worktree on behalf, lifecycle, release. Never deletes or resets anything')
|
|
1097
|
+
.option('--base <ref>', 'Base ref for --orphaned commits-ahead comparison (default: master)')
|
|
1017
1098
|
.option('--dry-run', 'Preview without writing events/markers')
|
|
1018
1099
|
.option('--worktree <path>', 'Explicit worktree path to scan (repeatable)', collect, [])
|
|
1019
1100
|
.option('--json', 'Output as JSON')
|
|
@@ -1236,13 +1317,19 @@ program
|
|
|
1236
1317
|
program
|
|
1237
1318
|
.command('check-security')
|
|
1238
1319
|
.description('Check supply chain security scores for packages via Socket.dev')
|
|
1239
|
-
.
|
|
1320
|
+
.option('--packages <names>', 'Comma-separated package names (e.g. "axios,express" or "axios@1.14.1")')
|
|
1321
|
+
.option('--requirements <file>', 'Path to a pip-style requirements.txt to scan')
|
|
1322
|
+
.option('--lockfile <file>', 'Path to a package-lock.json (npm) to scan top-level deps')
|
|
1240
1323
|
.option('--ecosystem <type>', 'Package ecosystem: npm or pypi', 'npm')
|
|
1324
|
+
.option('--mode <mode>', 'Override security mode: advisory or enforced (defaults to config)')
|
|
1241
1325
|
.option('--json', 'Output as JSON')
|
|
1242
1326
|
.action(async (options) => {
|
|
1243
1327
|
await runCheckSecurity({
|
|
1244
1328
|
packages: options.packages,
|
|
1329
|
+
requirements: options.requirements,
|
|
1330
|
+
lockfile: options.lockfile,
|
|
1245
1331
|
ecosystem: options.ecosystem,
|
|
1332
|
+
mode: options.mode,
|
|
1246
1333
|
json: options.json,
|
|
1247
1334
|
});
|
|
1248
1335
|
});
|
|
@@ -1338,7 +1425,7 @@ program
|
|
|
1338
1425
|
.option('--reflect-handoff', 'Materialize an open handoff from git commits since session start')
|
|
1339
1426
|
.option('--dispatch-review', 'When used with --reflect-handoff, auto-dispatch a code review if the handoff is reviewable')
|
|
1340
1427
|
.option('--reviewer <name>', 'Explicit reviewer to route the reflected handoff review to')
|
|
1341
|
-
.option('--reflect', '
|
|
1428
|
+
.option('--no-reflect', 'Suppress the dogfooding reflection prompt (project + your surfaces/skills/tools), shown by default')
|
|
1342
1429
|
.option('--json', 'Output as JSON')
|
|
1343
1430
|
.action(async (options) => {
|
|
1344
1431
|
await runSessionEnd({
|
|
@@ -1387,7 +1474,7 @@ program
|
|
|
1387
1474
|
program
|
|
1388
1475
|
.command('export')
|
|
1389
1476
|
.description('Export memory as instructions for IDE/AI tools')
|
|
1390
|
-
.option('--format <format>', 'Format: copilot-instructions, cursor-rules, agents-md, claude-md, gemini-md, windsurf, cline, roo, continue')
|
|
1477
|
+
.option('--format <format>', 'Format: copilot-instructions, cursor-rules, agents-md, claude-md, gemini-md, windsurf, cline, roo, continue, openclaw, nanoclaw, nemoclaw, picoclaw, zeroclaw')
|
|
1391
1478
|
.option('--detect', 'Auto-detect agent environment and write to its native file')
|
|
1392
1479
|
.option('--all', 'Write all known agent instruction files at once (claude-md, agents-md, copilot-instructions, cursor-rules, etc.)')
|
|
1393
1480
|
.option('--write', 'Write to canonical file path instead of stdout (when --format is given); local files are gitignored by default')
|
|
@@ -1465,8 +1552,8 @@ dispatchCmd
|
|
|
1465
1552
|
.option('--spawn', 'Autonomously launch CLI agents with invoke templates')
|
|
1466
1553
|
.option('--agent <name>', 'Dispatcher agent name')
|
|
1467
1554
|
.option('--json', 'Output as JSON')
|
|
1468
|
-
.action((options) => {
|
|
1469
|
-
runDispatch({
|
|
1555
|
+
.action(async (options) => {
|
|
1556
|
+
await runDispatch({
|
|
1470
1557
|
agents: options.agents,
|
|
1471
1558
|
lanes: options.lanes,
|
|
1472
1559
|
max: options.max,
|
|
@@ -1478,6 +1565,21 @@ dispatchCmd
|
|
|
1478
1565
|
json: options.json,
|
|
1479
1566
|
});
|
|
1480
1567
|
});
|
|
1568
|
+
dispatchCmd
|
|
1569
|
+
.command('watch <target>')
|
|
1570
|
+
.description('Block until a dispatched worker reaches a terminal state (asgn_/clm_/run_ id) — sentinels, lane-result, committed-clean and worker-process-gone heuristics')
|
|
1571
|
+
.option('--interval <seconds>', 'Poll interval in seconds (default 60)', parseInt)
|
|
1572
|
+
.option('--timeout <minutes>', 'Give up after N minutes (default 90, exit code 2)', parseInt)
|
|
1573
|
+
.option('--base <ref>', 'Base ref for commits-ahead evidence (default master)')
|
|
1574
|
+
.option('--json', 'One JSON object per poll line')
|
|
1575
|
+
.action(async (target, options) => {
|
|
1576
|
+
await runDispatchWatch(target, {
|
|
1577
|
+
intervalSeconds: options.interval,
|
|
1578
|
+
timeoutMinutes: options.timeout,
|
|
1579
|
+
base: options.base,
|
|
1580
|
+
json: options.json,
|
|
1581
|
+
});
|
|
1582
|
+
});
|
|
1481
1583
|
dispatchCmd
|
|
1482
1584
|
.command('review')
|
|
1483
1585
|
.description('Dispatch code reviews for completed handoffs')
|
|
@@ -1697,9 +1799,10 @@ program
|
|
|
1697
1799
|
.command('migrate')
|
|
1698
1800
|
.description('Migrate memory items between stores (e.g. promote machine-scoped items to user store)')
|
|
1699
1801
|
.option('--promote-machine-items', 'Move items with scope:machine from project store to user store (~/.brainclaw/)')
|
|
1700
|
-
.option('--
|
|
1802
|
+
.option('--enable-journal', 'Turn on the event journal (mode=dual) for this existing store and backfill it (pln#567)')
|
|
1803
|
+
.option('--dry-run', 'Show what would be done without writing')
|
|
1701
1804
|
.action((options) => {
|
|
1702
|
-
runMigrate({ promoteMachineItems: options.promoteMachineItems, dryRun: options.dryRun });
|
|
1805
|
+
runMigrate({ promoteMachineItems: options.promoteMachineItems, enableJournal: options.enableJournal, dryRun: options.dryRun });
|
|
1703
1806
|
});
|
|
1704
1807
|
program
|
|
1705
1808
|
.command('switch [project]')
|
|
@@ -1780,6 +1883,15 @@ worktreeCmd
|
|
|
1780
1883
|
const globalOpts = program.opts();
|
|
1781
1884
|
runWorktreeMerge({ branch, message: options.message, dryRun: options.dryRun, cwd: globalOpts.cwd });
|
|
1782
1885
|
});
|
|
1886
|
+
worktreeCmd
|
|
1887
|
+
.command('check')
|
|
1888
|
+
.description('Pre-merge conflict detection: which parallel lanes touch overlapping files, and who owns them (exit 3 if overlaps found)')
|
|
1889
|
+
.option('--base <ref>', 'Base ref each lane is diffed against (default: current branch)')
|
|
1890
|
+
.option('--json', 'Emit the full risk report as JSON')
|
|
1891
|
+
.action((options) => {
|
|
1892
|
+
const globalOpts = program.opts();
|
|
1893
|
+
runWorktreeCheck({ baseRef: options.base, json: options.json, cwd: globalOpts.cwd });
|
|
1894
|
+
});
|
|
1783
1895
|
// --- federation cloud ---
|
|
1784
1896
|
const federationCmd = program
|
|
1785
1897
|
.command('federation')
|
|
@@ -2022,6 +2134,20 @@ program
|
|
|
2022
2134
|
const globalOpts = program.opts();
|
|
2023
2135
|
runRunProfile(profileName, { ...options, cwd: globalOpts.cwd });
|
|
2024
2136
|
});
|
|
2137
|
+
{
|
|
2138
|
+
// Friendly trailing-global-option error must run before Commander parses:
|
|
2139
|
+
// with positional options enabled, Commander itself would reject a trailing
|
|
2140
|
+
// --cwd/--project as a bare "unknown option" otherwise.
|
|
2141
|
+
const argvTail = process.argv.slice(2);
|
|
2142
|
+
const guardCommand = findCommandFromArgv(argvTail);
|
|
2143
|
+
if (guardCommand) {
|
|
2144
|
+
const trailingError = trailingGlobalOptionError(argvTail, guardCommand);
|
|
2145
|
+
if (trailingError) {
|
|
2146
|
+
console.error(`Error: ${trailingError}`);
|
|
2147
|
+
process.exit(1);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2025
2151
|
program.parseAsync(process.argv).catch((err) => {
|
|
2026
2152
|
console.error(err);
|
|
2027
2153
|
process.exit(1);
|
|
@@ -5,7 +5,7 @@ export function runAddStep(planId, text, options = {}) {
|
|
|
5
5
|
requireInitialized(process.cwd());
|
|
6
6
|
validateCliInput(text);
|
|
7
7
|
try {
|
|
8
|
-
const result = addStep({ planId, text, assignee: options.assignee });
|
|
8
|
+
const result = addStep({ planId, text, assignee: options.assignee, estimatedEffort: options.estimatedEffort, actualEffort: options.actualEffort });
|
|
9
9
|
console.log(`✔ Step added: [${result.stepId}] ${text}`);
|
|
10
10
|
console.log(` Plan [${result.planId}] progress: ${result.doneSteps}/${result.totalSteps} steps done`);
|
|
11
11
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import readline from 'node:readline/promises';
|
|
3
|
-
import { stdin as input, stdout as output } from 'node:process';
|
|
4
2
|
import { memoryExists } from '../core/io.js';
|
|
5
3
|
import { applyBootstrapImport, renderBootstrapInterview, renderBootstrapSummary, runBootstrapProfile, uninstallBootstrapImport, } from '../core/bootstrap.js';
|
|
6
4
|
import { BootstrapInterviewAnswerSchema } from '../core/schema.js';
|
|
5
|
+
import { confirmAction } from './confirm.js';
|
|
7
6
|
export async function runBootstrap(options = {}) {
|
|
8
7
|
const cwd = options.cwd ?? process.cwd();
|
|
9
8
|
if (!memoryExists(cwd)) {
|
|
@@ -92,28 +91,5 @@ function loadBootstrapInterviewAnswers(filepath) {
|
|
|
92
91
|
}
|
|
93
92
|
return parsed.map((entry) => BootstrapInterviewAnswerSchema.parse(entry));
|
|
94
93
|
}
|
|
95
|
-
|
|
96
|
-
if (yes) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
100
|
-
console.error(`Error: ${question} Re-run with --yes in non-interactive mode.`);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
const rl = readline.createInterface({ input, output });
|
|
104
|
-
try {
|
|
105
|
-
const answer = await rl.question(`${question} [y/N] `);
|
|
106
|
-
if (answer.trim().toLowerCase() !== 'y') {
|
|
107
|
-
console.error('Cancelled.');
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
finally {
|
|
116
|
-
rl.close();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
94
|
+
const confirmBootstrapAction = confirmAction;
|
|
119
95
|
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -2,7 +2,9 @@ import { memoryExists, memoryPath } from '../core/io.js';
|
|
|
2
2
|
import { loadConfig } from '../core/config.js';
|
|
3
3
|
import { SecurityCache } from '../core/security-cache.js';
|
|
4
4
|
import { querySocketScores } from '../core/socket-client.js';
|
|
5
|
-
import { evaluateBatch, worstDecision } from '../core/security-scoring.js';
|
|
5
|
+
import { applyMode, evaluateBatch, worstDecision, } from '../core/security-scoring.js';
|
|
6
|
+
import { parsePackageSpec } from '../core/security-packages.js';
|
|
7
|
+
import { collectPackages } from '../core/security-extract.js';
|
|
6
8
|
import { createTrap } from '../core/operations/memory-write.js';
|
|
7
9
|
export async function handleCheckSecurity(args, cwd) {
|
|
8
10
|
if (!memoryExists(cwd)) {
|
|
@@ -13,20 +15,35 @@ export async function handleCheckSecurity(args, cwd) {
|
|
|
13
15
|
if (!preinstall?.enabled) {
|
|
14
16
|
return { content: [{ type: 'text', text: 'Security preinstall checks are not enabled. Set security.preinstall.enabled: true in config.yaml.' }] };
|
|
15
17
|
}
|
|
16
|
-
const packagesStr = String(args.packages ?? '').trim();
|
|
17
|
-
if (!packagesStr) {
|
|
18
|
-
return { content: [{ type: 'text', text: 'Error: missing required argument: packages' }] };
|
|
19
|
-
}
|
|
20
18
|
const ecosystem = (String(args.ecosystem ?? 'npm').trim());
|
|
21
|
-
const
|
|
19
|
+
const modeArg = args.mode ? String(args.mode).trim() : undefined;
|
|
20
|
+
const effectiveMode = (modeArg === 'enforced' || modeArg === 'advisory')
|
|
21
|
+
? modeArg
|
|
22
|
+
: (preinstall.mode ?? 'advisory');
|
|
23
|
+
let packageSpecs;
|
|
24
|
+
try {
|
|
25
|
+
packageSpecs = collectPackages({
|
|
26
|
+
packages: args.packages ? String(args.packages) : undefined,
|
|
27
|
+
requirements: args.requirements ? String(args.requirements) : undefined,
|
|
28
|
+
lockfile: args.lockfile ? String(args.lockfile) : undefined,
|
|
29
|
+
defaultEcosystem: ecosystem,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
34
|
+
return { content: [{ type: 'text', text: `Error: ${msg}` }] };
|
|
35
|
+
}
|
|
36
|
+
if (packageSpecs.length === 0) {
|
|
37
|
+
return { content: [{ type: 'text', text: 'Error: no packages specified (pass --packages, --requirements, or --lockfile).' }] };
|
|
38
|
+
}
|
|
22
39
|
// Build cache
|
|
23
40
|
const cachePath = memoryPath('security/cache.json', cwd);
|
|
24
41
|
const cache = new SecurityCache(cachePath, preinstall.cache_ttl_hours);
|
|
25
42
|
// Separate cached vs uncached
|
|
26
43
|
const queries = [];
|
|
27
44
|
const cachedScores = [];
|
|
28
|
-
for (const
|
|
29
|
-
const
|
|
45
|
+
for (const spec of packageSpecs) {
|
|
46
|
+
const { depname, version } = parsePackageSpec(spec);
|
|
30
47
|
const cached = cache.get(ecosystem, depname, version);
|
|
31
48
|
if (cached) {
|
|
32
49
|
cachedScores.push(cached);
|
|
@@ -55,25 +72,34 @@ export async function handleCheckSecurity(args, cwd) {
|
|
|
55
72
|
const allScores = [...cachedScores, ...fetchedScores];
|
|
56
73
|
if (allScores.length === 0 && fetchError) {
|
|
57
74
|
const fallback = preinstall.fallback_on_error;
|
|
75
|
+
const fallbackVerdict = fallback === 'block' ? 'block' : fallback === 'warn' ? 'warn' : 'pass';
|
|
76
|
+
const effective = applyMode(fallbackVerdict, effectiveMode);
|
|
58
77
|
return {
|
|
59
|
-
content: [{ type: 'text', text: `Socket MCP error: ${fetchError}\nFallback policy: ${fallback}` }],
|
|
60
|
-
structuredContent: {
|
|
78
|
+
content: [{ type: 'text', text: `Socket MCP error: ${fetchError}\nFallback policy: ${fallback} (mode=${effectiveMode}) → ${effective.toUpperCase()}` }],
|
|
79
|
+
structuredContent: {
|
|
80
|
+
error: fetchError,
|
|
81
|
+
fallback,
|
|
82
|
+
mode: effectiveMode,
|
|
83
|
+
decision: fallbackVerdict,
|
|
84
|
+
effective_decision: effective,
|
|
85
|
+
},
|
|
61
86
|
};
|
|
62
87
|
}
|
|
63
88
|
const verdicts = evaluateBatch(allScores, preinstall);
|
|
64
|
-
const
|
|
89
|
+
const intrinsic = worstDecision(verdicts);
|
|
90
|
+
const effective = applyMode(intrinsic, effectiveMode);
|
|
65
91
|
// Build text output
|
|
66
92
|
const lines = [];
|
|
67
93
|
if (fetchError) {
|
|
68
|
-
lines.push(
|
|
94
|
+
lines.push(`⚠ Socket MCP partial error: ${fetchError} (${cachedScores.length} results from cache)`);
|
|
69
95
|
lines.push('');
|
|
70
96
|
}
|
|
71
97
|
for (const v of verdicts) {
|
|
72
|
-
const icon = v.decision === 'pass' ? '
|
|
73
|
-
lines.push(`${icon} ${v.ecosystem}/${v.package}@${v.version}
|
|
98
|
+
const icon = v.decision === 'pass' ? '✅' : v.decision === 'warn' ? '⚠️' : '🛑';
|
|
99
|
+
lines.push(`${icon} ${v.ecosystem}/${v.package}@${v.version} — composite=${v.composite} [${v.decision.toUpperCase()}]`);
|
|
74
100
|
lines.push(` SC=${v.scores.supplyChain} vuln=${v.scores.vulnerability} qual=${v.scores.quality} maint=${v.scores.maintenance} lic=${v.scores.license}`);
|
|
75
101
|
for (const r of v.reasons) {
|
|
76
|
-
lines.push(`
|
|
102
|
+
lines.push(` → ${r}`);
|
|
77
103
|
}
|
|
78
104
|
}
|
|
79
105
|
// Auto-create traps for WARN and BLOCK verdicts
|
|
@@ -102,7 +128,12 @@ export async function handleCheckSecurity(args, cwd) {
|
|
|
102
128
|
lines.push(`Created ${trapsCreated.length} security trap(s): ${trapsCreated.join(', ')}`);
|
|
103
129
|
}
|
|
104
130
|
lines.push('');
|
|
105
|
-
|
|
131
|
+
if (intrinsic !== effective) {
|
|
132
|
+
lines.push(`Verdict: ${intrinsic.toUpperCase()} — downgraded to ${effective.toUpperCase()} by mode=${effectiveMode}.`);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
lines.push(`Verdict: ${intrinsic.toUpperCase()} (mode=${effectiveMode})`);
|
|
136
|
+
}
|
|
106
137
|
return {
|
|
107
138
|
content: [{ type: 'text', text: lines.join('\n') }],
|
|
108
139
|
structuredContent: {
|
|
@@ -121,25 +152,11 @@ export async function handleCheckSecurity(args, cwd) {
|
|
|
121
152
|
license: v.scores.license,
|
|
122
153
|
},
|
|
123
154
|
})),
|
|
124
|
-
decision:
|
|
155
|
+
decision: intrinsic,
|
|
156
|
+
effective_decision: effective,
|
|
157
|
+
mode: effectiveMode,
|
|
125
158
|
...(fetchError ? { fetch_error: fetchError } : {}),
|
|
126
159
|
},
|
|
127
160
|
};
|
|
128
161
|
}
|
|
129
|
-
function parsePackageName(name) {
|
|
130
|
-
// Handle scoped packages: @scope/pkg@version
|
|
131
|
-
if (name.startsWith('@')) {
|
|
132
|
-
const lastAt = name.lastIndexOf('@', name.length - 1);
|
|
133
|
-
if (lastAt > 0) {
|
|
134
|
-
return [name.slice(0, lastAt), name.slice(lastAt + 1)];
|
|
135
|
-
}
|
|
136
|
-
return [name, 'latest'];
|
|
137
|
-
}
|
|
138
|
-
// Regular: pkg@version
|
|
139
|
-
if (name.includes('@')) {
|
|
140
|
-
const [depname, version] = name.split('@');
|
|
141
|
-
return [depname, version || 'latest'];
|
|
142
|
-
}
|
|
143
|
-
return [name, 'latest'];
|
|
144
|
-
}
|
|
145
162
|
//# sourceMappingURL=check-security-mcp.js.map
|