brainclaw 0.19.2

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.
Files changed (128) hide show
  1. package/LICENSE +74 -0
  2. package/README.md +226 -0
  3. package/dist/cli.js +1037 -0
  4. package/dist/commands/accept.js +149 -0
  5. package/dist/commands/adapter-openclaw-import.js +75 -0
  6. package/dist/commands/add-step.js +35 -0
  7. package/dist/commands/agent-board.js +106 -0
  8. package/dist/commands/audit.js +35 -0
  9. package/dist/commands/bootstrap.js +34 -0
  10. package/dist/commands/capability.js +104 -0
  11. package/dist/commands/changes.js +112 -0
  12. package/dist/commands/check-constraints.js +63 -0
  13. package/dist/commands/claim-resource.js +54 -0
  14. package/dist/commands/claim.js +92 -0
  15. package/dist/commands/complete-step.js +34 -0
  16. package/dist/commands/constraint.js +44 -0
  17. package/dist/commands/context-diff.js +32 -0
  18. package/dist/commands/context.js +63 -0
  19. package/dist/commands/decision.js +45 -0
  20. package/dist/commands/delete-plan.js +20 -0
  21. package/dist/commands/diff.js +99 -0
  22. package/dist/commands/doctor.js +1275 -0
  23. package/dist/commands/enable-agent.js +63 -0
  24. package/dist/commands/env.js +46 -0
  25. package/dist/commands/estimation-report.js +167 -0
  26. package/dist/commands/explore.js +47 -0
  27. package/dist/commands/export.js +381 -0
  28. package/dist/commands/handoff.js +63 -0
  29. package/dist/commands/history.js +22 -0
  30. package/dist/commands/hooks.js +123 -0
  31. package/dist/commands/init.js +356 -0
  32. package/dist/commands/install-hooks.js +115 -0
  33. package/dist/commands/instruction.js +56 -0
  34. package/dist/commands/list-agents.js +44 -0
  35. package/dist/commands/list-claims.js +45 -0
  36. package/dist/commands/list-instructions.js +50 -0
  37. package/dist/commands/list-plans.js +48 -0
  38. package/dist/commands/mcp-worker.js +12 -0
  39. package/dist/commands/mcp.js +2272 -0
  40. package/dist/commands/memory.js +283 -0
  41. package/dist/commands/metrics.js +175 -0
  42. package/dist/commands/plan-resource.js +62 -0
  43. package/dist/commands/plan.js +76 -0
  44. package/dist/commands/prune-candidates.js +36 -0
  45. package/dist/commands/prune.js +48 -0
  46. package/dist/commands/pull.js +25 -0
  47. package/dist/commands/push.js +28 -0
  48. package/dist/commands/rebuild.js +14 -0
  49. package/dist/commands/reflect-runtime-note.js +74 -0
  50. package/dist/commands/reflect.js +286 -0
  51. package/dist/commands/register-agent.js +29 -0
  52. package/dist/commands/reject.js +52 -0
  53. package/dist/commands/release-claim.js +41 -0
  54. package/dist/commands/release-claims.js +67 -0
  55. package/dist/commands/review.js +242 -0
  56. package/dist/commands/rollback.js +156 -0
  57. package/dist/commands/runtime-note.js +144 -0
  58. package/dist/commands/runtime-status.js +49 -0
  59. package/dist/commands/search.js +36 -0
  60. package/dist/commands/session-end.js +187 -0
  61. package/dist/commands/session-start.js +147 -0
  62. package/dist/commands/set-trust.js +92 -0
  63. package/dist/commands/setup.js +446 -0
  64. package/dist/commands/show-candidate.js +31 -0
  65. package/dist/commands/star-candidate.js +28 -0
  66. package/dist/commands/status.js +133 -0
  67. package/dist/commands/sync.js +159 -0
  68. package/dist/commands/tool.js +126 -0
  69. package/dist/commands/trap.js +74 -0
  70. package/dist/commands/update-handoff.js +23 -0
  71. package/dist/commands/update-plan.js +37 -0
  72. package/dist/commands/upgrade.js +382 -0
  73. package/dist/commands/use-candidate.js +35 -0
  74. package/dist/commands/version.js +96 -0
  75. package/dist/commands/watch.js +215 -0
  76. package/dist/commands/whoami.js +104 -0
  77. package/dist/core/agent-context.js +340 -0
  78. package/dist/core/agent-files.js +874 -0
  79. package/dist/core/agent-integrations.js +135 -0
  80. package/dist/core/agent-inventory.js +401 -0
  81. package/dist/core/agent-registry.js +420 -0
  82. package/dist/core/ai-agent-detection.js +140 -0
  83. package/dist/core/audit.js +85 -0
  84. package/dist/core/bootstrap.js +658 -0
  85. package/dist/core/brainclaw-version.js +433 -0
  86. package/dist/core/candidates.js +137 -0
  87. package/dist/core/circuit-breaker.js +118 -0
  88. package/dist/core/claims.js +72 -0
  89. package/dist/core/config.js +86 -0
  90. package/dist/core/context-diff.js +122 -0
  91. package/dist/core/context.js +1212 -0
  92. package/dist/core/contradictions.js +270 -0
  93. package/dist/core/coordination.js +86 -0
  94. package/dist/core/cross-project.js +99 -0
  95. package/dist/core/duplicates.js +72 -0
  96. package/dist/core/event-log.js +152 -0
  97. package/dist/core/events.js +56 -0
  98. package/dist/core/execution-context.js +204 -0
  99. package/dist/core/freshness.js +87 -0
  100. package/dist/core/global-registry.js +182 -0
  101. package/dist/core/host.js +10 -0
  102. package/dist/core/identity.js +151 -0
  103. package/dist/core/ids.js +56 -0
  104. package/dist/core/input-validation.js +81 -0
  105. package/dist/core/instructions.js +117 -0
  106. package/dist/core/io.js +191 -0
  107. package/dist/core/json-store.js +63 -0
  108. package/dist/core/lifecycle.js +45 -0
  109. package/dist/core/lock.js +129 -0
  110. package/dist/core/logger.js +49 -0
  111. package/dist/core/machine-profile.js +332 -0
  112. package/dist/core/markdown.js +120 -0
  113. package/dist/core/memory-git.js +133 -0
  114. package/dist/core/migration.js +247 -0
  115. package/dist/core/project-registry.js +64 -0
  116. package/dist/core/reflection-safety.js +21 -0
  117. package/dist/core/repo-analysis.js +133 -0
  118. package/dist/core/reputation.js +409 -0
  119. package/dist/core/runtime.js +134 -0
  120. package/dist/core/schema.js +580 -0
  121. package/dist/core/search.js +115 -0
  122. package/dist/core/security.js +66 -0
  123. package/dist/core/setup-state.js +50 -0
  124. package/dist/core/state.js +83 -0
  125. package/dist/core/store-resolution.js +119 -0
  126. package/dist/core/sync-remote.js +83 -0
  127. package/dist/core/traps.js +86 -0
  128. package/package.json +60 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1037 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { runInit } from './commands/init.js';
