sdd-agent-platform 0.1.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 +405 -0
- package/dist/packages/cli/src/main.d.ts +2 -0
- package/dist/packages/cli/src/main.js +1499 -0
- package/dist/packages/cli/src/main.js.map +1 -0
- package/dist/packages/core/src/ai-tools.d.ts +50 -0
- package/dist/packages/core/src/ai-tools.js +223 -0
- package/dist/packages/core/src/ai-tools.js.map +1 -0
- package/dist/packages/core/src/index.d.ts +1016 -0
- package/dist/packages/core/src/index.js +4824 -0
- package/dist/packages/core/src/index.js.map +1 -0
- package/dist/packages/core/src/instructions.d.ts +14 -0
- package/dist/packages/core/src/instructions.js +117 -0
- package/dist/packages/core/src/instructions.js.map +1 -0
- package/package.json +52 -0
- package/tsconfig.build.json +6 -0
|
@@ -0,0 +1,1499 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { archiveRun, applyAiToolEntries, applySyncBack, createWorktreeLifecycle, createRun, doctor, evaluateLifecycleDecisionGate, evaluateGovernancePolicy, getProjectStatus, getDelegationStateMachine, getSddInstructions, initProject, inspectRun, inspectSddTask, inspectToolPluginContract, inspectToolCapability, inspectDelegationQueueItem, inspectSyncBack, inspectTaskGraph, inspectWavePlan, inspectWaveExecutor, inspectBackgroundExecutor, inspectArtifactResultIngestions, inspectWorktreeLifecycle, inspectWorkerAdapterContract, inspectWorktreeIsolation, inspectGovernancePolicy, keepWorktreeLifecycle, removeWorktreeLifecycle, listRuns, rebuildLocalRunIndex, inspectLocalRunIndex, queryLocalRunIndex, listToolPluginContracts, listToolCapabilities, listDelegationQueueItems, listWorkerAdapterContracts, ingestArtifactResult, parseSddBranch, readRunState, recordLifecycleDecision, renderDoctorReport, renderGoalVerifyResult, renderLifecycleDecisionGate, renderSddResultArtifactTemplate, renderSddInstructions, renderSingleTaskLoopResult, renderTaskGapReport, renderTaskInspect, renderTaskList, runGoalVerify, runSingleTaskLoop, runBackgroundExecutor, runWaveExecutor, SDD_VERSION, summarizeAiProjectionStatus, validateSddResultArtifact, } from '../../core/src/index.js';
|
|
3
|
+
async function main(args) {
|
|
4
|
+
const projectRoot = process.cwd();
|
|
5
|
+
const [command, subcommand, ...rest] = args;
|
|
6
|
+
if (!command || command === '--help' || command === '-h') {
|
|
7
|
+
return {
|
|
8
|
+
exitCode: 0,
|
|
9
|
+
output: helpText()
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (command === '--version' || command === '-v') {
|
|
13
|
+
return {
|
|
14
|
+
exitCode: 0,
|
|
15
|
+
output: SDD_VERSION
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (command === 'init') {
|
|
19
|
+
const initArgs = [subcommand, ...rest].filter(Boolean);
|
|
20
|
+
const force = initArgs.includes('--force');
|
|
21
|
+
const aiTool = readAiToolSelection(initArgs, true);
|
|
22
|
+
const branch = readOption(initArgs, '--branch') ?? 'master';
|
|
23
|
+
const scaffoldDocuments = !initArgs.includes('--no-scaffold-docs');
|
|
24
|
+
const result = await initProject(projectRoot, { force, aiTool, branch, scaffoldDocuments });
|
|
25
|
+
return {
|
|
26
|
+
exitCode: 0,
|
|
27
|
+
output: JSON.stringify({ command: 'init', ...result }, null, 2)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (command === 'update') {
|
|
31
|
+
const updateArgs = [subcommand, ...rest].filter(Boolean);
|
|
32
|
+
const check = updateArgs.includes('--check');
|
|
33
|
+
const aiTool = readAiToolSelection(updateArgs, false);
|
|
34
|
+
const results = await applyAiToolEntries(projectRoot, { tool: aiTool, check });
|
|
35
|
+
const status = summarizeAiProjectionStatus(results);
|
|
36
|
+
return {
|
|
37
|
+
exitCode: status === 'FAIL' ? 1 : 0,
|
|
38
|
+
output: JSON.stringify({ command: 'update', check, status, aiTools: results }, null, 2)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (command === 'instructions') {
|
|
42
|
+
const instructionArgs = [subcommand, ...rest].filter(Boolean);
|
|
43
|
+
const action = instructionArgs.find((item) => !item.startsWith('--')) ?? 'overview';
|
|
44
|
+
const payload = getSddInstructions(action);
|
|
45
|
+
const json = instructionArgs.includes('--json');
|
|
46
|
+
return {
|
|
47
|
+
exitCode: 0,
|
|
48
|
+
output: json ? JSON.stringify(payload, null, 2) : renderSddInstructions(payload)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (command === 'doctor') {
|
|
52
|
+
const doctorArgs = [subcommand, ...rest].filter(Boolean);
|
|
53
|
+
if (doctorArgs.includes('--latest-only') && doctorArgs.includes('--all-runs')) {
|
|
54
|
+
return {
|
|
55
|
+
exitCode: 2,
|
|
56
|
+
error: 'Usage: sdd doctor [--latest-only] [--all-runs] (choose only one scope flag)'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const report = await doctor(projectRoot, {
|
|
60
|
+
latestOnly: doctorArgs.includes('--latest-only'),
|
|
61
|
+
allRuns: doctorArgs.includes('--all-runs')
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
exitCode: report.status === 'FAIL' ? 1 : 0,
|
|
65
|
+
output: renderDoctorReport(report)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (command === 'status') {
|
|
69
|
+
const statusArgs = [subcommand, ...rest].filter(Boolean);
|
|
70
|
+
const result = await getProjectStatus(projectRoot, { branch: readOption(statusArgs, '--branch') ?? 'master' });
|
|
71
|
+
const json = statusArgs.includes('--json');
|
|
72
|
+
return {
|
|
73
|
+
exitCode: result.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
74
|
+
output: json ? JSON.stringify(result, null, 2) : renderProjectStatus(result)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (command === 'run' && subcommand === 'create') {
|
|
78
|
+
const state = await createRun(projectRoot);
|
|
79
|
+
return {
|
|
80
|
+
exitCode: 0,
|
|
81
|
+
output: JSON.stringify({ runId: state.runId, statePath: `.sdd/runs/${state.runId}/state.json`, eventLogPath: `.sdd/runs/${state.runId}/events.jsonl` }, null, 2)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (command === 'run' && subcommand === 'status') {
|
|
85
|
+
const runId = rest[0];
|
|
86
|
+
if (!runId) {
|
|
87
|
+
return {
|
|
88
|
+
exitCode: 2,
|
|
89
|
+
error: 'Usage: sdd run status <run_id>'
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const state = await readRunState(projectRoot, runId);
|
|
93
|
+
return {
|
|
94
|
+
exitCode: 0,
|
|
95
|
+
output: JSON.stringify({ runId: state.runId, status: state.status, phase: state.phase, currentTask: state.currentTask, updatedAt: state.updatedAt }, null, 2)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (command === 'run' && subcommand === 'list') {
|
|
99
|
+
const runs = await listRuns(projectRoot);
|
|
100
|
+
const json = rest.includes('--json');
|
|
101
|
+
return {
|
|
102
|
+
exitCode: 0,
|
|
103
|
+
output: json ? JSON.stringify(runs, null, 2) : renderRunList(runs)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (command === 'run' && subcommand === 'index') {
|
|
107
|
+
const action = rest[0];
|
|
108
|
+
const json = rest.includes('--json');
|
|
109
|
+
if (action === 'rebuild') {
|
|
110
|
+
const index = await rebuildLocalRunIndex(projectRoot);
|
|
111
|
+
return {
|
|
112
|
+
exitCode: 0,
|
|
113
|
+
output: json ? JSON.stringify(index, null, 2) : renderLocalRunIndex(index)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (action === 'inspect') {
|
|
117
|
+
const inspection = await inspectLocalRunIndex(projectRoot);
|
|
118
|
+
return {
|
|
119
|
+
exitCode: inspection.valid ? 0 : 1,
|
|
120
|
+
output: json ? JSON.stringify(inspection, null, 2) : renderLocalRunIndexInspection(inspection)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (action === 'query') {
|
|
124
|
+
const status = readRunStatus(rest, '--status');
|
|
125
|
+
if (readOption(rest, '--status') && !status) {
|
|
126
|
+
return {
|
|
127
|
+
exitCode: 2,
|
|
128
|
+
error: 'Usage: sdd run index query [--run <run_id>] [--task <task_id>] [--status created|running|completed|blocked|failed|archived] [--artifact <path>] [--json]'
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const index = await queryLocalRunIndex(projectRoot, {
|
|
132
|
+
runId: readOption(rest, '--run') ?? undefined,
|
|
133
|
+
taskId: readOption(rest, '--task') ?? undefined,
|
|
134
|
+
status: status ?? undefined,
|
|
135
|
+
artifact: readOption(rest, '--artifact') ?? undefined
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
exitCode: 0,
|
|
139
|
+
output: json ? JSON.stringify(index, null, 2) : renderLocalRunIndex(index)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
exitCode: 2,
|
|
144
|
+
error: 'Usage: sdd run index rebuild|inspect|query [options]'
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (command === 'run' && subcommand === 'inspect') {
|
|
148
|
+
const runId = rest[0];
|
|
149
|
+
if (!runId) {
|
|
150
|
+
return {
|
|
151
|
+
exitCode: 2,
|
|
152
|
+
error: 'Usage: sdd run inspect <run_id> [--json]'
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const result = await inspectRun(projectRoot, runId);
|
|
156
|
+
const json = rest.includes('--json');
|
|
157
|
+
return {
|
|
158
|
+
exitCode: 0,
|
|
159
|
+
output: json ? JSON.stringify(result, null, 2) : renderRunInspection(result)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (command === 'run' && subcommand === 'archive') {
|
|
163
|
+
const runId = rest[0];
|
|
164
|
+
if (!runId) {
|
|
165
|
+
return {
|
|
166
|
+
exitCode: 2,
|
|
167
|
+
error: 'Usage: sdd run archive <run_id> [--reason <text>]'
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const state = await archiveRun(projectRoot, runId, { reason: readOption(rest, '--reason') ?? undefined });
|
|
171
|
+
return {
|
|
172
|
+
exitCode: 0,
|
|
173
|
+
output: JSON.stringify({ runId: state.runId, status: state.status, updatedAt: state.updatedAt }, null, 2)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (command === 'sync-back' && subcommand === 'inspect') {
|
|
177
|
+
const runId = rest[0];
|
|
178
|
+
if (!runId) {
|
|
179
|
+
return {
|
|
180
|
+
exitCode: 2,
|
|
181
|
+
error: 'Usage: sdd sync-back inspect <run_id> [--branch <branch>] [--task <task_id>] [--json]'
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const result = await inspectSyncBack(projectRoot, {
|
|
185
|
+
runId,
|
|
186
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
187
|
+
taskId: readOption(rest, '--task') ?? undefined
|
|
188
|
+
});
|
|
189
|
+
const json = rest.includes('--json');
|
|
190
|
+
return {
|
|
191
|
+
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
192
|
+
output: json ? JSON.stringify(result, null, 2) : renderSyncBackInspection(result)
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (command === 'sync-back' && subcommand === 'apply') {
|
|
196
|
+
const runId = rest[0];
|
|
197
|
+
if (!runId) {
|
|
198
|
+
return {
|
|
199
|
+
exitCode: 2,
|
|
200
|
+
error: 'Usage: sdd sync-back apply <run_id> [--branch <branch>] [--task <task_id>] [--approved] [--json]'
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const result = await applySyncBack(projectRoot, {
|
|
204
|
+
runId,
|
|
205
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
206
|
+
taskId: readOption(rest, '--task') ?? undefined,
|
|
207
|
+
approved: rest.includes('--approved')
|
|
208
|
+
});
|
|
209
|
+
const json = rest.includes('--json');
|
|
210
|
+
return {
|
|
211
|
+
exitCode: 0,
|
|
212
|
+
output: json ? JSON.stringify(result, null, 2) : renderSyncBackApplyResult(result)
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
if (command === 'tasks' && subcommand === 'format') {
|
|
216
|
+
return {
|
|
217
|
+
exitCode: 0,
|
|
218
|
+
output: taskFormatText()
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (command === 'tasks' && subcommand === 'list') {
|
|
222
|
+
const model = await parseSddBranch(projectRoot, readOption(rest, '--branch') ?? 'master');
|
|
223
|
+
return {
|
|
224
|
+
exitCode: model.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
225
|
+
output: renderTaskList(model)
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
if (command === 'tasks' && subcommand === 'inspect') {
|
|
229
|
+
const taskId = rest.find((item) => !item.startsWith('--'));
|
|
230
|
+
if (!taskId) {
|
|
231
|
+
return {
|
|
232
|
+
exitCode: 2,
|
|
233
|
+
error: 'Usage: sdd tasks inspect <task_id> [--branch <branch>]'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const model = await parseSddBranch(projectRoot, readOption(rest, '--branch') ?? 'master');
|
|
237
|
+
const result = inspectSddTask(model, taskId);
|
|
238
|
+
if (!result.task && result.gaps.length === 0) {
|
|
239
|
+
return {
|
|
240
|
+
exitCode: 1,
|
|
241
|
+
error: `Task not found: ${taskId}`
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
exitCode: result.task === null || result.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
246
|
+
output: renderTaskInspect(result.task, result.gaps)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
if (command === 'tasks' && subcommand === 'gaps') {
|
|
250
|
+
const model = await parseSddBranch(projectRoot, readOption(rest, '--branch') ?? 'master');
|
|
251
|
+
return {
|
|
252
|
+
exitCode: model.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
253
|
+
output: renderTaskGapReport(model)
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (command === 'lifecycle' && subcommand === 'decide') {
|
|
257
|
+
const result = evaluateLifecycleDecisionGate(readLifecycleSignalOptions(rest));
|
|
258
|
+
const runId = readOption(rest, '--run');
|
|
259
|
+
if (runId) {
|
|
260
|
+
await recordLifecycleDecision(projectRoot, runId, result.record);
|
|
261
|
+
}
|
|
262
|
+
const json = rest.includes('--json');
|
|
263
|
+
return {
|
|
264
|
+
exitCode: 0,
|
|
265
|
+
output: json ? JSON.stringify({ ...result, recordedRunId: runId ?? null }, null, 2) : `${renderLifecycleDecisionGate(result)}${runId ? `\nrecorded_run=${runId}` : ''}`
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (command === 'do' && subcommand === 'task') {
|
|
269
|
+
const taskId = rest.find((item) => !item.startsWith('--'));
|
|
270
|
+
if (!taskId) {
|
|
271
|
+
return {
|
|
272
|
+
exitCode: 2,
|
|
273
|
+
error: 'Usage: sdd do task <task_id> [--branch <branch>] [--run <run_id>] [--implement-artifact artifacts/path.md] [--review-artifact artifacts/path.md] [--debug-artifact artifacts/path.md] [--validation-artifact artifacts/path.md]'
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
const result = await runSingleTaskLoop(projectRoot, {
|
|
277
|
+
taskId,
|
|
278
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
279
|
+
runId: readOption(rest, '--run') ?? undefined,
|
|
280
|
+
implementArtifact: readOption(rest, '--implement-artifact') ?? undefined,
|
|
281
|
+
reviewArtifact: readOption(rest, '--review-artifact') ?? undefined,
|
|
282
|
+
debugArtifact: readOption(rest, '--debug-artifact') ?? undefined,
|
|
283
|
+
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined
|
|
284
|
+
});
|
|
285
|
+
return {
|
|
286
|
+
exitCode: result.status === 'completed' ? 0 : 1,
|
|
287
|
+
output: renderSingleTaskLoopResult(result)
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (command === 'verify' && subcommand === 'task') {
|
|
291
|
+
const taskId = rest.find((item) => !item.startsWith('--'));
|
|
292
|
+
const runId = readOption(rest, '--run');
|
|
293
|
+
if (!taskId || !runId) {
|
|
294
|
+
return {
|
|
295
|
+
exitCode: 2,
|
|
296
|
+
error: 'Usage: sdd verify task <task_id> --run <run_id> [--branch <branch>] [--review-artifact artifacts/path.md] [--validation-artifact artifacts/path.md]'
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const result = await runGoalVerify(projectRoot, {
|
|
300
|
+
taskId,
|
|
301
|
+
runId,
|
|
302
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
303
|
+
reviewArtifact: readOption(rest, '--review-artifact') ?? undefined,
|
|
304
|
+
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined
|
|
305
|
+
});
|
|
306
|
+
return {
|
|
307
|
+
exitCode: result.status === 'PASS' ? 0 : 1,
|
|
308
|
+
output: renderGoalVerifyResult(result)
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
if (command === 'governance' && subcommand === 'inspect') {
|
|
312
|
+
const policy = await inspectGovernancePolicy(projectRoot);
|
|
313
|
+
return {
|
|
314
|
+
exitCode: 0,
|
|
315
|
+
output: rest.includes('--json') ? JSON.stringify(policy, null, 2) : renderGovernancePolicy(policy)
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
if (command === 'governance' && subcommand === 'evaluate') {
|
|
319
|
+
const operation = readGovernancePolicyOperation(rest[0]);
|
|
320
|
+
if (!operation) {
|
|
321
|
+
return {
|
|
322
|
+
exitCode: 2,
|
|
323
|
+
error: 'Usage: sdd governance evaluate background_executor|wave_executor|sync_back_apply|destructive_git|external_interaction|cleanup [--worker <adapter_id>] [--risk <tag>] [--approved] [--json]'
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const decision = await evaluateGovernancePolicy(projectRoot, {
|
|
327
|
+
operation,
|
|
328
|
+
workerAdapterId: readOption(rest, '--worker') ?? undefined,
|
|
329
|
+
riskTags: readRepeatedOption(rest, '--risk'),
|
|
330
|
+
approved: rest.includes('--approved')
|
|
331
|
+
});
|
|
332
|
+
return {
|
|
333
|
+
exitCode: decision.allowed ? 0 : 1,
|
|
334
|
+
output: rest.includes('--json') ? JSON.stringify(decision, null, 2) : renderGovernancePolicyDecision(decision)
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
if (command === 'capabilities' && subcommand === 'list') {
|
|
338
|
+
const registry = await listToolCapabilities(projectRoot);
|
|
339
|
+
return {
|
|
340
|
+
exitCode: 0,
|
|
341
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderCapabilityList(registry.capabilities)
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
if (command === 'capabilities' && subcommand === 'inspect') {
|
|
345
|
+
const capabilityId = rest.find((item) => !item.startsWith('--'));
|
|
346
|
+
if (!capabilityId) {
|
|
347
|
+
return {
|
|
348
|
+
exitCode: 2,
|
|
349
|
+
error: 'Usage: sdd capabilities inspect <capability_id> [--json]'
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
const capability = await inspectToolCapability(projectRoot, capabilityId);
|
|
353
|
+
if (!capability) {
|
|
354
|
+
return {
|
|
355
|
+
exitCode: 1,
|
|
356
|
+
error: `Unknown capability: ${capabilityId}`
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
exitCode: 0,
|
|
361
|
+
output: rest.includes('--json') ? JSON.stringify(capability, null, 2) : renderCapabilityInspect(capability)
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
if (command === 'plugins' && subcommand === 'list') {
|
|
365
|
+
const registry = await listToolPluginContracts(projectRoot);
|
|
366
|
+
return {
|
|
367
|
+
exitCode: 0,
|
|
368
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderPluginContractList(registry.contracts)
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (command === 'plugins' && subcommand === 'inspect') {
|
|
372
|
+
const pluginId = rest.find((item) => !item.startsWith('--'));
|
|
373
|
+
if (!pluginId) {
|
|
374
|
+
return {
|
|
375
|
+
exitCode: 2,
|
|
376
|
+
error: 'Usage: sdd plugins inspect <plugin_id> [--json]'
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
const contract = await inspectToolPluginContract(projectRoot, pluginId);
|
|
380
|
+
if (!contract) {
|
|
381
|
+
return {
|
|
382
|
+
exitCode: 1,
|
|
383
|
+
error: `Unknown plugin contract: ${pluginId}`
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
exitCode: 0,
|
|
388
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderPluginContractInspect(contract)
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
if (command === 'queue' && subcommand === 'list') {
|
|
392
|
+
const snapshot = await listDelegationQueueItems(projectRoot, { runId: readOption(rest, '--run') ?? undefined });
|
|
393
|
+
return {
|
|
394
|
+
exitCode: 0,
|
|
395
|
+
output: rest.includes('--json') ? JSON.stringify(snapshot, null, 2) : renderDelegationQueueList(snapshot.items)
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
if (command === 'queue' && subcommand === 'inspect') {
|
|
399
|
+
const queueItemId = rest.find((item) => !item.startsWith('--'));
|
|
400
|
+
if (!queueItemId) {
|
|
401
|
+
return {
|
|
402
|
+
exitCode: 2,
|
|
403
|
+
error: 'Usage: sdd queue inspect <queue_item_id> [--json]'
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const item = await inspectDelegationQueueItem(projectRoot, queueItemId);
|
|
407
|
+
if (!item) {
|
|
408
|
+
return {
|
|
409
|
+
exitCode: 1,
|
|
410
|
+
error: `Unknown queue item: ${queueItemId}`
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
exitCode: 0,
|
|
415
|
+
output: rest.includes('--json') ? JSON.stringify(item, null, 2) : renderDelegationQueueInspect(item)
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
if (command === 'state-machine' && subcommand === 'inspect') {
|
|
419
|
+
const machine = getDelegationStateMachine();
|
|
420
|
+
return {
|
|
421
|
+
exitCode: 0,
|
|
422
|
+
output: rest.includes('--json') ? JSON.stringify(machine, null, 2) : renderDelegationStateMachineInspect(machine)
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
if (command === 'isolation' && subcommand === 'inspect') {
|
|
426
|
+
const taskId = rest.find((item) => !item.startsWith('--'));
|
|
427
|
+
if (!taskId) {
|
|
428
|
+
return {
|
|
429
|
+
exitCode: 2,
|
|
430
|
+
error: 'Usage: sdd isolation inspect <task_id> [--branch <branch>] [--capability <capability_id>] [--peer-task <task_id>] [--json]'
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
const decision = await inspectWorktreeIsolation(projectRoot, {
|
|
434
|
+
taskId,
|
|
435
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
436
|
+
capabilityId: readOption(rest, '--capability') ?? undefined,
|
|
437
|
+
peerTaskIds: readRepeatedOptions(rest, '--peer-task')
|
|
438
|
+
});
|
|
439
|
+
return {
|
|
440
|
+
exitCode: decision.mode === 'blocked' ? 1 : 0,
|
|
441
|
+
output: rest.includes('--json') ? JSON.stringify(decision, null, 2) : renderWorktreeIsolationDecision(decision)
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
if (command === 'graph' && subcommand === 'inspect') {
|
|
445
|
+
const graph = await inspectTaskGraph(projectRoot, { branch: readOption(rest, '--branch') ?? 'master' });
|
|
446
|
+
return {
|
|
447
|
+
exitCode: graph.valid ? 0 : 1,
|
|
448
|
+
output: rest.includes('--json') ? JSON.stringify(graph, null, 2) : renderTaskGraphPlan(graph)
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
if (command === 'wave' && subcommand === 'inspect') {
|
|
452
|
+
const wavePlan = await inspectWavePlan(projectRoot, {
|
|
453
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
454
|
+
capabilityId: readOption(rest, '--capability') ?? undefined
|
|
455
|
+
});
|
|
456
|
+
return {
|
|
457
|
+
exitCode: wavePlan.valid ? 0 : 1,
|
|
458
|
+
output: rest.includes('--json') ? JSON.stringify(wavePlan, null, 2) : renderWavePlan(wavePlan)
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
if (command === 'wave' && subcommand === 'run') {
|
|
462
|
+
const strategy = readWaveExecutorStrategy(rest, '--strategy');
|
|
463
|
+
if (!strategy) {
|
|
464
|
+
return {
|
|
465
|
+
exitCode: 2,
|
|
466
|
+
error: 'Usage: sdd wave run [--branch <branch>] [--run <run_id>] [--capability <id>] [--agent <agent>] [--worker <adapter_id>] [--strategy fast-stop|safe-continue] [--artifact <task_id:path>]... [--json]'
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
const result = await runWaveExecutor(projectRoot, {
|
|
470
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
471
|
+
runId: readOption(rest, '--run') ?? undefined,
|
|
472
|
+
capabilityId: readOption(rest, '--capability') ?? undefined,
|
|
473
|
+
agent: readOption(rest, '--agent') ?? undefined,
|
|
474
|
+
workerAdapterId: readOption(rest, '--worker') ?? undefined,
|
|
475
|
+
strategy,
|
|
476
|
+
artifactPaths: readTaskArtifactOptions(rest)
|
|
477
|
+
});
|
|
478
|
+
return {
|
|
479
|
+
exitCode: result.status === 'completed' || result.status === 'claimed' ? 0 : 1,
|
|
480
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderWaveExecutorResult(result)
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
if (command === 'wave' && subcommand === 'executor') {
|
|
484
|
+
const runId = rest[0];
|
|
485
|
+
if (!runId) {
|
|
486
|
+
return {
|
|
487
|
+
exitCode: 2,
|
|
488
|
+
error: 'Usage: sdd wave executor <run_id> [--json]'
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
const inspection = await inspectWaveExecutor(projectRoot, runId);
|
|
492
|
+
return {
|
|
493
|
+
exitCode: inspection.valid ? 0 : 1,
|
|
494
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderWaveExecutorInspection(inspection)
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
if (command === 'background' && subcommand === 'run') {
|
|
498
|
+
const taskId = rest[0];
|
|
499
|
+
if (!taskId) {
|
|
500
|
+
return {
|
|
501
|
+
exitCode: 2,
|
|
502
|
+
error: 'Usage: sdd background run <task_id> [--run <run_id>] [--agent <agent>] [--worker <adapter_id>] [--artifact <path>] [--branch <branch>] [--json]'
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const result = await runBackgroundExecutor(projectRoot, {
|
|
506
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
507
|
+
runId: readOption(rest, '--run') ?? undefined,
|
|
508
|
+
taskId,
|
|
509
|
+
agent: readOption(rest, '--agent') ?? undefined,
|
|
510
|
+
workerAdapterId: readOption(rest, '--worker') ?? undefined,
|
|
511
|
+
artifactPath: readOption(rest, '--artifact') ?? undefined,
|
|
512
|
+
delegationId: readOption(rest, '--delegation') ?? undefined
|
|
513
|
+
});
|
|
514
|
+
return {
|
|
515
|
+
exitCode: result.status === 'blocked' || result.status === 'failed' ? 1 : 0,
|
|
516
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderBackgroundExecutorResult(result)
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (command === 'background' && subcommand === 'inspect') {
|
|
520
|
+
const runId = rest[0];
|
|
521
|
+
if (!runId) {
|
|
522
|
+
return {
|
|
523
|
+
exitCode: 2,
|
|
524
|
+
error: 'Usage: sdd background inspect <run_id> [--json]'
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
const inspection = await inspectBackgroundExecutor(projectRoot, runId);
|
|
528
|
+
return {
|
|
529
|
+
exitCode: inspection.valid ? 0 : 1,
|
|
530
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderBackgroundExecutorInspection(inspection)
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
if (command === 'worktree' && subcommand === 'create') {
|
|
534
|
+
const runId = rest[0];
|
|
535
|
+
const taskId = rest[1];
|
|
536
|
+
if (!runId || !taskId) {
|
|
537
|
+
return {
|
|
538
|
+
exitCode: 2,
|
|
539
|
+
error: 'Usage: sdd worktree create <run_id> <task_id> [--base <ref>] [--id <worktree_id>] [--json]'
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const record = await createWorktreeLifecycle(projectRoot, runId, {
|
|
543
|
+
taskId,
|
|
544
|
+
baseRef: readOption(rest, '--base') ?? undefined,
|
|
545
|
+
worktreeId: readOption(rest, '--id') ?? undefined
|
|
546
|
+
});
|
|
547
|
+
return {
|
|
548
|
+
exitCode: 0,
|
|
549
|
+
output: rest.includes('--json') ? JSON.stringify(record, null, 2) : renderWorktreeLifecycleRecord('Worktree created', record)
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
if (command === 'worktree' && subcommand === 'inspect') {
|
|
553
|
+
const runId = rest[0];
|
|
554
|
+
if (!runId) {
|
|
555
|
+
return {
|
|
556
|
+
exitCode: 2,
|
|
557
|
+
error: 'Usage: sdd worktree inspect <run_id> [--json]'
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
const inspection = await inspectWorktreeLifecycle(projectRoot, runId);
|
|
561
|
+
return {
|
|
562
|
+
exitCode: inspection.valid ? 0 : 1,
|
|
563
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderWorktreeLifecycleInspection(inspection)
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
if (command === 'worktree' && subcommand === 'keep') {
|
|
567
|
+
const runId = rest[0];
|
|
568
|
+
const worktreeId = rest[1];
|
|
569
|
+
if (!runId || !worktreeId) {
|
|
570
|
+
return {
|
|
571
|
+
exitCode: 2,
|
|
572
|
+
error: 'Usage: sdd worktree keep <run_id> <worktree_id> [--reason <text>] [--json]'
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
const record = await keepWorktreeLifecycle(projectRoot, runId, worktreeId, { reason: readOption(rest, '--reason') ?? undefined });
|
|
576
|
+
return {
|
|
577
|
+
exitCode: 0,
|
|
578
|
+
output: rest.includes('--json') ? JSON.stringify(record, null, 2) : renderWorktreeLifecycleRecord('Worktree kept', record)
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
if (command === 'worktree' && subcommand === 'remove') {
|
|
582
|
+
const runId = rest[0];
|
|
583
|
+
const worktreeId = rest[1];
|
|
584
|
+
if (!runId || !worktreeId) {
|
|
585
|
+
return {
|
|
586
|
+
exitCode: 2,
|
|
587
|
+
error: 'Usage: sdd worktree remove <run_id> <worktree_id> [--json]'
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
const record = await removeWorktreeLifecycle(projectRoot, runId, worktreeId);
|
|
591
|
+
return {
|
|
592
|
+
exitCode: 0,
|
|
593
|
+
output: rest.includes('--json') ? JSON.stringify(record, null, 2) : renderWorktreeLifecycleRecord('Worktree removed', record)
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
if (command === 'workers' && subcommand === 'list') {
|
|
597
|
+
const registry = await listWorkerAdapterContracts(projectRoot);
|
|
598
|
+
return {
|
|
599
|
+
exitCode: 0,
|
|
600
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderWorkerAdapterList(registry.adapters)
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
if (command === 'workers' && subcommand === 'inspect') {
|
|
604
|
+
const adapterId = rest.find((item) => !item.startsWith('--'));
|
|
605
|
+
if (!adapterId) {
|
|
606
|
+
return {
|
|
607
|
+
exitCode: 2,
|
|
608
|
+
error: 'Usage: sdd workers inspect <adapter_id> [--json]'
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
const adapter = await inspectWorkerAdapterContract(projectRoot, adapterId);
|
|
612
|
+
if (!adapter) {
|
|
613
|
+
return {
|
|
614
|
+
exitCode: 1,
|
|
615
|
+
error: `Unknown worker adapter: ${adapterId}`
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
return {
|
|
619
|
+
exitCode: 0,
|
|
620
|
+
output: rest.includes('--json') ? JSON.stringify(adapter, null, 2) : renderWorkerAdapterInspect(adapter)
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
if (command === 'artifact' && subcommand === 'template') {
|
|
624
|
+
const artifactPath = rest.find((item) => !item.startsWith('--'));
|
|
625
|
+
const taskId = readOption(rest, '--task');
|
|
626
|
+
const agent = readOption(rest, '--agent');
|
|
627
|
+
if (!artifactPath || !taskId || !agent) {
|
|
628
|
+
return {
|
|
629
|
+
exitCode: 2,
|
|
630
|
+
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> [--branch <branch>] [--status <status>]'
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
exitCode: 0,
|
|
635
|
+
output: await renderSddResultArtifactTemplate(projectRoot, {
|
|
636
|
+
artifactPath,
|
|
637
|
+
taskId,
|
|
638
|
+
agent,
|
|
639
|
+
branch: readOption(rest, '--branch') ?? 'master',
|
|
640
|
+
status: readSddResultStatus(rest, '--status') ?? 'PASS'
|
|
641
|
+
})
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
if (command === 'artifact' && subcommand === 'validate') {
|
|
645
|
+
const runId = rest[0];
|
|
646
|
+
const artifactPath = rest[1];
|
|
647
|
+
if (!runId || !artifactPath) {
|
|
648
|
+
return {
|
|
649
|
+
exitCode: 2,
|
|
650
|
+
error: 'Usage: sdd artifact validate <run_id> <artifacts/path.md> [--task <task_id>] [--agent <agent>] [--json]'
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
const expectedTask = readOption(rest, '--task') ?? undefined;
|
|
654
|
+
const expectedAgent = readOption(rest, '--agent') ?? undefined;
|
|
655
|
+
const report = await validateSddResultArtifact(projectRoot, runId, artifactPath, {
|
|
656
|
+
expectedTask,
|
|
657
|
+
expectedAgent
|
|
658
|
+
});
|
|
659
|
+
return {
|
|
660
|
+
exitCode: report.valid ? 0 : 1,
|
|
661
|
+
output: rest.includes('--json') ? JSON.stringify(report, null, 2) : renderArtifactValidationReport(artifactPath, report, expectedTask, expectedAgent)
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
if (command === 'artifact' && subcommand === 'ingest') {
|
|
665
|
+
const runId = rest[0];
|
|
666
|
+
const delegationId = rest[1];
|
|
667
|
+
const artifactPath = rest[2];
|
|
668
|
+
if (!runId || !delegationId || !artifactPath) {
|
|
669
|
+
return {
|
|
670
|
+
exitCode: 2,
|
|
671
|
+
error: 'Usage: sdd artifact ingest <run_id> <delegation_id> <artifacts/path.md> [--json]'
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
const result = await ingestArtifactResult(projectRoot, runId, { delegationId, artifactPath });
|
|
675
|
+
return {
|
|
676
|
+
exitCode: result.valid ? 0 : 1,
|
|
677
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderArtifactIngestionResult(result)
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
if (command === 'artifact' && subcommand === 'ingestions') {
|
|
681
|
+
const runId = rest[0];
|
|
682
|
+
if (!runId) {
|
|
683
|
+
return {
|
|
684
|
+
exitCode: 2,
|
|
685
|
+
error: 'Usage: sdd artifact ingestions <run_id> [--json]'
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
const inspection = await inspectArtifactResultIngestions(projectRoot, runId);
|
|
689
|
+
return {
|
|
690
|
+
exitCode: inspection.valid ? 0 : 1,
|
|
691
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderArtifactIngestionInspection(inspection)
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
return {
|
|
695
|
+
exitCode: 2,
|
|
696
|
+
error: `Unknown command: ${args.join(' ')}\n\n${helpText()}`
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
function helpText() {
|
|
700
|
+
return `sdd Phase 2 platform CLI
|
|
701
|
+
|
|
702
|
+
Commands:
|
|
703
|
+
sdd --version Print CLI/core version
|
|
704
|
+
sdd init [--force] [--ai <mode>] [--branch <branch>] [--no-scaffold-docs]
|
|
705
|
+
Create .sdd config, starter SDD docs, and generated AI entries
|
|
706
|
+
sdd update [--check] [--ai <mode>] Refresh or check managed generated AI entries
|
|
707
|
+
sdd instructions [action] [--json] Print dynamic SDD instruction payload
|
|
708
|
+
sdd doctor [--latest-only] [--all-runs] Check config, run evidence, specs, and AI entry drift
|
|
709
|
+
sdd status [--branch <branch>] [--json] Show tasks, latest run, gaps, and recommended next command
|
|
710
|
+
sdd run create Create .sdd/runs/<run_id> with state/events/artifacts
|
|
711
|
+
sdd run status <run_id> Print current run status
|
|
712
|
+
sdd run list [--json] List recorded runs by updated time
|
|
713
|
+
sdd run index rebuild|inspect|query [options] Rebuild, inspect, or query Phase 3.13 local run index
|
|
714
|
+
sdd run inspect <run_id> [--json] Inspect run state, events, artifacts, validation, sync-back
|
|
715
|
+
sdd run archive <run_id> [--reason] Archive a run without deleting evidence
|
|
716
|
+
sdd sync-back inspect <run_id> [options] Inspect explicit proposal-to-tasks.md write-back readiness
|
|
717
|
+
sdd sync-back apply <run_id> [--approved] Apply verified sync-back proposal to tasks.md
|
|
718
|
+
sdd lifecycle decide [options] Evaluate lifecycle decision gate
|
|
719
|
+
sdd do task <task_id> [options] Run ingestion-aware task workflow over supplied artifacts
|
|
720
|
+
sdd verify task <task_id> --run <run_id> Run goal-level acceptance coverage verify
|
|
721
|
+
sdd tasks format Print canonical sdd-task fenced block format
|
|
722
|
+
sdd tasks list [--branch <branch>] Parse and list sdd-task blocks
|
|
723
|
+
sdd tasks inspect <task_id> [--branch] Inspect one parsed task
|
|
724
|
+
sdd tasks gaps [--branch <branch>] Render parser task gap report
|
|
725
|
+
sdd artifact template <path> [options] Print a valid sdd-result artifact template
|
|
726
|
+
sdd artifact validate <run_id> <path> Validate a run-relative sdd-result artifact
|
|
727
|
+
sdd artifact ingest <run_id> <delegation_id> <path>
|
|
728
|
+
sdd artifact ingestions <run_id> [--json] Inspect Phase 3.6 artifact ingestion ledger
|
|
729
|
+
sdd capabilities list [--json] List Phase 3.1 tool/capability declarations
|
|
730
|
+
sdd capabilities inspect <id> [--json] Inspect one capability declaration
|
|
731
|
+
sdd governance inspect|evaluate [options] Inspect or evaluate Phase 3.14 governance policy
|
|
732
|
+
sdd plugins list [--json] List Phase 3.2 plugin loading contracts
|
|
733
|
+
sdd plugins inspect <id> [--json] Inspect one plugin loading contract
|
|
734
|
+
sdd queue list [--run <run_id>] [--json] List Phase 3.3 delegation queue items
|
|
735
|
+
sdd queue inspect <id> [--json] Inspect one delegation queue item
|
|
736
|
+
sdd state-machine inspect [--json] Inspect Phase 3.4 delegation state machine
|
|
737
|
+
sdd workers list [--json] List Phase 3.5 worker adapter contracts
|
|
738
|
+
sdd workers inspect <id> [--json] Inspect one worker adapter contract
|
|
739
|
+
sdd isolation inspect <task_id> [options] Dry-run Phase 3.7 worktree isolation decision
|
|
740
|
+
sdd graph inspect [--branch <branch>] [--json] Inspect Phase 3.9 task dependency graph
|
|
741
|
+
sdd wave inspect [--branch <branch>] [--capability <id>] [--json] Inspect Phase 3.10 dependency wave plan
|
|
742
|
+
sdd wave run [options] Run Phase 3.12 planner-driven wave executor
|
|
743
|
+
sdd wave executor <run_id> [--json] Inspect Phase 3.12 wave executor evidence
|
|
744
|
+
sdd background run <task_id> [options] Claim one Phase 3.11 background delegation; ingest supplied artifact if provided
|
|
745
|
+
sdd background inspect <run_id> [--json] Inspect Phase 3.11 background executor evidence
|
|
746
|
+
sdd worktree create <run_id> <task_id> [options]
|
|
747
|
+
sdd worktree inspect <run_id> [--json] Inspect Phase 3.8 worktree lifecycle records
|
|
748
|
+
sdd worktree keep <run_id> <id> Mark a worktree retained for inspection
|
|
749
|
+
sdd worktree remove <run_id> <id> Remove a clean tracked worktree
|
|
750
|
+
|
|
751
|
+
AI options:
|
|
752
|
+
--ai auto Project Claude Code entries when supported
|
|
753
|
+
--ai claude-code Project Claude Code entries explicitly
|
|
754
|
+
--ai none Skip AI entry projection during init
|
|
755
|
+
|
|
756
|
+
Init options:
|
|
757
|
+
--branch <branch> Create starter docs under specs/<branch>; default master
|
|
758
|
+
--no-scaffold-docs Skip starter spec.md/plan.md/tasks.md creation
|
|
759
|
+
|
|
760
|
+
Doctor options:
|
|
761
|
+
--latest-only Inspect only the newest non-archived run evidence
|
|
762
|
+
--all-runs Inspect every run, including archived runs
|
|
763
|
+
|
|
764
|
+
Run index options:
|
|
765
|
+
--run <run_id> Filter local run index query by run id
|
|
766
|
+
--task <task_id> Filter local run index query by task id
|
|
767
|
+
--status <status> Filter query by run status
|
|
768
|
+
--artifact <path> Filter query by indexed artifact path
|
|
769
|
+
--json Print machine-readable local run index output
|
|
770
|
+
|
|
771
|
+
Artifact options:
|
|
772
|
+
--task <task_id> Expected artifact task id
|
|
773
|
+
--agent <agent> Expected producing agent name
|
|
774
|
+
--branch <branch> Branch used to copy validator Acceptance mapping
|
|
775
|
+
--status <status> Template status; default PASS
|
|
776
|
+
--json Print machine-readable validation result
|
|
777
|
+
|
|
778
|
+
Governance options:
|
|
779
|
+
--worker <adapter_id> Worker adapter to evaluate
|
|
780
|
+
--risk <tag> Risk tag to evaluate; repeatable
|
|
781
|
+
--approved Record explicit approval for confirmation-gated operations
|
|
782
|
+
--json Print machine-readable governance output
|
|
783
|
+
|
|
784
|
+
Wave executor options:
|
|
785
|
+
--branch <branch> Read specs/<branch>/tasks.md; default master
|
|
786
|
+
--run <run_id> Reuse an existing run; default creates one
|
|
787
|
+
--capability <id> Capability used for planner isolation decisions
|
|
788
|
+
--strategy fast-stop|safe-continue Stop on first task failure or finish current safe wave
|
|
789
|
+
--artifact <task_id:path> Supply task-specific run-relative artifact; repeatable
|
|
790
|
+
|
|
791
|
+
Instructions actions:
|
|
792
|
+
overview | init | doctor | update | spec | plan | tasks | do | verify | run-task | verify-task
|
|
793
|
+
|
|
794
|
+
Do task options:
|
|
795
|
+
--branch <branch> Read specs/<branch>/spec.md, plan.md, tasks.md
|
|
796
|
+
--run <run_id> Reuse an existing run instead of creating one
|
|
797
|
+
--implement-artifact <path> Run-relative implementer artifact, if available
|
|
798
|
+
--review-artifact <path> Run-relative reviewer artifact, required to complete
|
|
799
|
+
--debug-artifact <path> Optional single debugger artifact after review failure
|
|
800
|
+
--validation-artifact <path> Run-relative validator artifact, required to complete
|
|
801
|
+
|
|
802
|
+
Verify task options:
|
|
803
|
+
--branch <branch> Read specs/<branch>/spec.md, plan.md, tasks.md
|
|
804
|
+
--run <run_id> Required run id containing state/events/artifacts
|
|
805
|
+
--review-artifact <path> Optional reviewer artifact override
|
|
806
|
+
--validation-artifact <path> Optional validator artifact override
|
|
807
|
+
|
|
808
|
+
Lifecycle decide options:
|
|
809
|
+
--direct-safe High clarity, high confidence, reversible, cheap local validation
|
|
810
|
+
--risk <tag> Add risk tag; api/schema/database/security/state-machine/ci force gates
|
|
811
|
+
--contract <name> Mark affected API/schema/contract
|
|
812
|
+
--impact-confidence <high|medium|low> Set impact confidence
|
|
813
|
+
--acceptance <high|medium|low> Set acceptance clarity
|
|
814
|
+
--validation <clear|partial|unclear> Set validation clarity
|
|
815
|
+
--external-unknown Require research route
|
|
816
|
+
--architecture Require architecture/research route
|
|
817
|
+
--checkpoint Force human checkpoint
|
|
818
|
+
--permission <name> Mark permission/checkpoint requirement
|
|
819
|
+
--run <run_id> Record decision to existing run state/events
|
|
820
|
+
--json Print machine-readable result
|
|
821
|
+
|
|
822
|
+
Sync-back options:
|
|
823
|
+
--branch <branch> Read target specs/<branch>/tasks.md
|
|
824
|
+
--task <task_id> Override run currentTask when inspecting or applying
|
|
825
|
+
--json Print machine-readable result
|
|
826
|
+
|
|
827
|
+
Isolation options:
|
|
828
|
+
--branch <branch> Read specs/<branch>/tasks.md
|
|
829
|
+
--capability <capability_id> Capability side effect used for isolation decision
|
|
830
|
+
--peer-task <task_id> Compare affected_files overlap against peer task
|
|
831
|
+
|
|
832
|
+
Graph options:
|
|
833
|
+
--branch <branch> Read specs/<branch>/tasks.md
|
|
834
|
+
|
|
835
|
+
Wave options:
|
|
836
|
+
--branch <branch> Read specs/<branch>/tasks.md
|
|
837
|
+
--capability <capability_id> Capability side effect used for isolation decisions
|
|
838
|
+
|
|
839
|
+
Background options:
|
|
840
|
+
--branch <branch> Read specs/<branch>/tasks.md
|
|
841
|
+
--run <run_id> Reuse an existing run; default creates one
|
|
842
|
+
--agent <agent> Delegated agent name; default implementer
|
|
843
|
+
--worker <adapter_id> Worker adapter id; default sdd-cli-task-worker
|
|
844
|
+
--artifact <path> Run-relative sdd-result artifact to ingest
|
|
845
|
+
--delegation <delegation_id> Stable delegation id for retry/ingest
|
|
846
|
+
Worktree options:
|
|
847
|
+
--base <ref> Base ref for git worktree add; default HEAD
|
|
848
|
+
--id <worktree_id> Stable lifecycle id; default wt-<run>-<task>
|
|
849
|
+
--reason <text> Reason when keeping a worktree
|
|
850
|
+
`;
|
|
851
|
+
}
|
|
852
|
+
function renderProjectStatus(status) {
|
|
853
|
+
const lines = [`SDD status for ${status.branch}`];
|
|
854
|
+
lines.push(`documents spec=${status.documents.specExists} plan=${status.documents.planExists} tasks=${status.documents.tasksExists}`);
|
|
855
|
+
lines.push(`tasks total=${status.tasks.total} pending=${status.tasks.pending} in_progress=${status.tasks.inProgress} completed=${status.tasks.completed} blocked=${status.tasks.blocked} deferred=${status.tasks.deferred} unknown=${status.tasks.unknown} gaps=${status.tasks.gaps}`);
|
|
856
|
+
if (status.latestRun) {
|
|
857
|
+
lines.push(`latest_run ${status.latestRun.runId} status=${status.latestRun.status} phase=${status.latestRun.phase ?? 'n/a'} task=${status.latestRun.currentTask ?? 'n/a'} validation=${status.latestRun.validationStatus} sync_back=${status.latestRun.syncBackStatus}`);
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
lines.push('latest_run none');
|
|
861
|
+
}
|
|
862
|
+
if (status.gaps.length > 0) {
|
|
863
|
+
lines.push('gaps');
|
|
864
|
+
for (const gap of status.gaps) {
|
|
865
|
+
lines.push(`- [${gap.severity}] ${gap.type} ${gap.taskId ?? 'document'} ${gap.field}: ${gap.message}`);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
lines.push(`next ${status.recommendedNextCommand}`);
|
|
869
|
+
return lines.join('\n');
|
|
870
|
+
}
|
|
871
|
+
function renderRunList(runs) {
|
|
872
|
+
if (runs.length === 0) {
|
|
873
|
+
return 'No SDD runs found.';
|
|
874
|
+
}
|
|
875
|
+
const lines = ['SDD runs'];
|
|
876
|
+
for (const run of runs) {
|
|
877
|
+
lines.push(`${run.runId}\t${run.status}\tphase=${run.phase ?? 'n/a'}\ttask=${run.currentTask ?? 'n/a'}\tvalidation=${run.validationStatus}\tsync_back=${run.syncBackStatus}\tupdated=${run.updatedAt}`);
|
|
878
|
+
}
|
|
879
|
+
return lines.join('\n');
|
|
880
|
+
}
|
|
881
|
+
function renderLocalRunIndex(index) {
|
|
882
|
+
const lines = [`Local run index ${index.contract}`];
|
|
883
|
+
lines.push(`generated=${index.generatedAt} runs=${index.runs.length} tasks=${index.tasks.length} delegations=${index.delegations.length} artifacts=${index.artifacts.length} waves=${index.waves.length}`);
|
|
884
|
+
for (const run of index.runs) {
|
|
885
|
+
lines.push(`- ${run.runId}: ${run.status} phase=${run.phase ?? 'n/a'} task=${run.currentTask ?? 'n/a'} artifacts=${run.artifactCount} updated=${run.updatedAt}`);
|
|
886
|
+
}
|
|
887
|
+
return lines.join('\n');
|
|
888
|
+
}
|
|
889
|
+
function renderLocalRunIndexInspection(inspection) {
|
|
890
|
+
const lines = [`Local run index ${inspection.valid ? 'valid' : 'invalid'}`];
|
|
891
|
+
lines.push(`path=${inspection.indexPath} exists=${inspection.exists}`);
|
|
892
|
+
if (inspection.index) {
|
|
893
|
+
lines.push(`contract=${inspection.index.contract} runs=${inspection.index.runs.length} tasks=${inspection.index.tasks.length} delegations=${inspection.index.delegations.length} artifacts=${inspection.index.artifacts.length} waves=${inspection.index.waves.length}`);
|
|
894
|
+
}
|
|
895
|
+
if (inspection.issues.length > 0) {
|
|
896
|
+
lines.push('issues');
|
|
897
|
+
for (const issue of inspection.issues) {
|
|
898
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
899
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return lines.join('\n');
|
|
903
|
+
}
|
|
904
|
+
function renderGovernancePolicy(policy) {
|
|
905
|
+
const lines = [`Governance policy ${policy.version}`];
|
|
906
|
+
lines.push(`concurrency background=${policy.concurrency.maxBackgroundDelegations} wave=${policy.concurrency.maxWaveExecutors}`);
|
|
907
|
+
lines.push(`confirmation operations=${policy.manualConfirmation.operations.join(',')}`);
|
|
908
|
+
lines.push(`confirmation workers=${policy.manualConfirmation.workerAdapters.join(',') || 'none'}`);
|
|
909
|
+
lines.push(`confirmation risks=${policy.manualConfirmation.riskTags.join(',') || 'none'}`);
|
|
910
|
+
lines.push(`cleanup archive_only=${policy.cleanup.archiveOnly} delete_run_history=${policy.cleanup.deleteRunHistory}`);
|
|
911
|
+
lines.push(`retry reopen_terminal=${policy.retry.reopenTerminalDelegation} max_attempts=${policy.retry.maxAttemptsPerDelegation}`);
|
|
912
|
+
lines.push(`stop_conditions=${policy.stopConditions.join(',')}`);
|
|
913
|
+
return lines.join('\n');
|
|
914
|
+
}
|
|
915
|
+
function renderGovernancePolicyDecision(decision) {
|
|
916
|
+
const lines = [`Governance decision ${decision.status} for ${decision.operation}`];
|
|
917
|
+
lines.push(`version=${decision.version} allowed=${decision.allowed}`);
|
|
918
|
+
lines.push('reasons');
|
|
919
|
+
for (const reason of decision.reasons) {
|
|
920
|
+
lines.push(`- ${reason}`);
|
|
921
|
+
}
|
|
922
|
+
if (decision.issues.length > 0) {
|
|
923
|
+
lines.push('issues');
|
|
924
|
+
for (const issue of decision.issues) {
|
|
925
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
926
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return lines.join('\n');
|
|
930
|
+
}
|
|
931
|
+
function renderRunInspection(inspection) {
|
|
932
|
+
const lines = [`SDD run ${inspection.summary.runId}`];
|
|
933
|
+
lines.push(`status=${inspection.summary.status} phase=${inspection.summary.phase ?? 'n/a'} task=${inspection.summary.currentTask ?? 'n/a'} updated=${inspection.summary.updatedAt}`);
|
|
934
|
+
lines.push(`validation=${inspection.validation.status} evidence=${inspection.validation.evidence.join(',') || 'none'}`);
|
|
935
|
+
lines.push(`sync_back=${inspection.syncBack.status} proposal=${inspection.syncBack.proposalPath ?? 'none'}`);
|
|
936
|
+
lines.push(`artifacts=${inspection.artifacts.length}`);
|
|
937
|
+
for (const artifact of inspection.artifacts) {
|
|
938
|
+
lines.push(`- ${artifact.path} kind=${artifact.kind} task=${artifact.task ?? 'n/a'} agent=${artifact.agent ?? 'n/a'}`);
|
|
939
|
+
}
|
|
940
|
+
lines.push(`artifact_ingestions=${inspection.artifactIngestions.length}`);
|
|
941
|
+
for (const ingestion of inspection.artifactIngestions) {
|
|
942
|
+
lines.push(`- ${ingestion.delegationId} ${ingestion.status} artifact=${ingestion.artifactPath} result=${ingestion.resultStatus ?? 'n/a'} delegation=${ingestion.delegationStatus ?? 'n/a'}`);
|
|
943
|
+
}
|
|
944
|
+
lines.push(`events=${inspection.eventCount}`);
|
|
945
|
+
for (const event of inspection.recentEvents) {
|
|
946
|
+
lines.push(`- ${event.time} ${event.event}${event.summary ? `: ${event.summary}` : ''}`);
|
|
947
|
+
}
|
|
948
|
+
return lines.join('\n');
|
|
949
|
+
}
|
|
950
|
+
function renderSyncBackInspection(inspection) {
|
|
951
|
+
const lines = [`Sync-back ${inspection.status} for ${inspection.runId}/${inspection.taskId ?? 'n/a'}`];
|
|
952
|
+
lines.push(`branch=${inspection.branch}`);
|
|
953
|
+
lines.push(`proposal=${inspection.proposalPath ?? 'none'}`);
|
|
954
|
+
lines.push(`run_task_status=${inspection.runTaskStatus ?? 'n/a'} markdown_status=${inspection.markdownStatus ?? 'n/a'}`);
|
|
955
|
+
if (inspection.reasons.length > 0) {
|
|
956
|
+
lines.push('reasons');
|
|
957
|
+
for (const reason of inspection.reasons) {
|
|
958
|
+
lines.push(`- ${reason}`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (inspection.gaps.length > 0) {
|
|
962
|
+
lines.push('gaps');
|
|
963
|
+
for (const gap of inspection.gaps) {
|
|
964
|
+
lines.push(`- [${gap.severity}] ${gap.type} ${gap.taskId ?? 'document'} ${gap.field}: ${gap.message}`);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
lines.push(`apply_policy=${inspection.applyPolicy.mode} approval_required=${inspection.applyPolicy.requiresApproval}`);
|
|
968
|
+
for (const reason of inspection.applyPolicy.reasons) {
|
|
969
|
+
lines.push(`- policy: ${reason}`);
|
|
970
|
+
}
|
|
971
|
+
if (inspection.status === 'ready') {
|
|
972
|
+
const approvedFlag = inspection.applyPolicy.requiresApproval ? ' --approved' : '';
|
|
973
|
+
lines.push(`next sdd sync-back apply ${inspection.runId} --branch ${inspection.branch} --task ${inspection.taskId}${approvedFlag}`);
|
|
974
|
+
}
|
|
975
|
+
return lines.join('\n');
|
|
976
|
+
}
|
|
977
|
+
function renderSyncBackApplyResult(result) {
|
|
978
|
+
const lines = [result.message];
|
|
979
|
+
lines.push(`tasks_path=${result.tasksPath}`);
|
|
980
|
+
lines.push(`applied=${result.applied}`);
|
|
981
|
+
lines.push(`sync_back=${result.inspection.status}`);
|
|
982
|
+
return lines.join('\n');
|
|
983
|
+
}
|
|
984
|
+
function renderCapabilityList(capabilities) {
|
|
985
|
+
const lines = ['SDD tool capabilities'];
|
|
986
|
+
for (const capability of capabilities) {
|
|
987
|
+
lines.push(`- ${capability.id} category=${capability.category} side_effect=${capability.sideEffect} default=${capability.defaultAvailable}`);
|
|
988
|
+
}
|
|
989
|
+
return lines.join('\n');
|
|
990
|
+
}
|
|
991
|
+
function renderCapabilityInspect(capability) {
|
|
992
|
+
const lines = [`Capability ${capability.id}`];
|
|
993
|
+
lines.push(`title=${capability.title}`);
|
|
994
|
+
lines.push(`category=${capability.category} side_effect=${capability.sideEffect} default=${capability.defaultAvailable}`);
|
|
995
|
+
lines.push(`summary=${capability.summary}`);
|
|
996
|
+
lines.push('allowed_stages');
|
|
997
|
+
for (const stage of capability.allowedStages) {
|
|
998
|
+
lines.push(`- ${stage}`);
|
|
999
|
+
}
|
|
1000
|
+
lines.push('required_evidence');
|
|
1001
|
+
for (const evidence of capability.requiredEvidence) {
|
|
1002
|
+
lines.push(`- ${evidence}`);
|
|
1003
|
+
}
|
|
1004
|
+
lines.push('forbidden_uses');
|
|
1005
|
+
for (const forbiddenUse of capability.forbiddenUses) {
|
|
1006
|
+
lines.push(`- ${forbiddenUse}`);
|
|
1007
|
+
}
|
|
1008
|
+
return lines.join('\n');
|
|
1009
|
+
}
|
|
1010
|
+
function renderPluginContractList(contracts) {
|
|
1011
|
+
const lines = ['SDD plugin loading contracts'];
|
|
1012
|
+
for (const contract of contracts) {
|
|
1013
|
+
lines.push(`- ${contract.id} capability=${contract.capabilityId} entry=${contract.entryKind} load_mode=${contract.loadMode}`);
|
|
1014
|
+
}
|
|
1015
|
+
return lines.join('\n');
|
|
1016
|
+
}
|
|
1017
|
+
function renderPluginContractInspect(contract) {
|
|
1018
|
+
const lines = [`Plugin contract ${contract.id}`];
|
|
1019
|
+
lines.push(`title=${contract.title}`);
|
|
1020
|
+
lines.push(`version=${contract.version} capability=${contract.capabilityId}`);
|
|
1021
|
+
lines.push(`entry=${contract.entryKind} load_mode=${contract.loadMode}`);
|
|
1022
|
+
lines.push(`asset_path=${contract.assetPath}`);
|
|
1023
|
+
lines.push(`checksum=${contract.checksum ?? 'none'}`);
|
|
1024
|
+
lines.push('required_evidence');
|
|
1025
|
+
for (const evidence of contract.requiredEvidence) {
|
|
1026
|
+
lines.push(`- ${evidence}`);
|
|
1027
|
+
}
|
|
1028
|
+
lines.push('forbidden_uses');
|
|
1029
|
+
for (const forbiddenUse of contract.forbiddenUses) {
|
|
1030
|
+
lines.push(`- ${forbiddenUse}`);
|
|
1031
|
+
}
|
|
1032
|
+
return lines.join('\n');
|
|
1033
|
+
}
|
|
1034
|
+
function renderDelegationQueueList(items) {
|
|
1035
|
+
const lines = ['SDD delegation queue items'];
|
|
1036
|
+
for (const item of items) {
|
|
1037
|
+
lines.push(`- ${item.id} task=${item.taskId} agent=${item.agent} status=${item.status} capability=${item.requestedCapabilityId}`);
|
|
1038
|
+
}
|
|
1039
|
+
return lines.join('\n');
|
|
1040
|
+
}
|
|
1041
|
+
function renderDelegationQueueInspect(item) {
|
|
1042
|
+
const lines = [`Queue item ${item.id}`];
|
|
1043
|
+
lines.push(`run=${item.runId} delegation=${item.delegationId}`);
|
|
1044
|
+
lines.push(`task=${item.taskId} agent=${item.agent} status=${item.status}`);
|
|
1045
|
+
lines.push(`capability=${item.requestedCapabilityId} source=${item.statusSource} run_mode=${item.runMode}`);
|
|
1046
|
+
lines.push(`dedupe_key=${item.dedupeKey}`);
|
|
1047
|
+
lines.push(`expected_artifact=${item.expectedArtifact}`);
|
|
1048
|
+
lines.push('required_evidence');
|
|
1049
|
+
for (const evidence of item.requiredEvidence) {
|
|
1050
|
+
lines.push(`- ${evidence}`);
|
|
1051
|
+
}
|
|
1052
|
+
return lines.join('\n');
|
|
1053
|
+
}
|
|
1054
|
+
function renderDelegationStateMachineInspect(machine) {
|
|
1055
|
+
const lines = [`Delegation state machine ${machine.version}`];
|
|
1056
|
+
lines.push(`statuses=${machine.statuses.join(',')}`);
|
|
1057
|
+
lines.push(`terminal_statuses=${machine.terminalStatuses.join(',')}`);
|
|
1058
|
+
lines.push('transitions');
|
|
1059
|
+
for (const transition of machine.transitions) {
|
|
1060
|
+
lines.push(`- ${transition.from} -> ${transition.to} event=${transition.event} terminal=${transition.terminal}`);
|
|
1061
|
+
}
|
|
1062
|
+
return lines.join('\n');
|
|
1063
|
+
}
|
|
1064
|
+
function renderWorkerAdapterList(adapters) {
|
|
1065
|
+
const lines = ['SDD worker adapter contracts'];
|
|
1066
|
+
for (const adapter of adapters) {
|
|
1067
|
+
lines.push(`- ${adapter.id} kind=${adapter.kind} capability=${adapter.capabilityId} plugin=${adapter.pluginContractId} side_effect=${adapter.sideEffect}`);
|
|
1068
|
+
}
|
|
1069
|
+
return lines.join('\n');
|
|
1070
|
+
}
|
|
1071
|
+
function renderWorkerAdapterInspect(adapter) {
|
|
1072
|
+
const lines = [`Worker adapter ${adapter.id}`];
|
|
1073
|
+
lines.push(`title=${adapter.title}`);
|
|
1074
|
+
lines.push(`version=${adapter.version} kind=${adapter.kind}`);
|
|
1075
|
+
lines.push(`capability=${adapter.capabilityId} plugin=${adapter.pluginContractId} side_effect=${adapter.sideEffect}`);
|
|
1076
|
+
lines.push(`state_machine=${adapter.input.stateMachineVersion}`);
|
|
1077
|
+
lines.push(`artifact_reference=${adapter.output.artifactReference}`);
|
|
1078
|
+
lines.push(`terminal_status=${adapter.output.terminalStatus.join(',')}`);
|
|
1079
|
+
lines.push(`exit_statuses=${adapter.output.exitStatuses.join(',')}`);
|
|
1080
|
+
lines.push(`permission_prompt=${adapter.permissionPrompt}`);
|
|
1081
|
+
lines.push('required_events');
|
|
1082
|
+
for (const event of adapter.output.requiredEvents) {
|
|
1083
|
+
lines.push(`- ${event}`);
|
|
1084
|
+
}
|
|
1085
|
+
lines.push('required_evidence');
|
|
1086
|
+
for (const evidence of adapter.requiredEvidence) {
|
|
1087
|
+
lines.push(`- ${evidence}`);
|
|
1088
|
+
}
|
|
1089
|
+
lines.push('forbidden_uses');
|
|
1090
|
+
for (const forbiddenUse of adapter.forbiddenUses) {
|
|
1091
|
+
lines.push(`- ${forbiddenUse}`);
|
|
1092
|
+
}
|
|
1093
|
+
return lines.join('\n');
|
|
1094
|
+
}
|
|
1095
|
+
function renderArtifactIngestionResult(result) {
|
|
1096
|
+
const lines = [`Artifact ingestion ${result.record.status}: ${result.record.artifactPath}`];
|
|
1097
|
+
lines.push(`delegation=${result.record.delegationId} duplicate=${result.duplicate} result=${result.record.resultStatus ?? 'n/a'} terminal=${result.record.delegationStatus ?? 'n/a'}`);
|
|
1098
|
+
if (result.record.issues.length > 0) {
|
|
1099
|
+
lines.push('issues');
|
|
1100
|
+
for (const issue of result.record.issues) {
|
|
1101
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1102
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (result.record.gaps.length > 0) {
|
|
1106
|
+
lines.push('gaps');
|
|
1107
|
+
for (const gap of result.record.gaps) {
|
|
1108
|
+
lines.push(`- [${gap.severity}] ${gap.type} ${gap.field}: ${gap.message}`);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return lines.join('\n');
|
|
1112
|
+
}
|
|
1113
|
+
function renderArtifactIngestionInspection(inspection) {
|
|
1114
|
+
const lines = [`Artifact ingestions ${inspection.valid ? 'valid' : 'invalid'} for ${inspection.runId}`];
|
|
1115
|
+
lines.push(`records=${inspection.records.length}`);
|
|
1116
|
+
for (const record of inspection.records) {
|
|
1117
|
+
lines.push(`- ${record.delegationId} ${record.status} artifact=${record.artifactPath} result=${record.resultStatus ?? 'n/a'} delegation=${record.delegationStatus ?? 'n/a'}`);
|
|
1118
|
+
}
|
|
1119
|
+
if (inspection.issues.length > 0) {
|
|
1120
|
+
lines.push('issues');
|
|
1121
|
+
for (const issue of inspection.issues) {
|
|
1122
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1123
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return lines.join('\n');
|
|
1127
|
+
}
|
|
1128
|
+
function renderBackgroundExecutorResult(result) {
|
|
1129
|
+
const lines = [`Background executor ${result.status} for ${result.taskId}`];
|
|
1130
|
+
lines.push(`version=${result.version}`);
|
|
1131
|
+
lines.push(`run=${result.runId} delegation=${result.delegationId ?? 'n/a'} queue=${result.queueItemId ?? 'n/a'} worker=${result.workerAdapterId}`);
|
|
1132
|
+
lines.push(`artifact=${result.artifactPath ?? 'pending'}`);
|
|
1133
|
+
lines.push(result.message);
|
|
1134
|
+
if (result.issues.length > 0) {
|
|
1135
|
+
lines.push('issues');
|
|
1136
|
+
for (const issue of result.issues) {
|
|
1137
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1138
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
return lines.join('\n');
|
|
1142
|
+
}
|
|
1143
|
+
function renderBackgroundExecutorInspection(inspection) {
|
|
1144
|
+
const lines = [`Background executor ${inspection.valid ? 'valid' : 'invalid'} for ${inspection.runId}`];
|
|
1145
|
+
lines.push(`version=${inspection.version}`);
|
|
1146
|
+
lines.push(`delegations=${inspection.delegations.length} running=${inspection.runningDelegations} terminal=${inspection.terminalDelegations} ingestions=${inspection.artifactIngestions.length}`);
|
|
1147
|
+
for (const delegation of inspection.delegations) {
|
|
1148
|
+
lines.push(`- ${delegation.delegationId} ${delegation.status} task=${delegation.taskId} agent=${delegation.agent} artifact=${delegation.expectedArtifact}`);
|
|
1149
|
+
}
|
|
1150
|
+
if (inspection.issues.length > 0) {
|
|
1151
|
+
lines.push('issues');
|
|
1152
|
+
for (const issue of inspection.issues) {
|
|
1153
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1154
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
return lines.join('\n');
|
|
1158
|
+
}
|
|
1159
|
+
function renderWaveExecutorResult(result) {
|
|
1160
|
+
const lines = [`Wave executor ${result.status} for ${result.branch}`];
|
|
1161
|
+
lines.push(`version=${result.version}`);
|
|
1162
|
+
lines.push(`run=${result.runId} strategy=${result.strategy} waves=${result.executedWaves}/${result.plannedWaves} tasks=${result.taskResults.length}`);
|
|
1163
|
+
lines.push(result.message);
|
|
1164
|
+
for (const task of result.taskResults) {
|
|
1165
|
+
lines.push(`- wave ${task.waveIndex} ${task.taskId}: ${task.result.status} delegation=${task.result.delegationId ?? 'n/a'} artifact=${task.result.artifactPath ?? 'pending'}`);
|
|
1166
|
+
}
|
|
1167
|
+
if (result.manualGates.length > 0) {
|
|
1168
|
+
lines.push('manual_gates');
|
|
1169
|
+
for (const gate of result.manualGates) {
|
|
1170
|
+
lines.push(`- ${gate.taskId}: ${gate.reasons.join(' | ')}`);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
if (result.blockedTasks.length > 0) {
|
|
1174
|
+
lines.push('blocked_tasks');
|
|
1175
|
+
for (const gate of result.blockedTasks) {
|
|
1176
|
+
lines.push(`- ${gate.taskId}: ${gate.reasons.join(' | ')}`);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (result.issues.length > 0) {
|
|
1180
|
+
lines.push('issues');
|
|
1181
|
+
for (const issue of result.issues) {
|
|
1182
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1183
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
return lines.join('\n');
|
|
1187
|
+
}
|
|
1188
|
+
function renderWaveExecutorInspection(inspection) {
|
|
1189
|
+
const lines = [`Wave executor ${inspection.valid ? 'valid' : 'invalid'} for ${inspection.runId}`];
|
|
1190
|
+
lines.push(`version=${inspection.version}`);
|
|
1191
|
+
lines.push(`events=${inspection.waveEvents.length} delegations=${inspection.background.delegations.length} terminal=${inspection.background.terminalDelegations}`);
|
|
1192
|
+
for (const event of inspection.waveEvents) {
|
|
1193
|
+
lines.push(`- ${event.event}: ${event.summary ?? ''}`);
|
|
1194
|
+
}
|
|
1195
|
+
if (inspection.issues.length > 0) {
|
|
1196
|
+
lines.push('issues');
|
|
1197
|
+
for (const issue of inspection.issues) {
|
|
1198
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1199
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return lines.join('\n');
|
|
1203
|
+
}
|
|
1204
|
+
function renderWorktreeIsolationDecision(decision) {
|
|
1205
|
+
const lines = [`Worktree isolation ${decision.mode} for ${decision.taskId}`];
|
|
1206
|
+
lines.push(`version=${decision.version}`);
|
|
1207
|
+
lines.push(`safe_concurrency=${decision.safeConcurrency} capability=${decision.capabilityId} side_effect=${decision.capabilitySideEffect}`);
|
|
1208
|
+
lines.push(`affected_files=${decision.affectedFiles.length > 0 ? decision.affectedFiles.join(',') : 'none'}`);
|
|
1209
|
+
lines.push(`risk=${decision.risk.length > 0 ? decision.risk.join(',') : 'none'}`);
|
|
1210
|
+
if (decision.overlaps.length > 0) {
|
|
1211
|
+
lines.push('overlaps');
|
|
1212
|
+
for (const overlap of decision.overlaps) {
|
|
1213
|
+
lines.push(`- ${overlap.peerTaskId}: ${overlap.files.join(',')}`);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
lines.push('gates');
|
|
1217
|
+
for (const gate of decision.gates) {
|
|
1218
|
+
lines.push(`- ${gate.name} ${gate.passed ? 'PASS' : 'FAIL'}: ${gate.message}`);
|
|
1219
|
+
}
|
|
1220
|
+
lines.push('reasons');
|
|
1221
|
+
for (const reason of decision.reasons) {
|
|
1222
|
+
lines.push(`- ${reason}`);
|
|
1223
|
+
}
|
|
1224
|
+
return lines.join('\n');
|
|
1225
|
+
}
|
|
1226
|
+
function renderWorktreeLifecycleRecord(title, record) {
|
|
1227
|
+
return [
|
|
1228
|
+
`${title}: ${record.worktreeId}`,
|
|
1229
|
+
`status=${record.status} task=${record.taskId} branch=${record.branchName}`,
|
|
1230
|
+
`path=${record.worktreePath} base=${record.baseRef} dirty=${record.dirty}`,
|
|
1231
|
+
`kept=${record.keepReason ?? 'n/a'} removed=${record.removedAt ?? 'n/a'}`
|
|
1232
|
+
].join('\n');
|
|
1233
|
+
}
|
|
1234
|
+
function renderWorktreeLifecycleInspection(inspection) {
|
|
1235
|
+
const lines = [`Worktree lifecycle ${inspection.valid ? 'valid' : 'invalid'} for ${inspection.runId}`];
|
|
1236
|
+
lines.push(`records=${inspection.records.length}`);
|
|
1237
|
+
for (const record of inspection.records) {
|
|
1238
|
+
lines.push(`- ${record.worktreeId} ${record.status} task=${record.taskId} path=${record.worktreePath} dirty=${record.dirty}`);
|
|
1239
|
+
}
|
|
1240
|
+
if (inspection.issues.length > 0) {
|
|
1241
|
+
lines.push('issues');
|
|
1242
|
+
for (const issue of inspection.issues) {
|
|
1243
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1244
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return lines.join('\n');
|
|
1248
|
+
}
|
|
1249
|
+
function renderTaskGraphPlan(graph) {
|
|
1250
|
+
const lines = [`Task graph ${graph.valid ? 'valid' : 'blocked'} for ${graph.branch}`];
|
|
1251
|
+
lines.push(`version=${graph.version}`);
|
|
1252
|
+
lines.push(`tasks=${graph.summary.tasks} dependencies=${graph.summary.dependencies} file_overlaps=${graph.summary.fileOverlaps}`);
|
|
1253
|
+
lines.push(`high_risk_tasks=${graph.summary.highRiskTasks.length > 0 ? graph.summary.highRiskTasks.join(',') : 'none'}`);
|
|
1254
|
+
lines.push(`validation=${graph.summary.validationCommands.length > 0 ? graph.summary.validationCommands.join(' | ') : 'none'}`);
|
|
1255
|
+
lines.push('nodes');
|
|
1256
|
+
for (const node of graph.nodes) {
|
|
1257
|
+
lines.push(`- ${node.taskId} status=${node.status} wave=${node.wave ?? 'n/a'} deps=${node.dependsOn.join(',') || 'none'} files=${node.affectedFiles.length}`);
|
|
1258
|
+
}
|
|
1259
|
+
if (graph.dependencyEdges.length > 0) {
|
|
1260
|
+
lines.push('dependency_edges');
|
|
1261
|
+
for (const edge of graph.dependencyEdges) {
|
|
1262
|
+
lines.push(`- ${edge.from} -> ${edge.to}`);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
if (graph.fileOverlapEdges.length > 0) {
|
|
1266
|
+
lines.push('file_overlap_edges');
|
|
1267
|
+
for (const edge of graph.fileOverlapEdges) {
|
|
1268
|
+
lines.push(`- ${edge.from} <-> ${edge.to}: ${edge.files.join(',')}`);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
if (graph.diagnostics.length > 0) {
|
|
1272
|
+
lines.push('diagnostics');
|
|
1273
|
+
for (const diagnostic of graph.diagnostics) {
|
|
1274
|
+
lines.push(`- [${diagnostic.severity}] ${diagnostic.taskId ?? 'document'} ${diagnostic.field}: ${diagnostic.message}`);
|
|
1275
|
+
lines.push(` recommendation: ${diagnostic.recommendation}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
return lines.join('\n');
|
|
1279
|
+
}
|
|
1280
|
+
function renderWavePlan(plan) {
|
|
1281
|
+
const lines = [`Wave plan ${plan.valid ? 'valid' : 'blocked'} for ${plan.branch}`];
|
|
1282
|
+
lines.push(`version=${plan.version}`);
|
|
1283
|
+
lines.push(`tasks=${plan.summary.tasks} waves=${plan.summary.waves} planned=${plan.summary.plannedTasks} manual=${plan.summary.manualTasks} blocked=${plan.summary.blockedTasks}`);
|
|
1284
|
+
if (plan.waves.length > 0) {
|
|
1285
|
+
lines.push('waves');
|
|
1286
|
+
for (const wave of plan.waves) {
|
|
1287
|
+
const tasks = wave.tasks.map((task) => `${task.taskId}(${task.isolationMode})`).join(', ');
|
|
1288
|
+
lines.push(`- wave ${wave.index}: ${tasks}`);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (plan.manualGates.length > 0) {
|
|
1292
|
+
lines.push('manual_gates');
|
|
1293
|
+
for (const gate of plan.manualGates) {
|
|
1294
|
+
lines.push(`- ${gate.taskId}: ${gate.reasons.join(' | ')}`);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (plan.blockedTasks.length > 0) {
|
|
1298
|
+
lines.push('blocked_tasks');
|
|
1299
|
+
for (const gate of plan.blockedTasks) {
|
|
1300
|
+
lines.push(`- ${gate.taskId}: ${gate.reasons.join(' | ')}`);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
if (plan.diagnostics.length > 0) {
|
|
1304
|
+
lines.push('diagnostics');
|
|
1305
|
+
for (const diagnostic of plan.diagnostics) {
|
|
1306
|
+
lines.push(`- [${diagnostic.severity}] ${diagnostic.taskId ?? 'document'} ${diagnostic.field}: ${diagnostic.message}`);
|
|
1307
|
+
lines.push(` recommendation: ${diagnostic.recommendation}`);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
return lines.join('\n');
|
|
1311
|
+
}
|
|
1312
|
+
function readOption(args, name) {
|
|
1313
|
+
const index = args.indexOf(name);
|
|
1314
|
+
if (index < 0) {
|
|
1315
|
+
return null;
|
|
1316
|
+
}
|
|
1317
|
+
return args[index + 1] ?? null;
|
|
1318
|
+
}
|
|
1319
|
+
function readWaveExecutorStrategy(args, name) {
|
|
1320
|
+
const value = readOption(args, name) ?? 'fast-stop';
|
|
1321
|
+
return value === 'fast-stop' || value === 'safe-continue' ? value : null;
|
|
1322
|
+
}
|
|
1323
|
+
function readRunStatus(args, name) {
|
|
1324
|
+
const value = readOption(args, name);
|
|
1325
|
+
return value === 'created' || value === 'running' || value === 'completed' || value === 'blocked' || value === 'failed' || value === 'archived' ? value : null;
|
|
1326
|
+
}
|
|
1327
|
+
function readGovernancePolicyOperation(value) {
|
|
1328
|
+
return value === 'background_executor' || value === 'wave_executor' || value === 'sync_back_apply' || value === 'destructive_git' || value === 'external_interaction' || value === 'cleanup' ? value : null;
|
|
1329
|
+
}
|
|
1330
|
+
function readRepeatedOption(args, name) {
|
|
1331
|
+
const values = [];
|
|
1332
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1333
|
+
if (args[index] === name && args[index + 1]) {
|
|
1334
|
+
values.push(args[index + 1]);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return values;
|
|
1338
|
+
}
|
|
1339
|
+
function readTaskArtifactOptions(args) {
|
|
1340
|
+
const artifacts = {};
|
|
1341
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1342
|
+
if (args[index] !== '--artifact') {
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
const value = args[index + 1];
|
|
1346
|
+
const separator = value?.indexOf(':') ?? -1;
|
|
1347
|
+
if (!value || separator <= 0) {
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
artifacts[value.slice(0, separator)] = value.slice(separator + 1);
|
|
1351
|
+
}
|
|
1352
|
+
return artifacts;
|
|
1353
|
+
}
|
|
1354
|
+
function readSddResultStatus(args, name) {
|
|
1355
|
+
const value = readOption(args, name);
|
|
1356
|
+
return value === 'PASS' || value === 'PASS_WITH_GAPS' || value === 'FAIL' || value === 'BLOCKED' || value === 'TIMED_OUT' || value === 'CANCELLED' ? value : null;
|
|
1357
|
+
}
|
|
1358
|
+
function renderArtifactValidationReport(artifactPath, report, expectedTask, expectedAgent) {
|
|
1359
|
+
if (report.valid) {
|
|
1360
|
+
return `Artifact valid: ${artifactPath}`;
|
|
1361
|
+
}
|
|
1362
|
+
const lines = [`Artifact invalid: ${artifactPath}`];
|
|
1363
|
+
for (const issue of report.issues) {
|
|
1364
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1365
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1366
|
+
}
|
|
1367
|
+
if (expectedTask && expectedAgent) {
|
|
1368
|
+
lines.push(`next sdd artifact template ${artifactPath} --task ${expectedTask} --agent ${expectedAgent}`);
|
|
1369
|
+
}
|
|
1370
|
+
return lines.join('\n');
|
|
1371
|
+
}
|
|
1372
|
+
function readAiToolSelection(args, allowNone) {
|
|
1373
|
+
const value = readOption(args, '--ai') ?? 'auto';
|
|
1374
|
+
if (value === 'auto' || value === 'claude-code' || (allowNone && value === 'none')) {
|
|
1375
|
+
return value;
|
|
1376
|
+
}
|
|
1377
|
+
throw new Error(`Unsupported --ai value: ${value}`);
|
|
1378
|
+
}
|
|
1379
|
+
function readLifecycleSignalOptions(args) {
|
|
1380
|
+
const directSafe = args.includes('--direct-safe');
|
|
1381
|
+
const riskTags = readRepeatedOptions(args, '--risk');
|
|
1382
|
+
const contracts = readRepeatedOptions(args, '--contract');
|
|
1383
|
+
const permissions = readRepeatedOptions(args, '--permission');
|
|
1384
|
+
return {
|
|
1385
|
+
intent_clarity: directSafe ? 'high' : readSignalClarity(args, '--intent') ?? 'medium',
|
|
1386
|
+
acceptance_clarity: directSafe ? 'high' : readSignalClarity(args, '--acceptance') ?? 'medium',
|
|
1387
|
+
estimated_change_size: directSafe ? 'tiny' : readEstimatedChangeSize(args, '--size') ?? 'small',
|
|
1388
|
+
task_count_estimate: Number(readOption(args, '--tasks') ?? (directSafe ? '1' : '1')),
|
|
1389
|
+
file_count_estimate: Number(readOption(args, '--files') ?? (directSafe ? '1' : '1')),
|
|
1390
|
+
affected_layers: readRepeatedOptions(args, '--layer'),
|
|
1391
|
+
affected_contracts: contracts,
|
|
1392
|
+
dependency_fanout: readDependencyFanout(args, '--fanout') ?? 'local',
|
|
1393
|
+
impact_confidence: directSafe ? 'high' : readImpactConfidence(args, '--impact-confidence') ?? 'medium',
|
|
1394
|
+
risk_tags: riskTags,
|
|
1395
|
+
reversibility: directSafe ? 'reversible' : readReversibility(args, '--reversibility') ?? 'unknown',
|
|
1396
|
+
validation_clarity: directSafe ? 'clear' : readValidationClarity(args, '--validation') ?? 'partial',
|
|
1397
|
+
validation_available: directSafe || args.includes('--validation-available'),
|
|
1398
|
+
validation_cost: directSafe ? 'cheap' : readValidationCost(args, '--validation-cost') ?? 'unknown',
|
|
1399
|
+
policy_hits: readRepeatedOptions(args, '--policy'),
|
|
1400
|
+
permission_required: permissions,
|
|
1401
|
+
requires_agents: args.includes('--requires-agents'),
|
|
1402
|
+
handoff_count: Number(readOption(args, '--handoffs') ?? '0'),
|
|
1403
|
+
artifact_dependency: args.includes('--artifact-dependency'),
|
|
1404
|
+
runtime_recovery_need: args.includes('--runtime-recovery'),
|
|
1405
|
+
orchestration_uncertainty: directSafe ? 'low' : readOrchestrationUncertainty(args, '--orchestration') ?? 'medium',
|
|
1406
|
+
human_checkpoint_required: args.includes('--checkpoint'),
|
|
1407
|
+
approval_reason: readRepeatedOptions(args, '--approval-reason'),
|
|
1408
|
+
source_artifacts: readRepeatedOptions(args, '--source-artifact'),
|
|
1409
|
+
can_scout_impact: !args.includes('--cannot-scout-impact'),
|
|
1410
|
+
architecture_decision_required: args.includes('--architecture'),
|
|
1411
|
+
external_unknown: args.includes('--external-unknown')
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
function readRepeatedOptions(args, name) {
|
|
1415
|
+
const values = [];
|
|
1416
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1417
|
+
if (args[index] === name && args[index + 1]) {
|
|
1418
|
+
values.push(args[index + 1]);
|
|
1419
|
+
index += 1;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
return values;
|
|
1423
|
+
}
|
|
1424
|
+
function readSignalClarity(args, name) {
|
|
1425
|
+
const value = readOption(args, name);
|
|
1426
|
+
return value === 'high' || value === 'medium' || value === 'low' ? value : null;
|
|
1427
|
+
}
|
|
1428
|
+
function readEstimatedChangeSize(args, name) {
|
|
1429
|
+
const value = readOption(args, name);
|
|
1430
|
+
return value === 'tiny' || value === 'small' || value === 'medium' || value === 'large' ? value : null;
|
|
1431
|
+
}
|
|
1432
|
+
function readImpactConfidence(args, name) {
|
|
1433
|
+
return readSignalClarity(args, name);
|
|
1434
|
+
}
|
|
1435
|
+
function readValidationClarity(args, name) {
|
|
1436
|
+
const value = readOption(args, name);
|
|
1437
|
+
return value === 'clear' || value === 'partial' || value === 'unclear' ? value : null;
|
|
1438
|
+
}
|
|
1439
|
+
function readValidationCost(args, name) {
|
|
1440
|
+
const value = readOption(args, name);
|
|
1441
|
+
return value === 'cheap' || value === 'moderate' || value === 'expensive' || value === 'unknown' ? value : null;
|
|
1442
|
+
}
|
|
1443
|
+
function readDependencyFanout(args, name) {
|
|
1444
|
+
const value = readOption(args, name);
|
|
1445
|
+
return value === 'none' || value === 'local' || value === 'multi_component' || value === 'unknown' ? value : null;
|
|
1446
|
+
}
|
|
1447
|
+
function readReversibility(args, name) {
|
|
1448
|
+
const value = readOption(args, name);
|
|
1449
|
+
return value === 'reversible' || value === 'irreversible' || value === 'unknown' ? value : null;
|
|
1450
|
+
}
|
|
1451
|
+
function readOrchestrationUncertainty(args, name) {
|
|
1452
|
+
const value = readOption(args, name);
|
|
1453
|
+
return value === 'low' || value === 'medium' || value === 'high' ? value : null;
|
|
1454
|
+
}
|
|
1455
|
+
function taskFormatText() {
|
|
1456
|
+
return `# Canonical sdd-task format
|
|
1457
|
+
|
|
1458
|
+
\`\`\`sdd-task
|
|
1459
|
+
id: T1
|
|
1460
|
+
status: pending
|
|
1461
|
+
wave: 1
|
|
1462
|
+
depends_on: []
|
|
1463
|
+
affected_files:
|
|
1464
|
+
- path/to/file
|
|
1465
|
+
validation:
|
|
1466
|
+
- command string
|
|
1467
|
+
risk: []
|
|
1468
|
+
\`\`\`
|
|
1469
|
+
|
|
1470
|
+
Companion sections such as #### Boundary, #### Acceptance, and #### Implementation Notes must stay outside the fenced sdd-task metadata block. Keep only metadata inside the fence.
|
|
1471
|
+
|
|
1472
|
+
#### Boundary
|
|
1473
|
+
|
|
1474
|
+
Allowed implementation scope. Explicitly list forbidden scope when relevant.
|
|
1475
|
+
|
|
1476
|
+
#### Acceptance
|
|
1477
|
+
|
|
1478
|
+
- Verifiable acceptance item.
|
|
1479
|
+
|
|
1480
|
+
#### Implementation Notes
|
|
1481
|
+
|
|
1482
|
+
Reserved for approved sync-back notes and artifact links.
|
|
1483
|
+
`;
|
|
1484
|
+
}
|
|
1485
|
+
main(process.argv.slice(2))
|
|
1486
|
+
.then((result) => {
|
|
1487
|
+
if (result.output) {
|
|
1488
|
+
console.log(result.output);
|
|
1489
|
+
}
|
|
1490
|
+
if (result.error) {
|
|
1491
|
+
console.error(result.error);
|
|
1492
|
+
}
|
|
1493
|
+
process.exitCode = result.exitCode;
|
|
1494
|
+
})
|
|
1495
|
+
.catch((error) => {
|
|
1496
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1497
|
+
process.exitCode = 1;
|
|
1498
|
+
});
|
|
1499
|
+
//# sourceMappingURL=main.js.map
|