brainclaw 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -263
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli/register-capture.js +209 -0
- package/dist/cli/register-code-map.js +19 -0
- package/dist/cli/register-coordination.js +472 -0
- package/dist/cli/register-federation.js +258 -0
- package/dist/cli/register-lifecycle.js +436 -0
- package/dist/cli/register-memory-context.js +502 -0
- package/dist/cli/register-planning.js +167 -0
- package/dist/cli/register-review.js +149 -0
- package/dist/cli/shared.js +5 -0
- package/dist/cli.js +212 -2015
- package/dist/commands/dispatch-watch.js +25 -2
- package/dist/commands/harvest.js +31 -6
- package/dist/commands/mcp-catalog.js +1438 -0
- package/dist/commands/mcp-contract.js +33 -0
- package/dist/commands/mcp-presentation.js +27 -0
- package/dist/commands/mcp-read-handlers.js +72 -36
- package/dist/commands/mcp-write-admin.js +328 -0
- package/dist/commands/mcp-write-claims.js +864 -0
- package/dist/commands/mcp-write-coordination.js +1825 -0
- package/dist/commands/mcp-write-entities.js +620 -0
- package/dist/commands/mcp-write-memory.js +451 -0
- package/dist/commands/mcp-write-sequences.js +116 -0
- package/dist/commands/mcp-write-support.js +367 -0
- package/dist/commands/mcp.js +261 -5570
- package/dist/commands/update-handoff.js +28 -42
- package/dist/core/agent-capability.js +31 -14
- package/dist/core/agent-files.js +1 -1
- package/dist/core/agent-registry.js +51 -3
- package/dist/core/claims.js +18 -0
- package/dist/core/coordination.js +5 -2
- package/dist/core/cross-project.js +35 -1
- package/dist/core/dispatcher.js +34 -20
- package/dist/core/entity-operations.js +335 -12
- package/dist/core/entity-registry.js +72 -9
- package/dist/core/execution.js +28 -4
- package/dist/core/facade-schema.js +30 -4
- package/dist/core/federation-cloud.js +142 -11
- package/dist/core/federation-outbox.js +292 -0
- package/dist/core/federation-signing.js +115 -0
- package/dist/core/handoff-review.js +35 -0
- package/dist/core/io.js +6 -0
- package/dist/core/protocol-tool-policy.js +113 -0
- package/dist/core/review-loop-close.js +115 -0
- package/dist/core/schema.js +25 -2
- package/dist/core/security-detectors.js +35 -6
- package/dist/core/security.js +32 -12
- package/dist/core/worktree.js +98 -9
- package/dist/facts.js +13 -11
- package/dist/facts.json +12 -10
- package/docs/PROTOCOL.md +7 -3
- package/docs/concepts/coordinator-runbook.md +3 -0
- package/docs/concepts/dispatch-lifecycle.md +4 -4
- package/docs/concepts/loop-engine.md +3 -1
- package/docs/concepts/troubleshooting.md +1 -1
- package/docs/integrations/codex.md +3 -3
- package/docs/integrations/overview.md +1 -1
- package/docs/mcp-schema-changelog.md +153 -2
- package/docs/playbooks/orchestration.md +1 -1
- package/docs/product/entity-model-audit.md +3 -2
- package/docs/security.md +22 -1
- package/package.json +3 -1
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { runClaimResource } from '../commands/claim-resource.js';
|
|
2
|
+
import { runAssignmentResource } from '../commands/assignment-resource.js';
|
|
3
|
+
import { runListClaims } from '../commands/list-claims.js';
|
|
4
|
+
import { runReleaseClaim } from '../commands/release-claim.js';
|
|
5
|
+
import { runReleaseClaims } from '../commands/release-claims.js';
|
|
6
|
+
import { runAgentBoard } from '../commands/agent-board.js';
|
|
7
|
+
import { runWatch } from '../commands/watch.js';
|
|
8
|
+
import { runDispatchAnalysis, runDispatch, runDispatchReview } from '../commands/dispatch.js';
|
|
9
|
+
import { runDispatchWatch } from '../commands/dispatch-watch.js';
|
|
10
|
+
import { runInboxList, runInboxAck, runInboxArchive, runInboxSend, runInboxThread } from '../commands/inbox.js';
|
|
11
|
+
import { runCheckEvents } from '../commands/check-events.js';
|
|
12
|
+
import { runWorktreeCreate, runWorktreeList, runWorktreeRemove, runWorktreePrune, runWorktreeClean, runWorktreeMerge, runWorktreeCheck } from '../commands/worktree.js';
|
|
13
|
+
import { runQuestionsCommand } from '../commands/questions.js';
|
|
14
|
+
import { runReplyCommand } from '../commands/reply.js';
|
|
15
|
+
import { runRunProfile } from '../commands/run-profile.js';
|
|
16
|
+
function isCodevEnabled() {
|
|
17
|
+
return process.env.BRAINCLAW_ENABLE_CODEV === '1';
|
|
18
|
+
}
|
|
19
|
+
export function registerCoordinationCommands(program) {
|
|
20
|
+
// --- claim ---
|
|
21
|
+
program
|
|
22
|
+
.command('claim <subcommand> [args...]')
|
|
23
|
+
.description('Manage work claims (create, list, release)')
|
|
24
|
+
.option('--agent <agent>', 'Agent or person name; defaults to the configured current agent')
|
|
25
|
+
.option('--scope <scope>', 'Scope being claimed (e.g. file path, module)')
|
|
26
|
+
.option('--project <project>', 'Optional project namespace for this claim')
|
|
27
|
+
.option('--plan <id>', 'Optional linked plan item ID')
|
|
28
|
+
.option('--ttl <duration>', 'Auto-expire after duration: 30m, 2h, 8h, 1d')
|
|
29
|
+
.option('--all', 'Include released claims in list')
|
|
30
|
+
.option('--json', 'Output as JSON for list')
|
|
31
|
+
.option('--plan-status <status>', 'Optional linked plan status when releasing: todo, in_progress, blocked, done, dropped')
|
|
32
|
+
.option('--coordinator-override', 'Trusted+ only: release a claim owned by another agent')
|
|
33
|
+
.option('--store <target>', 'Target store level: local (default), repo, workspace')
|
|
34
|
+
.option('--local-only', 'Read from local store only for list (skip parent stores in chain)')
|
|
35
|
+
.action((subcommand, args, options) => {
|
|
36
|
+
runClaimResource(subcommand, args, {
|
|
37
|
+
...options,
|
|
38
|
+
planStatus: options.planStatus,
|
|
39
|
+
coordinatorOverride: options.coordinatorOverride,
|
|
40
|
+
localOnly: options.localOnly,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
// --- assignment ---
|
|
44
|
+
program
|
|
45
|
+
.command('assignment <subcommand> [args...]')
|
|
46
|
+
.description('Manage work assignments (list, show, update, cancel)')
|
|
47
|
+
.option('--json', 'Output as JSON for list/show')
|
|
48
|
+
.option('--all', 'Include terminal assignments in list')
|
|
49
|
+
.option('--status <status>', 'Status filter for list or target status for update')
|
|
50
|
+
.option('--agent <agent>', 'Filter by agent name')
|
|
51
|
+
.option('--claim <id>', 'Filter by linked claim ID')
|
|
52
|
+
.option('--plan <id>', 'Filter by linked plan ID')
|
|
53
|
+
.option('--sequence <id>', 'Filter by linked sequence ID')
|
|
54
|
+
.option('--reason <text>', 'Optional status reason for update/cancel')
|
|
55
|
+
.action((subcommand, args, options) => {
|
|
56
|
+
runAssignmentResource(subcommand, args, {
|
|
57
|
+
...options,
|
|
58
|
+
claim: options.claim,
|
|
59
|
+
plan: options.plan,
|
|
60
|
+
sequence: options.sequence,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
// --- list-claims ---
|
|
64
|
+
program
|
|
65
|
+
.command('list-claims')
|
|
66
|
+
.description('List work claims')
|
|
67
|
+
.option('--json', 'Output as JSON')
|
|
68
|
+
.option('--all', 'Include released claims')
|
|
69
|
+
.option('--project <project>', 'Filter by project namespace')
|
|
70
|
+
.option('--plan <id>', 'Filter by linked plan item')
|
|
71
|
+
.option('--agent <agent>', 'Filter by agent name')
|
|
72
|
+
.option('--local-only', 'Read from local store only (skip parent stores in chain)')
|
|
73
|
+
.action((options) => {
|
|
74
|
+
runListClaims({ ...options, localOnly: options.localOnly });
|
|
75
|
+
});
|
|
76
|
+
// --- release-claim ---
|
|
77
|
+
program
|
|
78
|
+
.command('release-claim <id>')
|
|
79
|
+
.description('Release a work claim')
|
|
80
|
+
.option('--plan-status <status>', 'Optional linked plan status: todo, in_progress, blocked, done, dropped')
|
|
81
|
+
.option('--coordinator-override', 'Trusted+ only: release a claim owned by another agent')
|
|
82
|
+
.action((id, options) => {
|
|
83
|
+
runReleaseClaim(id, { ...options, coordinatorOverride: options.coordinatorOverride });
|
|
84
|
+
});
|
|
85
|
+
// --- release-claims ---
|
|
86
|
+
program
|
|
87
|
+
.command('release-claims')
|
|
88
|
+
.description('Bulk-release claims whose scope overlaps with git-changed files')
|
|
89
|
+
.option('--from-git-diff', 'Use ORIG_HEAD..HEAD diff to detect changed files (post-merge)')
|
|
90
|
+
.option('--ref1 <ref>', 'First git ref (default: ORIG_HEAD)')
|
|
91
|
+
.option('--ref2 <ref>', 'Second git ref (default: HEAD)')
|
|
92
|
+
.action((options) => {
|
|
93
|
+
runReleaseClaims({ fromGitDiff: options.fromGitDiff, ref1: options.ref1, ref2: options.ref2 });
|
|
94
|
+
});
|
|
95
|
+
// --- agent-board ---
|
|
96
|
+
program
|
|
97
|
+
.command('agent-board')
|
|
98
|
+
.description('Show a coordination board for agents, plans, claims, handoffs, and instructions')
|
|
99
|
+
.option('--agent <agent>', 'Filter by agent name')
|
|
100
|
+
.option('--project <project>', 'Filter by project namespace')
|
|
101
|
+
.option('--for <target>', 'Infer project from target path')
|
|
102
|
+
.option('--host <host>', 'Include machine-local runtime notes for a specific host')
|
|
103
|
+
.option('--all-hosts', 'Include machine-local runtime notes from all hosts')
|
|
104
|
+
.option('--json', 'Output as JSON')
|
|
105
|
+
.option('--with-reputation', 'Include bounded reputation summaries when available')
|
|
106
|
+
.option('--capabilities', 'List all registered agents with their declared capabilities')
|
|
107
|
+
.option('--suggest <query>', 'Suggest agents whose capabilities match a query string')
|
|
108
|
+
.option('--include-session-meta', 'Include session_start/session_end runtime notes (hidden by default)')
|
|
109
|
+
.option('--all-agents', 'Show unfiltered board (supervisor mode — all claims, all agents)')
|
|
110
|
+
.action((options) => {
|
|
111
|
+
runAgentBoard(options);
|
|
112
|
+
});
|
|
113
|
+
// --- watch ---
|
|
114
|
+
program
|
|
115
|
+
.command('watch')
|
|
116
|
+
.description('Watch for memory changes and emit NDJSON events on stdout')
|
|
117
|
+
.option('--interval <seconds>', 'Poll interval in seconds', parseInt)
|
|
118
|
+
.option('--auto-claim', 'Auto-create advisory claims on first write to workspace files')
|
|
119
|
+
.option('--agent <name>', 'Agent name for auto-claim')
|
|
120
|
+
.action((options) => {
|
|
121
|
+
runWatch({ ...options, autoClaim: options.autoClaim });
|
|
122
|
+
});
|
|
123
|
+
// --- dispatch ---
|
|
124
|
+
const dispatchCmd = program
|
|
125
|
+
.command('dispatch')
|
|
126
|
+
.description('Local agent dispatcher — analyze lanes and assign work');
|
|
127
|
+
dispatchCmd
|
|
128
|
+
.command('analysis')
|
|
129
|
+
.description('Analyze the active sequence: show ready, active, blocked, and done lanes')
|
|
130
|
+
.option('--json', 'Output as JSON')
|
|
131
|
+
.action((options) => {
|
|
132
|
+
runDispatchAnalysis({ json: options.json });
|
|
133
|
+
});
|
|
134
|
+
dispatchCmd
|
|
135
|
+
.command('run')
|
|
136
|
+
.description('Run a dispatch cycle: assign ready lanes to available agents')
|
|
137
|
+
.option('--agents <names>', 'Comma-separated list of agents to dispatch to')
|
|
138
|
+
.option('--lanes <names>', 'Comma-separated list of lanes to dispatch')
|
|
139
|
+
.option('--max <n>', 'Maximum assignments', parseInt)
|
|
140
|
+
.option('--max-concurrency <n>', 'Opt-in cap on concurrent instances per host-binary (default: unlimited)', parseInt)
|
|
141
|
+
.option('--model <name>', 'Model to run, decoupled from agent identity (e.g. --model sonnet)')
|
|
142
|
+
.option('--dry', 'Preview assignments without sending messages')
|
|
143
|
+
.option('--spawn', 'Autonomously launch CLI agents with invoke templates')
|
|
144
|
+
.option('--agent <name>', 'Dispatcher agent name')
|
|
145
|
+
.option('--json', 'Output as JSON')
|
|
146
|
+
.action(async (options) => {
|
|
147
|
+
await runDispatch({
|
|
148
|
+
agents: options.agents,
|
|
149
|
+
lanes: options.lanes,
|
|
150
|
+
max: options.max,
|
|
151
|
+
maxConcurrency: options.maxConcurrency,
|
|
152
|
+
model: options.model,
|
|
153
|
+
dry: options.dry,
|
|
154
|
+
spawn: options.spawn,
|
|
155
|
+
agent: options.agent,
|
|
156
|
+
json: options.json,
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
dispatchCmd
|
|
160
|
+
.command('watch <target>')
|
|
161
|
+
.description('Block until a dispatched worker reaches a terminal state (asgn_/clm_/run_ id) — sentinels, lane-result, committed-clean and worker-process-gone heuristics')
|
|
162
|
+
.option('--interval <seconds>', 'Poll interval in seconds (default 60)', parseInt)
|
|
163
|
+
.option('--timeout <minutes>', 'Give up after N minutes (default 90, exit code 2)', parseInt)
|
|
164
|
+
.option('--base <ref>', 'Base ref for commits-ahead evidence (default master)')
|
|
165
|
+
.option('--json', 'One JSON object per poll line')
|
|
166
|
+
.action(async (target, options) => {
|
|
167
|
+
await runDispatchWatch(target, {
|
|
168
|
+
intervalSeconds: options.interval,
|
|
169
|
+
timeoutMinutes: options.timeout,
|
|
170
|
+
base: options.base,
|
|
171
|
+
json: options.json,
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
dispatchCmd
|
|
175
|
+
.command('review')
|
|
176
|
+
.description('Dispatch code reviews for completed handoffs')
|
|
177
|
+
.option('--handoff <id>', 'Specific handoff ID to review')
|
|
178
|
+
.option('--reviewer <name>', 'Specific reviewer agent')
|
|
179
|
+
.option('--spawn', 'Launch the reviewer CLI agent')
|
|
180
|
+
.option('--dry', 'Preview without sending')
|
|
181
|
+
.option('--agent <name>', 'Dispatcher agent name')
|
|
182
|
+
.option('--json', 'Output as JSON')
|
|
183
|
+
.action((options) => {
|
|
184
|
+
runDispatchReview({
|
|
185
|
+
handoff: options.handoff,
|
|
186
|
+
reviewer: options.reviewer,
|
|
187
|
+
spawn: options.spawn,
|
|
188
|
+
dry: options.dry,
|
|
189
|
+
agent: options.agent,
|
|
190
|
+
json: options.json,
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
// --- inbox ---
|
|
194
|
+
const inboxCmd = program
|
|
195
|
+
.command('inbox')
|
|
196
|
+
.description('Inter-agent messaging inbox');
|
|
197
|
+
inboxCmd
|
|
198
|
+
.command('list')
|
|
199
|
+
.description('List inbox messages (default: pending only)')
|
|
200
|
+
.option('--agent <name>', 'Agent name')
|
|
201
|
+
.option('--status <status>', 'Filter by status: pending, read, acknowledged, archived')
|
|
202
|
+
.option('--type <type>', 'Filter by type: assign, review, rfc, info, reply')
|
|
203
|
+
.option('--thread <id>', 'Filter by thread ID')
|
|
204
|
+
.option('--all', 'Show all messages, not just pending')
|
|
205
|
+
.option('--json', 'Output as JSON')
|
|
206
|
+
.option('--local-only', 'Read from local store only (skip parent stores in chain)')
|
|
207
|
+
.action((options) => {
|
|
208
|
+
runInboxList({ ...options, localOnly: options.localOnly });
|
|
209
|
+
});
|
|
210
|
+
inboxCmd
|
|
211
|
+
.command('ack <id>')
|
|
212
|
+
.description('Acknowledge a message')
|
|
213
|
+
.option('--agent <name>', 'Agent name')
|
|
214
|
+
.option('--json', 'Output as JSON')
|
|
215
|
+
.action((id, options) => {
|
|
216
|
+
runInboxAck(id, options);
|
|
217
|
+
});
|
|
218
|
+
inboxCmd
|
|
219
|
+
.command('archive <id>')
|
|
220
|
+
.description('Archive a message')
|
|
221
|
+
.option('--agent <name>', 'Agent name')
|
|
222
|
+
.option('--json', 'Output as JSON')
|
|
223
|
+
.action((id, options) => {
|
|
224
|
+
runInboxArchive(id, options);
|
|
225
|
+
});
|
|
226
|
+
inboxCmd
|
|
227
|
+
.command('send <to> <text>')
|
|
228
|
+
.description('Send a message to another agent')
|
|
229
|
+
.option('--type <type>', 'Message type: assign, review, rfc, info, reply (default: info)')
|
|
230
|
+
.option('--ref <id>', 'Reference to a plan, sequence, or other entity')
|
|
231
|
+
.option('--scope <path>', 'File scope')
|
|
232
|
+
.option('--thread <id>', 'Thread ID for conversations')
|
|
233
|
+
.option('--ack', 'Require acknowledgment')
|
|
234
|
+
.option('--agent <name>', 'Sender agent name')
|
|
235
|
+
.option('--json', 'Output as JSON')
|
|
236
|
+
.action((to, text, options) => {
|
|
237
|
+
runInboxSend(to, text, options);
|
|
238
|
+
});
|
|
239
|
+
inboxCmd
|
|
240
|
+
.command('thread <id>')
|
|
241
|
+
.description('Show all messages in a thread')
|
|
242
|
+
.option('--json', 'Output as JSON')
|
|
243
|
+
.action((id, options) => {
|
|
244
|
+
runInboxThread(id, options);
|
|
245
|
+
});
|
|
246
|
+
// --- check-events ---
|
|
247
|
+
program
|
|
248
|
+
.command('check-events')
|
|
249
|
+
.description('Show unseen events from the event bus (events.jsonl) for the current agent')
|
|
250
|
+
.option('--agent <name>', 'Agent name for cursor lookup (default: auto-detected)')
|
|
251
|
+
.option('--json', 'Output as JSON')
|
|
252
|
+
.action((options) => {
|
|
253
|
+
runCheckEvents(options);
|
|
254
|
+
});
|
|
255
|
+
const worktreeCmd = program
|
|
256
|
+
.command('worktree')
|
|
257
|
+
.description('Manage git worktrees for parallel agent isolation');
|
|
258
|
+
worktreeCmd
|
|
259
|
+
.command('create <branch>')
|
|
260
|
+
.description('Create a linked git worktree for a given branch')
|
|
261
|
+
.option('--session-id <id>', 'Associate this worktree with a brainclaw session')
|
|
262
|
+
.option('--agent <name>', 'Associate this worktree with an agent name')
|
|
263
|
+
.action((branch, options) => {
|
|
264
|
+
const globalOpts = program.opts();
|
|
265
|
+
runWorktreeCreate({ branch, sessionId: options.sessionId, agent: options.agent, cwd: globalOpts.cwd });
|
|
266
|
+
});
|
|
267
|
+
worktreeCmd
|
|
268
|
+
.command('list')
|
|
269
|
+
.description('List all git worktrees for this project')
|
|
270
|
+
.action(() => {
|
|
271
|
+
const globalOpts = program.opts();
|
|
272
|
+
runWorktreeList({ cwd: globalOpts.cwd });
|
|
273
|
+
});
|
|
274
|
+
worktreeCmd
|
|
275
|
+
.command('remove <path>')
|
|
276
|
+
.description('Remove a linked git worktree')
|
|
277
|
+
.option('--force', 'Force removal even with uncommitted changes')
|
|
278
|
+
.action((worktreePath, options) => {
|
|
279
|
+
const globalOpts = program.opts();
|
|
280
|
+
runWorktreeRemove({ path: worktreePath, force: options.force, cwd: globalOpts.cwd });
|
|
281
|
+
});
|
|
282
|
+
worktreeCmd
|
|
283
|
+
.command('prune')
|
|
284
|
+
.description('Prune stale worktree administrative files')
|
|
285
|
+
.action(() => {
|
|
286
|
+
const globalOpts = program.opts();
|
|
287
|
+
runWorktreePrune({ cwd: globalOpts.cwd });
|
|
288
|
+
});
|
|
289
|
+
worktreeCmd
|
|
290
|
+
.command('clean')
|
|
291
|
+
.description('Remove worktrees whose branch is fully merged and orphan worktree directories')
|
|
292
|
+
.option('--force', 'Force removal even with uncommitted changes')
|
|
293
|
+
.option('--dry-run', 'Show what would be removed without actually removing')
|
|
294
|
+
.action((options) => {
|
|
295
|
+
const globalOpts = program.opts();
|
|
296
|
+
runWorktreeClean({ force: options.force, dryRun: options.dryRun, cwd: globalOpts.cwd });
|
|
297
|
+
});
|
|
298
|
+
worktreeCmd
|
|
299
|
+
.command('merge <branch>')
|
|
300
|
+
.description('Merge a worktree branch with auto-restoration of parasitic deletions')
|
|
301
|
+
.option('-m, --message <message>', 'Merge commit message')
|
|
302
|
+
.option('--dry-run', 'Show what would be merged without committing')
|
|
303
|
+
.action((branch, options) => {
|
|
304
|
+
const globalOpts = program.opts();
|
|
305
|
+
runWorktreeMerge({ branch, message: options.message, dryRun: options.dryRun, cwd: globalOpts.cwd });
|
|
306
|
+
});
|
|
307
|
+
worktreeCmd
|
|
308
|
+
.command('check')
|
|
309
|
+
.description('Pre-merge conflict detection: which parallel lanes touch overlapping files, and who owns them (exit 3 if overlaps found)')
|
|
310
|
+
.option('--base <ref>', 'Base ref each lane is diffed against (default: current branch)')
|
|
311
|
+
.option('--json', 'Emit the full risk report as JSON')
|
|
312
|
+
.action((options) => {
|
|
313
|
+
const globalOpts = program.opts();
|
|
314
|
+
runWorktreeCheck({ baseRef: options.base, json: options.json, cwd: globalOpts.cwd });
|
|
315
|
+
});
|
|
316
|
+
// --- codev (legacy experimental) ---
|
|
317
|
+
if (isCodevEnabled()) {
|
|
318
|
+
program
|
|
319
|
+
.command('codev [topic]')
|
|
320
|
+
.description('Experimental legacy ideation session using persona-based consultation')
|
|
321
|
+
.option('--personas <tier>', 'Persona tier: tier1 (default), tier2, or list', 'tier1')
|
|
322
|
+
.option('--checkpoint', 'Pause after clarification for human input')
|
|
323
|
+
.option('--spawn', 'Spawn each consultant as an agent CLI instance')
|
|
324
|
+
.option('--fresh', 'Clear cached responses before starting a new run')
|
|
325
|
+
.option('--agents <list>', 'Comma-separated agent names for spawn (e.g. claude-code,codex,antigravity). Default: auto-detect')
|
|
326
|
+
.option('--rounds <N>', 'Number of discussion rounds in spawn mode (default 3, min 2)', '3')
|
|
327
|
+
.option('--target-duration <seconds>', 'Target duration per round indicated to agents (default 120)', '120')
|
|
328
|
+
.option('--quorum <N>', 'Advance to next round after N agent responses (default: all)')
|
|
329
|
+
.option('--model-map <map>', 'Per-persona model overrides, e.g. simplificateur:sonnet,stratege:opus')
|
|
330
|
+
.option('--metrics', 'Display response timing metrics at end of session')
|
|
331
|
+
.option('--json', 'Output as JSON')
|
|
332
|
+
.action(async (topic, options) => {
|
|
333
|
+
const globalOpts = program.opts();
|
|
334
|
+
const { runCodev } = await import('../commands/codev.js');
|
|
335
|
+
runCodev(topic, {
|
|
336
|
+
...options,
|
|
337
|
+
rounds: parseInt(options.rounds, 10),
|
|
338
|
+
targetDuration: parseInt(options.targetDuration, 10),
|
|
339
|
+
quorum: options.quorum != null ? parseInt(options.quorum, 10) : undefined,
|
|
340
|
+
cwd: globalOpts.cwd,
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
program
|
|
344
|
+
.command('codev-metrics <thread>')
|
|
345
|
+
.description('Show per-agent avg/p95 response metrics for an experimental CoDev thread')
|
|
346
|
+
.option('--json', 'Output as JSON')
|
|
347
|
+
.action(async (thread, options) => {
|
|
348
|
+
const globalOpts = program.opts();
|
|
349
|
+
const { runCodevMetrics } = await import('../commands/codev.js');
|
|
350
|
+
runCodevMetrics(thread, { ...options, cwd: globalOpts.cwd });
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
// --- questions (operator-question artifacts across loops; pln#508 step 4) ---
|
|
354
|
+
program
|
|
355
|
+
.command('questions')
|
|
356
|
+
.description('List pending operator_question artifacts across loops in the current project')
|
|
357
|
+
.option('--loop <loop_id>', 'Filter to a single loop')
|
|
358
|
+
.option('--status <status>', 'Filter by status: awaiting (default), answered, timed_out', 'awaiting')
|
|
359
|
+
.option('--mine', 'Filter to questions targeted at the current agent (v1 heuristic: humans see all awaiting)')
|
|
360
|
+
.option('--json', 'Output as JSON')
|
|
361
|
+
.action((options) => {
|
|
362
|
+
const globalOpts = program.opts();
|
|
363
|
+
const status = options.status;
|
|
364
|
+
if (!['awaiting', 'answered', 'timed_out'].includes(status)) {
|
|
365
|
+
console.error(`Error: --status must be one of awaiting|answered|timed_out (got "${options.status}")`);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
runQuestionsCommand({
|
|
369
|
+
loop: options.loop,
|
|
370
|
+
status,
|
|
371
|
+
mine: options.mine,
|
|
372
|
+
json: options.json,
|
|
373
|
+
}, globalOpts.cwd);
|
|
374
|
+
});
|
|
375
|
+
// --- bootstrap-loop (open/join/status/cancel a bootstrap loop; pln#513 step 3) ---
|
|
376
|
+
program
|
|
377
|
+
.command('bootstrap-loop')
|
|
378
|
+
.description('Open or join a bootstrap loop on the current project, or query its status')
|
|
379
|
+
.option('--status', 'Report current state')
|
|
380
|
+
.option('--cancel', 'Cancel the active bootstrap loop')
|
|
381
|
+
.option('--yes', 'Skip confirmation prompts')
|
|
382
|
+
.option('--json', 'Machine-readable output')
|
|
383
|
+
.action(async (options) => {
|
|
384
|
+
const globalOpts = program.opts();
|
|
385
|
+
const { runBootstrapLoopCommand } = await import('../commands/bootstrap-loop.js');
|
|
386
|
+
await runBootstrapLoopCommand(options, globalOpts.cwd);
|
|
387
|
+
});
|
|
388
|
+
// --- loop (drive loop turn verbs; pln#517 step 2) ---
|
|
389
|
+
const loopCmd = program
|
|
390
|
+
.command('loop')
|
|
391
|
+
.description('Drive a loop turn (turn / complete-turn / advance / add-artifact)');
|
|
392
|
+
loopCmd
|
|
393
|
+
.command('turn <loop_id>')
|
|
394
|
+
.description('Issue a turn assignment on a slot')
|
|
395
|
+
.requiredOption('--slot <slot_id>', 'Target slot id (lsl_...)')
|
|
396
|
+
.option('--input <text>', 'Free-form input passed to the slot')
|
|
397
|
+
.option('--role <role>', 'Slot role (resolves the first non-done slot with that role)')
|
|
398
|
+
.option('--assignment-id <id>', 'Dispatcher-provided assignment id to record on the slot')
|
|
399
|
+
.option('--json', 'Machine-readable output')
|
|
400
|
+
.action(async (loop_id, options) => {
|
|
401
|
+
const globalOpts = program.opts();
|
|
402
|
+
const { runLoopCommand } = await import('../commands/loop.js');
|
|
403
|
+
await runLoopCommand('turn', { loop_id }, options, globalOpts.cwd);
|
|
404
|
+
});
|
|
405
|
+
loopCmd
|
|
406
|
+
.command('complete-turn <loop_id>')
|
|
407
|
+
.description('Complete a slot turn')
|
|
408
|
+
.requiredOption('--slot <slot_id>', 'Target slot id (lsl_...)')
|
|
409
|
+
.requiredOption('--outcome <outcome>', 'Turn outcome: done, failed, or cancelled')
|
|
410
|
+
.option('--failure-reason <text>', 'Reason when outcome is failed')
|
|
411
|
+
.option('--artifact <json>', 'JSON object payload for an artifact to attach')
|
|
412
|
+
.option('--json', 'Machine-readable output')
|
|
413
|
+
.action(async (loop_id, options) => {
|
|
414
|
+
const globalOpts = program.opts();
|
|
415
|
+
const { runLoopCommand } = await import('../commands/loop.js');
|
|
416
|
+
await runLoopCommand('complete-turn', { loop_id }, options, globalOpts.cwd);
|
|
417
|
+
});
|
|
418
|
+
loopCmd
|
|
419
|
+
.command('advance <loop_id>')
|
|
420
|
+
.description('Advance a loop to its next phase')
|
|
421
|
+
.option('--to-phase <name>', 'Explicit target phase')
|
|
422
|
+
.option('--force', 'Bypass phase gate checks')
|
|
423
|
+
.option('--reason <text>', 'Reason to record on the phase advance event')
|
|
424
|
+
.option('--json', 'Machine-readable output')
|
|
425
|
+
.action(async (loop_id, options) => {
|
|
426
|
+
const globalOpts = program.opts();
|
|
427
|
+
const { runLoopCommand } = await import('../commands/loop.js');
|
|
428
|
+
await runLoopCommand('advance', { loop_id }, options, globalOpts.cwd);
|
|
429
|
+
});
|
|
430
|
+
loopCmd
|
|
431
|
+
.command('add-artifact <loop_id>')
|
|
432
|
+
.description('Attach an artifact to a loop')
|
|
433
|
+
.requiredOption('--phase <phase>', 'Artifact phase')
|
|
434
|
+
.requiredOption('--type <type>', 'Artifact type')
|
|
435
|
+
.requiredOption('--body <json-or-text>', 'Artifact body as JSON or text')
|
|
436
|
+
.option('--produced-by <agent>', 'Agent that produced the artifact')
|
|
437
|
+
.option('--ref <ref>', 'JSON ref object, e.g. {"kind":"plan","id":"pln_..."}')
|
|
438
|
+
.option('--json', 'Machine-readable output')
|
|
439
|
+
.action(async (loop_id, options) => {
|
|
440
|
+
const globalOpts = program.opts();
|
|
441
|
+
const { runLoopCommand } = await import('../commands/loop.js');
|
|
442
|
+
await runLoopCommand('add-artifact', { loop_id }, options, globalOpts.cwd);
|
|
443
|
+
});
|
|
444
|
+
// --- reply (provide_input to an operator_question; pln#508 step 4) ---
|
|
445
|
+
program
|
|
446
|
+
.command('reply <qst_id>')
|
|
447
|
+
.description('Resolve an operator_question artifact (wraps bclaw_loop.provide_input)')
|
|
448
|
+
.option('--answer <text>', 'Free-form answer text')
|
|
449
|
+
.option('--choose <option_id>', 'Pick one of the question\'s structured options[].id')
|
|
450
|
+
.option('--skip', 'Materialize the question\'s suggested_default')
|
|
451
|
+
.option('--json', 'Output as JSON')
|
|
452
|
+
.action((qstId, options) => {
|
|
453
|
+
const globalOpts = program.opts();
|
|
454
|
+
runReplyCommand(qstId, {
|
|
455
|
+
answer: options.answer,
|
|
456
|
+
choose: options.choose,
|
|
457
|
+
skip: options.skip,
|
|
458
|
+
json: options.json,
|
|
459
|
+
}, globalOpts.cwd);
|
|
460
|
+
});
|
|
461
|
+
// --- run (agent profiles) ---
|
|
462
|
+
program
|
|
463
|
+
.command('run [profile-name]')
|
|
464
|
+
.description('Run an agent profile (list profiles if no name given)')
|
|
465
|
+
.option('--dry', 'Print the resolved command without executing')
|
|
466
|
+
.option('--agent <agent>', 'Override the invoke template with a known agent')
|
|
467
|
+
.action((profileName, options) => {
|
|
468
|
+
const globalOpts = program.opts();
|
|
469
|
+
runRunProfile(profileName, { ...options, cwd: globalOpts.cwd });
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
//# sourceMappingURL=register-coordination.js.map
|