brainclaw 0.29.2 → 1.5.4
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/LICENSE +21 -74
- package/README.md +199 -176
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +710 -25
- package/dist/commands/accept.js +3 -0
- package/dist/commands/add-step.js +11 -26
- package/dist/commands/agent-board.js +70 -3
- package/dist/commands/audit.js +19 -0
- package/dist/commands/check-policy.js +54 -0
- package/dist/commands/check-security-mcp.js +145 -0
- package/dist/commands/check-security.js +106 -0
- package/dist/commands/claim-resource.js +1 -0
- package/dist/commands/codev.js +672 -0
- package/dist/commands/compact.js +74 -0
- package/dist/commands/complete-step.js +16 -26
- package/dist/commands/constraint.js +8 -20
- package/dist/commands/decision.js +9 -20
- package/dist/commands/delete-plan.js +10 -12
- package/dist/commands/delete-step.js +16 -0
- package/dist/commands/dispatch.js +163 -0
- package/dist/commands/doctor.js +1122 -49
- package/dist/commands/enable-agent.js +1 -0
- package/dist/commands/export.js +280 -22
- package/dist/commands/handoff.js +33 -0
- package/dist/commands/harvest.js +189 -0
- package/dist/commands/hooks.js +82 -25
- package/dist/commands/inbox.js +169 -0
- package/dist/commands/init.js +38 -31
- package/dist/commands/install-hooks.js +71 -44
- package/dist/commands/link.js +89 -0
- package/dist/commands/list-claims.js +48 -3
- package/dist/commands/list-plans.js +129 -25
- package/dist/commands/loops-handlers.js +409 -0
- package/dist/commands/mcp-read-handlers.js +1628 -0
- package/dist/commands/mcp-schemas.generated.js +269 -0
- package/dist/commands/mcp.js +4224 -1501
- package/dist/commands/plan-resource.js +64 -0
- package/dist/commands/plan.js +12 -26
- package/dist/commands/prune.js +37 -2
- package/dist/commands/reflect.js +20 -7
- package/dist/commands/release-claim.js +11 -6
- package/dist/commands/release-notes.js +170 -0
- package/dist/commands/repair.js +210 -0
- package/dist/commands/run-profile.js +57 -0
- package/dist/commands/sequence.js +113 -0
- package/dist/commands/session-end.js +423 -14
- package/dist/commands/session-start.js +214 -41
- package/dist/commands/setup-security.js +103 -0
- package/dist/commands/setup.js +42 -4
- package/dist/commands/stale.js +109 -0
- package/dist/commands/switch.js +100 -2
- package/dist/commands/trap.js +14 -31
- package/dist/commands/update-handoff.js +63 -4
- package/dist/commands/update-plan.js +21 -28
- package/dist/commands/update-step.js +37 -0
- package/dist/commands/upgrade.js +313 -6
- package/dist/commands/usage.js +102 -0
- package/dist/commands/version.js +20 -0
- package/dist/commands/who.js +33 -5
- package/dist/commands/worktree.js +105 -0
- package/dist/core/actions.js +315 -0
- package/dist/core/agent-capability.js +610 -17
- package/dist/core/agent-context.js +7 -1
- package/dist/core/agent-files.js +1169 -85
- package/dist/core/agent-integrations.js +160 -5
- package/dist/core/agent-inventory.js +2 -0
- package/dist/core/agent-profiles.js +93 -0
- package/dist/core/agent-registry.js +162 -30
- package/dist/core/agentrun-reconciler.js +345 -0
- package/dist/core/agentruns.js +424 -0
- package/dist/core/ai-agent-detection.js +31 -10
- package/dist/core/archival.js +77 -0
- package/dist/core/assignment-sweeper.js +82 -0
- package/dist/core/assignments.js +367 -0
- package/dist/core/audit.js +30 -0
- package/dist/core/brainclaw-version.js +94 -2
- package/dist/core/candidates.js +93 -2
- package/dist/core/claims.js +419 -0
- package/dist/core/codev-metrics.js +77 -0
- package/dist/core/codev-personas.js +31 -0
- package/dist/core/codev-plan-gen.js +35 -0
- package/dist/core/codev-prompts.js +74 -0
- package/dist/core/codev-responses.js +62 -0
- package/dist/core/codev-rounds.js +218 -0
- package/dist/core/config.js +4 -0
- package/dist/core/context.js +381 -34
- package/dist/core/coordination.js +201 -6
- package/dist/core/cross-project.js +230 -16
- package/dist/core/default-profiles/doctor.yaml +11 -0
- package/dist/core/default-profiles/janitor.yaml +11 -0
- package/dist/core/default-profiles/onboarder.yaml +11 -0
- package/dist/core/default-profiles/reviewer.yaml +13 -0
- package/dist/core/dispatcher.js +1189 -0
- package/dist/core/duplicates.js +2 -2
- package/dist/core/entity-operations.js +450 -0
- package/dist/core/entity-registry.js +344 -0
- package/dist/core/events.js +106 -2
- package/dist/core/execution-adapters.js +154 -0
- package/dist/core/execution-context.js +63 -0
- package/dist/core/execution-profile.js +270 -0
- package/dist/core/execution.js +255 -0
- package/dist/core/facade-schema.js +81 -0
- package/dist/core/federation-cloud.js +99 -0
- package/dist/core/federation-message.js +52 -0
- package/dist/core/federation-transport.js +65 -0
- package/dist/core/gc-semantic.js +482 -0
- package/dist/core/governance.js +247 -0
- package/dist/core/guards.js +19 -0
- package/dist/core/ideation.js +72 -0
- package/dist/core/identity.js +110 -25
- package/dist/core/ids.js +6 -0
- package/dist/core/input-validation.js +2 -2
- package/dist/core/instruction-templates.js +344 -136
- package/dist/core/io.js +90 -11
- package/dist/core/lock.js +6 -2
- package/dist/core/loops/brief-assembly.js +213 -0
- package/dist/core/loops/facade-schema.js +148 -0
- package/dist/core/loops/index.js +7 -0
- package/dist/core/loops/iteration-engine.js +139 -0
- package/dist/core/loops/lock.js +385 -0
- package/dist/core/loops/store.js +201 -0
- package/dist/core/loops/types.js +403 -0
- package/dist/core/loops/verbs.js +534 -0
- package/dist/core/markdown.js +15 -3
- package/dist/core/memory-compactor.js +432 -0
- package/dist/core/memory-git.js +152 -8
- package/dist/core/messaging.js +278 -0
- package/dist/core/migration.js +32 -1
- package/dist/core/mutation-pipeline.js +4 -2
- package/dist/core/operations/memory-mutation.js +129 -0
- package/dist/core/operations/memory-write.js +78 -0
- package/dist/core/operations/plan.js +190 -0
- package/dist/core/policy.js +169 -0
- package/dist/core/reputation.js +9 -3
- package/dist/core/schema.js +491 -6
- package/dist/core/search.js +21 -2
- package/dist/core/security-cache.js +71 -0
- package/dist/core/security-guard.js +152 -0
- package/dist/core/security-scoring.js +86 -0
- package/dist/core/sequence.js +130 -0
- package/dist/core/socket-client.js +113 -0
- package/dist/core/staleness.js +246 -0
- package/dist/core/state.js +98 -22
- package/dist/core/store-resolution.js +43 -11
- package/dist/core/toml-writer.js +76 -0
- package/dist/core/upgrades/backup.js +232 -0
- package/dist/core/upgrades/health-check.js +169 -0
- package/dist/core/upgrades/patches/candidate-archive.js +145 -0
- package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
- package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
- package/dist/core/upgrades/schema-version.js +97 -0
- package/dist/core/worktree.js +606 -0
- package/dist/facts.js +114 -0
- package/dist/facts.json +111 -0
- package/docs/architecture/project-refs.md +5 -1
- package/docs/cli.md +690 -43
- package/docs/concepts/ideation-loop.md +317 -0
- package/docs/concepts/loop-engine.md +456 -0
- package/docs/concepts/mcp-governance.md +268 -0
- package/docs/concepts/memory-staleness.md +122 -0
- package/docs/concepts/multi-agent-workflows.md +166 -0
- package/docs/concepts/plans-and-claims.md +31 -6
- package/docs/concepts/project-md-convention.md +35 -0
- package/docs/concepts/troubleshooting.md +220 -0
- package/docs/concepts/upgrade-cli.md +202 -0
- package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
- package/docs/context-format-changelog.md +2 -2
- package/docs/context-format.md +2 -2
- package/docs/index.md +68 -0
- package/docs/integrations/agents.md +15 -16
- package/docs/integrations/cline.md +88 -0
- package/docs/integrations/codex.md +75 -23
- package/docs/integrations/continue.md +60 -0
- package/docs/integrations/copilot.md +67 -9
- package/docs/integrations/kilocode.md +72 -0
- package/docs/integrations/mcp.md +304 -21
- package/docs/integrations/mistral-vibe.md +122 -0
- package/docs/integrations/opencode.md +84 -0
- package/docs/integrations/overview.md +23 -8
- package/docs/integrations/roo.md +74 -0
- package/docs/integrations/windsurf.md +83 -0
- package/docs/mcp-schema-changelog.md +191 -1
- package/docs/playbooks/integration/index.md +121 -0
- package/docs/playbooks/productivity/index.md +102 -0
- package/docs/playbooks/team/index.md +122 -0
- package/docs/product/agent-first-model.md +184 -0
- package/docs/product/entity-model-audit.md +462 -0
- package/docs/product/positioning.md +10 -10
- package/docs/quickstart-existing-project.md +135 -0
- package/docs/quickstart.md +124 -37
- package/docs/release-maintenance.md +79 -0
- package/docs/review.md +2 -0
- package/docs/server-operations.md +118 -0
- package/package.json +21 -13
- package/dist/commands/claude-desktop-extension.js +0 -18
- package/dist/commands/diff.js +0 -99
- package/dist/core/claude-desktop-extension.js +0 -224
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Command } from 'commander';
|
|
|
4
4
|
import { runInit } from './commands/init.js';
|
|
5
5
|
import { runSetup } from './commands/setup.js';
|
|
6
6
|
import { runUpgrade } from './commands/upgrade.js';
|
|
7
|
+
import { patchAllMcpConfigs } from './core/agent-files.js';
|
|
7
8
|
import { runReconcile } from './commands/reconcile.js';
|
|
8
9
|
import { getMemoryLog, rollbackMemory, hasMemoryRepo } from './core/memory-git.js';
|
|
9
10
|
import { buildMachineProfile, saveMachineProfile, loadMachineProfile, renderMachineProfileSummary } from './core/machine-profile.js';
|
|
@@ -18,7 +19,10 @@ import { runListPlans } from './commands/list-plans.js';
|
|
|
18
19
|
import { runUpdatePlan } from './commands/update-plan.js';
|
|
19
20
|
import { runDeletePlan } from './commands/delete-plan.js';
|
|
20
21
|
import { runPlanResource } from './commands/plan-resource.js';
|
|
22
|
+
import { runSequenceResource } from './commands/sequence.js';
|
|
21
23
|
import { runAddStep } from './commands/add-step.js';
|
|
24
|
+
import { runDeleteStep } from './commands/delete-step.js';
|
|
25
|
+
import { runUpdateStep } from './commands/update-step.js';
|
|
22
26
|
import { runEstimationReport } from './commands/estimation-report.js';
|
|
23
27
|
import { runCompleteStep } from './commands/complete-step.js';
|
|
24
28
|
import { runUpdateHandoff } from './commands/update-handoff.js';
|
|
@@ -27,6 +31,8 @@ import { runListAgents } from './commands/list-agents.js';
|
|
|
27
31
|
import { runSurfaceTaskResource } from './commands/surface-task-resource.js';
|
|
28
32
|
import { runListInstructions } from './commands/list-instructions.js';
|
|
29
33
|
import { runDoctor } from './commands/doctor.js';
|
|
34
|
+
import { runRepair } from './commands/repair.js';
|
|
35
|
+
import { runStale } from './commands/stale.js';
|
|
30
36
|
import { runRebuild } from './commands/rebuild.js';
|
|
31
37
|
import { runReflect } from './commands/reflect.js';
|
|
32
38
|
import { runReflectRuntimeNote } from './commands/reflect-runtime-note.js';
|
|
@@ -37,6 +43,7 @@ import { runUseCandidate } from './commands/use-candidate.js';
|
|
|
37
43
|
import { runAccept } from './commands/accept.js';
|
|
38
44
|
import { runReject } from './commands/reject.js';
|
|
39
45
|
import { runPruneCandidates } from './commands/prune-candidates.js';
|
|
46
|
+
import { cleanupStaleCandidates } from './core/candidates.js';
|
|
40
47
|
import { runListClaims } from './commands/list-claims.js';
|
|
41
48
|
import { runReleaseClaim } from './commands/release-claim.js';
|
|
42
49
|
import { runClaimResource } from './commands/claim-resource.js';
|
|
@@ -52,9 +59,13 @@ import { runEnv } from './commands/env.js';
|
|
|
52
59
|
import { runAdapterOpenclawImport } from './commands/adapter-openclaw-import.js';
|
|
53
60
|
import { runInstallHooks } from './commands/install-hooks.js';
|
|
54
61
|
import { runCheckConstraints } from './commands/check-constraints.js';
|
|
62
|
+
import { runCheckPolicy } from './commands/check-policy.js';
|
|
63
|
+
import { runCheckSecurity } from './commands/check-security.js';
|
|
64
|
+
import { runSetupSecurity } from './commands/setup-security.js';
|
|
55
65
|
import { runRegisterAgent } from './commands/register-agent.js';
|
|
56
66
|
import { runEnableAgent } from './commands/enable-agent.js';
|
|
57
67
|
import { runVersion } from './commands/version.js';
|
|
68
|
+
import { runReleaseNotes } from './commands/release-notes.js';
|
|
58
69
|
import { runDiff } from './commands/changes.js';
|
|
59
70
|
import { runPrune } from './commands/prune.js';
|
|
60
71
|
import { runMcp } from './commands/mcp.js';
|
|
@@ -62,10 +73,13 @@ import { runSetTrust } from './commands/set-trust.js';
|
|
|
62
73
|
import { runSessionStart } from './commands/session-start.js';
|
|
63
74
|
import { runSessionEnd } from './commands/session-end.js';
|
|
64
75
|
import { runWhoami } from './commands/whoami.js';
|
|
76
|
+
import { runUsage } from './commands/usage.js';
|
|
65
77
|
import { runSearch } from './commands/search.js';
|
|
66
|
-
import { runExport } from './commands/export.js';
|
|
78
|
+
import { runExport, runRefresh } from './commands/export.js';
|
|
67
79
|
import { runHooks } from './commands/hooks.js';
|
|
68
80
|
import { runWatch } from './commands/watch.js';
|
|
81
|
+
import { runDispatchAnalysis, runDispatch, runDispatchReview } from './commands/dispatch.js';
|
|
82
|
+
import { runInboxList, runInboxAck, runInboxArchive, runInboxSend, runInboxThread } from './commands/inbox.js';
|
|
69
83
|
import { runMetrics } from './commands/metrics.js';
|
|
70
84
|
import { runRollback } from './commands/rollback.js';
|
|
71
85
|
import { runPull } from './commands/pull.js';
|
|
@@ -74,20 +88,66 @@ import { runAuditCommand } from './commands/audit.js';
|
|
|
74
88
|
import { runHistory } from './commands/history.js';
|
|
75
89
|
import { runContextDiff } from './commands/context-diff.js';
|
|
76
90
|
import { runCapability } from './commands/capability.js';
|
|
91
|
+
import { runLink } from './commands/link.js';
|
|
77
92
|
import { runTool } from './commands/tool.js';
|
|
78
93
|
import { runExplore } from './commands/explore.js';
|
|
79
94
|
import { getInstalledBrainclawVersion } from './core/brainclaw-version.js';
|
|
80
|
-
import { cleanOrphanFiles, memoryDir } from './core/io.js';
|
|
95
|
+
import { cleanOrphanFiles, memoryDir, memoryExists } from './core/io.js';
|
|
81
96
|
import { initLogLevel, logger } from './core/logger.js';
|
|
82
97
|
import { resolveEffectiveCwd } from './core/store-resolution.js';
|
|
98
|
+
import { resolveProjectCwd } from './core/cross-project.js';
|
|
83
99
|
import { runSwitch } from './commands/switch.js';
|
|
100
|
+
import { runWorktreeCreate, runWorktreeList, runWorktreeRemove, runWorktreePrune, runWorktreeClean, runWorktreeMerge } from './commands/worktree.js';
|
|
84
101
|
import { runCheckEvents } from './commands/check-events.js';
|
|
85
102
|
import { runDiscover } from './commands/discover.js';
|
|
86
103
|
import { runMigrate } from './commands/migrate.js';
|
|
104
|
+
import { runRunProfile } from './commands/run-profile.js';
|
|
105
|
+
import { runCompact } from './commands/compact.js';
|
|
106
|
+
import { runHarvestCandidates } from './commands/harvest.js';
|
|
107
|
+
import { requireRegisteredAgentIdentity } from './core/agent-registry.js';
|
|
87
108
|
const program = new Command();
|
|
88
109
|
function collect(value, previous) {
|
|
89
110
|
return [...previous, value];
|
|
90
111
|
}
|
|
112
|
+
function parseLeadingGlobalOptions(argv) {
|
|
113
|
+
const result = {};
|
|
114
|
+
for (let i = 0; i < argv.length; i++) {
|
|
115
|
+
const token = argv[i];
|
|
116
|
+
if (!token.startsWith('-')) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
if (token === '--verbose') {
|
|
120
|
+
result.verbose = true;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (token === '--debug') {
|
|
124
|
+
result.debug = true;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (token === '--cwd') {
|
|
128
|
+
result.cwd = argv[i + 1];
|
|
129
|
+
i++;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (token.startsWith('--cwd=')) {
|
|
133
|
+
result.cwd = token.slice('--cwd='.length);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (token === '--project') {
|
|
137
|
+
result.project = argv[i + 1];
|
|
138
|
+
i++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (token.startsWith('--project=')) {
|
|
142
|
+
result.project = token.slice('--project='.length);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
function isCodevEnabled() {
|
|
149
|
+
return process.env.BRAINCLAW_ENABLE_CODEV === '1';
|
|
150
|
+
}
|
|
91
151
|
program
|
|
92
152
|
.name('brainclaw')
|
|
93
153
|
.description('Shared project memory for humans and coding agents.')
|
|
@@ -95,15 +155,33 @@ program
|
|
|
95
155
|
.option('--verbose', 'Show info-level log messages on stderr')
|
|
96
156
|
.option('--debug', 'Show debug-level log messages on stderr')
|
|
97
157
|
.option('--cwd <path>', 'Override working directory for this invocation')
|
|
158
|
+
.option('--project <name>', 'Run the command against a linked project (cross_project_links or workspace store-chain child). Resolves via resolveProjectCwd; mutually exclusive with --cwd.')
|
|
98
159
|
.hook('preAction', (_thisCommand, actionCommand) => {
|
|
99
|
-
const root =
|
|
160
|
+
const root = parseLeadingGlobalOptions(process.argv.slice(2));
|
|
100
161
|
initLogLevel({ verbose: root.verbose, debug: root.debug });
|
|
101
162
|
// Skip effective cwd resolution for commands that create the store
|
|
102
163
|
const cmdName = actionCommand.name();
|
|
103
164
|
const skipResolution = cmdName === 'init' || cmdName === 'setup';
|
|
165
|
+
// pln#359 phase 1c — `--project <name>` resolves a linked project to an
|
|
166
|
+
// absolute path via resolveProjectCwd, then feeds the same chdir flow
|
|
167
|
+
// as --cwd. Mutually exclusive with --cwd to avoid ambiguity.
|
|
168
|
+
let explicitCwd = root.cwd;
|
|
169
|
+
if (root.project) {
|
|
170
|
+
if (root.cwd) {
|
|
171
|
+
console.error('Error: --project and --cwd are mutually exclusive. Use one.');
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
explicitCwd = resolveProjectCwd(root.project, process.cwd());
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
console.error(`Error: ${err.message}`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
104
182
|
if (!skipResolution) {
|
|
105
|
-
// Resolve effective cwd (
|
|
106
|
-
const effectiveCwd = resolveEffectiveCwd({ explicitCwd
|
|
183
|
+
// Resolve effective cwd (explicit > BRAINCLAW_PROJECT > active-project > process.cwd)
|
|
184
|
+
const effectiveCwd = resolveEffectiveCwd({ explicitCwd });
|
|
107
185
|
if (effectiveCwd !== process.cwd()) {
|
|
108
186
|
// Change process.cwd() so all commands resolve the correct store
|
|
109
187
|
// without needing individual --cwd plumbing
|
|
@@ -115,9 +193,9 @@ program
|
|
|
115
193
|
logger.info(`Cleaned ${removed} orphan lock/tmp file(s) in ${memoryDir()}`);
|
|
116
194
|
}
|
|
117
195
|
}
|
|
118
|
-
else if (
|
|
119
|
-
// For init/setup, still respect explicit --cwd but nothing else
|
|
120
|
-
process.chdir(path.resolve(
|
|
196
|
+
else if (explicitCwd) {
|
|
197
|
+
// For init/setup, still respect explicit --cwd / --project but nothing else
|
|
198
|
+
process.chdir(path.resolve(explicitCwd));
|
|
121
199
|
}
|
|
122
200
|
});
|
|
123
201
|
// --- init ---
|
|
@@ -131,6 +209,7 @@ program
|
|
|
131
209
|
.option('--project-mode <mode>', 'Project mode: single-project, multi-project, auto')
|
|
132
210
|
.option('--project-strategy <strategy>', 'Project strategy for multi-project mode: manual, folder')
|
|
133
211
|
.option('--no-analyze-repo', 'Skip repository analysis when suggesting a project mode')
|
|
212
|
+
.option('--no-ai-scan', 'Skip AI surface scan during init')
|
|
134
213
|
.option('--scan', 'Scan subdirectories for service boundaries and suggest init targets')
|
|
135
214
|
.action(async (options) => {
|
|
136
215
|
await runInit(options);
|
|
@@ -165,15 +244,34 @@ program
|
|
|
165
244
|
// --- memory-rollback ---
|
|
166
245
|
program
|
|
167
246
|
.command('memory-rollback <ref>')
|
|
168
|
-
.description('
|
|
169
|
-
.
|
|
247
|
+
.description('Restore live project memory from a previous git snapshot without deleting audit or archive artifacts')
|
|
248
|
+
.option('--actor <name>', 'Registered human identity required to authorize the rollback')
|
|
249
|
+
.action((ref, options) => {
|
|
250
|
+
const cwd = process.cwd();
|
|
170
251
|
if (!hasMemoryRepo()) {
|
|
171
252
|
console.error('Error: no memory git repo. Run `brainclaw init --force` to enable.');
|
|
172
253
|
process.exit(1);
|
|
173
254
|
}
|
|
174
|
-
|
|
255
|
+
let actor;
|
|
256
|
+
try {
|
|
257
|
+
actor = requireRegisteredAgentIdentity({
|
|
258
|
+
agentName: options.actor,
|
|
259
|
+
allowCurrent: true,
|
|
260
|
+
allowEnv: true,
|
|
261
|
+
cwd,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
if (actor.kind !== 'human') {
|
|
269
|
+
console.error(`Error: memory-rollback is reserved to registered human identities. Resolved actor '${actor.agent_name}' is kind='${actor.kind}'.`);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
}
|
|
272
|
+
const success = rollbackMemory(ref, cwd);
|
|
175
273
|
if (success) {
|
|
176
|
-
console.log(`✔
|
|
274
|
+
console.log(`✔ Live project memory restored to ${ref} (audit, archives, backups preserved)`);
|
|
177
275
|
}
|
|
178
276
|
else {
|
|
179
277
|
console.error(`Error: failed to rollback to '${ref}'. Check memory-log for valid refs.`);
|
|
@@ -186,12 +284,45 @@ program
|
|
|
186
284
|
.description('Upgrade project memory structure and refresh managed workspace agent files without losing data')
|
|
187
285
|
.option('--json', 'Output as JSON')
|
|
188
286
|
.option('--dry-run', 'Show what would be done without making changes')
|
|
287
|
+
.option('--self-update', 'Check for a newer brainclaw package version and install it before upgrading memory')
|
|
288
|
+
.option('--to <version>', 'One-shot target schema version (e.g. --to=1.0). Real runs require a backup.')
|
|
289
|
+
.option('--backup', 'Create a timestamped backup of .brainclaw/ before any write (always on for --to runs)')
|
|
290
|
+
.option('--no-backup', 'Disable the automatic backup for housekeeping-only upgrade runs')
|
|
291
|
+
.option('--rollback', 'Restore the most recent backup, park the current live store, exit')
|
|
292
|
+
.option('--yes', 'Skip interactive confirmations (reserved for later prompt additions)')
|
|
189
293
|
.action((options) => {
|
|
190
294
|
runUpgrade({
|
|
191
295
|
json: options.json,
|
|
192
296
|
dryRun: options.dryRun,
|
|
297
|
+
selfUpdate: options.selfUpdate,
|
|
298
|
+
to: options.to,
|
|
299
|
+
backup: options.backup,
|
|
300
|
+
rollback: options.rollback,
|
|
301
|
+
yes: options.yes,
|
|
193
302
|
});
|
|
194
303
|
});
|
|
304
|
+
// --- patch-configs ---
|
|
305
|
+
program
|
|
306
|
+
.command('patch-configs')
|
|
307
|
+
.description('Patch all MCP config files to use the current brainclaw binary path')
|
|
308
|
+
.option('--json', 'Output as JSON')
|
|
309
|
+
.action((options) => {
|
|
310
|
+
const cwd = process.env.BRAINCLAW_CWD ?? process.cwd();
|
|
311
|
+
const results = patchAllMcpConfigs(cwd);
|
|
312
|
+
if (options.json) {
|
|
313
|
+
console.log(JSON.stringify(results, null, 2));
|
|
314
|
+
}
|
|
315
|
+
else if (results.length === 0) {
|
|
316
|
+
console.log('✔ All MCP configs are already up to date.');
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
for (const r of results) {
|
|
320
|
+
const tag = r.created ? 'created' : 'updated';
|
|
321
|
+
console.log(`✔ ${r.filePath} (${tag}) — ${r.label}`);
|
|
322
|
+
}
|
|
323
|
+
console.log(`\n${results.length} MCP config(s) patched.`);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
195
326
|
// --- machine-profile ---
|
|
196
327
|
program
|
|
197
328
|
.command('machine-profile')
|
|
@@ -346,6 +477,11 @@ program
|
|
|
346
477
|
.option('--plan <id>', 'Optional linked plan item ID')
|
|
347
478
|
.option('--author <author>', 'Author name')
|
|
348
479
|
.option('--capture-diff', 'Capture current git diff into the handoff snapshot')
|
|
480
|
+
.option('--files <files...>', 'Files touched in this handoff')
|
|
481
|
+
.option('--pre-condition <conditions...>', 'Pre-conditions for the receiving agent')
|
|
482
|
+
.option('--post-condition <conditions...>', 'Post-conditions the receiving agent must satisfy')
|
|
483
|
+
.option('--test <tests...>', 'Tests the receiving agent should verify')
|
|
484
|
+
.option('--linked-plan <plans...>', 'Linked plan IDs')
|
|
349
485
|
.action((text, options) => {
|
|
350
486
|
runHandoff(text, options);
|
|
351
487
|
});
|
|
@@ -376,8 +512,10 @@ program
|
|
|
376
512
|
.option('--estimate <minutes>', 'Estimated effort in minutes (positive integer, e.g. --estimate 30)')
|
|
377
513
|
.option('--actual-effort <effort>', 'Actual effort spent (e.g. "20min", "1h30m")')
|
|
378
514
|
.option('--store <target>', 'Target store level: local (default), repo, workspace, user')
|
|
515
|
+
.option('--recursive', 'Include plans from descendant brainclaw projects (for list)')
|
|
516
|
+
.option('--local-only', 'Read from local store only for list (skip parent stores in chain)')
|
|
379
517
|
.action((subcommand, args, options) => {
|
|
380
|
-
runPlanResource(subcommand, args, { ...options, actualEffort: options.actualEffort });
|
|
518
|
+
runPlanResource(subcommand, args, { ...options, actualEffort: options.actualEffort, localOnly: options.localOnly });
|
|
381
519
|
});
|
|
382
520
|
// --- list-plans ---
|
|
383
521
|
program
|
|
@@ -389,8 +527,24 @@ program
|
|
|
389
527
|
.option('--assignee <assignee>', 'Filter by assignee')
|
|
390
528
|
.option('--project <project>', 'Filter by project namespace')
|
|
391
529
|
.option('--all', 'Include done and dropped plan items')
|
|
530
|
+
.option('--recursive', 'Include plans from descendant brainclaw projects')
|
|
531
|
+
.option('--local-only', 'Read from local store only (skip parent stores in chain)')
|
|
392
532
|
.action((options) => {
|
|
393
|
-
runListPlans(options);
|
|
533
|
+
runListPlans({ ...options, localOnly: options.localOnly });
|
|
534
|
+
});
|
|
535
|
+
program
|
|
536
|
+
.command('sequence <subcommand> [args...]')
|
|
537
|
+
.description('Manage coordination sequences (create, list, show, update)')
|
|
538
|
+
.option('--json', 'Output as JSON')
|
|
539
|
+
.option('--description <text>', 'Optional sequence description')
|
|
540
|
+
.option('--status <status>', 'Sequence status: draft, active, archived')
|
|
541
|
+
.option('--owner <owner>', 'Optional sequence owner')
|
|
542
|
+
.option('--items <json>', 'Sequence items JSON array')
|
|
543
|
+
.option('--name <name>', 'Optional sequence name for update')
|
|
544
|
+
.option('--tag <tags...>', 'Tags for this sequence')
|
|
545
|
+
.option('--author <author>', 'Author name')
|
|
546
|
+
.action((subcommand, args, options) => {
|
|
547
|
+
runSequenceResource(subcommand, args, options);
|
|
394
548
|
});
|
|
395
549
|
// --- add-step ---
|
|
396
550
|
program
|
|
@@ -407,6 +561,23 @@ program
|
|
|
407
561
|
.action((planId, stepId) => {
|
|
408
562
|
runCompleteStep(planId, stepId);
|
|
409
563
|
});
|
|
564
|
+
// --- update-step ---
|
|
565
|
+
program
|
|
566
|
+
.command('update-step <planId> <stepId>')
|
|
567
|
+
.description('Update a plan step (status, text, assignee)')
|
|
568
|
+
.option('--status <status>', 'New status: todo, in_progress, testing, done, blocked')
|
|
569
|
+
.option('--text <text>', 'Replace step description')
|
|
570
|
+
.option('--assign <assignee>', 'Assign the step (empty string to unassign)')
|
|
571
|
+
.action((planId, stepId, options) => {
|
|
572
|
+
runUpdateStep(planId, stepId, options);
|
|
573
|
+
});
|
|
574
|
+
// --- delete-step ---
|
|
575
|
+
program
|
|
576
|
+
.command('delete-step <planId> <stepId>')
|
|
577
|
+
.description('Remove a step from a plan')
|
|
578
|
+
.action((planId, stepId) => {
|
|
579
|
+
runDeleteStep(planId, stepId);
|
|
580
|
+
});
|
|
410
581
|
// --- estimation-report ---
|
|
411
582
|
program
|
|
412
583
|
.command('estimation-report')
|
|
@@ -460,11 +631,25 @@ program
|
|
|
460
631
|
// --- update-handoff ---
|
|
461
632
|
program
|
|
462
633
|
.command('update-handoff <id>')
|
|
463
|
-
.description('Update the status of a handoff')
|
|
634
|
+
.description('Update the status, recipient, or review state of a handoff')
|
|
464
635
|
.option('--status <status>', 'Status: open, accepted, closed')
|
|
465
636
|
.option('--to <agent>', 'Change the receiving agent')
|
|
637
|
+
.option('--narrative <text>', 'Update the narrative attached to the handoff')
|
|
638
|
+
.option('--reviewer <agent>', 'Set or override the assigned reviewer')
|
|
639
|
+
.option('--review-verdict <verdict>', 'Set review verdict: approve or request_changes')
|
|
640
|
+
.option('--reviewed-by <agent>', 'Set the reviewer identity that produced the verdict')
|
|
641
|
+
.option('--review-summary <text>', 'Attach a short review summary')
|
|
642
|
+
.option('--blocking-issue <text>', 'Add a blocking review issue (repeatable)', collect, [])
|
|
643
|
+
.option('--suggestion <text>', 'Add a non-blocking review suggestion (repeatable)', collect, [])
|
|
466
644
|
.action((id, options) => {
|
|
467
|
-
runUpdateHandoff(id,
|
|
645
|
+
runUpdateHandoff(id, {
|
|
646
|
+
...options,
|
|
647
|
+
review_verdict: options.reviewVerdict,
|
|
648
|
+
reviewed_by: options.reviewedBy,
|
|
649
|
+
review_summary: options.reviewSummary,
|
|
650
|
+
blocking_issues: options.blockingIssue,
|
|
651
|
+
suggestions: options.suggestion,
|
|
652
|
+
});
|
|
468
653
|
});
|
|
469
654
|
// --- doctor ---
|
|
470
655
|
program
|
|
@@ -473,8 +658,34 @@ program
|
|
|
473
658
|
.option('--json', 'Output as JSON dashboard')
|
|
474
659
|
.option('--migration-check', 'Report versioned documents that need schema migration')
|
|
475
660
|
.option('--fix-agent-ignore', 'Add missing .gitignore entries for generated local Brainclaw agent files')
|
|
661
|
+
.option('--fix', 'Fix auto-resolvable issues (e.g. drifting MCP configs)')
|
|
662
|
+
.option('--repair', 'Rebuild dist/ when the MCP runtime is missing or stale')
|
|
663
|
+
.option('--after-migration', 'Run the v1.0 post-migration health check only (exits non-zero on any failure)')
|
|
664
|
+
.option('--dispatch', 'Run dispatch-health diagnostic only: reconcile open agent_runs and report stuck/unverified/silent failures (pln#496 step stp_8c072d75)')
|
|
476
665
|
.action((options) => {
|
|
477
|
-
runDoctor(options);
|
|
666
|
+
runDoctor({ ...options, afterMigration: options.afterMigration, dispatch: options.dispatch });
|
|
667
|
+
});
|
|
668
|
+
// --- repair (Phase 4 Sprint 2 Lane C / pln#397) ---
|
|
669
|
+
program
|
|
670
|
+
.command('repair')
|
|
671
|
+
.description('Apply safe, non-destructive fixes for the repair candidates surfaced by doctor')
|
|
672
|
+
.option('--dry-run', 'Print the plan without executing anything')
|
|
673
|
+
.option('--include-unsafe', 'Also apply candidates flagged unsafe (preserves data but requires confirmation)')
|
|
674
|
+
.option('--json', 'Output as JSON')
|
|
675
|
+
.action((options) => {
|
|
676
|
+
runRepair({
|
|
677
|
+
dryRun: options.dryRun,
|
|
678
|
+
includeUnsafe: options.includeUnsafe,
|
|
679
|
+
json: options.json,
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
// --- stale (Phase 4 Sprint 1 Lane A / pln#390) ---
|
|
683
|
+
program
|
|
684
|
+
.command('stale [subcommand] [id]')
|
|
685
|
+
.description('List or resolve stale memory items (plans, traps, handoffs, candidates, runtime notes). Subcommands: list (default), resolve <id>.')
|
|
686
|
+
.option('--json', 'Output as JSON')
|
|
687
|
+
.action((subcommand, id, options) => {
|
|
688
|
+
runStale(subcommand, id, { json: options.json });
|
|
478
689
|
});
|
|
479
690
|
// --- version ---
|
|
480
691
|
program
|
|
@@ -482,11 +693,23 @@ program
|
|
|
482
693
|
.description('Show the installed brainclaw version and the project version policy')
|
|
483
694
|
.option('--check', 'Check the configured installable update source')
|
|
484
695
|
.option('--publish-local', 'Create/update the local installable .releases channel via npm pack')
|
|
485
|
-
.option('--release-notes <text>', 'Attach release notes to the generated local-pack manifest')
|
|
696
|
+
.option('--release-notes <text>', 'Attach plain-text release notes to the generated local-pack manifest')
|
|
697
|
+
.option('--agent-release-notes <json>', 'Attach structured agent-first release notes (JSON) to the generated local-pack manifest')
|
|
698
|
+
.option('--auto-release-notes', 'Auto-generate agent-first release notes from git log (use with --publish-local)')
|
|
486
699
|
.option('--json', 'Output as JSON')
|
|
487
700
|
.action((options) => {
|
|
488
701
|
runVersion(options);
|
|
489
702
|
});
|
|
703
|
+
// --- release-notes ---
|
|
704
|
+
program
|
|
705
|
+
.command('release-notes')
|
|
706
|
+
.description('Show or generate agent-first release notes')
|
|
707
|
+
.option('--generate', 'Generate release notes from git log instead of showing configured ones')
|
|
708
|
+
.option('--since <ref>', 'Git ref to generate from (default: last version tag)')
|
|
709
|
+
.option('--json', 'Output as JSON')
|
|
710
|
+
.action((options) => {
|
|
711
|
+
runReleaseNotes(options);
|
|
712
|
+
});
|
|
490
713
|
// --- uninstall ---
|
|
491
714
|
import { runUninstall } from './commands/uninstall.js';
|
|
492
715
|
program
|
|
@@ -662,6 +885,7 @@ program
|
|
|
662
885
|
.command('enable-agent <name>')
|
|
663
886
|
.description('Activate a supported coding agent on an already initialized project')
|
|
664
887
|
.option('--kind <kind>', 'Identity kind: agent, human, unknown', 'agent')
|
|
888
|
+
.option('--context-profile <profile>', 'Default context profile: dev, dense, compact, copilot, quick, openclaw, ops, research')
|
|
665
889
|
.option('--capability <value>', 'Declare a capability on the agent profile (repeatable)', collect, [])
|
|
666
890
|
.option('--replace-capabilities', 'Replace existing capabilities instead of merging')
|
|
667
891
|
.option('--generate-fingerprint', 'Generate or rotate a local public identity fingerprint for this agent')
|
|
@@ -749,6 +973,17 @@ program
|
|
|
749
973
|
.action((id, options) => {
|
|
750
974
|
runReject(id, options.reason, options.by);
|
|
751
975
|
});
|
|
976
|
+
// --- harvest-candidates ---
|
|
977
|
+
program
|
|
978
|
+
.command('harvest-candidates')
|
|
979
|
+
.description('Harvest candidates from worktree inboxes into the main project store (codex sandbox bridge)')
|
|
980
|
+
.option('--dry-run', 'Preview what would be imported without writing anything')
|
|
981
|
+
.option('--worktree <path>', 'Explicit worktree path to scan (repeatable)', collect, [])
|
|
982
|
+
.option('--json', 'Output as JSON')
|
|
983
|
+
.action((options) => {
|
|
984
|
+
const globalOpts = program.opts();
|
|
985
|
+
runHarvestCandidates({ ...options, cwd: globalOpts.cwd });
|
|
986
|
+
});
|
|
752
987
|
// --- prune-candidates ---
|
|
753
988
|
program
|
|
754
989
|
.command('prune-candidates')
|
|
@@ -758,6 +993,35 @@ program
|
|
|
758
993
|
.action((options) => {
|
|
759
994
|
runPruneCandidates(options);
|
|
760
995
|
});
|
|
996
|
+
// --- cleanup-candidates ---
|
|
997
|
+
program
|
|
998
|
+
.command('cleanup-candidates')
|
|
999
|
+
.description('Remove stale auto-generated pending candidates')
|
|
1000
|
+
.option('--max-age <days>', 'Max age in days before cleanup', parseInt)
|
|
1001
|
+
.option('--dry-run', 'Preview without deleting')
|
|
1002
|
+
.action((options) => {
|
|
1003
|
+
if (!memoryExists()) {
|
|
1004
|
+
console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
|
|
1005
|
+
process.exit(1);
|
|
1006
|
+
}
|
|
1007
|
+
const maxAgeDays = options.maxAge ?? 30;
|
|
1008
|
+
const result = cleanupStaleCandidates({
|
|
1009
|
+
maxAgeDays,
|
|
1010
|
+
dryRun: options.dryRun,
|
|
1011
|
+
});
|
|
1012
|
+
if (result.matched === 0) {
|
|
1013
|
+
console.log(`No stale auto-generated candidates older than ${maxAgeDays} days found.`);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
if (options.dryRun) {
|
|
1017
|
+
console.log(`Would remove ${result.matched} stale auto-generated candidate(s):`);
|
|
1018
|
+
for (const candidate of result.candidates) {
|
|
1019
|
+
console.log(` [${candidate.id}] ${candidate.text}`);
|
|
1020
|
+
}
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
console.log(`✔ Removed ${result.deleted} stale auto-generated candidate(s) older than ${maxAgeDays} days.`);
|
|
1024
|
+
});
|
|
761
1025
|
// --- claim ---
|
|
762
1026
|
program
|
|
763
1027
|
.command('claim <subcommand> [args...]')
|
|
@@ -771,8 +1035,9 @@ program
|
|
|
771
1035
|
.option('--json', 'Output as JSON for list')
|
|
772
1036
|
.option('--plan-status <status>', 'Optional linked plan status when releasing: todo, in_progress, blocked, done, dropped')
|
|
773
1037
|
.option('--store <target>', 'Target store level: local (default), repo, workspace')
|
|
1038
|
+
.option('--local-only', 'Read from local store only for list (skip parent stores in chain)')
|
|
774
1039
|
.action((subcommand, args, options) => {
|
|
775
|
-
runClaimResource(subcommand, args, { ...options, planStatus: options.planStatus });
|
|
1040
|
+
runClaimResource(subcommand, args, { ...options, planStatus: options.planStatus, localOnly: options.localOnly });
|
|
776
1041
|
});
|
|
777
1042
|
// --- list-claims ---
|
|
778
1043
|
program
|
|
@@ -783,8 +1048,9 @@ program
|
|
|
783
1048
|
.option('--project <project>', 'Filter by project namespace')
|
|
784
1049
|
.option('--plan <id>', 'Filter by linked plan item')
|
|
785
1050
|
.option('--agent <agent>', 'Filter by agent name')
|
|
1051
|
+
.option('--local-only', 'Read from local store only (skip parent stores in chain)')
|
|
786
1052
|
.action((options) => {
|
|
787
|
-
runListClaims(options);
|
|
1053
|
+
runListClaims({ ...options, localOnly: options.localOnly });
|
|
788
1054
|
});
|
|
789
1055
|
// --- release-claim ---
|
|
790
1056
|
program
|
|
@@ -818,6 +1084,7 @@ program
|
|
|
818
1084
|
.option('--capabilities', 'List all registered agents with their declared capabilities')
|
|
819
1085
|
.option('--suggest <query>', 'Suggest agents whose capabilities match a query string')
|
|
820
1086
|
.option('--include-session-meta', 'Include session_start/session_end runtime notes (hidden by default)')
|
|
1087
|
+
.option('--all-agents', 'Show unfiltered board (supervisor mode — all claims, all agents)')
|
|
821
1088
|
.action((options) => {
|
|
822
1089
|
runAgentBoard(options);
|
|
823
1090
|
});
|
|
@@ -836,6 +1103,24 @@ program
|
|
|
836
1103
|
.action((text, options) => {
|
|
837
1104
|
runRuntimeNote(text, { ...options, autoReflect: options.autoReflect });
|
|
838
1105
|
});
|
|
1106
|
+
// --- note create ---
|
|
1107
|
+
const noteCommand = program
|
|
1108
|
+
.command('note')
|
|
1109
|
+
.description('Manage runtime notes');
|
|
1110
|
+
noteCommand
|
|
1111
|
+
.command('create <text>')
|
|
1112
|
+
.description('Alias for runtime-note')
|
|
1113
|
+
.option('--agent <agent>', 'Agent name; defaults to the configured current agent')
|
|
1114
|
+
.option('--project <project>', 'Optional project namespace')
|
|
1115
|
+
.option('--plan <id>', 'Optional linked plan item ID')
|
|
1116
|
+
.option('--visibility <visibility>', 'Visibility: shared, machine, private', 'shared')
|
|
1117
|
+
.option('--host <host>', 'Optional host identifier override for machine/private runtime notes')
|
|
1118
|
+
.option('--tag <tags...>', 'Tags')
|
|
1119
|
+
.option('--ttl <duration>', 'Time-to-live: 30m, 2h, 7d (note auto-expires after this duration)')
|
|
1120
|
+
.option('--auto-reflect', 'Attempt to turn this runtime note into durable memory immediately')
|
|
1121
|
+
.action((text, options) => {
|
|
1122
|
+
runRuntimeNote(text, { ...options, autoReflect: options.autoReflect });
|
|
1123
|
+
});
|
|
839
1124
|
// --- runtime-status ---
|
|
840
1125
|
program
|
|
841
1126
|
.command('runtime-status')
|
|
@@ -872,6 +1157,46 @@ program
|
|
|
872
1157
|
.action((options) => {
|
|
873
1158
|
runCheckConstraints({ staged: options.staged, files: options.files, json: options.json });
|
|
874
1159
|
});
|
|
1160
|
+
// --- check-policy ---
|
|
1161
|
+
program
|
|
1162
|
+
.command('check-policy')
|
|
1163
|
+
.description('Pre-execution policy check: verify claims, constraints, traps and instructions for a scope')
|
|
1164
|
+
.requiredOption('--scope <path>', 'File or directory scope to check')
|
|
1165
|
+
.option('--agent <name>', 'Agent name to check claims for')
|
|
1166
|
+
.option('--agent-id <id>', 'Agent id to check claims for')
|
|
1167
|
+
.option('--action <action>', 'Intended action: edit, create, delete')
|
|
1168
|
+
.option('--json', 'Output as JSON')
|
|
1169
|
+
.action((options) => {
|
|
1170
|
+
runCheckPolicy({
|
|
1171
|
+
scope: options.scope,
|
|
1172
|
+
agent: options.agent,
|
|
1173
|
+
agentId: options.agentId,
|
|
1174
|
+
action: options.action,
|
|
1175
|
+
json: options.json,
|
|
1176
|
+
});
|
|
1177
|
+
});
|
|
1178
|
+
// --- check-security ---
|
|
1179
|
+
program
|
|
1180
|
+
.command('check-security')
|
|
1181
|
+
.description('Check supply chain security scores for packages via Socket.dev')
|
|
1182
|
+
.requiredOption('--packages <names>', 'Comma-separated package names (e.g. "axios,express" or "axios@1.14.1")')
|
|
1183
|
+
.option('--ecosystem <type>', 'Package ecosystem: npm or pypi', 'npm')
|
|
1184
|
+
.option('--json', 'Output as JSON')
|
|
1185
|
+
.action(async (options) => {
|
|
1186
|
+
await runCheckSecurity({
|
|
1187
|
+
packages: options.packages,
|
|
1188
|
+
ecosystem: options.ecosystem,
|
|
1189
|
+
json: options.json,
|
|
1190
|
+
});
|
|
1191
|
+
});
|
|
1192
|
+
// --- setup-security ---
|
|
1193
|
+
program
|
|
1194
|
+
.command('setup-security')
|
|
1195
|
+
.description('Enable supply chain security gate: generate wrapper scripts and configure preinstall checks')
|
|
1196
|
+
.option('--mode <mode>', 'Security mode: advisory (default) or enforced', 'advisory')
|
|
1197
|
+
.action((options) => {
|
|
1198
|
+
runSetupSecurity({ mode: options.mode });
|
|
1199
|
+
});
|
|
875
1200
|
// --- install-hooks ---
|
|
876
1201
|
program
|
|
877
1202
|
.command('install-hooks')
|
|
@@ -894,9 +1219,26 @@ program
|
|
|
894
1219
|
.command('prune')
|
|
895
1220
|
.description('Prune expired constraints and stale memory')
|
|
896
1221
|
.option('--expired', 'Also prune expired runtime notes and traps')
|
|
1222
|
+
.option('--archive', 'Archive done plans and closed handoffs (>30 days) to cold storage JSONL')
|
|
1223
|
+
.option('--semantic', 'Detect near-duplicate clusters and stale items via semantic analysis')
|
|
1224
|
+
.option('--dry-run', 'Preview compaction without applying (use with --semantic)')
|
|
897
1225
|
.action((options) => {
|
|
898
1226
|
runPrune(options);
|
|
899
1227
|
});
|
|
1228
|
+
// --- compact ---
|
|
1229
|
+
program
|
|
1230
|
+
.command('compact')
|
|
1231
|
+
.description('LLM-driven semantic memory compaction — archive old items and get a summary template')
|
|
1232
|
+
.option('--assess', 'Show pressure assessment and compaction template without archiving')
|
|
1233
|
+
.option('--dry-run', 'Preview eligible items without archiving')
|
|
1234
|
+
.option('--max-items <n>', 'Maximum items to compact (default: 20)', parseInt)
|
|
1235
|
+
.option('--min-age <days>', 'Minimum age in days for eligibility (default: 7)', parseInt)
|
|
1236
|
+
.option('--no-dedup-handoffs', 'Skip deduplication of auto-generated session-end handoffs')
|
|
1237
|
+
.option('--no-purge-claims', 'Skip archival of released claims')
|
|
1238
|
+
.option('--no-purge-session-notes', 'Skip archival of session-lifecycle runtime_notes')
|
|
1239
|
+
.action((options) => {
|
|
1240
|
+
runCompact(options);
|
|
1241
|
+
});
|
|
900
1242
|
// --- mcp ---
|
|
901
1243
|
program
|
|
902
1244
|
.command('mcp')
|
|
@@ -921,6 +1263,8 @@ program
|
|
|
921
1263
|
.option('--agent <agent>', 'Agent name (defaults to current configured agent)')
|
|
922
1264
|
.option('--context <path>', 'Context target path for initial hash capture')
|
|
923
1265
|
.option('--model <id>', 'Model identifier (e.g. claude-sonnet-4-6)')
|
|
1266
|
+
.option('--maintenance-mode <mode>', 'Maintenance mode: full (default) or fast')
|
|
1267
|
+
.option('--include-context', 'Output full project context after starting session (replaces separate context call)')
|
|
924
1268
|
.option('--json', 'Output as JSON')
|
|
925
1269
|
.action((options) => {
|
|
926
1270
|
runSessionStart(options);
|
|
@@ -934,10 +1278,21 @@ program
|
|
|
934
1278
|
.option('--summary <text>', 'Session summary text')
|
|
935
1279
|
.option('--auto-reflect', 'Auto-reflect session notes as pending candidates')
|
|
936
1280
|
.option('--auto-release', 'Auto-release any active claims at session end')
|
|
937
|
-
.option('--reflect-handoff', '
|
|
1281
|
+
.option('--reflect-handoff', 'Materialize an open handoff from git commits since session start')
|
|
1282
|
+
.option('--dispatch-review', 'When used with --reflect-handoff, auto-dispatch a code review if the handoff is reviewable')
|
|
1283
|
+
.option('--reviewer <name>', 'Explicit reviewer to route the reflected handoff review to')
|
|
1284
|
+
.option('--reflect', 'Include structured reflection questions for the agent to answer')
|
|
938
1285
|
.option('--json', 'Output as JSON')
|
|
939
1286
|
.action((options) => {
|
|
940
|
-
runSessionEnd({
|
|
1287
|
+
runSessionEnd({
|
|
1288
|
+
...options,
|
|
1289
|
+
autoReflect: options.autoReflect,
|
|
1290
|
+
autoRelease: options.autoRelease,
|
|
1291
|
+
reflectHandoff: options.reflectHandoff,
|
|
1292
|
+
dispatchReview: options.dispatchReview,
|
|
1293
|
+
reviewer: options.reviewer,
|
|
1294
|
+
reflect: options.reflect,
|
|
1295
|
+
});
|
|
941
1296
|
});
|
|
942
1297
|
// --- whoami ---
|
|
943
1298
|
program
|
|
@@ -947,6 +1302,17 @@ program
|
|
|
947
1302
|
.action((options) => {
|
|
948
1303
|
runWhoami(options);
|
|
949
1304
|
});
|
|
1305
|
+
// --- usage ---
|
|
1306
|
+
program
|
|
1307
|
+
.command('usage')
|
|
1308
|
+
.description('Show brainclaw context volume stats (tokens injected per agent/tool)')
|
|
1309
|
+
.option('--agent <name>', 'Filter by agent name')
|
|
1310
|
+
.option('--tool <name>', 'Filter by tool name')
|
|
1311
|
+
.option('--days <n>', 'Limit to last N days', parseInt)
|
|
1312
|
+
.option('--json', 'Output as JSON')
|
|
1313
|
+
.action((options) => {
|
|
1314
|
+
runUsage(options);
|
|
1315
|
+
});
|
|
950
1316
|
// --- search ---
|
|
951
1317
|
program
|
|
952
1318
|
.command('search <query>')
|
|
@@ -968,6 +1334,7 @@ program
|
|
|
968
1334
|
.option('--detect', 'Auto-detect agent environment and write to its native file')
|
|
969
1335
|
.option('--all', 'Write all known agent instruction files at once (claude-md, agents-md, copilot-instructions, cursor-rules, etc.)')
|
|
970
1336
|
.option('--write', 'Write to canonical file path instead of stdout (when --format is given); local files are gitignored by default')
|
|
1337
|
+
.option('--include-live', 'Also write the native live companion file when the target agent supports one')
|
|
971
1338
|
.option('--shared', 'Keep the main exported instruction file versionable instead of auto-ignoring it (companions remain local)')
|
|
972
1339
|
.option('--output <file>', 'Write to a specific file path instead of stdout')
|
|
973
1340
|
.option('--project <project>', 'Project namespace filter')
|
|
@@ -975,6 +1342,12 @@ program
|
|
|
975
1342
|
.action((options) => {
|
|
976
1343
|
runExport(options);
|
|
977
1344
|
});
|
|
1345
|
+
program
|
|
1346
|
+
.command('refresh')
|
|
1347
|
+
.description('Refresh live companion files with current state (plans, claims, traps, sequences). Gitignored, safe to run frequently.')
|
|
1348
|
+
.action(() => {
|
|
1349
|
+
runRefresh();
|
|
1350
|
+
});
|
|
978
1351
|
program
|
|
979
1352
|
.command('reconcile')
|
|
980
1353
|
.description('Refresh machine and workspace bootstrap state after updates or onboarding on complex installs')
|
|
@@ -1012,6 +1385,110 @@ program
|
|
|
1012
1385
|
.action((options) => {
|
|
1013
1386
|
runWatch({ ...options, autoClaim: options.autoClaim });
|
|
1014
1387
|
});
|
|
1388
|
+
// --- dispatch ---
|
|
1389
|
+
const dispatchCmd = program
|
|
1390
|
+
.command('dispatch')
|
|
1391
|
+
.description('Local agent dispatcher — analyze lanes and assign work');
|
|
1392
|
+
dispatchCmd
|
|
1393
|
+
.command('analysis')
|
|
1394
|
+
.description('Analyze the active sequence: show ready, active, blocked, and done lanes')
|
|
1395
|
+
.option('--json', 'Output as JSON')
|
|
1396
|
+
.action((options) => {
|
|
1397
|
+
runDispatchAnalysis({ json: options.json });
|
|
1398
|
+
});
|
|
1399
|
+
dispatchCmd
|
|
1400
|
+
.command('run')
|
|
1401
|
+
.description('Run a dispatch cycle: assign ready lanes to available agents')
|
|
1402
|
+
.option('--agents <names>', 'Comma-separated list of agents to dispatch to')
|
|
1403
|
+
.option('--lanes <names>', 'Comma-separated list of lanes to dispatch')
|
|
1404
|
+
.option('--max <n>', 'Maximum assignments', parseInt)
|
|
1405
|
+
.option('--dry', 'Preview assignments without sending messages')
|
|
1406
|
+
.option('--spawn', 'Autonomously launch CLI agents with invoke templates')
|
|
1407
|
+
.option('--agent <name>', 'Dispatcher agent name')
|
|
1408
|
+
.option('--json', 'Output as JSON')
|
|
1409
|
+
.action((options) => {
|
|
1410
|
+
runDispatch({
|
|
1411
|
+
agents: options.agents,
|
|
1412
|
+
lanes: options.lanes,
|
|
1413
|
+
max: options.max,
|
|
1414
|
+
dry: options.dry,
|
|
1415
|
+
spawn: options.spawn,
|
|
1416
|
+
agent: options.agent,
|
|
1417
|
+
json: options.json,
|
|
1418
|
+
});
|
|
1419
|
+
});
|
|
1420
|
+
dispatchCmd
|
|
1421
|
+
.command('review')
|
|
1422
|
+
.description('Dispatch code reviews for completed handoffs')
|
|
1423
|
+
.option('--handoff <id>', 'Specific handoff ID to review')
|
|
1424
|
+
.option('--reviewer <name>', 'Specific reviewer agent')
|
|
1425
|
+
.option('--spawn', 'Launch the reviewer CLI agent')
|
|
1426
|
+
.option('--dry', 'Preview without sending')
|
|
1427
|
+
.option('--agent <name>', 'Dispatcher agent name')
|
|
1428
|
+
.option('--json', 'Output as JSON')
|
|
1429
|
+
.action((options) => {
|
|
1430
|
+
runDispatchReview({
|
|
1431
|
+
handoff: options.handoff,
|
|
1432
|
+
reviewer: options.reviewer,
|
|
1433
|
+
spawn: options.spawn,
|
|
1434
|
+
dry: options.dry,
|
|
1435
|
+
agent: options.agent,
|
|
1436
|
+
json: options.json,
|
|
1437
|
+
});
|
|
1438
|
+
});
|
|
1439
|
+
// --- inbox ---
|
|
1440
|
+
const inboxCmd = program
|
|
1441
|
+
.command('inbox')
|
|
1442
|
+
.description('Inter-agent messaging inbox');
|
|
1443
|
+
inboxCmd
|
|
1444
|
+
.command('list')
|
|
1445
|
+
.description('List inbox messages (default: pending only)')
|
|
1446
|
+
.option('--agent <name>', 'Agent name')
|
|
1447
|
+
.option('--status <status>', 'Filter by status: pending, read, acknowledged, archived')
|
|
1448
|
+
.option('--type <type>', 'Filter by type: assign, review, rfc, info, reply')
|
|
1449
|
+
.option('--thread <id>', 'Filter by thread ID')
|
|
1450
|
+
.option('--all', 'Show all messages, not just pending')
|
|
1451
|
+
.option('--json', 'Output as JSON')
|
|
1452
|
+
.option('--local-only', 'Read from local store only (skip parent stores in chain)')
|
|
1453
|
+
.action((options) => {
|
|
1454
|
+
runInboxList({ ...options, localOnly: options.localOnly });
|
|
1455
|
+
});
|
|
1456
|
+
inboxCmd
|
|
1457
|
+
.command('ack <id>')
|
|
1458
|
+
.description('Acknowledge a message')
|
|
1459
|
+
.option('--agent <name>', 'Agent name')
|
|
1460
|
+
.option('--json', 'Output as JSON')
|
|
1461
|
+
.action((id, options) => {
|
|
1462
|
+
runInboxAck(id, options);
|
|
1463
|
+
});
|
|
1464
|
+
inboxCmd
|
|
1465
|
+
.command('archive <id>')
|
|
1466
|
+
.description('Archive a message')
|
|
1467
|
+
.option('--agent <name>', 'Agent name')
|
|
1468
|
+
.option('--json', 'Output as JSON')
|
|
1469
|
+
.action((id, options) => {
|
|
1470
|
+
runInboxArchive(id, options);
|
|
1471
|
+
});
|
|
1472
|
+
inboxCmd
|
|
1473
|
+
.command('send <to> <text>')
|
|
1474
|
+
.description('Send a message to another agent')
|
|
1475
|
+
.option('--type <type>', 'Message type: assign, review, rfc, info, reply (default: info)')
|
|
1476
|
+
.option('--ref <id>', 'Reference to a plan, sequence, or other entity')
|
|
1477
|
+
.option('--scope <path>', 'File scope')
|
|
1478
|
+
.option('--thread <id>', 'Thread ID for conversations')
|
|
1479
|
+
.option('--ack', 'Require acknowledgment')
|
|
1480
|
+
.option('--agent <name>', 'Sender agent name')
|
|
1481
|
+
.option('--json', 'Output as JSON')
|
|
1482
|
+
.action((to, text, options) => {
|
|
1483
|
+
runInboxSend(to, text, options);
|
|
1484
|
+
});
|
|
1485
|
+
inboxCmd
|
|
1486
|
+
.command('thread <id>')
|
|
1487
|
+
.description('Show all messages in a thread')
|
|
1488
|
+
.option('--json', 'Output as JSON')
|
|
1489
|
+
.action((id, options) => {
|
|
1490
|
+
runInboxThread(id, options);
|
|
1491
|
+
});
|
|
1015
1492
|
// --- check-events ---
|
|
1016
1493
|
program
|
|
1017
1494
|
.command('check-events')
|
|
@@ -1063,14 +1540,16 @@ program
|
|
|
1063
1540
|
// --- audit ---
|
|
1064
1541
|
program
|
|
1065
1542
|
.command('audit')
|
|
1066
|
-
.description('View the append-only audit log
|
|
1543
|
+
.description('View the append-only audit log, or generate a governance posture report with --governance')
|
|
1067
1544
|
.option('--since <date>', 'Show entries since this ISO date')
|
|
1068
1545
|
.option('--actor <agent>', 'Filter by actor name or agent ID')
|
|
1069
1546
|
.option('--action <action>', 'Filter by action type (create, accept, reject, etc.)')
|
|
1070
1547
|
.option('--limit <n>', 'Show last N entries', parseInt)
|
|
1071
1548
|
.option('--json', 'Output as JSON')
|
|
1549
|
+
.option('--governance', 'Generate a governance posture report (aggregated view of claims, constraints, traps, instructions)')
|
|
1550
|
+
.option('--scope <path>', 'Filter governance report by scope (used with --governance)')
|
|
1072
1551
|
.action((options) => {
|
|
1073
|
-
runAuditCommand({ since: options.since, actor: options.actor, action: options.action, limit: options.limit, json: options.json });
|
|
1552
|
+
runAuditCommand({ since: options.since, actor: options.actor, action: options.action, limit: options.limit, json: options.json, governance: options.governance, scope: options.scope });
|
|
1074
1553
|
});
|
|
1075
1554
|
// --- history ---
|
|
1076
1555
|
program
|
|
@@ -1102,6 +1581,25 @@ program
|
|
|
1102
1581
|
store: options.store,
|
|
1103
1582
|
});
|
|
1104
1583
|
});
|
|
1584
|
+
program
|
|
1585
|
+
.command('link <subcommand> [args...]')
|
|
1586
|
+
.description('Manage cross-project federation links (add, list, remove)')
|
|
1587
|
+
.option('--name <slug>', 'Override the auto-derived link name')
|
|
1588
|
+
.option('--role <role>', 'Link role: publisher (push signals out) or subscriber (default)')
|
|
1589
|
+
.option('--channels <list>', 'Comma-separated allow-list of channels: candidate,handoff,runtime_note', (val) => val.split(',').map((s) => s.trim()).filter(Boolean))
|
|
1590
|
+
.option('--force', 'Replace an existing link of the same name/path')
|
|
1591
|
+
.option('--json', 'Output as JSON')
|
|
1592
|
+
.option('--store <target>', 'Store level: local (default), repo, workspace, user')
|
|
1593
|
+
.action((subcommand, args, options) => {
|
|
1594
|
+
runLink(subcommand, args, {
|
|
1595
|
+
name: options.name,
|
|
1596
|
+
role: options.role,
|
|
1597
|
+
channels: options.channels,
|
|
1598
|
+
force: options.force,
|
|
1599
|
+
json: options.json,
|
|
1600
|
+
store: options.store,
|
|
1601
|
+
});
|
|
1602
|
+
});
|
|
1105
1603
|
program
|
|
1106
1604
|
.command('tool <subcommand> [args...]')
|
|
1107
1605
|
.description('Manage project tools (list, add, describe, search)')
|
|
@@ -1163,10 +1661,197 @@ program
|
|
|
1163
1661
|
.option('--json', 'Output as JSON')
|
|
1164
1662
|
.option('--all', 'Include stale sessions')
|
|
1165
1663
|
.option('--gc', 'Remove stale sessions')
|
|
1664
|
+
.option('--local-only', 'Read claims from local store only (skip parent stores in chain)')
|
|
1166
1665
|
.action(async (options) => {
|
|
1167
1666
|
const globalOpts = program.opts();
|
|
1168
1667
|
const { runWho } = await import('./commands/who.js');
|
|
1169
|
-
runWho({ json: options.json, all: options.all, gc: options.gc, cwd: globalOpts.cwd });
|
|
1668
|
+
runWho({ json: options.json, all: options.all, gc: options.gc, cwd: globalOpts.cwd, localOnly: options.localOnly });
|
|
1669
|
+
});
|
|
1670
|
+
const worktreeCmd = program
|
|
1671
|
+
.command('worktree')
|
|
1672
|
+
.description('Manage git worktrees for parallel agent isolation');
|
|
1673
|
+
worktreeCmd
|
|
1674
|
+
.command('create <branch>')
|
|
1675
|
+
.description('Create a linked git worktree for a given branch')
|
|
1676
|
+
.option('--session-id <id>', 'Associate this worktree with a brainclaw session')
|
|
1677
|
+
.option('--agent <name>', 'Associate this worktree with an agent name')
|
|
1678
|
+
.action((branch, options) => {
|
|
1679
|
+
const globalOpts = program.opts();
|
|
1680
|
+
runWorktreeCreate({ branch, sessionId: options.sessionId, agent: options.agent, cwd: globalOpts.cwd });
|
|
1681
|
+
});
|
|
1682
|
+
worktreeCmd
|
|
1683
|
+
.command('list')
|
|
1684
|
+
.description('List all git worktrees for this project')
|
|
1685
|
+
.action(() => {
|
|
1686
|
+
const globalOpts = program.opts();
|
|
1687
|
+
runWorktreeList({ cwd: globalOpts.cwd });
|
|
1688
|
+
});
|
|
1689
|
+
worktreeCmd
|
|
1690
|
+
.command('remove <path>')
|
|
1691
|
+
.description('Remove a linked git worktree')
|
|
1692
|
+
.option('--force', 'Force removal even with uncommitted changes')
|
|
1693
|
+
.action((worktreePath, options) => {
|
|
1694
|
+
const globalOpts = program.opts();
|
|
1695
|
+
runWorktreeRemove({ path: worktreePath, force: options.force, cwd: globalOpts.cwd });
|
|
1696
|
+
});
|
|
1697
|
+
worktreeCmd
|
|
1698
|
+
.command('prune')
|
|
1699
|
+
.description('Prune stale worktree administrative files')
|
|
1700
|
+
.action(() => {
|
|
1701
|
+
const globalOpts = program.opts();
|
|
1702
|
+
runWorktreePrune({ cwd: globalOpts.cwd });
|
|
1703
|
+
});
|
|
1704
|
+
worktreeCmd
|
|
1705
|
+
.command('clean')
|
|
1706
|
+
.description('Remove worktrees whose branch is fully merged and orphan worktree directories')
|
|
1707
|
+
.option('--force', 'Force removal even with uncommitted changes')
|
|
1708
|
+
.option('--dry-run', 'Show what would be removed without actually removing')
|
|
1709
|
+
.action((options) => {
|
|
1710
|
+
const globalOpts = program.opts();
|
|
1711
|
+
runWorktreeClean({ force: options.force, dryRun: options.dryRun, cwd: globalOpts.cwd });
|
|
1712
|
+
});
|
|
1713
|
+
worktreeCmd
|
|
1714
|
+
.command('merge <branch>')
|
|
1715
|
+
.description('Merge a worktree branch with auto-restoration of parasitic deletions')
|
|
1716
|
+
.option('-m, --message <message>', 'Merge commit message')
|
|
1717
|
+
.option('--dry-run', 'Show what would be merged without committing')
|
|
1718
|
+
.action((branch, options) => {
|
|
1719
|
+
const globalOpts = program.opts();
|
|
1720
|
+
runWorktreeMerge({ branch, message: options.message, dryRun: options.dryRun, cwd: globalOpts.cwd });
|
|
1721
|
+
});
|
|
1722
|
+
// --- federation cloud ---
|
|
1723
|
+
const federationCmd = program
|
|
1724
|
+
.command('federation')
|
|
1725
|
+
.description('Cloud federation — sync signals with app.brainclaw.dev');
|
|
1726
|
+
federationCmd
|
|
1727
|
+
.command('push <message>')
|
|
1728
|
+
.description('Push a test signal to the cloud')
|
|
1729
|
+
.option('--type <type>', 'Signal type', 'runtime_note')
|
|
1730
|
+
.option('--to-project <project>', 'Target project name')
|
|
1731
|
+
.option('--to-agent <agent>', 'Target agent name')
|
|
1732
|
+
.action(async (message, options) => {
|
|
1733
|
+
const { pushSignalToCloud, isCloudConfigured } = await import('./core/federation-cloud.js');
|
|
1734
|
+
const { createFederationMessage } = await import('./core/federation-message.js');
|
|
1735
|
+
const { loadConfig } = await import('./core/config.js');
|
|
1736
|
+
const { resolveCurrentAgentName } = await import('./core/agent-registry.js');
|
|
1737
|
+
if (!isCloudConfigured()) {
|
|
1738
|
+
console.error('Error: cloud not configured. Set BRAINCLAW_CLOUD_API_KEY env var.');
|
|
1739
|
+
process.exit(1);
|
|
1740
|
+
}
|
|
1741
|
+
const config = loadConfig();
|
|
1742
|
+
const agent = resolveCurrentAgentName() ?? 'unknown';
|
|
1743
|
+
const msg = createFederationMessage({
|
|
1744
|
+
version: 1,
|
|
1745
|
+
from: { project_name: config.project_name, project_path: process.cwd(), agent_name: agent },
|
|
1746
|
+
to: { project_name: options.toProject ?? 'broadcast', project_path: '' },
|
|
1747
|
+
type: options.type,
|
|
1748
|
+
payload: { text: message },
|
|
1749
|
+
});
|
|
1750
|
+
const ok = await pushSignalToCloud(msg);
|
|
1751
|
+
if (ok) {
|
|
1752
|
+
console.log(`✔ Signal pushed to cloud: [${msg.id}] ${message}`);
|
|
1753
|
+
}
|
|
1754
|
+
else {
|
|
1755
|
+
console.error('Error: failed to push signal to cloud.');
|
|
1756
|
+
process.exit(1);
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
federationCmd
|
|
1760
|
+
.command('pull')
|
|
1761
|
+
.description('Pull signals from the cloud inbox')
|
|
1762
|
+
.option('--agent <name>', 'Agent name to pull for')
|
|
1763
|
+
.option('--since <date>', 'Only pull signals after this ISO date')
|
|
1764
|
+
.option('--limit <n>', 'Max signals to pull', '20')
|
|
1765
|
+
.action(async (options) => {
|
|
1766
|
+
const { pullSignalsFromCloud, isCloudConfigured } = await import('./core/federation-cloud.js');
|
|
1767
|
+
const { resolveCurrentAgentName } = await import('./core/agent-registry.js');
|
|
1768
|
+
if (!isCloudConfigured()) {
|
|
1769
|
+
console.error('Error: cloud not configured. Set BRAINCLAW_CLOUD_API_KEY env var.');
|
|
1770
|
+
process.exit(1);
|
|
1771
|
+
}
|
|
1772
|
+
const agent = options.agent ?? resolveCurrentAgentName() ?? 'unknown';
|
|
1773
|
+
const signals = await pullSignalsFromCloud(agent, {
|
|
1774
|
+
since: options.since,
|
|
1775
|
+
limit: parseInt(options.limit, 10),
|
|
1776
|
+
});
|
|
1777
|
+
if (signals.length === 0) {
|
|
1778
|
+
console.log('No signals in cloud inbox.');
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
console.log(`${signals.length} signal(s) from cloud:\n`);
|
|
1782
|
+
for (const s of signals) {
|
|
1783
|
+
const payload = typeof s.payload === 'object' && s.payload !== null ? s.payload.text ?? JSON.stringify(s.payload) : String(s.payload);
|
|
1784
|
+
console.log(` [${s.id}] ${s.type} from ${s.from.project_name}/${s.from.agent_name}`);
|
|
1785
|
+
console.log(` ${String(payload).slice(0, 120)}`);
|
|
1786
|
+
console.log(` ${s.created_at}\n`);
|
|
1787
|
+
}
|
|
1788
|
+
});
|
|
1789
|
+
federationCmd
|
|
1790
|
+
.command('status')
|
|
1791
|
+
.description('Check cloud federation configuration')
|
|
1792
|
+
.action(async () => {
|
|
1793
|
+
const { isCloudConfigured } = await import('./core/federation-cloud.js');
|
|
1794
|
+
const url = process.env.BRAINCLAW_CLOUD_URL ?? 'https://app.brainclaw.dev';
|
|
1795
|
+
console.log(`Cloud URL: ${url}`);
|
|
1796
|
+
console.log(`API Key: ${process.env.BRAINCLAW_CLOUD_API_KEY ? '***configured***' : 'NOT SET'}`);
|
|
1797
|
+
console.log(`Configured: ${isCloudConfigured() ? 'yes' : 'no'}`);
|
|
1798
|
+
if (isCloudConfigured()) {
|
|
1799
|
+
try {
|
|
1800
|
+
const res = await fetch(`${url}/api/v1/health`);
|
|
1801
|
+
const data = await res.json();
|
|
1802
|
+
console.log(`Cloud status: ${data.status} (v${data.version})`);
|
|
1803
|
+
}
|
|
1804
|
+
catch (e) {
|
|
1805
|
+
console.error(`Cloud unreachable: ${e.message}`);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
});
|
|
1809
|
+
// --- codev (legacy experimental) ---
|
|
1810
|
+
if (isCodevEnabled()) {
|
|
1811
|
+
program
|
|
1812
|
+
.command('codev [topic]')
|
|
1813
|
+
.description('Experimental legacy ideation session using persona-based consultation')
|
|
1814
|
+
.option('--personas <tier>', 'Persona tier: tier1 (default), tier2, or list', 'tier1')
|
|
1815
|
+
.option('--checkpoint', 'Pause after clarification for human input')
|
|
1816
|
+
.option('--spawn', 'Spawn each consultant as an agent CLI instance')
|
|
1817
|
+
.option('--fresh', 'Clear cached responses before starting a new run')
|
|
1818
|
+
.option('--agents <list>', 'Comma-separated agent names for spawn (e.g. claude-code,codex,antigravity). Default: auto-detect')
|
|
1819
|
+
.option('--rounds <N>', 'Number of discussion rounds in spawn mode (default 3, min 2)', '3')
|
|
1820
|
+
.option('--target-duration <seconds>', 'Target duration per round indicated to agents (default 120)', '120')
|
|
1821
|
+
.option('--quorum <N>', 'Advance to next round after N agent responses (default: all)')
|
|
1822
|
+
.option('--model-map <map>', 'Per-persona model overrides, e.g. simplificateur:sonnet,stratege:opus')
|
|
1823
|
+
.option('--metrics', 'Display response timing metrics at end of session')
|
|
1824
|
+
.option('--json', 'Output as JSON')
|
|
1825
|
+
.action(async (topic, options) => {
|
|
1826
|
+
const globalOpts = program.opts();
|
|
1827
|
+
const { runCodev } = await import('./commands/codev.js');
|
|
1828
|
+
runCodev(topic, {
|
|
1829
|
+
...options,
|
|
1830
|
+
rounds: parseInt(options.rounds, 10),
|
|
1831
|
+
targetDuration: parseInt(options.targetDuration, 10),
|
|
1832
|
+
quorum: options.quorum != null ? parseInt(options.quorum, 10) : undefined,
|
|
1833
|
+
cwd: globalOpts.cwd,
|
|
1834
|
+
});
|
|
1835
|
+
});
|
|
1836
|
+
program
|
|
1837
|
+
.command('codev-metrics <thread>')
|
|
1838
|
+
.description('Show per-agent avg/p95 response metrics for an experimental CoDev thread')
|
|
1839
|
+
.option('--json', 'Output as JSON')
|
|
1840
|
+
.action(async (thread, options) => {
|
|
1841
|
+
const globalOpts = program.opts();
|
|
1842
|
+
const { runCodevMetrics } = await import('./commands/codev.js');
|
|
1843
|
+
runCodevMetrics(thread, { ...options, cwd: globalOpts.cwd });
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
// --- run (agent profiles) ---
|
|
1847
|
+
program
|
|
1848
|
+
.command('run [profile-name]')
|
|
1849
|
+
.description('Run an agent profile (list profiles if no name given)')
|
|
1850
|
+
.option('--dry', 'Print the resolved command without executing')
|
|
1851
|
+
.option('--agent <agent>', 'Override the invoke template with a known agent')
|
|
1852
|
+
.action((profileName, options) => {
|
|
1853
|
+
const globalOpts = program.opts();
|
|
1854
|
+
runRunProfile(profileName, { ...options, cwd: globalOpts.cwd });
|
|
1170
1855
|
});
|
|
1171
1856
|
program.parseAsync(process.argv).catch((err) => {
|
|
1172
1857
|
console.error(err);
|