4
+ import { runSetup } from './commands/setup.js';
5
+ import { runUpgrade } from './commands/upgrade.js';
6
+ import { getMemoryLog, rollbackMemory, hasMemoryRepo } from './core/memory-git.js';
7
+ import { buildMachineProfile, saveMachineProfile, loadMachineProfile, renderMachineProfileSummary } from './core/machine-profile.js';
8
+ import { buildAgentInventory, saveAgentInventory, loadAgentInventory, renderAgentInventorySummary } from './core/agent-inventory.js';
9
+ import { scanAndRegister, scanProject, upsertProject, loadGlobalRegistry, renderGlobalRegistrySummary } from './core/global-registry.js';
10
+ import { runStatus } from './commands/status.js';
11
+ import { runDecision } from './commands/decision.js';
12
+ import { runConstraint } from './commands/constraint.js';
13
+ import { runTrap } from './commands/trap.js';
14
+ import { runHandoff } from './commands/handoff.js';
15
+ import { runListPlans } from './commands/list-plans.js';
16
+ import { runUpdatePlan } from './commands/update-plan.js';
17
+ import { runDeletePlan } from './commands/delete-plan.js';
18
+ import { runPlanResource } from './commands/plan-resource.js';
19
+ import { runAddStep } from './commands/add-step.js';
20
+ import { runEstimationReport } from './commands/estimation-report.js';
21
+ import { runCompleteStep } from './commands/complete-step.js';
22
+ import { runUpdateHandoff } from './commands/update-handoff.js';
23
+ import { runInstruction } from './commands/instruction.js';
24
+ import { runListAgents } from './commands/list-agents.js';
25
+ import { runListInstructions } from './commands/list-instructions.js';
26
+ import { runDoctor } from './commands/doctor.js';
27
+ import { runRebuild } from './commands/rebuild.js';
28
+ import { runReflect } from './commands/reflect.js';
29
+ import { runReflectRuntimeNote } from './commands/reflect-runtime-note.js';
30
+ import { runReview } from './commands/review.js';
31
+ import { runShowCandidate } from './commands/show-candidate.js';
32
+ import { runStarCandidate } from './commands/star-candidate.js';
33
+ import { runUseCandidate } from './commands/use-candidate.js';
34
+ import { runAccept } from './commands/accept.js';
35
+ import { runReject } from './commands/reject.js';
36
+ import { runPruneCandidates } from './commands/prune-candidates.js';
37
+ import { runListClaims } from './commands/list-claims.js';
38
+ import { runReleaseClaim } from './commands/release-claim.js';
39
+ import { runClaimResource } from './commands/claim-resource.js';
40
+ import { runMemoryCommand } from './commands/memory.js';
41
+ import { runReleaseClaims } from './commands/release-claims.js';
42
+ import { runAgentBoard } from './commands/agent-board.js';
43
+ import { runRuntimeNote } from './commands/runtime-note.js';
44
+ import { runRuntimeStatus } from './commands/runtime-status.js';
45
+ import { runSync } from './commands/sync.js';
46
+ import { runContext } from './commands/context.js';
47
+ import { runBootstrap } from './commands/bootstrap.js';
48
+ import { runEnv } from './commands/env.js';
49
+ import { runAdapterOpenclawImport } from './commands/adapter-openclaw-import.js';
50
+ import { runInstallHooks } from './commands/install-hooks.js';
51
+ import { runCheckConstraints } from './commands/check-constraints.js';
52
+ import { runRegisterAgent } from './commands/register-agent.js';
53
+ import { runEnableAgent } from './commands/enable-agent.js';
54
+ import { runVersion } from './commands/version.js';
55
+ import { runDiff } from './commands/changes.js';
56
+ import { runPrune } from './commands/prune.js';
57
+ import { runMcp } from './commands/mcp.js';
58
+ import { runSetTrust } from './commands/set-trust.js';
59
+ import { runSessionStart } from './commands/session-start.js';
60
+ import { runSessionEnd } from './commands/session-end.js';
61
+ import { runWhoami } from './commands/whoami.js';
62
+ import { runSearch } from './commands/search.js';
63
+ import { runExport } from './commands/export.js';
64
+ import { runHooks } from './commands/hooks.js';
65
+ import { runWatch } from './commands/watch.js';
66
+ import { runMetrics } from './commands/metrics.js';
67
+ import { runRollback } from './commands/rollback.js';
68
+ import { runPull } from './commands/pull.js';
69
+ import { runPush } from './commands/push.js';
70
+ import { runAuditCommand } from './commands/audit.js';
71
+ import { runHistory } from './commands/history.js';
72
+ import { runContextDiff } from './commands/context-diff.js';
73
+ import { runCapability } from './commands/capability.js';
74
+ import { runTool } from './commands/tool.js';
75
+ import { runExplore } from './commands/explore.js';
76
+ import { getInstalledBrainclawVersion } from './core/brainclaw-version.js';
77
+ import { cleanOrphanFiles, memoryDir } from './core/io.js';
78
+ import { initLogLevel, logger } from './core/logger.js';
79
+ const program = new Command();
80
+ function collect(value, previous) {
81
+ return [...previous, value];
82
+ }
83
+ program
84
+ .name('brainclaw')
85
+ .description('Shared project memory for humans and coding agents.')
86
+ .version(getInstalledBrainclawVersion())
87
+ .option('--verbose', 'Show info-level log messages on stderr')
88
+ .option('--debug', 'Show debug-level log messages on stderr')
89
+ .hook('preAction', (_thisCommand, actionCommand) => {
90
+ const root = actionCommand.optsWithGlobals();
91
+ initLogLevel({ verbose: root.verbose, debug: root.debug });
92
+ const removed = cleanOrphanFiles(memoryDir());
93
+ if (removed > 0) {
94
+ logger.info(`Cleaned ${removed} orphan lock/tmp file(s) in ${memoryDir()}`);
95
+ }
96
+ });
97
+ // --- init ---
98
+ program
99
+ .command('init')
100
+ .description('Initialize project memory in .brainclaw/ storage directory')
101
+ .option('-y, --yes', 'Skip interactive wizard and use defaults')
102
+ .option('--force', 'Overwrite existing project memory directory')
103
+ .option('--compact', 'Enable compact markdown mode')
104
+ .option('--topology <mode>', 'Topology mode: embedded, sidecar, local-only')
105
+ .option('--project-mode <mode>', 'Project mode: single-project, multi-project, auto')
106
+ .option('--project-strategy <strategy>', 'Project strategy for multi-project mode: manual, folder')
107
+ .option('--no-analyze-repo', 'Skip repository analysis when suggesting a project mode')
108
+ .option('--scan', 'Scan subdirectories for service boundaries and suggest init targets')
109
+ .action(async (options) => {
110
+ await runInit(options);
111
+ });
112
+ // --- setup ---
113
+ program
114
+ .command('setup')
115
+ .description('Interactive onboarding wizard — global agent install + multi-repo init')
116
+ .option('--roots <paths>', 'Comma-separated root directories to scan (skips interactive prompt)')
117
+ .option('--agents <agents>', 'Agents to configure: all, detected, or comma-separated names')
118
+ .option('--repos <mode>', 'Repo selection: all, current, or comma-separated numbers')
119
+ .option('-y, --yes', 'Accept all defaults non-interactively')
120
+ .action(async (options) => {
121
+ await runSetup(options);
122
+ });
123
+ // --- memory-log ---
124
+ program
125
+ .command('memory-log')
126
+ .description('Show recent memory change history (from internal git repo)')
127
+ .option('-n, --limit <count>', 'Number of entries to show', '20')
128
+ .action((options) => {
129
+ const entries = getMemoryLog(parseInt(options.limit, 10));
130
+ if (entries.length === 0) {
131
+ console.log('No memory history available. Run `brainclaw init --force` to enable memory versioning.');
132
+ return;
133
+ }
134
+ console.log(`Memory history (${entries.length} entries):\n`);
135
+ for (const entry of entries) {
136
+ console.log(` ${entry}`);
137
+ }
138
+ });
139
+ // --- memory-rollback ---
140
+ program
141
+ .command('memory-rollback <ref>')
142
+ .description('Rollback entire memory to a previous git snapshot (use memory-log to find refs)')
143
+ .action((ref) => {
144
+ if (!hasMemoryRepo()) {
145
+ console.error('Error: no memory git repo. Run `brainclaw init --force` to enable.');
146
+ process.exit(1);
147
+ }
148
+ const success = rollbackMemory(ref);
149
+ if (success) {
150
+ console.log(`✔ Memory rolled back to ${ref}`);
151
+ }
152
+ else {
153
+ console.error(`Error: failed to rollback to '${ref}'. Check memory-log for valid refs.`);
154
+ process.exit(1);
155
+ }
156
+ });
157
+ // --- upgrade ---
158
+ program
159
+ .command('upgrade')
160
+ .description('Upgrade project memory structure and refresh managed workspace agent files without losing data')
161
+ .option('--json', 'Output as JSON')
162
+ .option('--dry-run', 'Show what would be done without making changes')
163
+ .action((options) => {
164
+ runUpgrade({
165
+ json: options.json,
166
+ dryRun: options.dryRun,
167
+ });
168
+ });
169
+ // --- machine-profile ---
170
+ program
171
+ .command('machine-profile')
172
+ .description('Detect and persist machine capabilities (OS, shells, git users, SSH keys, toolchains, WSL)')
173
+ .option('--refresh', 'Force regeneration even if profile exists')
174
+ .option('--json', 'Output as JSON')
175
+ .action(async (options) => {
176
+ const existing = loadMachineProfile();
177
+ if (existing && !options.refresh) {
178
+ if (options.json) {
179
+ console.log(JSON.stringify(existing, null, 2));
180
+ }
181
+ else {
182
+ console.log(renderMachineProfileSummary(existing));
183
+ console.log('\nUse --refresh to regenerate.');
184
+ }
185
+ return;
186
+ }
187
+ console.log('Detecting machine capabilities...');
188
+ const profile = buildMachineProfile();
189
+ const filePath = saveMachineProfile(profile);
190
+ if (options.json) {
191
+ console.log(JSON.stringify(profile, null, 2));
192
+ }
193
+ else {
194
+ console.log(renderMachineProfileSummary(profile));
195
+ console.log(`\n✔ Profile saved to ${filePath}`);
196
+ }
197
+ });
198
+ // --- agent-inventory ---
199
+ program
200
+ .command('agent-inventory')
201
+ .description('Detect all installed AI coding agents and their capabilities')
202
+ .option('--refresh', 'Force regeneration even if inventory exists')
203
+ .option('--json', 'Output as JSON')
204
+ .action(async (options) => {
205
+ const existing = loadAgentInventory();
206
+ if (existing && !options.refresh) {
207
+ if (options.json) {
208
+ console.log(JSON.stringify(existing, null, 2));
209
+ }
210
+ else {
211
+ console.log(renderAgentInventorySummary(existing));
212
+ console.log('\nUse --refresh to regenerate.');
213
+ }
214
+ return;
215
+ }
216
+ console.log('Detecting installed agents...');
217
+ const inventory = buildAgentInventory();
218
+ const filePath = saveAgentInventory(inventory);
219
+ if (options.json) {
220
+ console.log(JSON.stringify(inventory, null, 2));
221
+ }
222
+ else {
223
+ console.log(renderAgentInventorySummary(inventory));
224
+ console.log(`\n✔ Inventory saved to ${filePath}`);
225
+ }
226
+ });
227
+ // --- projects ---
228
+ program
229
+ .command('projects')
230
+ .description('List all brainclaw-initialized projects on this machine')
231
+ .option('--scan <roots>', 'Comma-separated directories to scan for projects')
232
+ .option('--register', 'Register the current project in the global registry')
233
+ .option('--json', 'Output as JSON')
234
+ .action(async (options) => {
235
+ if (options.register) {
236
+ const entry = scanProject(process.cwd());
237
+ if (!entry) {
238
+ console.error('No brainclaw project found in current directory. Run brainclaw init first.');
239
+ process.exit(1);
240
+ }
241
+ upsertProject(entry);
242
+ console.log(`✔ Registered ${entry.project_name} (${entry.project_id})`);
243
+ return;
244
+ }
245
+ if (options.scan) {
246
+ const roots = options.scan.split(',').map((r) => r.trim());
247
+ console.log(`Scanning ${roots.join(', ')}...`);
248
+ const registry = scanAndRegister(roots);
249
+ if (options.json) {
250
+ console.log(JSON.stringify(registry, null, 2));
251
+ }
252
+ else {
253
+ console.log(renderGlobalRegistrySummary(registry));
254
+ }
255
+ return;
256
+ }
257
+ // Default: show existing registry
258
+ const registry = loadGlobalRegistry();
259
+ if (!registry || registry.projects.length === 0) {
260
+ console.log('No projects registered. Use --scan <roots> or --register to add projects.');
261
+ return;
262
+ }
263
+ if (options.json) {
264
+ console.log(JSON.stringify(registry, null, 2));
265
+ }
266
+ else {
267
+ console.log(renderGlobalRegistrySummary(registry));
268
+ }
269
+ });
270
+ // --- decision ---
271
+ program
272
+ .command('decision <text>')
273
+ .description('Add a recent decision')
274
+ .option('--outcome <outcome>', 'Outcome: approved, rejected, deferred, pending')
275
+ .option('--tag <tags...>', 'Tags for this decision')
276
+ .option('--path <paths...>', 'Related file paths')
277
+ .option('--author <author>', 'Author name')
278
+ .option('--plan <id>', 'Optional linked plan item ID')
279
+ .option('--store <target>', 'Target store level: local (default), repo, workspace, user')
280
+ .action((text, options) => {
281
+ runDecision(text, options);
282
+ });
283
+ // --- constraint ---
284
+ program
285
+ .command('constraint <text>')
286
+ .description('Add an active constraint')
287
+ .option('--category <category>', 'Category: architecture, performance, security, reliability, compatibility, process, other')
288
+ .option('--tag <tags...>', 'Tags for this constraint')
289
+ .option('--path <paths...>', 'Related file paths')
290
+ .option('--author <author>', 'Author name')
291
+ .option('--store <target>', 'Target store level: local (default), repo, workspace, user')
292
+ .action((text, options) => {
293
+ runConstraint(text, options);
294
+ });
295
+ // --- trap ---
296
+ program
297
+ .command('trap <text>')
298
+ .description('Add a known trap')
299
+ .option('--status <status>', 'Status: active, resolved, expired', 'active')
300
+ .option('--severity <severity>', 'Severity: low, medium, high', 'medium')
301
+ .option('--visibility <visibility>', 'Visibility: shared, machine, private', 'shared')
302
+ .option('--host <host>', 'Optional host identifier override for machine/private traps')
303
+ .option('--tag <tags...>', 'Tags for this trap')
304
+ .option('--path <paths...>', 'Related file paths')
305
+ .option('--author <author>', 'Author name')
306
+ .option('--ttl <duration>', 'Time-to-live: 30m, 2h, 7d (trap auto-expires after this duration)')
307
+ .option('--store <target>', 'Target store level: local (default), repo, workspace, user')
308
+ .action((text, options) => {
309
+ runTrap(text, options);
310
+ });
311
+ // --- handoff ---
312
+ program
313
+ .command('handoff <text>')
314
+ .description('Create a handoff')
315
+ .requiredOption('--from <from>', 'Source of the handoff')
316
+ .requiredOption('--to <to>', 'Destination of the handoff')
317
+ .option('--tag <tags...>', 'Tags for this handoff')
318
+ .option('--path <paths...>', 'Related file paths')
319
+ .option('--project <project>', 'Optional project namespace')
320
+ .option('--plan <id>', 'Optional linked plan item ID')
321
+ .option('--author <author>', 'Author name')
322
+ .option('--capture-diff', 'Capture current git diff into the handoff snapshot')
323
+ .action((text, options) => {
324
+ runHandoff(text, options);
325
+ });
326
+ // --- status ---
327
+ program
328
+ .command('status')
329
+ .description('Show project memory status')
330
+ .option('--json', 'Output as JSON')
331
+ .option('--markdown', 'Output as Markdown')
332
+ .action((options) => {
333
+ runStatus(options);
334
+ });
335
+ // --- plan ---
336
+ program
337
+ .command('plan <subcommand> [args...]')
338
+ .description('Manage shared plan items (create, list, update, delete)')
339
+ .option('--json', 'Output as JSON for list')
340
+ .option('--all', 'Include done and dropped plan items in list')
341
+ .option('--type <type>', 'Plan type or filter: feat, fix, chore, spike, doc')
342
+ .option('--status <status>', 'Status filter/update: todo, in_progress, blocked, done, dropped')
343
+ .option('--priority <priority>', 'Priority: low, medium, high', 'medium')
344
+ .option('--assignee <assignee>', 'Assignee for this plan item')
345
+ .option('--project <project>', 'Optional project namespace')
346
+ .option('--tag <tags...>', 'Tags for this plan item')
347
+ .option('--path <paths...>', 'Related file paths')
348
+ .option('--depends-on <ids...>', 'Dependency IDs for this plan item')
349
+ .option('--author <author>', 'Author name')
350
+ .option('--estimate <minutes>', 'Estimated effort in minutes (positive integer, e.g. --estimate 30)')
351
+ .option('--actual-effort <effort>', 'Actual effort spent (e.g. "20min", "1h30m")')
352
+ .option('--store <target>', 'Target store level: local (default), repo, workspace, user')
353
+ .action((subcommand, args, options) => {
354
+ runPlanResource(subcommand, args, { ...options, actualEffort: options.actualEffort });
355
+ });
356
+ // --- list-plans ---
357
+ program
358
+ .command('list-plans')
359
+ .description('List shared plan items')
360
+ .option('--json', 'Output as JSON')
361
+ .option('--status <status>', 'Status: todo, in_progress, blocked, done, dropped')
362
+ .option('--type <type>', 'Filter by type: feat, fix, chore, spike, doc')
363
+ .option('--assignee <assignee>', 'Filter by assignee')
364
+ .option('--project <project>', 'Filter by project namespace')
365
+ .option('--all', 'Include done and dropped plan items')
366
+ .action((options) => {
367
+ runListPlans(options);
368
+ });
369
+ // --- add-step ---
370
+ program
371
+ .command('add-step <planId> <text>')
372
+ .description('Add an optional step to a plan item')
373
+ .option('--assign <assignee>', 'Assign this step to an agent or person')
374
+ .action((planId, text, options) => {
375
+ runAddStep(planId, text, { assignee: options.assign });
376
+ });
377
+ // --- complete-step ---
378
+ program
379
+ .command('complete-step <planId> <stepId>')
380
+ .description('Mark a plan step as done')
381
+ .action((planId, stepId) => {
382
+ runCompleteStep(planId, stepId);
383
+ });
384
+ // --- estimation-report ---
385
+ program
386
+ .command('estimation-report')
387
+ .description('Show estimation accuracy report for completed plans')
388
+ .option('--agent <name>', 'Filter by agent/author name')
389
+ .option('--json', 'Output as JSON')
390
+ .action((options) => {
391
+ runEstimationReport(options);
392
+ });
393
+ // --- update-plan ---
394
+ program
395
+ .command('update-plan <id>')
396
+ .description('Update a shared plan item')
397
+ .option('--status <status>', 'Status: todo, in_progress, blocked, done, dropped')
398
+ .option('--assignee <assignee>', 'Assign a user or agent to this plan item')
399
+ .option('--project <project>', 'Set or change project namespace')
400
+ .option('--priority <priority>', 'Priority: low, medium, high')
401
+ .option('--actual-effort <effort>', 'Actual effort spent (e.g. "20min", "1h30m")')
402
+ .action((id, options) => {
403
+ runUpdatePlan(id, { ...options, actualEffort: options.actualEffort });
404
+ });
405
+ // --- delete-plan ---
406
+ program
407
+ .command('delete-plan <id>')
408
+ .description('Delete a shared plan item')
409
+ .action((id) => {
410
+ runDeletePlan(id);
411
+ });
412
+ // --- update-handoff ---
413
+ program
414
+ .command('update-handoff <id>')
415
+ .description('Update the status of a handoff')
416
+ .option('--status <status>', 'Status: open, accepted, closed')
417
+ .option('--to <agent>', 'Change the receiving agent')
418
+ .action((id, options) => {
419
+ runUpdateHandoff(id, options);
420
+ });
421
+ // --- doctor ---
422
+ program
423
+ .command('doctor')
424
+ .description('Check memory health and security')
425
+ .option('--json', 'Output as JSON dashboard')
426
+ .option('--migration-check', 'Report versioned documents that need schema migration')
427
+ .option('--fix-agent-ignore', 'Add missing .gitignore entries for generated local Brainclaw agent files')
428
+ .action((options) => {
429
+ runDoctor(options);
430
+ });
431
+ // --- version ---
432
+ program
433
+ .command('version')
434
+ .description('Show the installed brainclaw version and the project version policy')
435
+ .option('--check', 'Check the configured installable update source')
436
+ .option('--publish-local', 'Create/update the local installable .releases channel via npm pack')
437
+ .option('--release-notes <text>', 'Attach release notes to the generated local-pack manifest')
438
+ .option('--json', 'Output as JSON')
439
+ .action((options) => {
440
+ runVersion(options);
441
+ });
442
+ // --- rebuild ---
443
+ program
444
+ .command('rebuild')
445
+ .description('Rebuild project.md from canonical memory state')
446
+ .action(() => {
447
+ runRebuild();
448
+ });
449
+ // --- reflect ---
450
+ program
451
+ .command('reflect [text]')
452
+ .description('Create a memory candidate for review')
453
+ .option('--type <type>', 'Type: constraint, decision, trap, handoff')
454
+ .option('--batch <file>', 'Import runtime events from JSON file')
455
+ .option('--session <id>', 'Import runtime events by session id from .brainclaw/runtime/')
456
+ .option('--tag <tags...>', 'Tags')
457
+ .option('--author <author>', 'Author name')
458
+ .option('--source <source>', 'Source context (e.g. agent name)')
459
+ .option('--severity <severity>', 'Severity for traps: low, medium, high')
460
+ .option('--from <from>', 'Handoff source')
461
+ .option('--to <to>', 'Handoff destination')
462
+ .option('--path <paths...>', 'Related file paths')
463
+ .action((text, options) => {
464
+ runReflect(text, options);
465
+ });
466
+ // --- reflect-runtime-note ---
467
+ program
468
+ .command('reflect-runtime-note <id> [text]')
469
+ .description('Turn a visible runtime note into a shared review candidate')
470
+ .option('--type <type>', 'Type: constraint, decision, trap, handoff')
471
+ .option('--host <host>', 'Look up machine-local runtime note for a specific host')
472
+ .option('--all-hosts', 'Look up runtime notes across all hosts')
473
+ .option('--suggest', 'Show candidate type suggestions before or instead of creation')
474
+ .option('--json', 'Output suggestions as JSON when used with --suggest or without --type')
475
+ .option('--tag <tags...>', 'Additional tags to merge with the runtime note tags')
476
+ .option('--author <author>', 'Author name for the candidate')
477
+ .option('--source <source>', 'Source context for the candidate')
478
+ .option('--severity <severity>', 'Severity for traps: low, medium, high')
479
+ .option('--from <from>', 'Handoff source')
480
+ .option('--to <to>', 'Handoff destination')
481
+ .option('--path <paths...>', 'Related file paths')
482
+ .action((id, text, options) => {
483
+ runReflectRuntimeNote(id, text, options);
484
+ });
485
+ // --- context ---
486
+ program
487
+ .command('context')
488
+ .description('Generate compact context for agents')
489
+ .option('--for <target>', 'Task/path/goal to prioritize')
490
+ .option('--project <project>', 'Explicit project namespace for layered instructions')
491
+ .option('--agent <agent>', 'Agent name for agent-layer instructions')
492
+ .option('--host <host>', 'Include machine-local runtime notes for a specific host')
493
+ .option('--all-hosts', 'Include machine-local runtime notes from all hosts')
494
+ .option('--profile <profile>', 'Profile: dev, openclaw, ops, research')
495
+ .option('--include-pending', 'Include pending candidates')
496
+ .option('--max-items <count>', 'Limit number of items', parseInt)
497
+ .option('--max-chars <count>', 'Approximate output budget for selected item content', parseInt)
498
+ .option('--digest', 'Include a short deterministic digest ahead of the detailed context')
499
+ .option('--since-session <id>', 'Include a compact memory diff since the given session started')
500
+ .option('--no-bootstrap', 'Disable brownfield bootstrap fallback when canonical memory is sparse')
501
+ .option('--refresh-bootstrap', 'Refresh brownfield bootstrap profile before building context')
502
+ .option('--template', 'Output prompt-ready context template')
503
+ .option('--compact-template', 'Use compact template format (default for openclaw profile)')
504
+ .option('--explain', 'Show ranking reasons in human-readable output')
505
+ .option('--json', 'Output as JSON')
506
+ .action((options) => {
507
+ runContext(options);
508
+ });
509
+ // --- bootstrap ---
510
+ program
511
+ .command('bootstrap')
512
+ .description('Derive brownfield bootstrap signals from the current repository')
513
+ .option('--for <target>', 'Target path or scope to tailor the bootstrap')
514
+ .option('--json', 'Output as JSON')
515
+ .option('--refresh', 'Force a fresh bootstrap scan instead of reusing the current profile')
516
+ .action((options) => {
517
+ runBootstrap(options);
518
+ });
519
+ // --- env ---
520
+ program
521
+ .command('env')
522
+ .description('Show the local execution context and optionally detected agent tooling')
523
+ .option('--json', 'Output as JSON')
524
+ .option('--agent-tooling', 'Include AGENTS.md, local skills, and local MCP inventory')
525
+ .action((options) => {
526
+ runEnv({ ...options, agentTooling: options.agentTooling });
527
+ });
528
+ // --- memory ---
529
+ program
530
+ .command('memory <subcommand> [args...]')
531
+ .description('Manage canonical memory items (create, list, update, delete)')
532
+ .option('--json', 'Output as JSON for list')
533
+ .option('--type <type>', 'Memory type/filter: decision, constraint, trap, handoff')
534
+ .option('--text <text>', 'Replacement text for memory update')
535
+ .option('--tag <tags...>', 'Tags')
536
+ .option('--path <paths...>', 'Related file paths')
537
+ .option('--author <author>', 'Author name')
538
+ .option('--outcome <outcome>', 'Decision outcome: approved, rejected, deferred, pending')
539
+ .option('--category <category>', 'Constraint category: architecture, performance, security, reliability, compatibility, process, other')
540
+ .option('--status <status>', 'Constraint, trap, or handoff status')
541
+ .option('--severity <severity>', 'Trap severity: low, medium, high')
542
+ .option('--project <project>', 'Optional project namespace')
543
+ .option('--plan <id>', 'Optional linked plan item ID')
544
+ .option('--from <from>', 'Handoff source')
545
+ .option('--to <to>', 'Handoff destination')
546
+ .option('--visibility <visibility>', 'Trap visibility: shared, machine, private', 'shared')
547
+ .option('--host <host>', 'Optional host identifier override for machine/private traps')
548
+ .option('--ttl <duration>', 'Time-to-live: 30m, 2h, 7d')
549
+ .option('--store <target>', 'Target store level: local (default), repo, workspace, user')
550
+ .action((subcommand, args, options) => {
551
+ runMemoryCommand(subcommand, args, options);
552
+ });
553
+ // --- instruction ---
554
+ program
555
+ .command('instruction <text>')
556
+ .description('Add a layered shared instruction')
557
+ .option('--layer <layer>', 'Instruction layer: global, project, agent', 'global')
558
+ .option('--project <project>', 'Project namespace when --layer project is used')
559
+ .option('--agent <agent>', 'Agent name when --layer agent is used')
560
+ .option('--tag <tags...>', 'Tags for this instruction')
561
+ .option('--author <author>', 'Author name')
562
+ .option('--supersedes <id>', 'Supersede an older instruction entry')
563
+ .option('--store <target>', 'Target store level: local (default), repo, workspace, user')
564
+ .action((text, options) => {
565
+ runInstruction(text, options);
566
+ });
567
+ // --- list-instructions ---
568
+ program
569
+ .command('list-instructions')
570
+ .description('List raw or resolved shared instructions')
571
+ .option('--json', 'Output as JSON')
572
+ .option('--layer <layer>', 'Filter by layer: global, project, agent')
573
+ .option('--project <project>', 'Project namespace filter')
574
+ .option('--agent <agent>', 'Agent name filter')
575
+ .option('--active', 'Only show active entries')
576
+ .option('--resolved', 'Resolve effective instructions for the given scope')
577
+ .option('--for <target>', 'Infer project namespace from target path when strategy=folder')
578
+ .action((options) => {
579
+ runListInstructions(options);
580
+ });
581
+ // --- register-agent ---
582
+ program
583
+ .command('register-agent <name>')
584
+ .description('Register an agent or human identity in project memory')
585
+ .option('--kind <kind>', 'Identity kind: agent, human, unknown', 'unknown')
586
+ .option('--capability <value>', 'Declare a capability on the agent profile (repeatable)', collect, [])
587
+ .option('--replace-capabilities', 'Replace existing capabilities instead of merging')
588
+ .option('--generate-fingerprint', 'Generate or rotate a local public identity fingerprint for this agent')
589
+ .option('--set-current', 'Set this identity as the current agent in config')
590
+ .option('--curator', 'Register this agent as a curator (project owner with direct-write access)')
591
+ .option('--json', 'Output as JSON')
592
+ .action((name, options) => {
593
+ runRegisterAgent(name, options);
594
+ });
595
+ // --- enable-agent ---
596
+ program
597
+ .command('enable-agent <name>')
598
+ .description('Activate a supported coding agent on an already initialized project')
599
+ .option('--kind <kind>', 'Identity kind: agent, human, unknown', 'agent')
600
+ .option('--capability <value>', 'Declare a capability on the agent profile (repeatable)', collect, [])
601
+ .option('--replace-capabilities', 'Replace existing capabilities instead of merging')
602
+ .option('--generate-fingerprint', 'Generate or rotate a local public identity fingerprint for this agent')
603
+ .option('--set-current', 'Set this identity as the current agent in config')
604
+ .option('--json', 'Output as JSON')
605
+ .action((name, options) => {
606
+ runEnableAgent(name, options);
607
+ });
608
+ // --- list-agents ---
609
+ program
610
+ .command('list-agents')
611
+ .description('List registered agent identities')
612
+ .option('--json', 'Output as JSON')
613
+ .option('--with-reputation', 'Include bounded reputation summaries when available')
614
+ .action((options) => {
615
+ runListAgents(options);
616
+ });
617
+ // --- review ---
618
+ program
619
+ .command('review')
620
+ .description('List pending memory candidates')
621
+ .option('--json', 'Output as JSON')
622
+ .option('--type <type>', 'Filter by type')
623
+ .option('--prioritized', 'Sort by review priority and show SLA')
624
+ .option('--only-overdue', 'Show only candidates overdue review SLA')
625
+ .option('--assignee <assignee>', 'Filter by assignee tag (assignee:<name>)')
626
+ .option('--for-curator <curator>', 'Shortcut assignee filter for curator queue')
627
+ .option('--take <count>', 'Limit number of reviewed items', parseInt)
628
+ .option('--claim <curator>', 'Atomically assign selected candidates to a curator')
629
+ .option('--auto', 'Auto-promote candidates meeting the configured score threshold')
630
+ .option('--auto-by <actor>', 'Actor identity for auto-promotion (defaults to current user)')
631
+ .action((options) => {
632
+ runReview({ ...options, autoBy: options.autoBy });
633
+ });
634
+ // --- show-candidate ---
635
+ program
636
+ .command('show-candidate <id>')
637
+ .description('Show details of a memory candidate')
638
+ .option('--related', 'Show related candidates by shared tags/paths')
639
+ .action((id, options) => {
640
+ runShowCandidate(id, { related: options.related });
641
+ });
642
+ // --- star-candidate ---
643
+ program
644
+ .command('star-candidate <id>')
645
+ .description('Add an adoption star to a pending candidate')
646
+ .option('--by <actor>', 'Agent or person adding the star')
647
+ .action((id, options) => {
648
+ runStarCandidate(id, options);
649
+ });
650
+ // --- use-candidate ---
651
+ program
652
+ .command('use-candidate <id>')
653
+ .description('Record that a pending candidate was reused in a concrete work context')
654
+ .option('--by <actor>', 'Agent or person using the candidate')
655
+ .requiredOption('--context <context>', 'Work context where the candidate was reused')
656
+ .action((id, options) => {
657
+ runUseCandidate(id, options);
658
+ });
659
+ // --- accept ---
660
+ program
661
+ .command('accept <id>')
662
+ .description('Accept a candidate into canonical memory')
663
+ .option('--by <reviewer>', 'Reviewer identity used for governance checks')
664
+ .action((id, options) => {
665
+ runAccept(id, options.by);
666
+ });
667
+ // --- adapter-openclaw-import ---
668
+ program
669
+ .command('adapter-openclaw-import [file]')
670
+ .description('Import OpenClaw runtime events file as memory candidates')
671
+ .option('--session <id>', 'Import runtime events from a session id in .brainclaw/runtime/')
672
+ .option('--dry-run', 'Preview import without creating candidates')
673
+ .option('--source <source>', 'Source label for imported candidates', 'openclaw')
674
+ .option('--author <author>', 'Author for imported candidates')
675
+ .action((file, options) => {
676
+ runAdapterOpenclawImport(file, options);
677
+ });
678
+ // --- reject ---
679
+ program
680
+ .command('reject <id>')
681
+ .description('Reject a memory candidate')
682
+ .option('--by <reviewer>', 'Reviewer identity used for rejection attribution')
683
+ .option('--reason <reason>', 'Reason for rejection')
684
+ .action((id, options) => {
685
+ runReject(id, options.reason, options.by);
686
+ });
687
+ // --- prune-candidates ---
688
+ program
689
+ .command('prune-candidates')
690
+ .description('Remove old rejected candidates')
691
+ .option('--days <days>', 'Max age in days', parseInt)
692
+ .option('--dry-run', 'Preview without deleting')
693
+ .action((options) => {
694
+ runPruneCandidates(options);
695
+ });
696
+ // --- claim ---
697
+ program
698
+ .command('claim <subcommand> [args...]')
699
+ .description('Manage work claims (create, list, release)')
700
+ .option('--agent <agent>', 'Agent or person name; defaults to the configured current agent')
701
+ .option('--scope <scope>', 'Scope being claimed (e.g. file path, module)')
702
+ .option('--project <project>', 'Optional project namespace for this claim')
703
+ .option('--plan <id>', 'Optional linked plan item ID')
704
+ .option('--ttl <duration>', 'Auto-expire after duration: 30m, 2h, 8h, 1d')
705
+ .option('--all', 'Include released claims in list')
706
+ .option('--json', 'Output as JSON for list')
707
+ .option('--plan-status <status>', 'Optional linked plan status when releasing: todo, in_progress, blocked, done, dropped')
708
+ .option('--store <target>', 'Target store level: local (default), repo, workspace')
709
+ .action((subcommand, args, options) => {
710
+ runClaimResource(subcommand, args, { ...options, planStatus: options.planStatus });
711
+ });
712
+ // --- list-claims ---
713
+ program
714
+ .command('list-claims')
715
+ .description('List work claims')
716
+ .option('--json', 'Output as JSON')
717
+ .option('--all', 'Include released claims')
718
+ .option('--project <project>', 'Filter by project namespace')
719
+ .option('--plan <id>', 'Filter by linked plan item')
720
+ .option('--agent <agent>', 'Filter by agent name')
721
+ .action((options) => {
722
+ runListClaims(options);
723
+ });
724
+ // --- release-claim ---
725
+ program
726
+ .command('release-claim <id>')
727
+ .description('Release a work claim')
728
+ .option('--plan-status <status>', 'Optional linked plan status: todo, in_progress, blocked, done, dropped')
729
+ .action((id, options) => {
730
+ runReleaseClaim(id, options);
731
+ });
732
+ // --- release-claims ---
733
+ program
734
+ .command('release-claims')
735
+ .description('Bulk-release claims whose scope overlaps with git-changed files')
736
+ .option('--from-git-diff', 'Use ORIG_HEAD..HEAD diff to detect changed files (post-merge)')
737
+ .option('--ref1 <ref>', 'First git ref (default: ORIG_HEAD)')
738
+ .option('--ref2 <ref>', 'Second git ref (default: HEAD)')
739
+ .action((options) => {
740
+ runReleaseClaims({ fromGitDiff: options.fromGitDiff, ref1: options.ref1, ref2: options.ref2 });
741
+ });
742
+ // --- agent-board ---
743
+ program
744
+ .command('agent-board')
745
+ .description('Show a coordination board for agents, plans, claims, handoffs, and instructions')
746
+ .option('--agent <agent>', 'Filter by agent name')
747
+ .option('--project <project>', 'Filter by project namespace')
748
+ .option('--for <target>', 'Infer project from target path')
749
+ .option('--host <host>', 'Include machine-local runtime notes for a specific host')
750
+ .option('--all-hosts', 'Include machine-local runtime notes from all hosts')
751
+ .option('--json', 'Output as JSON')
752
+ .option('--with-reputation', 'Include bounded reputation summaries when available')
753
+ .option('--capabilities', 'List all registered agents with their declared capabilities')
754
+ .option('--suggest <query>', 'Suggest agents whose capabilities match a query string')
755
+ .option('--include-session-meta', 'Include session_start/session_end runtime notes (hidden by default)')
756
+ .action((options) => {
757
+ runAgentBoard(options);
758
+ });
759
+ // --- runtime-note ---
760
+ program
761
+ .command('runtime-note <text>')
762
+ .description('Add a runtime note for an agent')
763
+ .option('--agent <agent>', 'Agent name; defaults to the configured current agent')
764
+ .option('--project <project>', 'Optional project namespace')
765
+ .option('--plan <id>', 'Optional linked plan item ID')
766
+ .option('--visibility <visibility>', 'Visibility: shared, machine, private', 'shared')
767
+ .option('--host <host>', 'Optional host identifier override for machine/private runtime notes')
768
+ .option('--tag <tags...>', 'Tags')
769
+ .option('--ttl <duration>', 'Time-to-live: 30m, 2h, 7d (note auto-expires after this duration)')
770
+ .option('--auto-reflect', 'Attempt to turn this runtime note into durable memory immediately')
771
+ .action((text, options) => {
772
+ runRuntimeNote(text, { ...options, autoReflect: options.autoReflect });
773
+ });
774
+ // --- runtime-status ---
775
+ program
776
+ .command('runtime-status')
777
+ .description('Show runtime notes')
778
+ .option('--agent <agent>', 'Filter by agent')
779
+ .option('--plan <id>', 'Filter by linked plan item')
780
+ .option('--visibility <visibility>', 'Visibility filter: shared, machine, private, all')
781
+ .option('--host <host>', 'Include machine-local notes for a specific host')
782
+ .option('--all-hosts', 'Include machine-local notes from all hosts')
783
+ .option('--json', 'Output as JSON')
784
+ .action((options) => {
785
+ runRuntimeStatus(options);
786
+ });
787
+ // --- sync ---
788
+ program
789
+ .command('sync')
790
+ .description('Summarize memory changes and optionally commit')
791
+ .option('--commit', 'Create a local git commit')
792
+ .option('--message <message>', 'Custom commit message')
793
+ .option('--summary-only', 'Print summary only; skip git status and commit checks')
794
+ .option('--scope <scope>', 'Scope: all, state, config, project, inbox, archive, claims, runtime, runtime-local, trap-local')
795
+ .option('--include-machine-runtime', 'Include machine-local runtime memory in sync scope for all')
796
+ .option('--remote', 'Pull + push from/to remote memory repo in one step')
797
+ .action((options) => {
798
+ runSync({ ...options, remote: options.remote });
799
+ });
800
+ // --- check-constraints ---
801
+ program
802
+ .command('check-constraints')
803
+ .description('Check if staged files (or given files) violate active constraints')
804
+ .option('--staged', 'Check git staged files (git diff --cached --name-only)')
805
+ .option('--files <files...>', 'Explicit list of files to check')
806
+ .option('--json', 'Output as JSON')
807
+ .action((options) => {
808
+ runCheckConstraints({ staged: options.staged, files: options.files, json: options.json });
809
+ });
810
+ // --- install-hooks ---
811
+ program
812
+ .command('install-hooks')
813
+ .description('Install a Git pre-commit hook that blocks sensitive content in .brainclaw/ and checks active constraints')
814
+ .option('--force', 'Overwrite existing pre-commit hook')
815
+ .action((options) => {
816
+ runInstallHooks(options);
817
+ });
818
+ // --- diff ---
819
+ program
820
+ .command('diff')
821
+ .description('Show what changed in .brainclaw/ since a timestamp or last context read')
822
+ .option('--since <timestamp>', 'ISO 8601 timestamp to diff from')
823
+ .option('--json', 'Output as JSON')
824
+ .action((options) => {
825
+ runDiff(options);
826
+ });
827
+ // --- prune ---
828
+ program
829
+ .command('prune')
830
+ .description('Prune expired constraints and stale memory')
831
+ .option('--expired', 'Also prune expired runtime notes and traps')
832
+ .action((options) => {
833
+ runPrune(options);
834
+ });
835
+ // --- mcp ---
836
+ program
837
+ .command('mcp')
838
+ .description('Start the standalone MCP server over stdio')
839
+ .action(() => {
840
+ runMcp();
841
+ });
842
+ // --- set-trust ---
843
+ program
844
+ .command('set-trust <agent>')
845
+ .description('Set the trust level for a registered agent or manage circuit-breaker state')
846
+ .option('--level <level>', 'Trust level: observer, contributor, trusted, curator')
847
+ .option('--reset-breaker', 'Reset circuit-breaker suspension for the agent (restores auto-promote)')
848
+ .option('--json', 'Output as JSON')
849
+ .action((agent, options) => {
850
+ runSetTrust(agent, { level: options.level, resetBreaker: options.resetBreaker, json: options.json });
851
+ });
852
+ // --- session-start ---
853
+ program
854
+ .command('session-start')
855
+ .description('Start a memory session and capture initial context')
856
+ .option('--agent <agent>', 'Agent name (defaults to current configured agent)')
857
+ .option('--context <path>', 'Context target path for initial hash capture')
858
+ .option('--model <id>', 'Model identifier (e.g. claude-sonnet-4-6)')
859
+ .option('--json', 'Output as JSON')
860
+ .action((options) => {
861
+ runSessionStart(options);
862
+ });
863
+ // --- session-end ---
864
+ program
865
+ .command('session-end')
866
+ .description('End a memory session and optionally auto-reflect observations')
867
+ .option('--session <id>', 'Session ID (defaults to BRAINCLAW_SESSION_ID env var)')
868
+ .option('--agent <agent>', 'Agent name')
869
+ .option('--summary <text>', 'Session summary text')
870
+ .option('--auto-reflect', 'Auto-reflect session notes as pending candidates')
871
+ .option('--auto-release', 'Auto-release any active claims at session end')
872
+ .option('--reflect-handoff', 'Generate a handoff candidate from git commits since session start')
873
+ .option('--json', 'Output as JSON')
874
+ .action((options) => {
875
+ runSessionEnd({ ...options, autoReflect: options.autoReflect, autoRelease: options.autoRelease, reflectHandoff: options.reflectHandoff });
876
+ });
877
+ // --- whoami ---
878
+ program
879
+ .command('whoami')
880
+ .description('Show the current resolved agent identity and trust level')
881
+ .option('--json', 'Output as JSON')
882
+ .action((options) => {
883
+ runWhoami(options);
884
+ });
885
+ // --- search ---
886
+ program
887
+ .command('search <query>')
888
+ .description('Full-text search across project memory')
889
+ .option('--section <section>', 'Filter by section: constraints, decisions, traps, handoffs, plans')
890
+ .option('--since <timestamp>', 'ISO timestamp filter')
891
+ .option('--tag <tags...>', 'Filter by tags')
892
+ .option('--pending', 'Include pending candidates')
893
+ .option('--max-results <count>', 'Maximum results to return', parseInt)
894
+ .option('--json', 'Output as JSON')
895
+ .action((query, options) => {
896
+ runSearch(query, options);
897
+ });
898
+ // --- export ---
899
+ program
900
+ .command('export')
901
+ .description('Export memory as instructions for IDE/AI tools')
902
+ .option('--format <format>', 'Format: copilot-instructions, cursor-rules, agents-md, claude-md, gemini-md, windsurf, cline, roo, continue')
903
+ .option('--detect', 'Auto-detect agent environment and write to its native file')
904
+ .option('--write', 'Write to canonical file path instead of stdout (when --format is given); local files are gitignored by default')
905
+ .option('--shared', 'Keep the main exported instruction file versionable instead of auto-ignoring it (companions remain local)')
906
+ .option('--output <file>', 'Write to a specific file path instead of stdout')
907
+ .option('--project <project>', 'Project namespace filter')
908
+ .option('--agent <agent>', 'Agent name for agent-layer instructions')
909
+ .action((options) => {
910
+ runExport(options);
911
+ });
912
+ // --- hooks ---
913
+ program
914
+ .command('hooks')
915
+ .description('Write deterministic session-trigger hooks for Cursor (.cursor/rules/brainclaw-session.mdc) and Windsurf (.windsurfrules)')
916
+ .option('--target <target>', 'Which hooks to write: cursor, windsurf, all (default: all)')
917
+ .action((options) => {
918
+ runHooks(options);
919
+ });
920
+ // --- watch ---
921
+ program
922
+ .command('watch')
923
+ .description('Watch for memory changes and emit NDJSON events on stdout')
924
+ .option('--interval <seconds>', 'Poll interval in seconds', parseInt)
925
+ .option('--auto-claim', 'Auto-create advisory claims on first write to workspace files')
926
+ .option('--agent <name>', 'Agent name for auto-claim')
927
+ .action((options) => {
928
+ runWatch({ ...options, autoClaim: options.autoClaim });
929
+ });
930
+ // --- metrics ---
931
+ program
932
+ .command('metrics')
933
+ .description('Show memory health metrics dashboard')
934
+ .option('--json', 'Output as JSON')
935
+ .option('--since <timestamp>', 'Filter audit log stats from this ISO timestamp')
936
+ .action((options) => {
937
+ runMetrics(options);
938
+ });
939
+ // --- rollback ---
940
+ program
941
+ .command('rollback')
942
+ .description('Restore a memory item to a previous state from audit log')
943
+ .option('--audit-id <timestamp>', 'Audit log entry timestamp to roll back')
944
+ .option('--item-id <id>', 'Memory item ID to roll back (uses most recent audit entry with before-state)')
945
+ .option('--dry-run', 'Preview rollback without applying changes')
946
+ .option('--json', 'Output as JSON')
947
+ .action((options) => {
948
+ runRollback({ auditId: options.auditId, itemId: options.itemId, dryRun: options.dryRun, json: options.json });
949
+ });
950
+ // --- pull ---
951
+ program
952
+ .command('pull')
953
+ .description('Pull memory updates from a git remote')
954
+ .option('--remote <remote>', 'Remote name (defaults to origin)')
955
+ .option('--json', 'Output as JSON')
956
+ .action((options) => {
957
+ runPull(options);
958
+ });
959
+ // --- push ---
960
+ program
961
+ .command('push')
962
+ .description('Push memory updates to a git remote')
963
+ .option('--remote <remote>', 'Remote name (defaults to origin)')
964
+ .option('--message <message>', 'Custom commit message')
965
+ .option('--json', 'Output as JSON')
966
+ .action((options) => {
967
+ runPush(options);
968
+ });
969
+ // --- audit ---
970
+ program
971
+ .command('audit')
972
+ .description('View the append-only audit log of all memory mutations')
973
+ .option('--since <date>', 'Show entries since this ISO date')
974
+ .option('--actor <agent>', 'Filter by actor name or agent ID')
975
+ .option('--action <action>', 'Filter by action type (create, accept, reject, etc.)')
976
+ .option('--limit <n>', 'Show last N entries', parseInt)
977
+ .option('--json', 'Output as JSON')
978
+ .action((options) => {
979
+ runAuditCommand({ since: options.since, actor: options.actor, action: options.action, limit: options.limit, json: options.json });
980
+ });
981
+ // --- history ---
982
+ program
983
+ .command('history <id>')
984
+ .description('Show full mutation history of a memory item from the audit log')
985
+ .action((id) => {
986
+ runHistory(id);
987
+ });
988
+ // --- context-diff ---
989
+ program
990
+ .command('context-diff')
991
+ .description('Show what changed in memory since last context read, a session start, or a given timestamp')
992
+ .option('--since <date>', 'Show changes since this ISO date')
993
+ .option('--session <id>', 'Show changes since the start of this session')
994
+ .option('--json', 'Output as JSON')
995
+ .action((options) => {
996
+ runContextDiff({ since: options.since, session: options.session, json: options.json });
997
+ });
998
+ program
999
+ .command('capability <subcommand> [args...]')
1000
+ .description('Manage project capabilities (list, add, describe)')
1001
+ .option('--tag <tag>', 'Tag for categorization (repeatable)', (val, prev) => [...(prev || []), val])
1002
+ .option('--author <name>', 'Author name')
1003
+ .option('--store <target>', 'Store level: local (default), repo, workspace, user')
1004
+ .action((subcommand, args, options) => {
1005
+ runCapability(subcommand, args, {
1006
+ tag: options.tag,
1007
+ author: options.author,
1008
+ store: options.store,
1009
+ });
1010
+ });
1011
+ program
1012
+ .command('tool <subcommand> [args...]')
1013
+ .description('Manage project tools (list, add, describe, search)')
1014
+ .option('--tag <tag>', 'Tag for categorization (repeatable)', (val, prev) => [...(prev || []), val])
1015
+ .option('--type <type>', 'Tool type: workflow, validator, generator, utility, explorer')
1016
+ .option('--author <name>', 'Author name')
1017
+ .option('--store <target>', 'Store level: local (default), repo, workspace, user')
1018
+ .action((subcommand, args, options) => {
1019
+ runTool(subcommand, args, {
1020
+ tag: options.tag,
1021
+ type: options.type,
1022
+ author: options.author,
1023
+ store: options.store,
1024
+ });
1025
+ });
1026
+ program
1027
+ .command('explore')
1028
+ .description('Explore project capabilities and available tools')
1029
+ .option('--query <q>', 'Search for specific capability or tool')
1030
+ .action((options) => {
1031
+ runExplore({ query: options.query });
1032
+ });
1033
+ program.parseAsync(process.argv).catch((err) => {
1034
+ console.error(err);
1035
+ process.exit(1);
1036
+ });
1037
+ //# sourceMappingURL=cli.js.map