sdd-agent-platform 0.1.0 → 0.2.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 +144 -310
- package/dist/packages/cli/src/main.js +1174 -309
- package/dist/packages/cli/src/main.js.map +1 -1
- package/dist/packages/cli/src/options.d.ts +4 -0
- package/dist/packages/cli/src/options.js +35 -0
- package/dist/packages/cli/src/options.js.map +1 -0
- package/dist/packages/core/src/ai-tools.d.ts +19 -2
- package/dist/packages/core/src/ai-tools.js +112 -21
- package/dist/packages/core/src/ai-tools.js.map +1 -1
- package/dist/packages/core/src/index.d.ts +739 -4
- package/dist/packages/core/src/index.js +3800 -220
- package/dist/packages/core/src/index.js.map +1 -1
- package/dist/packages/core/src/instructions.js +35 -34
- package/dist/packages/core/src/instructions.js.map +1 -1
- package/dist/packages/core/src/path-safety.d.ts +4 -0
- package/dist/packages/core/src/path-safety.js +35 -0
- package/dist/packages/core/src/path-safety.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { writeArtifact, archiveRun, applyAiToolEntries, applySyncBack, createWorktreeLifecycle, createRun, doctor, evaluateLifecycleDecisionGate, extractLifecycleRiskSignalsFromText, evaluateGovernancePolicy, getProjectStatus, getDelegationStateMachine, getSddInstructions, initProject, inspectRun, claimResidentWorkerRuntime, heartbeatResidentWorkerRuntime, inspectSddTask, inspectToolPluginContract, inspectToolCapability, inspectDelegationQueueItem, inspectSyncBack, inspectTaskGraph, inspectWavePlan, inspectWaveExecutor, inspectBackgroundExecutor, inspectResidentWorkerRuntime, inspectArtifactResultIngestions, inspectWorktreeLifecycle, inspectWorkerAdapterContract, inspectWorktreeIsolation, inspectGovernancePolicy, inspectWorkflowGate, inspectAgentRegistryEntry, inspectQueryStatusContract, inspectSkillAgentEvalContract, inspectHarnessLearningContract, inspectProjectContextPackContract, inspectAgentSkillTeamRuntime, inspectSkillCapability, inspectCapabilitySource, inspectExternalAgentPackImport, inspectTeamModePolicy, keepWorktreeLifecycle, removeWorktreeLifecycle, listRuns, rebuildLocalRunIndex, inspectLocalRunIndex, queryLocalRunIndex, listToolPluginContracts, listToolCapabilities, listDelegationQueueItems, listWorkerAdapterContracts, listResidentWorkerRuntimes, listWorkflowGates, listAgentRegistry, listSkillCapabilities, listCapabilitySources, ingestArtifactResult, parseSddBranch, readRunState, resolveSddContext, recordLifecycleDecision, renderDoctorReport, renderGoalVerifyResult, renderLifecycleDecisionGate, renderSddResultArtifactTemplate, renderSddInstructions, renderSingleTaskLoopResult, renderTaskGapReport, renderTaskInspect, renderTaskList, runGoalVerify, runSingleTaskLoop, runBackgroundExecutor, runWaveExecutor, SDD_VERSION, summarizeAiProjectionStatus, validateSddResultArtifact, validateWorkflowGates, validateAgentRegistry, validateQueryStatusContract, validateSkillAgentEvalContract, validateHarnessLearningContract, validateProjectContextPackContract, routeSddTask, validateAgentSkillTeamRuntime, toArtifactRootRelativePath } from '../../core/src/index.js';
|
|
4
|
+
import { readOption, readPositiveIntegerOption, readRepeatedOption, readRepeatedOptions } from './options.js';
|
|
3
5
|
async function main(args) {
|
|
4
6
|
const projectRoot = process.cwd();
|
|
5
7
|
const [command, subcommand, ...rest] = args;
|
|
@@ -9,6 +11,12 @@ async function main(args) {
|
|
|
9
11
|
output: helpText()
|
|
10
12
|
};
|
|
11
13
|
}
|
|
14
|
+
if (command === 'help') {
|
|
15
|
+
return {
|
|
16
|
+
exitCode: 0,
|
|
17
|
+
output: helpText(subcommand)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
12
20
|
if (command === '--version' || command === '-v') {
|
|
13
21
|
return {
|
|
14
22
|
exitCode: 0,
|
|
@@ -19,12 +27,13 @@ async function main(args) {
|
|
|
19
27
|
const initArgs = [subcommand, ...rest].filter(Boolean);
|
|
20
28
|
const force = initArgs.includes('--force');
|
|
21
29
|
const aiTool = readAiToolSelection(initArgs, true);
|
|
22
|
-
const branch = readOption(initArgs, '--branch') ??
|
|
23
|
-
const scaffoldDocuments =
|
|
30
|
+
const branch = readOption(initArgs, '--branch') ?? undefined;
|
|
31
|
+
const scaffoldDocuments = initArgs.includes('--no-scaffold-docs') ? false : initArgs.includes('--scaffold-docs') || branch !== undefined;
|
|
24
32
|
const result = await initProject(projectRoot, { force, aiTool, branch, scaffoldDocuments });
|
|
33
|
+
const json = wantsJson(initArgs);
|
|
25
34
|
return {
|
|
26
35
|
exitCode: 0,
|
|
27
|
-
output:
|
|
36
|
+
output: json ? jsonOutput({ command: 'init', ...result }, initArgs) : renderInitResult(result)
|
|
28
37
|
};
|
|
29
38
|
}
|
|
30
39
|
if (command === 'update') {
|
|
@@ -42,10 +51,9 @@ async function main(args) {
|
|
|
42
51
|
const instructionArgs = [subcommand, ...rest].filter(Boolean);
|
|
43
52
|
const action = instructionArgs.find((item) => !item.startsWith('--')) ?? 'overview';
|
|
44
53
|
const payload = getSddInstructions(action);
|
|
45
|
-
const json = instructionArgs.includes('--json');
|
|
46
54
|
return {
|
|
47
55
|
exitCode: 0,
|
|
48
|
-
output:
|
|
56
|
+
output: renderTextOrJson(instructionArgs, payload, renderSddInstructions)
|
|
49
57
|
};
|
|
50
58
|
}
|
|
51
59
|
if (command === 'doctor') {
|
|
@@ -60,18 +68,19 @@ async function main(args) {
|
|
|
60
68
|
latestOnly: doctorArgs.includes('--latest-only'),
|
|
61
69
|
allRuns: doctorArgs.includes('--all-runs')
|
|
62
70
|
});
|
|
71
|
+
const json = wantsJson(doctorArgs);
|
|
63
72
|
return {
|
|
64
73
|
exitCode: report.status === 'FAIL' ? 1 : 0,
|
|
65
|
-
output: renderDoctorReport(report)
|
|
74
|
+
output: json ? jsonOutput(report, doctorArgs) : renderDoctorReport(report)
|
|
66
75
|
};
|
|
67
76
|
}
|
|
68
77
|
if (command === 'status') {
|
|
69
78
|
const statusArgs = [subcommand, ...rest].filter(Boolean);
|
|
70
|
-
const result = await getProjectStatus(projectRoot,
|
|
71
|
-
const json = statusArgs
|
|
79
|
+
const result = await getProjectStatus(projectRoot, readBranchContext(statusArgs));
|
|
80
|
+
const json = wantsJson(statusArgs);
|
|
72
81
|
return {
|
|
73
82
|
exitCode: result.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
74
|
-
output: json ?
|
|
83
|
+
output: json ? jsonOutput(result, statusArgs) : renderProjectStatus(result)
|
|
75
84
|
};
|
|
76
85
|
}
|
|
77
86
|
if (command === 'run' && subcommand === 'create') {
|
|
@@ -105,19 +114,19 @@ async function main(args) {
|
|
|
105
114
|
}
|
|
106
115
|
if (command === 'run' && subcommand === 'index') {
|
|
107
116
|
const action = rest[0];
|
|
108
|
-
const json = rest
|
|
117
|
+
const json = wantsJson(rest);
|
|
109
118
|
if (action === 'rebuild') {
|
|
110
119
|
const index = await rebuildLocalRunIndex(projectRoot);
|
|
111
120
|
return {
|
|
112
121
|
exitCode: 0,
|
|
113
|
-
output: json ?
|
|
122
|
+
output: json ? jsonOutput(index, rest) : renderLocalRunIndex(index)
|
|
114
123
|
};
|
|
115
124
|
}
|
|
116
125
|
if (action === 'inspect') {
|
|
117
126
|
const inspection = await inspectLocalRunIndex(projectRoot);
|
|
118
127
|
return {
|
|
119
128
|
exitCode: inspection.valid ? 0 : 1,
|
|
120
|
-
output: json ?
|
|
129
|
+
output: json ? jsonOutput(inspection, rest) : renderLocalRunIndexInspection(inspection)
|
|
121
130
|
};
|
|
122
131
|
}
|
|
123
132
|
if (action === 'query') {
|
|
@@ -125,7 +134,7 @@ async function main(args) {
|
|
|
125
134
|
if (readOption(rest, '--status') && !status) {
|
|
126
135
|
return {
|
|
127
136
|
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]'
|
|
137
|
+
error: 'Usage: sdd run index query [--run <run_id>] [--task <task_id>] [--status created|running|completed|blocked|failed|archived] [--artifact <path>] [--json|--compact-json]'
|
|
129
138
|
};
|
|
130
139
|
}
|
|
131
140
|
const index = await queryLocalRunIndex(projectRoot, {
|
|
@@ -136,7 +145,7 @@ async function main(args) {
|
|
|
136
145
|
});
|
|
137
146
|
return {
|
|
138
147
|
exitCode: 0,
|
|
139
|
-
output: json ?
|
|
148
|
+
output: json ? jsonOutput(index, rest) : renderLocalRunIndex(index)
|
|
140
149
|
};
|
|
141
150
|
}
|
|
142
151
|
return {
|
|
@@ -153,10 +162,10 @@ async function main(args) {
|
|
|
153
162
|
};
|
|
154
163
|
}
|
|
155
164
|
const result = await inspectRun(projectRoot, runId);
|
|
156
|
-
const json = rest
|
|
165
|
+
const json = wantsJson(rest);
|
|
157
166
|
return {
|
|
158
167
|
exitCode: 0,
|
|
159
|
-
output: json ?
|
|
168
|
+
output: json ? jsonOutput(result, rest) : renderRunInspection(result)
|
|
160
169
|
};
|
|
161
170
|
}
|
|
162
171
|
if (command === 'run' && subcommand === 'archive') {
|
|
@@ -174,42 +183,44 @@ async function main(args) {
|
|
|
174
183
|
};
|
|
175
184
|
}
|
|
176
185
|
if (command === 'sync-back' && subcommand === 'inspect') {
|
|
177
|
-
const runId = rest
|
|
178
|
-
|
|
186
|
+
const runId = readOptionalPositionalArgument(rest);
|
|
187
|
+
const taskId = readOption(rest, '--task') ?? undefined;
|
|
188
|
+
if (!runId && !taskId) {
|
|
179
189
|
return {
|
|
180
190
|
exitCode: 2,
|
|
181
|
-
error: 'Usage: sdd sync-back inspect <run_id> [--branch <branch>]
|
|
191
|
+
error: 'Usage: sdd sync-back inspect [<run_id>] [--branch <branch>] --task <task_id> [--json|--compact-json]'
|
|
182
192
|
};
|
|
183
193
|
}
|
|
184
194
|
const result = await inspectSyncBack(projectRoot, {
|
|
185
195
|
runId,
|
|
186
|
-
branch:
|
|
187
|
-
taskId
|
|
196
|
+
branch: readBranchOption(rest),
|
|
197
|
+
taskId
|
|
188
198
|
});
|
|
189
|
-
const json = rest
|
|
199
|
+
const json = wantsJson(rest);
|
|
190
200
|
return {
|
|
191
201
|
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
192
|
-
output: json ?
|
|
202
|
+
output: json ? jsonOutput(result, rest) : renderSyncBackInspection(result)
|
|
193
203
|
};
|
|
194
204
|
}
|
|
195
205
|
if (command === 'sync-back' && subcommand === 'apply') {
|
|
196
|
-
const runId = rest
|
|
197
|
-
|
|
206
|
+
const runId = readOptionalPositionalArgument(rest);
|
|
207
|
+
const taskId = readOption(rest, '--task') ?? undefined;
|
|
208
|
+
if (!runId && !taskId) {
|
|
198
209
|
return {
|
|
199
210
|
exitCode: 2,
|
|
200
|
-
error: 'Usage: sdd sync-back apply <run_id> [--branch <branch>]
|
|
211
|
+
error: 'Usage: sdd sync-back apply [<run_id>] [--branch <branch>] --task <task_id> [--approved] [--json|--compact-json]'
|
|
201
212
|
};
|
|
202
213
|
}
|
|
203
214
|
const result = await applySyncBack(projectRoot, {
|
|
204
215
|
runId,
|
|
205
|
-
branch:
|
|
206
|
-
taskId
|
|
216
|
+
branch: readBranchOption(rest),
|
|
217
|
+
taskId,
|
|
207
218
|
approved: rest.includes('--approved')
|
|
208
219
|
});
|
|
209
|
-
const json = rest
|
|
220
|
+
const json = wantsJson(rest);
|
|
210
221
|
return {
|
|
211
222
|
exitCode: 0,
|
|
212
|
-
output: json ?
|
|
223
|
+
output: json ? jsonOutput(result, rest) : renderSyncBackApplyResult(result)
|
|
213
224
|
};
|
|
214
225
|
}
|
|
215
226
|
if (command === 'tasks' && subcommand === 'format') {
|
|
@@ -219,7 +230,7 @@ async function main(args) {
|
|
|
219
230
|
};
|
|
220
231
|
}
|
|
221
232
|
if (command === 'tasks' && subcommand === 'list') {
|
|
222
|
-
const model = await parseSddBranch(projectRoot,
|
|
233
|
+
const model = await parseSddBranch(projectRoot, await readResolvedBranch(projectRoot, rest));
|
|
223
234
|
return {
|
|
224
235
|
exitCode: model.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
225
236
|
output: renderTaskList(model)
|
|
@@ -230,10 +241,10 @@ async function main(args) {
|
|
|
230
241
|
if (!taskId) {
|
|
231
242
|
return {
|
|
232
243
|
exitCode: 2,
|
|
233
|
-
error: 'Usage: sdd tasks inspect <task_id> [--branch <branch>]'
|
|
244
|
+
error: 'Usage: sdd tasks inspect <task_id> [--branch <branch>] [--json]'
|
|
234
245
|
};
|
|
235
246
|
}
|
|
236
|
-
const model = await parseSddBranch(projectRoot,
|
|
247
|
+
const model = await parseSddBranch(projectRoot, await readResolvedBranch(projectRoot, rest));
|
|
237
248
|
const result = inspectSddTask(model, taskId);
|
|
238
249
|
if (!result.task && result.gaps.length === 0) {
|
|
239
250
|
return {
|
|
@@ -241,20 +252,46 @@ async function main(args) {
|
|
|
241
252
|
error: `Task not found: ${taskId}`
|
|
242
253
|
};
|
|
243
254
|
}
|
|
255
|
+
const json = wantsJson(rest);
|
|
244
256
|
return {
|
|
245
257
|
exitCode: result.task === null || result.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
246
|
-
output: renderTaskInspect(result.task, result.gaps)
|
|
258
|
+
output: json ? jsonOutput(result, rest) : renderTaskInspect(result.task, result.gaps)
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (command === 'tasks' && subcommand === 'route') {
|
|
262
|
+
const taskId = rest.find((item) => !item.startsWith('--'));
|
|
263
|
+
if (!taskId) {
|
|
264
|
+
return {
|
|
265
|
+
exitCode: 2,
|
|
266
|
+
error: 'Usage: sdd tasks route <task_id> [--branch <branch>] [--team-mode [auto|force|off]] [--no-team-mode] [--json]'
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const decision = await routeSddTask(projectRoot, {
|
|
270
|
+
taskId,
|
|
271
|
+
branch: readBranchOption(rest),
|
|
272
|
+
teamModeActivation: readTeamModeActivation(rest)
|
|
273
|
+
});
|
|
274
|
+
return {
|
|
275
|
+
exitCode: decision.blockedReason ? 1 : 0,
|
|
276
|
+
output: wantsJson(rest) ? jsonOutput(decision, rest) : renderAgentRouterDecision(decision)
|
|
247
277
|
};
|
|
248
278
|
}
|
|
249
279
|
if (command === 'tasks' && subcommand === 'gaps') {
|
|
250
|
-
const model = await parseSddBranch(projectRoot,
|
|
280
|
+
const model = await parseSddBranch(projectRoot, await readResolvedBranch(projectRoot, rest));
|
|
251
281
|
return {
|
|
252
282
|
exitCode: model.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
253
283
|
output: renderTaskGapReport(model)
|
|
254
284
|
};
|
|
255
285
|
}
|
|
256
286
|
if (command === 'lifecycle' && subcommand === 'decide') {
|
|
257
|
-
const
|
|
287
|
+
const lifecycleInput = await readLifecycleSignalOptions(rest);
|
|
288
|
+
if (lifecycleInput.error) {
|
|
289
|
+
return {
|
|
290
|
+
exitCode: 2,
|
|
291
|
+
error: lifecycleInput.error
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const result = evaluateLifecycleDecisionGate(lifecycleInput.signals);
|
|
258
295
|
const runId = readOption(rest, '--run');
|
|
259
296
|
if (runId) {
|
|
260
297
|
await recordLifecycleDecision(projectRoot, runId, result.record);
|
|
@@ -262,7 +299,9 @@ async function main(args) {
|
|
|
262
299
|
const json = rest.includes('--json');
|
|
263
300
|
return {
|
|
264
301
|
exitCode: 0,
|
|
265
|
-
output: json
|
|
302
|
+
output: json
|
|
303
|
+
? JSON.stringify({ riskExtraction: lifecycleInput.riskExtraction, ...result, recordedRunId: runId ?? null }, null, 2)
|
|
304
|
+
: `${renderLifecycleRiskExtraction(lifecycleInput.riskExtraction)}${renderLifecycleDecisionGate(result)}${runId ? `\nrecorded_run=${runId}` : ''}`
|
|
266
305
|
};
|
|
267
306
|
}
|
|
268
307
|
if (command === 'do' && subcommand === 'task') {
|
|
@@ -270,42 +309,45 @@ async function main(args) {
|
|
|
270
309
|
if (!taskId) {
|
|
271
310
|
return {
|
|
272
311
|
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]'
|
|
312
|
+
error: 'Usage: sdd do task <task_id> [--branch <branch>] [--run <run_id>] [--team-mode [auto|force|off]] [--no-team-mode] [--implement-artifact artifacts/path.md] [--review-artifact artifacts/path.md] [--debug-artifact artifacts/path.md] [--validation-artifact artifacts/path.md]'
|
|
274
313
|
};
|
|
275
314
|
}
|
|
276
315
|
const result = await runSingleTaskLoop(projectRoot, {
|
|
277
316
|
taskId,
|
|
278
|
-
branch:
|
|
317
|
+
branch: readBranchOption(rest),
|
|
279
318
|
runId: readOption(rest, '--run') ?? undefined,
|
|
280
319
|
implementArtifact: readOption(rest, '--implement-artifact') ?? undefined,
|
|
281
320
|
reviewArtifact: readOption(rest, '--review-artifact') ?? undefined,
|
|
282
321
|
debugArtifact: readOption(rest, '--debug-artifact') ?? undefined,
|
|
283
|
-
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined
|
|
322
|
+
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined,
|
|
323
|
+
teamModeActivation: readTeamModeActivation(rest)
|
|
284
324
|
});
|
|
325
|
+
const json = wantsJson(rest);
|
|
285
326
|
return {
|
|
286
327
|
exitCode: result.status === 'completed' ? 0 : 1,
|
|
287
|
-
output: renderSingleTaskLoopResult(result)
|
|
328
|
+
output: json ? jsonOutput(result, rest) : renderSingleTaskLoopResult(result)
|
|
288
329
|
};
|
|
289
330
|
}
|
|
290
331
|
if (command === 'verify' && subcommand === 'task') {
|
|
291
|
-
const taskId = rest
|
|
332
|
+
const taskId = readOptionalPositionalArgument(rest);
|
|
292
333
|
const runId = readOption(rest, '--run');
|
|
293
|
-
if (!taskId
|
|
334
|
+
if (!taskId) {
|
|
294
335
|
return {
|
|
295
336
|
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]'
|
|
337
|
+
error: 'Usage: sdd verify task <task_id> [--run <run_id>] [--branch <branch>] [--review-artifact artifacts/path.md] [--validation-artifact artifacts/path.md] [--json]'
|
|
297
338
|
};
|
|
298
339
|
}
|
|
299
340
|
const result = await runGoalVerify(projectRoot, {
|
|
300
341
|
taskId,
|
|
301
|
-
runId,
|
|
302
|
-
branch:
|
|
342
|
+
runId: runId ?? undefined,
|
|
343
|
+
branch: readBranchOption(rest),
|
|
303
344
|
reviewArtifact: readOption(rest, '--review-artifact') ?? undefined,
|
|
304
345
|
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined
|
|
305
346
|
});
|
|
347
|
+
const json = wantsJson(rest);
|
|
306
348
|
return {
|
|
307
349
|
exitCode: result.status === 'PASS' ? 0 : 1,
|
|
308
|
-
output: renderGoalVerifyResult(result)
|
|
350
|
+
output: json ? jsonOutput(result, rest) : renderGoalVerifyResult(result)
|
|
309
351
|
};
|
|
310
352
|
}
|
|
311
353
|
if (command === 'governance' && subcommand === 'inspect') {
|
|
@@ -334,6 +376,217 @@ async function main(args) {
|
|
|
334
376
|
output: rest.includes('--json') ? JSON.stringify(decision, null, 2) : renderGovernancePolicyDecision(decision)
|
|
335
377
|
};
|
|
336
378
|
}
|
|
379
|
+
if (command === 'workflow' && subcommand === 'list') {
|
|
380
|
+
const registry = await listWorkflowGates(projectRoot);
|
|
381
|
+
return {
|
|
382
|
+
exitCode: 0,
|
|
383
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderWorkflowGateList(registry.workflows)
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (command === 'workflow' && subcommand === 'inspect') {
|
|
387
|
+
const workflowId = rest.find((item) => !item.startsWith('--'));
|
|
388
|
+
if (!workflowId) {
|
|
389
|
+
return {
|
|
390
|
+
exitCode: 2,
|
|
391
|
+
error: 'Usage: sdd workflow inspect <workflow_id> [--json]'
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
const workflow = await inspectWorkflowGate(projectRoot, workflowId);
|
|
395
|
+
if (!workflow) {
|
|
396
|
+
return {
|
|
397
|
+
exitCode: 1,
|
|
398
|
+
error: `Unknown workflow: ${workflowId}`
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
exitCode: 0,
|
|
403
|
+
output: rest.includes('--json') ? JSON.stringify(workflow, null, 2) : renderWorkflowGateInspect(workflow)
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
if (command === 'workflow' && subcommand === 'validate') {
|
|
407
|
+
const result = await validateWorkflowGates(projectRoot);
|
|
408
|
+
return {
|
|
409
|
+
exitCode: result.valid ? 0 : 1,
|
|
410
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderWorkflowGateValidation(result)
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
if (command === 'agents' && subcommand === 'list') {
|
|
414
|
+
const registry = await listAgentRegistry(projectRoot);
|
|
415
|
+
return {
|
|
416
|
+
exitCode: 0,
|
|
417
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderAgentRegistryList(registry.agents)
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (command === 'agents' && subcommand === 'inspect') {
|
|
421
|
+
const agentId = rest.find((item) => !item.startsWith('--'));
|
|
422
|
+
if (!agentId) {
|
|
423
|
+
return {
|
|
424
|
+
exitCode: 2,
|
|
425
|
+
error: 'Usage: sdd agents inspect <agent_id> [--json]'
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const agent = await inspectAgentRegistryEntry(projectRoot, agentId);
|
|
429
|
+
if (!agent) {
|
|
430
|
+
return {
|
|
431
|
+
exitCode: 1,
|
|
432
|
+
error: `Unknown agent: ${agentId}`
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
exitCode: 0,
|
|
437
|
+
output: rest.includes('--json') ? JSON.stringify(agent, null, 2) : renderAgentRegistryInspect(agent)
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (command === 'agents' && subcommand === 'validate') {
|
|
441
|
+
const result = await validateAgentRegistry(projectRoot);
|
|
442
|
+
return {
|
|
443
|
+
exitCode: result.valid ? 0 : 1,
|
|
444
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderAgentRegistryValidation(result)
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (command === 'agent-runtime' && subcommand === 'inspect') {
|
|
448
|
+
const inspection = await inspectAgentSkillTeamRuntime(projectRoot);
|
|
449
|
+
return {
|
|
450
|
+
exitCode: 0,
|
|
451
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderAgentSkillTeamRuntimeInspection(inspection)
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
if (command === 'agent-runtime' && subcommand === 'validate') {
|
|
455
|
+
const result = await validateAgentSkillTeamRuntime(projectRoot);
|
|
456
|
+
return {
|
|
457
|
+
exitCode: result.valid ? 0 : 1,
|
|
458
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderAgentSkillTeamRuntimeValidation(result)
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
if (command === 'skill-capabilities' && subcommand === 'list') {
|
|
462
|
+
const registry = await listSkillCapabilities(projectRoot);
|
|
463
|
+
return {
|
|
464
|
+
exitCode: 0,
|
|
465
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderSkillCapabilityList(registry.capabilities, registry.registrySources)
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
if (command === 'skill-capabilities' && subcommand === 'inspect') {
|
|
469
|
+
const capabilityId = rest.find((item) => !item.startsWith('--'));
|
|
470
|
+
if (!capabilityId) {
|
|
471
|
+
return {
|
|
472
|
+
exitCode: 2,
|
|
473
|
+
error: 'Usage: sdd skill-capabilities inspect <capability_id> [--json]'
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const capability = await inspectSkillCapability(projectRoot, capabilityId);
|
|
477
|
+
if (!capability) {
|
|
478
|
+
return { exitCode: 1, error: `Unknown skill capability: ${capabilityId}` };
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
exitCode: 0,
|
|
482
|
+
output: rest.includes('--json') ? JSON.stringify(capability, null, 2) : renderSkillCapabilityInspect(capability)
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
if (command === 'capability-sources' && subcommand === 'list') {
|
|
486
|
+
const catalog = await listCapabilitySources(projectRoot);
|
|
487
|
+
return {
|
|
488
|
+
exitCode: 0,
|
|
489
|
+
output: rest.includes('--json') ? JSON.stringify(catalog, null, 2) : renderCapabilitySourceList(catalog.sources, catalog.registrySources)
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
if (command === 'capability-sources' && subcommand === 'inspect') {
|
|
493
|
+
const sourceId = rest.find((item) => !item.startsWith('--'));
|
|
494
|
+
if (!sourceId) {
|
|
495
|
+
return {
|
|
496
|
+
exitCode: 2,
|
|
497
|
+
error: 'Usage: sdd capability-sources inspect <source_id> [--json]'
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
const source = await inspectCapabilitySource(projectRoot, sourceId);
|
|
501
|
+
if (!source) {
|
|
502
|
+
return { exitCode: 1, error: `Unknown capability source: ${sourceId}` };
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
exitCode: 0,
|
|
506
|
+
output: rest.includes('--json') ? JSON.stringify(source, null, 2) : renderCapabilitySourceInspect(source)
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
if (command === 'external-packs' && subcommand === 'inspect') {
|
|
510
|
+
const sourceId = rest.find((item) => !item.startsWith('--'));
|
|
511
|
+
if (!sourceId) {
|
|
512
|
+
return {
|
|
513
|
+
exitCode: 2,
|
|
514
|
+
error: 'Usage: sdd external-packs inspect <source_id> [--json]'
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
const inspection = await inspectExternalAgentPackImport(projectRoot, sourceId);
|
|
518
|
+
return {
|
|
519
|
+
exitCode: inspection.status === 'denied' ? 1 : 0,
|
|
520
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderExternalAgentPackImportInspection(inspection)
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (command === 'team-mode' && subcommand === 'inspect') {
|
|
524
|
+
const policy = await inspectTeamModePolicy(projectRoot, {
|
|
525
|
+
taskId: readOption(rest, '--task') ?? undefined,
|
|
526
|
+
branch: readBranchOption(rest),
|
|
527
|
+
teamModeActivation: readTeamModeActivation(rest, rest.includes('--enabled') ? 'force' : undefined)
|
|
528
|
+
});
|
|
529
|
+
return {
|
|
530
|
+
exitCode: policy.decision === 'blocked' ? 1 : 0,
|
|
531
|
+
output: rest.includes('--json') ? JSON.stringify(policy, null, 2) : renderTeamModePolicy(policy)
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
if (command === 'query-status' && subcommand === 'inspect') {
|
|
535
|
+
const contract = await inspectQueryStatusContract(projectRoot);
|
|
536
|
+
return {
|
|
537
|
+
exitCode: 0,
|
|
538
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderQueryStatusContract(contract)
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
if (command === 'query-status' && subcommand === 'validate') {
|
|
542
|
+
const result = await validateQueryStatusContract(projectRoot);
|
|
543
|
+
return {
|
|
544
|
+
exitCode: result.valid ? 0 : 1,
|
|
545
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderQueryStatusValidation(result)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
if (command === 'eval' && subcommand === 'inspect') {
|
|
549
|
+
const contract = await inspectSkillAgentEvalContract(projectRoot);
|
|
550
|
+
return {
|
|
551
|
+
exitCode: 0,
|
|
552
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderSkillAgentEvalContract(contract)
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
if (command === 'eval' && subcommand === 'validate') {
|
|
556
|
+
const result = await validateSkillAgentEvalContract(projectRoot);
|
|
557
|
+
return {
|
|
558
|
+
exitCode: result.valid ? 0 : 1,
|
|
559
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderSkillAgentEvalValidation(result)
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
if (command === 'learning' && subcommand === 'inspect') {
|
|
563
|
+
const contract = await inspectHarnessLearningContract(projectRoot);
|
|
564
|
+
return {
|
|
565
|
+
exitCode: 0,
|
|
566
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderHarnessLearningContract(contract)
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
if (command === 'learning' && subcommand === 'validate') {
|
|
570
|
+
const result = await validateHarnessLearningContract(projectRoot);
|
|
571
|
+
return {
|
|
572
|
+
exitCode: result.valid ? 0 : 1,
|
|
573
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderHarnessLearningValidation(result)
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
if (command === 'context-pack' && subcommand === 'inspect') {
|
|
577
|
+
const contract = await inspectProjectContextPackContract(projectRoot);
|
|
578
|
+
return {
|
|
579
|
+
exitCode: 0,
|
|
580
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderProjectContextPackContract(contract)
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
if (command === 'context-pack' && subcommand === 'validate') {
|
|
584
|
+
const result = await validateProjectContextPackContract(projectRoot);
|
|
585
|
+
return {
|
|
586
|
+
exitCode: result.valid ? 0 : 1,
|
|
587
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderProjectContextPackValidation(result)
|
|
588
|
+
};
|
|
589
|
+
}
|
|
337
590
|
if (command === 'capabilities' && subcommand === 'list') {
|
|
338
591
|
const registry = await listToolCapabilities(projectRoot);
|
|
339
592
|
return {
|
|
@@ -432,7 +685,7 @@ async function main(args) {
|
|
|
432
685
|
}
|
|
433
686
|
const decision = await inspectWorktreeIsolation(projectRoot, {
|
|
434
687
|
taskId,
|
|
435
|
-
branch:
|
|
688
|
+
branch: readBranchOption(rest),
|
|
436
689
|
capabilityId: readOption(rest, '--capability') ?? undefined,
|
|
437
690
|
peerTaskIds: readRepeatedOptions(rest, '--peer-task')
|
|
438
691
|
});
|
|
@@ -442,7 +695,7 @@ async function main(args) {
|
|
|
442
695
|
};
|
|
443
696
|
}
|
|
444
697
|
if (command === 'graph' && subcommand === 'inspect') {
|
|
445
|
-
const graph = await inspectTaskGraph(projectRoot, { branch:
|
|
698
|
+
const graph = await inspectTaskGraph(projectRoot, { branch: readBranchOption(rest) });
|
|
446
699
|
return {
|
|
447
700
|
exitCode: graph.valid ? 0 : 1,
|
|
448
701
|
output: rest.includes('--json') ? JSON.stringify(graph, null, 2) : renderTaskGraphPlan(graph)
|
|
@@ -450,7 +703,7 @@ async function main(args) {
|
|
|
450
703
|
}
|
|
451
704
|
if (command === 'wave' && subcommand === 'inspect') {
|
|
452
705
|
const wavePlan = await inspectWavePlan(projectRoot, {
|
|
453
|
-
branch:
|
|
706
|
+
branch: readBranchOption(rest),
|
|
454
707
|
capabilityId: readOption(rest, '--capability') ?? undefined
|
|
455
708
|
});
|
|
456
709
|
return {
|
|
@@ -467,7 +720,7 @@ async function main(args) {
|
|
|
467
720
|
};
|
|
468
721
|
}
|
|
469
722
|
const result = await runWaveExecutor(projectRoot, {
|
|
470
|
-
branch:
|
|
723
|
+
branch: readBranchOption(rest),
|
|
471
724
|
runId: readOption(rest, '--run') ?? undefined,
|
|
472
725
|
capabilityId: readOption(rest, '--capability') ?? undefined,
|
|
473
726
|
agent: readOption(rest, '--agent') ?? undefined,
|
|
@@ -503,7 +756,7 @@ async function main(args) {
|
|
|
503
756
|
};
|
|
504
757
|
}
|
|
505
758
|
const result = await runBackgroundExecutor(projectRoot, {
|
|
506
|
-
branch:
|
|
759
|
+
branch: readBranchOption(rest),
|
|
507
760
|
runId: readOption(rest, '--run') ?? undefined,
|
|
508
761
|
taskId,
|
|
509
762
|
agent: readOption(rest, '--agent') ?? undefined,
|
|
@@ -530,6 +783,78 @@ async function main(args) {
|
|
|
530
783
|
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderBackgroundExecutorInspection(inspection)
|
|
531
784
|
};
|
|
532
785
|
}
|
|
786
|
+
if (command === 'worker-runtime' && subcommand === 'claim') {
|
|
787
|
+
const taskId = rest[0];
|
|
788
|
+
if (!taskId) {
|
|
789
|
+
return {
|
|
790
|
+
exitCode: 2,
|
|
791
|
+
error: 'Usage: sdd worker-runtime claim <task_id> [--run <run_id>] [--runtime <runtime_id>] [--agent <agent>] [--worker <adapter_id>] [--delegation <delegation_id>] [--lease-seconds <n>] [--branch <branch>] [--json]'
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
const result = await claimResidentWorkerRuntime(projectRoot, {
|
|
795
|
+
branch: readBranchOption(rest),
|
|
796
|
+
runId: readOption(rest, '--run') ?? undefined,
|
|
797
|
+
taskId,
|
|
798
|
+
runtimeId: readOption(rest, '--runtime') ?? undefined,
|
|
799
|
+
agent: readOption(rest, '--agent') ?? undefined,
|
|
800
|
+
workerAdapterId: readOption(rest, '--worker') ?? undefined,
|
|
801
|
+
delegationId: readOption(rest, '--delegation') ?? undefined,
|
|
802
|
+
leaseSeconds: readPositiveIntegerOption(rest, '--lease-seconds') ?? undefined
|
|
803
|
+
});
|
|
804
|
+
return {
|
|
805
|
+
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
806
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeClaimResult(result)
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
if (command === 'worker-runtime' && subcommand === 'heartbeat') {
|
|
810
|
+
const runtimeId = rest[0];
|
|
811
|
+
const runId = readOption(rest, '--run');
|
|
812
|
+
if (!runtimeId || !runId) {
|
|
813
|
+
return {
|
|
814
|
+
exitCode: 2,
|
|
815
|
+
error: 'Usage: sdd worker-runtime heartbeat <runtime_id> --run <run_id> [--lease-seconds <n>] [--json]'
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
const result = await heartbeatResidentWorkerRuntime(projectRoot, {
|
|
819
|
+
runId,
|
|
820
|
+
runtimeId,
|
|
821
|
+
leaseSeconds: readPositiveIntegerOption(rest, '--lease-seconds') ?? undefined
|
|
822
|
+
});
|
|
823
|
+
return {
|
|
824
|
+
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
825
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeHeartbeatResult(result)
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
if (command === 'worker-runtime' && subcommand === 'status') {
|
|
829
|
+
const positionalRunId = rest[0] && !rest[0].startsWith('--') ? rest[0] : null;
|
|
830
|
+
const runId = readOption(rest, '--run') ?? positionalRunId;
|
|
831
|
+
if (!runId) {
|
|
832
|
+
return {
|
|
833
|
+
exitCode: 2,
|
|
834
|
+
error: 'Usage: sdd worker-runtime status --run <run_id> [--json]'
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const result = await listResidentWorkerRuntimes(projectRoot, { runId });
|
|
838
|
+
return {
|
|
839
|
+
exitCode: result.valid ? 0 : 1,
|
|
840
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeList(result)
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
if (command === 'worker-runtime' && subcommand === 'inspect') {
|
|
844
|
+
const runtimeId = rest[0];
|
|
845
|
+
const runId = readOption(rest, '--run');
|
|
846
|
+
if (!runtimeId || !runId) {
|
|
847
|
+
return {
|
|
848
|
+
exitCode: 2,
|
|
849
|
+
error: 'Usage: sdd worker-runtime inspect <runtime_id> --run <run_id> [--json]'
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
const result = await inspectResidentWorkerRuntime(projectRoot, { runId, runtimeId });
|
|
853
|
+
return {
|
|
854
|
+
exitCode: result.valid ? 0 : 1,
|
|
855
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeInspection(result)
|
|
856
|
+
};
|
|
857
|
+
}
|
|
533
858
|
if (command === 'worktree' && subcommand === 'create') {
|
|
534
859
|
const runId = rest[0];
|
|
535
860
|
const taskId = rest[1];
|
|
@@ -627,18 +952,33 @@ async function main(args) {
|
|
|
627
952
|
if (!artifactPath || !taskId || !agent) {
|
|
628
953
|
return {
|
|
629
954
|
exitCode: 2,
|
|
630
|
-
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> [--branch <branch>] [--status <status>]'
|
|
955
|
+
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> [--run <run_id> --write] [--branch <branch>] [--status <status>]'
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
const template = await renderSddResultArtifactTemplate(projectRoot, {
|
|
959
|
+
artifactPath,
|
|
960
|
+
taskId,
|
|
961
|
+
agent,
|
|
962
|
+
branch: readBranchOption(rest),
|
|
963
|
+
status: readSddResultStatus(rest, '--status') ?? 'PASS'
|
|
964
|
+
});
|
|
965
|
+
const runId = readOption(rest, '--run');
|
|
966
|
+
if (rest.includes('--write')) {
|
|
967
|
+
if (!runId) {
|
|
968
|
+
return {
|
|
969
|
+
exitCode: 2,
|
|
970
|
+
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> --run <run_id> --write'
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
const written = await writeArtifact(projectRoot, runId, toArtifactRootRelativePath(artifactPath), template);
|
|
974
|
+
return {
|
|
975
|
+
exitCode: 0,
|
|
976
|
+
output: `Artifact template written: ${written.runRelativePath}\nphysical_path=${written.absolutePath}`
|
|
631
977
|
};
|
|
632
978
|
}
|
|
633
979
|
return {
|
|
634
980
|
exitCode: 0,
|
|
635
|
-
output:
|
|
636
|
-
artifactPath,
|
|
637
|
-
taskId,
|
|
638
|
-
agent,
|
|
639
|
-
branch: readOption(rest, '--branch') ?? 'master',
|
|
640
|
-
status: readSddResultStatus(rest, '--status') ?? 'PASS'
|
|
641
|
-
})
|
|
981
|
+
output: template
|
|
642
982
|
};
|
|
643
983
|
}
|
|
644
984
|
if (command === 'artifact' && subcommand === 'validate') {
|
|
@@ -647,7 +987,7 @@ async function main(args) {
|
|
|
647
987
|
if (!runId || !artifactPath) {
|
|
648
988
|
return {
|
|
649
989
|
exitCode: 2,
|
|
650
|
-
error: 'Usage: sdd artifact validate <run_id> <artifacts/path.md> [--task <task_id>] [--agent <agent>] [--json]'
|
|
990
|
+
error: 'Usage: sdd artifact validate <run_id> <artifacts/path.md> [--task <task_id>] [--agent <agent>] [--json|--compact-json]'
|
|
651
991
|
};
|
|
652
992
|
}
|
|
653
993
|
const expectedTask = readOption(rest, '--task') ?? undefined;
|
|
@@ -658,7 +998,7 @@ async function main(args) {
|
|
|
658
998
|
});
|
|
659
999
|
return {
|
|
660
1000
|
exitCode: report.valid ? 0 : 1,
|
|
661
|
-
output: rest
|
|
1001
|
+
output: renderTextOrJson(rest, report, (value) => renderArtifactValidationReport(artifactPath, value, expectedTask, expectedAgent))
|
|
662
1002
|
};
|
|
663
1003
|
}
|
|
664
1004
|
if (command === 'artifact' && subcommand === 'ingest') {
|
|
@@ -696,175 +1036,193 @@ async function main(args) {
|
|
|
696
1036
|
error: `Unknown command: ${args.join(' ')}\n\n${helpText()}`
|
|
697
1037
|
};
|
|
698
1038
|
}
|
|
699
|
-
function helpText() {
|
|
1039
|
+
function helpText(topic) {
|
|
1040
|
+
if (topic === 'advanced') {
|
|
1041
|
+
return advancedHelpText();
|
|
1042
|
+
}
|
|
1043
|
+
if (topic === 'workflow') {
|
|
1044
|
+
return workflowHelpText();
|
|
1045
|
+
}
|
|
700
1046
|
return `sdd Phase 2 platform CLI
|
|
701
1047
|
|
|
702
|
-
|
|
703
|
-
sdd --
|
|
704
|
-
sdd
|
|
705
|
-
|
|
706
|
-
sdd
|
|
707
|
-
sdd
|
|
708
|
-
sdd
|
|
709
|
-
sdd
|
|
710
|
-
sdd
|
|
711
|
-
sdd
|
|
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
|
|
1048
|
+
Common workflow:
|
|
1049
|
+
sdd init [--force] [--ai <mode>] [--scaffold-docs] [--json]
|
|
1050
|
+
sdd status [--branch <branch>] [--json|--compact-json]
|
|
1051
|
+
sdd tasks inspect <task_id> [--branch <branch>] [--json|--compact-json]
|
|
1052
|
+
sdd tasks route <task_id> [--branch <branch>] [--json|--compact-json]
|
|
1053
|
+
sdd do task <task_id> [options]
|
|
1054
|
+
sdd verify task <task_id> [--branch <branch>] [--run <run_id>] [--json|--compact-json]
|
|
1055
|
+
sdd sync-back inspect [<run_id>] [--task <task_id>] [--branch <branch>] [--json|--compact-json]
|
|
1056
|
+
sdd sync-back apply [<run_id>] [--task <task_id>] [--branch <branch>] [--approved] [--json|--compact-json]
|
|
1057
|
+
sdd doctor [--latest-only] [--all-runs] [--json|--compact-json]
|
|
750
1058
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1059
|
+
Evidence helpers:
|
|
1060
|
+
sdd run create
|
|
1061
|
+
sdd run list [--json]
|
|
1062
|
+
sdd run inspect <run_id> [--json|--compact-json]
|
|
1063
|
+
sdd run index rebuild|inspect|query [options] [--json|--compact-json]
|
|
1064
|
+
sdd artifact template <path> --task <task_id> --agent <agent> [--run <run_id> --write]
|
|
1065
|
+
sdd artifact validate <run_id> <path> [--task <task_id>] [--agent <agent>] [--json|--compact-json]
|
|
755
1066
|
|
|
756
|
-
|
|
757
|
-
--
|
|
758
|
-
|
|
1067
|
+
Generated AI entries:
|
|
1068
|
+
sdd update [--check] [--ai <mode>]
|
|
1069
|
+
sdd instructions [action] [--json|--compact-json]
|
|
759
1070
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1071
|
+
More help:
|
|
1072
|
+
sdd help workflow Show core workflow options.
|
|
1073
|
+
sdd help advanced Show platform/agent/runtime commands.
|
|
763
1074
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
--
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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
|
|
1075
|
+
Notes:
|
|
1076
|
+
/sdd:spec owns workflow partition docs after project init.
|
|
1077
|
+
init --branch is legacy starter-doc scaffolding; prefer sdd status --branch or /sdd:spec --branch for workflow partitions.
|
|
1078
|
+
`;
|
|
1079
|
+
}
|
|
1080
|
+
function workflowHelpText() {
|
|
1081
|
+
return `sdd workflow help
|
|
807
1082
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
--
|
|
813
|
-
--
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
--
|
|
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
|
|
1083
|
+
Core path:
|
|
1084
|
+
1. sdd status [--branch <branch>]
|
|
1085
|
+
2. sdd tasks inspect <task_id> [--branch <branch>]
|
|
1086
|
+
3. sdd tasks route <task_id> [--branch <branch>]
|
|
1087
|
+
4. sdd artifact template artifacts/<agent>-<task_id>.md --task <task_id> --agent <agent> --run <run_id> --write
|
|
1088
|
+
5. sdd do task <task_id> --run <run_id> --implement-artifact <path> --review-artifact <path> --validation-artifact <path>
|
|
1089
|
+
6. sdd verify task <task_id> [--branch <branch>]
|
|
1090
|
+
7. sdd sync-back inspect --task <task_id> [--branch <branch>]
|
|
1091
|
+
8. sdd sync-back apply --task <task_id> [--branch <branch>]
|
|
821
1092
|
|
|
822
|
-
|
|
823
|
-
--
|
|
824
|
-
|
|
825
|
-
|
|
1093
|
+
JSON:
|
|
1094
|
+
--json prints readable JSON; --compact-json prints one-line JSON for logs and scripts.
|
|
1095
|
+
`;
|
|
1096
|
+
}
|
|
1097
|
+
function advancedHelpText() {
|
|
1098
|
+
return `sdd advanced help
|
|
826
1099
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1100
|
+
Runtime/catalog:
|
|
1101
|
+
sdd agent-runtime inspect|validate [--json]
|
|
1102
|
+
sdd skill-capabilities list|inspect [--json]
|
|
1103
|
+
sdd capability-sources list|inspect [--json]
|
|
1104
|
+
sdd external-packs inspect <source_id> [--json]
|
|
1105
|
+
sdd team-mode inspect [--task <id>] [--team-mode [auto|force|off]] [--no-team-mode] [--json]
|
|
831
1106
|
|
|
832
|
-
|
|
833
|
-
|
|
1107
|
+
Harness/platform:
|
|
1108
|
+
sdd workflow list|inspect|validate [--json]
|
|
1109
|
+
sdd agents list|inspect|validate [--json]
|
|
1110
|
+
sdd query-status inspect|validate [--json]
|
|
1111
|
+
sdd eval inspect|validate [--json]
|
|
1112
|
+
sdd learning inspect|validate [--json]
|
|
1113
|
+
sdd context-pack inspect|validate [--json]
|
|
1114
|
+
sdd capabilities list|inspect [--json]
|
|
1115
|
+
sdd governance inspect|evaluate [options]
|
|
1116
|
+
sdd plugins list|inspect [--json]
|
|
1117
|
+
sdd queue list|inspect [options]
|
|
1118
|
+
sdd state-machine inspect [--json]
|
|
1119
|
+
sdd workers list|inspect [--json]
|
|
834
1120
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1121
|
+
Execution/isolation:
|
|
1122
|
+
sdd background run|inspect [options]
|
|
1123
|
+
sdd worker-runtime claim|heartbeat|status|inspect [options]
|
|
1124
|
+
sdd isolation inspect <task_id> [options]
|
|
1125
|
+
sdd graph inspect [--branch <branch>] [--json]
|
|
1126
|
+
sdd wave inspect|run|executor [options]
|
|
1127
|
+
sdd worktree create|inspect|keep|remove [options]
|
|
838
1128
|
|
|
839
|
-
|
|
840
|
-
--branch <branch>
|
|
841
|
-
|
|
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
|
-
`;
|
|
1129
|
+
Legacy init partition option:
|
|
1130
|
+
sdd init --branch <branch> creates starter docs for that branch, but normal workflow partitioning belongs to /sdd:spec and sdd status --branch.
|
|
1131
|
+
`;
|
|
851
1132
|
}
|
|
852
|
-
function
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1133
|
+
function wantsJson(args) {
|
|
1134
|
+
return args.includes('--json') || args.includes('--compact-json');
|
|
1135
|
+
}
|
|
1136
|
+
function jsonOutput(value, args) {
|
|
1137
|
+
return JSON.stringify(value, null, args.includes('--compact-json') ? 0 : 2);
|
|
1138
|
+
}
|
|
1139
|
+
function renderTextOrJson(args, value, renderText) {
|
|
1140
|
+
return wantsJson(args) ? jsonOutput(value, args) : renderText(value);
|
|
1141
|
+
}
|
|
1142
|
+
function renderInitResult(result) {
|
|
1143
|
+
const aiEntries = result.aiTools.flatMap((tool) => tool.entries);
|
|
1144
|
+
const aiCounts = new Map();
|
|
1145
|
+
for (const entry of aiEntries) {
|
|
1146
|
+
aiCounts.set(entry.status, (aiCounts.get(entry.status) ?? 0) + 1);
|
|
1147
|
+
}
|
|
1148
|
+
const aiSummary = Array.from(aiCounts.entries()).map(([status, count]) => `${status}=${count}`).join(' ') || 'none';
|
|
1149
|
+
const scaffoldedDocuments = result.documents.documents.filter((document) => document.status !== 'skipped');
|
|
1150
|
+
const lines = ['SDD init', 'changed'];
|
|
1151
|
+
lines.push(`- config ${result.created ? 'created/updated' : 'unchanged'} at ${result.configPath}`);
|
|
1152
|
+
lines.push(`- semantic docs ${scaffoldedDocuments.map((document) => `${document.status}:${document.relativePath}`).join(', ') || 'none'}`);
|
|
1153
|
+
lines.push(`- ai entries ${aiSummary}`);
|
|
1154
|
+
lines.push('decision');
|
|
1155
|
+
if (scaffoldedDocuments.length > 0) {
|
|
1156
|
+
lines.push(`- legacy_scaffold_branch=${result.documents.branch}`);
|
|
1157
|
+
lines.push(`- legacy_spec_dir=${result.documents.root}`);
|
|
1158
|
+
}
|
|
1159
|
+
lines.push('- sdd init is project-level setup; /sdd:spec is the workflow partition/spec entry');
|
|
1160
|
+
lines.push('evidence');
|
|
1161
|
+
for (const document of scaffoldedDocuments) {
|
|
1162
|
+
lines.push(`- [${document.status}] ${document.relativePath}: ${document.message}`);
|
|
1163
|
+
}
|
|
1164
|
+
if (aiEntries.length === 0) {
|
|
1165
|
+
lines.push('- ai entries skipped');
|
|
858
1166
|
}
|
|
859
1167
|
else {
|
|
860
|
-
lines.push(
|
|
1168
|
+
lines.push(`- ${aiEntries.length} managed AI entry projection(s) checked/applied`);
|
|
861
1169
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1170
|
+
lines.push('- doctor checks git repository health; run git init first in fresh temporary projects before relying on doctor/run-index checks');
|
|
1171
|
+
lines.push('gaps');
|
|
1172
|
+
const driftEntries = aiEntries.filter((entry) => entry.status === 'drifted' || entry.status === 'user-modified' || entry.status === 'foreign' || entry.status === 'conflict');
|
|
1173
|
+
if (driftEntries.length === 0) {
|
|
1174
|
+
lines.push('- none');
|
|
1175
|
+
}
|
|
1176
|
+
else {
|
|
1177
|
+
for (const entry of driftEntries) {
|
|
1178
|
+
lines.push(`- [${entry.status}] ${entry.relativePath}: ${entry.action ?? entry.message}`);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
lines.push('next');
|
|
1182
|
+
lines.push('- /sdd:spec');
|
|
1183
|
+
return lines.join('\n');
|
|
1184
|
+
}
|
|
1185
|
+
function renderProjectStatus(status) {
|
|
1186
|
+
const lines = [`SDD status for ${status.branch}`];
|
|
1187
|
+
const staleDocuments = [
|
|
1188
|
+
status.documents.planStale ? 'plan' : null,
|
|
1189
|
+
status.documents.tasksStale ? 'tasks' : null
|
|
1190
|
+
].filter((item) => item !== null);
|
|
1191
|
+
const hasDocumentHashes = Boolean(status.documents.specHash
|
|
1192
|
+
|| status.documents.planHash
|
|
1193
|
+
|| status.documents.tasksHash
|
|
1194
|
+
|| status.documents.planBasedOnSpecHash
|
|
1195
|
+
|| status.documents.tasksBasedOnPlanHash);
|
|
1196
|
+
lines.push('decision');
|
|
1197
|
+
lines.push(`- workflow_status=${status.workflowStatus}`);
|
|
1198
|
+
lines.push(`- context raw_branch=${status.context.rawBranch} partition=${status.context.partition} source=${status.context.branchSource} spec_dir=${status.context.specDir}`);
|
|
1199
|
+
lines.push(`- git current_branch=${status.context.currentGitBranch ?? 'none'} working_tree_matched=${status.context.workingTreeMatched ?? 'unknown'}`);
|
|
1200
|
+
lines.push(`- documents spec=${status.documents.specExists} plan=${status.documents.planExists} tasks=${status.documents.tasksExists} stale=${staleDocuments.join(',') || 'none'}`);
|
|
1201
|
+
if (hasDocumentHashes) {
|
|
1202
|
+
lines.push(`- document_hashes spec=${status.documents.specHash ?? 'none'} plan=${status.documents.planHash ?? 'none'} tasks=${status.documents.tasksHash ?? 'none'} plan_based_on_spec=${status.documents.planBasedOnSpecHash ?? 'none'} tasks_based_on_plan=${status.documents.tasksBasedOnPlanHash ?? 'none'}`);
|
|
1203
|
+
}
|
|
1204
|
+
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}`);
|
|
1205
|
+
if (status.latestRun) {
|
|
1206
|
+
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}`);
|
|
1207
|
+
if (status.latestRunEvidence) {
|
|
1208
|
+
lines.push(`- latest_run_evidence route_preflight=${status.latestRunEvidence.routePreflight} agent_executions=${status.latestRunEvidence.agentExecutions} team_sessions=${status.latestRunEvidence.teamSessions} worker_runtimes=${status.latestRunEvidence.workerRuntimes} stale_worker_runtimes=${status.latestRunEvidence.staleWorkerRuntimes} artifact_ingestions=${status.latestRunEvidence.artifactIngestions}`);
|
|
1209
|
+
if (status.latestRunEvidence.tasksChangedAfterRun && status.latestRun.syncBackStatus !== 'applied') {
|
|
1210
|
+
lines.push('- latest_run_evidence may be stale: tasks.md changed after the latest run; inspect the task or rerun before relying on this run.');
|
|
1211
|
+
}
|
|
1212
|
+
else if (status.latestRunEvidence.tasksChangedAfterRun) {
|
|
1213
|
+
lines.push('- latest_run_evidence tasks.md changed after sync-back apply; task completion state is already recorded.');
|
|
1214
|
+
}
|
|
866
1215
|
}
|
|
867
1216
|
}
|
|
1217
|
+
else {
|
|
1218
|
+
lines.push('- latest_run none');
|
|
1219
|
+
}
|
|
1220
|
+
lines.push('evidence');
|
|
1221
|
+
lines.push(`- branch documents loaded from ${status.context.specDir}`);
|
|
1222
|
+
lines.push(status.gitRoot
|
|
1223
|
+
? `- git repository detected at ${status.gitRoot}; doctor and run-index checks can use Git repository context`
|
|
1224
|
+
: '- doctor and run-index checks expect Git repository context; run git init first in fresh temporary projects');
|
|
1225
|
+
renderDocumentGaps(lines, status.gaps);
|
|
868
1226
|
lines.push(`next ${status.recommendedNextCommand}`);
|
|
869
1227
|
return lines.join('\n');
|
|
870
1228
|
}
|
|
@@ -892,13 +1250,7 @@ function renderLocalRunIndexInspection(inspection) {
|
|
|
892
1250
|
if (inspection.index) {
|
|
893
1251
|
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
1252
|
}
|
|
895
|
-
|
|
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
|
-
}
|
|
1253
|
+
renderIssues(lines, inspection.issues);
|
|
902
1254
|
return lines.join('\n');
|
|
903
1255
|
}
|
|
904
1256
|
function renderGovernancePolicy(policy) {
|
|
@@ -919,13 +1271,7 @@ function renderGovernancePolicyDecision(decision) {
|
|
|
919
1271
|
for (const reason of decision.reasons) {
|
|
920
1272
|
lines.push(`- ${reason}`);
|
|
921
1273
|
}
|
|
922
|
-
|
|
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
|
-
}
|
|
1274
|
+
renderIssues(lines, decision.issues);
|
|
929
1275
|
return lines.join('\n');
|
|
930
1276
|
}
|
|
931
1277
|
function renderRunInspection(inspection) {
|
|
@@ -933,6 +1279,7 @@ function renderRunInspection(inspection) {
|
|
|
933
1279
|
lines.push(`status=${inspection.summary.status} phase=${inspection.summary.phase ?? 'n/a'} task=${inspection.summary.currentTask ?? 'n/a'} updated=${inspection.summary.updatedAt}`);
|
|
934
1280
|
lines.push(`validation=${inspection.validation.status} evidence=${inspection.validation.evidence.join(',') || 'none'}`);
|
|
935
1281
|
lines.push(`sync_back=${inspection.syncBack.status} proposal=${inspection.syncBack.proposalPath ?? 'none'}`);
|
|
1282
|
+
lines.push(`task_run_evidence=${inspection.taskRunEvidence.version} gaps=${inspection.taskRunEvidence.gaps.length} sync_back=${inspection.taskRunEvidence.syncBackProposal ?? 'none'}`);
|
|
936
1283
|
lines.push(`artifacts=${inspection.artifacts.length}`);
|
|
937
1284
|
for (const artifact of inspection.artifacts) {
|
|
938
1285
|
lines.push(`- ${artifact.path} kind=${artifact.kind} task=${artifact.task ?? 'n/a'} agent=${artifact.agent ?? 'n/a'}`);
|
|
@@ -941,6 +1288,18 @@ function renderRunInspection(inspection) {
|
|
|
941
1288
|
for (const ingestion of inspection.artifactIngestions) {
|
|
942
1289
|
lines.push(`- ${ingestion.delegationId} ${ingestion.status} artifact=${ingestion.artifactPath} result=${ingestion.resultStatus ?? 'n/a'} delegation=${ingestion.delegationStatus ?? 'n/a'}`);
|
|
943
1290
|
}
|
|
1291
|
+
lines.push(`agent_executions=${inspection.agentExecutions.length}`);
|
|
1292
|
+
for (const execution of inspection.agentExecutions) {
|
|
1293
|
+
lines.push(`- ${execution.executionId} profile=${execution.profile} status=${execution.status} task=${execution.taskId} artifacts=${execution.artifacts.join(',') || 'none'}`);
|
|
1294
|
+
}
|
|
1295
|
+
lines.push(`team_sessions=${inspection.teamSessions.length}`);
|
|
1296
|
+
for (const session of inspection.teamSessions) {
|
|
1297
|
+
lines.push(`- ${session.teamId} status=${session.status} mode=${session.teamMode.mode} activation=${session.teamMode.activation} cost=${session.teamMode.costClass} chief=${session.chiefProfile} members=${session.memberProfiles.join(',') || 'none'} artifacts=${session.artifacts.join(',') || 'none'}`);
|
|
1298
|
+
}
|
|
1299
|
+
lines.push(`worker_runtimes=${inspection.workerRuntimes.length}`);
|
|
1300
|
+
for (const runtime of inspection.workerRuntimes) {
|
|
1301
|
+
lines.push(`- ${runtime.runtimeId} status=${runtime.status} task=${runtime.taskId} agent=${runtime.agent} delegation=${runtime.delegationId} lease_expires=${runtime.leaseExpiresAt}`);
|
|
1302
|
+
}
|
|
944
1303
|
lines.push(`events=${inspection.eventCount}`);
|
|
945
1304
|
for (const event of inspection.recentEvents) {
|
|
946
1305
|
lines.push(`- ${event.time} ${event.event}${event.summary ? `: ${event.summary}` : ''}`);
|
|
@@ -958,12 +1317,7 @@ function renderSyncBackInspection(inspection) {
|
|
|
958
1317
|
lines.push(`- ${reason}`);
|
|
959
1318
|
}
|
|
960
1319
|
}
|
|
961
|
-
|
|
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
|
-
}
|
|
1320
|
+
renderDocumentGaps(lines, inspection.gaps);
|
|
967
1321
|
lines.push(`apply_policy=${inspection.applyPolicy.mode} approval_required=${inspection.applyPolicy.requiresApproval}`);
|
|
968
1322
|
for (const reason of inspection.applyPolicy.reasons) {
|
|
969
1323
|
lines.push(`- policy: ${reason}`);
|
|
@@ -981,6 +1335,399 @@ function renderSyncBackApplyResult(result) {
|
|
|
981
1335
|
lines.push(`sync_back=${result.inspection.status}`);
|
|
982
1336
|
return lines.join('\n');
|
|
983
1337
|
}
|
|
1338
|
+
function renderWorkflowGateList(workflows) {
|
|
1339
|
+
const lines = ['SDD workflow gates'];
|
|
1340
|
+
for (const workflow of workflows) {
|
|
1341
|
+
lines.push(`- ${workflow.id} command=${workflow.command} agents=${workflow.allowedAgents.join(',') || 'none'}`);
|
|
1342
|
+
}
|
|
1343
|
+
return lines.join('\n');
|
|
1344
|
+
}
|
|
1345
|
+
function renderWorkflowGateInspect(workflow) {
|
|
1346
|
+
const lines = [`Workflow gate ${workflow.id}`];
|
|
1347
|
+
lines.push(`version=${workflow.version}`);
|
|
1348
|
+
lines.push(`command=${workflow.command}`);
|
|
1349
|
+
lines.push(`agents=${workflow.allowedAgents.join(',') || 'none'}`);
|
|
1350
|
+
lines.push('required_inputs');
|
|
1351
|
+
for (const input of workflow.requiredInputs) {
|
|
1352
|
+
lines.push(`- ${input}`);
|
|
1353
|
+
}
|
|
1354
|
+
lines.push('required_artifacts');
|
|
1355
|
+
for (const artifact of workflow.requiredArtifacts) {
|
|
1356
|
+
lines.push(`- ${artifact}`);
|
|
1357
|
+
}
|
|
1358
|
+
lines.push('gate_conditions');
|
|
1359
|
+
for (const condition of workflow.gateConditions) {
|
|
1360
|
+
lines.push(`- ${condition}`);
|
|
1361
|
+
}
|
|
1362
|
+
lines.push(`gap_closure=${workflow.gapClosureBehavior}`);
|
|
1363
|
+
lines.push(`next=${workflow.nextAction}`);
|
|
1364
|
+
return lines.join('\n');
|
|
1365
|
+
}
|
|
1366
|
+
function renderWorkflowGateValidation(result) {
|
|
1367
|
+
const lines = ['SDD workflow gate validation'];
|
|
1368
|
+
lines.push(`valid=${result.valid}`);
|
|
1369
|
+
lines.push(`workflows=${result.workflows.length}`);
|
|
1370
|
+
lines.push('issues');
|
|
1371
|
+
if (result.issues.length === 0) {
|
|
1372
|
+
lines.push('- none');
|
|
1373
|
+
}
|
|
1374
|
+
else {
|
|
1375
|
+
for (const issue of result.issues) {
|
|
1376
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return lines.join('\n');
|
|
1380
|
+
}
|
|
1381
|
+
function renderAgentRegistryList(agents) {
|
|
1382
|
+
const lines = ['SDD agent registry'];
|
|
1383
|
+
for (const agent of agents) {
|
|
1384
|
+
lines.push(`- ${agent.id} stages=${agent.allowedStages.join(',')} autonomy=${agent.autonomyCeiling}`);
|
|
1385
|
+
}
|
|
1386
|
+
return lines.join('\n');
|
|
1387
|
+
}
|
|
1388
|
+
function renderAgentRegistryInspect(agent) {
|
|
1389
|
+
const lines = [`Agent ${agent.id}`];
|
|
1390
|
+
lines.push(`version=${agent.version}`);
|
|
1391
|
+
lines.push(`role=${agent.role}`);
|
|
1392
|
+
lines.push(`allowed_stages=${agent.allowedStages.join(',')}`);
|
|
1393
|
+
lines.push(`autonomy_ceiling=${agent.autonomyCeiling}`);
|
|
1394
|
+
lines.push(`required_artifact=${agent.requiredArtifact}`);
|
|
1395
|
+
lines.push(`verification=${agent.verificationExpectation}`);
|
|
1396
|
+
lines.push('capabilities');
|
|
1397
|
+
for (const capability of agent.capabilities) {
|
|
1398
|
+
lines.push(`- ${capability}`);
|
|
1399
|
+
}
|
|
1400
|
+
lines.push('read_boundary');
|
|
1401
|
+
for (const item of agent.readBoundary) {
|
|
1402
|
+
lines.push(`- ${item}`);
|
|
1403
|
+
}
|
|
1404
|
+
lines.push('write_boundary');
|
|
1405
|
+
for (const item of agent.writeBoundary) {
|
|
1406
|
+
lines.push(`- ${item}`);
|
|
1407
|
+
}
|
|
1408
|
+
lines.push('tool_allowlist');
|
|
1409
|
+
for (const tool of agent.toolAllowlist) {
|
|
1410
|
+
lines.push(`- ${tool}`);
|
|
1411
|
+
}
|
|
1412
|
+
lines.push(`stop_condition=${agent.stopCondition}`);
|
|
1413
|
+
return lines.join('\n');
|
|
1414
|
+
}
|
|
1415
|
+
function renderAgentRegistryValidation(result) {
|
|
1416
|
+
const lines = ['SDD agent registry validation'];
|
|
1417
|
+
lines.push(`valid=${result.valid}`);
|
|
1418
|
+
lines.push(`agents=${result.agents.length}`);
|
|
1419
|
+
lines.push('issues');
|
|
1420
|
+
if (result.issues.length === 0) {
|
|
1421
|
+
lines.push('- none');
|
|
1422
|
+
}
|
|
1423
|
+
else {
|
|
1424
|
+
for (const issue of result.issues) {
|
|
1425
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
return lines.join('\n');
|
|
1429
|
+
}
|
|
1430
|
+
function renderRegistryOriginCounts(sources) {
|
|
1431
|
+
if (!sources || sources.length === 0) {
|
|
1432
|
+
return 'none';
|
|
1433
|
+
}
|
|
1434
|
+
const counts = new Map();
|
|
1435
|
+
for (const source of sources) {
|
|
1436
|
+
counts.set(source.origin, (counts.get(source.origin) ?? 0) + 1);
|
|
1437
|
+
}
|
|
1438
|
+
return [...counts.entries()].map(([origin, count]) => `${origin}:${count}`).join(',');
|
|
1439
|
+
}
|
|
1440
|
+
function idsByOrigin(sources, kind, origin) {
|
|
1441
|
+
const ids = sources?.filter((source) => source.kind === kind && source.origin === origin).map((source) => source.id) ?? [];
|
|
1442
|
+
return ids.join(',') || 'none';
|
|
1443
|
+
}
|
|
1444
|
+
function renderAgentRouterDecision(decision) {
|
|
1445
|
+
const lines = [`Agent router decision ${decision.taskId}`];
|
|
1446
|
+
lines.push(`version=${decision.version}`);
|
|
1447
|
+
lines.push(`branch=${decision.branch} category=${decision.category}`);
|
|
1448
|
+
lines.push(`recommended_profile=${decision.recommendedProfile ?? 'none'} autonomy_ceiling=${decision.autonomyCeiling}`);
|
|
1449
|
+
lines.push(`allowed_profiles=${decision.allowedProfiles.join(',') || 'none'}`);
|
|
1450
|
+
lines.push(`required_capabilities=${decision.requiredCapabilities.join(',') || 'none'}`);
|
|
1451
|
+
lines.push(`source_capability=${decision.sourceCapability ?? 'none'} reuse=${decision.reuseDecision ?? 'none'}`);
|
|
1452
|
+
if (decision.registrySources && decision.registrySources.length > 0) {
|
|
1453
|
+
lines.push(`registry_sources=${decision.registrySources.map((source) => `${source.kind}:${source.id}:${source.origin}`).join(',')}`);
|
|
1454
|
+
}
|
|
1455
|
+
if (decision.resolvedAliases && decision.resolvedAliases.length > 0) {
|
|
1456
|
+
lines.push(`alias_resolutions=${decision.resolvedAliases.map((alias) => `${alias.input}->${alias.resolved}:${alias.source}`).join(',')}`);
|
|
1457
|
+
}
|
|
1458
|
+
if (decision.routingRuleHits && decision.routingRuleHits.length > 0) {
|
|
1459
|
+
lines.push(`routing_rule_hits=${decision.routingRuleHits.join(',')}`);
|
|
1460
|
+
}
|
|
1461
|
+
if (decision.quarantineWarnings && decision.quarantineWarnings.length > 0) {
|
|
1462
|
+
lines.push('quarantine_warnings');
|
|
1463
|
+
for (const warning of decision.quarantineWarnings) {
|
|
1464
|
+
lines.push(`- ${warning}`);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
if (decision.adapterMapping) {
|
|
1468
|
+
lines.push(`adapter_mapping profile=${decision.adapterMapping.profile} host=${decision.adapterMapping.hostAdapter} projection=${decision.adapterMapping.projection}`);
|
|
1469
|
+
}
|
|
1470
|
+
if (decision.toolPermission) {
|
|
1471
|
+
lines.push(`tool_permission profile=${decision.toolPermission.profile} policy=${decision.toolPermission.policy} groups=${decision.toolPermission.toolGroups.join(',')}`);
|
|
1472
|
+
lines.push(`approval=${decision.toolPermission.approvalPolicy}`);
|
|
1473
|
+
}
|
|
1474
|
+
lines.push(`model_policy=${decision.modelPolicy.id} category=${decision.modelPolicy.category}`);
|
|
1475
|
+
lines.push(`team_mode=${decision.teamMode.decision} mode=${decision.teamMode.mode} activation=${decision.teamMode.activation} cost=${decision.teamMode.costClass} waves=${decision.teamMode.waveRecommendation.join(',') || 'none'}`);
|
|
1476
|
+
lines.push(`team_mode_reason=${decision.teamMode.reason}`);
|
|
1477
|
+
lines.push(`required_artifacts=${decision.requiredArtifacts.join(',') || 'none'}`);
|
|
1478
|
+
if (decision.blockedReason) {
|
|
1479
|
+
lines.push(`blocked_reason=${decision.blockedReason}`);
|
|
1480
|
+
}
|
|
1481
|
+
lines.push(`next=${decision.nextAction}`);
|
|
1482
|
+
return lines.join('\n');
|
|
1483
|
+
}
|
|
1484
|
+
function renderAgentSkillTeamRuntimeInspection(inspection) {
|
|
1485
|
+
const lines = ['SDD agent/skill/team runtime'];
|
|
1486
|
+
lines.push(`version=${inspection.version}`);
|
|
1487
|
+
lines.push(`profiles=${inspection.profiles.length} skill_capabilities=${inspection.skillCapabilities.length} capability_sources=${inspection.capabilitySources.length}`);
|
|
1488
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(inspection.registrySources)}`);
|
|
1489
|
+
lines.push(`project_profiles=${idsByOrigin(inspection.registrySources, 'profile', 'project_config')}`);
|
|
1490
|
+
lines.push(`project_capabilities=${idsByOrigin(inspection.registrySources, 'skill_capability', 'project_config')}`);
|
|
1491
|
+
lines.push(`project_sources=${idsByOrigin(inspection.registrySources, 'capability_source', 'project_config')}`);
|
|
1492
|
+
if (inspection.aliases && Object.keys(inspection.aliases).length > 0) {
|
|
1493
|
+
lines.push(`aliases=${Object.entries(inspection.aliases).map(([alias, target]) => `${alias}->${target}`).join(',')}`);
|
|
1494
|
+
}
|
|
1495
|
+
if (inspection.routingRules && inspection.routingRules.length > 0) {
|
|
1496
|
+
lines.push(`routing_rules=${inspection.routingRules.map((rule) => rule.id).join(',')}`);
|
|
1497
|
+
}
|
|
1498
|
+
if (inspection.adapterMappings && inspection.adapterMappings.length > 0) {
|
|
1499
|
+
lines.push(`adapter_mappings=${inspection.adapterMappings.map((mapping) => `${mapping.profile}:${mapping.hostAdapter}`).join(',')}`);
|
|
1500
|
+
}
|
|
1501
|
+
lines.push(`host_adapter=${inspection.hostAdapter.id} host=${inspection.hostAdapter.host}`);
|
|
1502
|
+
lines.push(`team_mode_default=${inspection.teamMode.decision}`);
|
|
1503
|
+
lines.push(`reuse_policy=${inspection.reusePolicy}`);
|
|
1504
|
+
lines.push('profiles');
|
|
1505
|
+
for (const profile of inspection.profiles) {
|
|
1506
|
+
lines.push(`- ${profile.id} stages=${profile.stageScope.join(',')} risk_ceiling=${profile.riskCeiling}`);
|
|
1507
|
+
}
|
|
1508
|
+
lines.push('capabilities');
|
|
1509
|
+
for (const capability of inspection.skillCapabilities) {
|
|
1510
|
+
lines.push(`- ${capability.id} reuse=${capability.reuseDecision} evidence=${capability.evidenceType}`);
|
|
1511
|
+
}
|
|
1512
|
+
return lines.join('\n');
|
|
1513
|
+
}
|
|
1514
|
+
function renderAgentSkillTeamRuntimeValidation(result) {
|
|
1515
|
+
const lines = ['SDD agent/skill/team runtime validation'];
|
|
1516
|
+
lines.push(`valid=${result.valid}`);
|
|
1517
|
+
lines.push(`profiles=${result.inspection.profiles.length}`);
|
|
1518
|
+
lines.push(`capabilities=${result.inspection.skillCapabilities.length}`);
|
|
1519
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(result.inspection.registrySources)}`);
|
|
1520
|
+
lines.push('issues');
|
|
1521
|
+
if (result.issues.length === 0) {
|
|
1522
|
+
lines.push('- none');
|
|
1523
|
+
}
|
|
1524
|
+
else {
|
|
1525
|
+
for (const issue of result.issues) {
|
|
1526
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return lines.join('\n');
|
|
1530
|
+
}
|
|
1531
|
+
function renderSkillCapabilityList(capabilities, registrySources) {
|
|
1532
|
+
const lines = ['SDD skill capabilities'];
|
|
1533
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(registrySources)}`);
|
|
1534
|
+
for (const capability of capabilities) {
|
|
1535
|
+
const source = registrySources?.find((candidate) => candidate.kind === 'skill_capability' && candidate.id === capability.id);
|
|
1536
|
+
lines.push(`- ${capability.id} domain=${capability.capabilityDomain.join(',')} reuse=${capability.reuseDecision} evidence=${capability.evidenceType} origin=${source?.origin ?? 'unknown'}`);
|
|
1537
|
+
}
|
|
1538
|
+
return lines.join('\n');
|
|
1539
|
+
}
|
|
1540
|
+
function renderSkillCapabilityInspect(capability) {
|
|
1541
|
+
const lines = [`Skill capability ${capability.id}`];
|
|
1542
|
+
lines.push(`version=${capability.version}`);
|
|
1543
|
+
lines.push(`name=${capability.name}`);
|
|
1544
|
+
lines.push(`kind=${capability.kind} source=${capability.source} source_ref=${capability.sourceRef}`);
|
|
1545
|
+
lines.push(`domain=${capability.capabilityDomain.join(',')}`);
|
|
1546
|
+
lines.push(`allowed_stages=${capability.allowedStages.join(',')}`);
|
|
1547
|
+
lines.push(`risk_ceiling=${capability.requiredRiskCeiling}`);
|
|
1548
|
+
lines.push(`evidence_type=${capability.evidenceType}`);
|
|
1549
|
+
lines.push(`reuse_decision=${capability.reuseDecision}`);
|
|
1550
|
+
if (capability.buildExceptionReason) {
|
|
1551
|
+
lines.push(`build_exception=${capability.buildExceptionReason}`);
|
|
1552
|
+
}
|
|
1553
|
+
return lines.join('\n');
|
|
1554
|
+
}
|
|
1555
|
+
function renderCapabilitySourceList(sources, registrySources) {
|
|
1556
|
+
const lines = ['SDD capability sources'];
|
|
1557
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(registrySources)}`);
|
|
1558
|
+
for (const source of sources) {
|
|
1559
|
+
const registrySource = registrySources?.find((candidate) => candidate.kind === 'capability_source' && candidate.id === source.id);
|
|
1560
|
+
lines.push(`- ${source.id} kind=${source.kind} reuse=${source.reuseDecision} quarantine=${source.quarantineRequired} origin=${registrySource?.origin ?? 'unknown'}`);
|
|
1561
|
+
}
|
|
1562
|
+
return lines.join('\n');
|
|
1563
|
+
}
|
|
1564
|
+
function renderCapabilitySourceInspect(source) {
|
|
1565
|
+
const lines = [`Capability source ${source.id}`];
|
|
1566
|
+
lines.push(`version=${source.version}`);
|
|
1567
|
+
lines.push(`name=${source.name}`);
|
|
1568
|
+
lines.push(`kind=${source.kind} reuse=${source.reuseDecision} quarantine=${source.quarantineRequired}`);
|
|
1569
|
+
lines.push(`source_ref=${source.sourceRef}`);
|
|
1570
|
+
lines.push(`allowed_use=${source.allowedUse}`);
|
|
1571
|
+
lines.push(`attribution=${source.attribution}`);
|
|
1572
|
+
lines.push(`rationale=${source.rationale}`);
|
|
1573
|
+
return lines.join('\n');
|
|
1574
|
+
}
|
|
1575
|
+
function renderExternalAgentPackImportInspection(inspection) {
|
|
1576
|
+
const lines = [`External pack import ${inspection.sourceId}`];
|
|
1577
|
+
lines.push(`version=${inspection.version}`);
|
|
1578
|
+
lines.push(`status=${inspection.status} risk_ceiling=${inspection.riskCeiling}`);
|
|
1579
|
+
lines.push(`allowed_profiles=${inspection.allowedProfiles.join(',') || 'none'}`);
|
|
1580
|
+
lines.push(`mapping=${inspection.mappingResult}`);
|
|
1581
|
+
lines.push(`reason=${inspection.reason}`);
|
|
1582
|
+
lines.push('checks');
|
|
1583
|
+
for (const check of inspection.checks) {
|
|
1584
|
+
lines.push(`- ${check.check} status=${check.status} evidence=${check.evidence}`);
|
|
1585
|
+
}
|
|
1586
|
+
return lines.join('\n');
|
|
1587
|
+
}
|
|
1588
|
+
function renderTeamModePolicy(policy) {
|
|
1589
|
+
const lines = ['SDD team-mode policy'];
|
|
1590
|
+
lines.push(`version=${policy.version}`);
|
|
1591
|
+
lines.push(`enabled=${policy.enabled} decision=${policy.decision} mode=${policy.mode} activation=${policy.activation} cost=${policy.costClass}`);
|
|
1592
|
+
lines.push(`reason=${policy.reason}`);
|
|
1593
|
+
lines.push(`chief=${policy.chiefProfile} members=${policy.memberProfiles.join(',') || 'none'} max_members=${policy.maxMembers}`);
|
|
1594
|
+
lines.push(`require_artifacts=${policy.requireArtifacts}`);
|
|
1595
|
+
lines.push(`waves=${policy.waveRecommendation.join(',') || 'none'}`);
|
|
1596
|
+
if (policy.blockedReason) {
|
|
1597
|
+
lines.push(`blocked_reason=${policy.blockedReason}`);
|
|
1598
|
+
}
|
|
1599
|
+
for (const wave of policy.allowedWaves) {
|
|
1600
|
+
lines.push(`- ${wave.id} kind=${wave.waveKind} members=${wave.memberProfiles.join(',')} merge_gate=${wave.mergeGate}`);
|
|
1601
|
+
}
|
|
1602
|
+
return lines.join('\n');
|
|
1603
|
+
}
|
|
1604
|
+
function renderQueryStatusContract(contract) {
|
|
1605
|
+
const lines = ['SDD query status contract'];
|
|
1606
|
+
lines.push(`version=${contract.version}`);
|
|
1607
|
+
lines.push(`source=${contract.sourceDocument}`);
|
|
1608
|
+
for (const surface of contract.surfaces) {
|
|
1609
|
+
lines.push(`- ${surface.id} command=${surface.command}`);
|
|
1610
|
+
lines.push(` responsibility=${surface.responsibility}`);
|
|
1611
|
+
lines.push(` includes=${surface.includes.join(',')}`);
|
|
1612
|
+
lines.push(` excludes=${surface.excludes.join(',')}`);
|
|
1613
|
+
lines.push(` next=${surface.nextActionRule}`);
|
|
1614
|
+
}
|
|
1615
|
+
return lines.join('\n');
|
|
1616
|
+
}
|
|
1617
|
+
function renderQueryStatusValidation(result) {
|
|
1618
|
+
const lines = ['SDD query status validation'];
|
|
1619
|
+
lines.push(`valid=${result.valid}`);
|
|
1620
|
+
lines.push(`surfaces=${result.surfaces.length}`);
|
|
1621
|
+
lines.push('issues');
|
|
1622
|
+
if (result.issues.length === 0) {
|
|
1623
|
+
lines.push('- none');
|
|
1624
|
+
}
|
|
1625
|
+
else {
|
|
1626
|
+
for (const issue of result.issues) {
|
|
1627
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
return lines.join('\n');
|
|
1631
|
+
}
|
|
1632
|
+
function renderSkillAgentEvalContract(contract) {
|
|
1633
|
+
const lines = ['SDD skill/agent eval contract'];
|
|
1634
|
+
lines.push(`version=${contract.version}`);
|
|
1635
|
+
lines.push(`source=${contract.sourceReport}`);
|
|
1636
|
+
lines.push(`corpus=${contract.corpus.length}`);
|
|
1637
|
+
lines.push('dimensions');
|
|
1638
|
+
for (const dimension of contract.dimensions) {
|
|
1639
|
+
lines.push(`- ${dimension.id} threshold=${dimension.passThreshold}`);
|
|
1640
|
+
lines.push(` expectation=${dimension.expectation}`);
|
|
1641
|
+
lines.push(` baseline=${dimension.baselineFinding}`);
|
|
1642
|
+
}
|
|
1643
|
+
lines.push('regression_assertions');
|
|
1644
|
+
for (const assertion of contract.regressionAssertions) {
|
|
1645
|
+
lines.push(`- ${assertion}`);
|
|
1646
|
+
}
|
|
1647
|
+
return lines.join('\n');
|
|
1648
|
+
}
|
|
1649
|
+
function renderSkillAgentEvalValidation(result) {
|
|
1650
|
+
const lines = ['SDD skill/agent eval validation'];
|
|
1651
|
+
lines.push(`valid=${result.valid}`);
|
|
1652
|
+
lines.push(`dimensions=${result.contract.dimensions.length}`);
|
|
1653
|
+
lines.push(`corpus=${result.contract.corpus.length}`);
|
|
1654
|
+
lines.push('issues');
|
|
1655
|
+
if (result.issues.length === 0) {
|
|
1656
|
+
lines.push('- none');
|
|
1657
|
+
}
|
|
1658
|
+
else {
|
|
1659
|
+
for (const issue of result.issues) {
|
|
1660
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
return lines.join('\n');
|
|
1664
|
+
}
|
|
1665
|
+
function renderHarnessLearningContract(contract) {
|
|
1666
|
+
const lines = ['SDD harness learning contract'];
|
|
1667
|
+
lines.push(`version=${contract.version}`);
|
|
1668
|
+
lines.push(`source=${contract.sourceTrial}`);
|
|
1669
|
+
lines.push(`promotion=${contract.promotionRule}`);
|
|
1670
|
+
lines.push('allowed_sinks');
|
|
1671
|
+
for (const sink of contract.allowedSinks) {
|
|
1672
|
+
lines.push(`- ${sink.id}: ${sink.output}`);
|
|
1673
|
+
lines.push(` boundary=${sink.boundary}`);
|
|
1674
|
+
}
|
|
1675
|
+
lines.push('forbidden_outputs');
|
|
1676
|
+
for (const output of contract.forbiddenOutputs) {
|
|
1677
|
+
lines.push(`- ${output}`);
|
|
1678
|
+
}
|
|
1679
|
+
return lines.join('\n');
|
|
1680
|
+
}
|
|
1681
|
+
function renderHarnessLearningValidation(result) {
|
|
1682
|
+
const lines = ['SDD harness learning validation'];
|
|
1683
|
+
lines.push(`valid=${result.valid}`);
|
|
1684
|
+
lines.push(`allowed_sinks=${result.contract.allowedSinks.length}`);
|
|
1685
|
+
lines.push(`forbidden_outputs=${result.contract.forbiddenOutputs.length}`);
|
|
1686
|
+
lines.push('issues');
|
|
1687
|
+
if (result.issues.length === 0) {
|
|
1688
|
+
lines.push('- none');
|
|
1689
|
+
}
|
|
1690
|
+
else {
|
|
1691
|
+
for (const issue of result.issues) {
|
|
1692
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return lines.join('\n');
|
|
1696
|
+
}
|
|
1697
|
+
function renderProjectContextPackContract(contract) {
|
|
1698
|
+
const lines = ['SDD project context pack contract'];
|
|
1699
|
+
lines.push(`version=${contract.version}`);
|
|
1700
|
+
lines.push(`entry=${contract.entryPoint}`);
|
|
1701
|
+
lines.push('durable_context');
|
|
1702
|
+
for (const item of contract.durableContext) {
|
|
1703
|
+
lines.push(`- ${item}`);
|
|
1704
|
+
}
|
|
1705
|
+
lines.push('runtime_sources_of_truth');
|
|
1706
|
+
for (const source of contract.runtimeSourcesOfTruth) {
|
|
1707
|
+
lines.push(`- ${source}`);
|
|
1708
|
+
}
|
|
1709
|
+
lines.push('boundaries');
|
|
1710
|
+
for (const boundary of contract.boundaries) {
|
|
1711
|
+
lines.push(`- ${boundary}`);
|
|
1712
|
+
}
|
|
1713
|
+
return lines.join('\n');
|
|
1714
|
+
}
|
|
1715
|
+
function renderProjectContextPackValidation(result) {
|
|
1716
|
+
const lines = ['SDD project context pack validation'];
|
|
1717
|
+
lines.push(`valid=${result.valid}`);
|
|
1718
|
+
lines.push(`entry=${result.contract.entryPoint}`);
|
|
1719
|
+
lines.push(`runtime_sources=${result.contract.runtimeSourcesOfTruth.length}`);
|
|
1720
|
+
lines.push('issues');
|
|
1721
|
+
if (result.issues.length === 0) {
|
|
1722
|
+
lines.push('- none');
|
|
1723
|
+
}
|
|
1724
|
+
else {
|
|
1725
|
+
for (const issue of result.issues) {
|
|
1726
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return lines.join('\n');
|
|
1730
|
+
}
|
|
984
1731
|
function renderCapabilityList(capabilities) {
|
|
985
1732
|
const lines = ['SDD tool capabilities'];
|
|
986
1733
|
for (const capability of capabilities) {
|
|
@@ -1116,13 +1863,7 @@ function renderArtifactIngestionInspection(inspection) {
|
|
|
1116
1863
|
for (const record of inspection.records) {
|
|
1117
1864
|
lines.push(`- ${record.delegationId} ${record.status} artifact=${record.artifactPath} result=${record.resultStatus ?? 'n/a'} delegation=${record.delegationStatus ?? 'n/a'}`);
|
|
1118
1865
|
}
|
|
1119
|
-
|
|
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
|
-
}
|
|
1866
|
+
renderIssues(lines, inspection.issues);
|
|
1126
1867
|
return lines.join('\n');
|
|
1127
1868
|
}
|
|
1128
1869
|
function renderBackgroundExecutorResult(result) {
|
|
@@ -1131,13 +1872,7 @@ function renderBackgroundExecutorResult(result) {
|
|
|
1131
1872
|
lines.push(`run=${result.runId} delegation=${result.delegationId ?? 'n/a'} queue=${result.queueItemId ?? 'n/a'} worker=${result.workerAdapterId}`);
|
|
1132
1873
|
lines.push(`artifact=${result.artifactPath ?? 'pending'}`);
|
|
1133
1874
|
lines.push(result.message);
|
|
1134
|
-
|
|
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
|
-
}
|
|
1875
|
+
renderIssues(lines, result.issues);
|
|
1141
1876
|
return lines.join('\n');
|
|
1142
1877
|
}
|
|
1143
1878
|
function renderBackgroundExecutorInspection(inspection) {
|
|
@@ -1147,15 +1882,77 @@ function renderBackgroundExecutorInspection(inspection) {
|
|
|
1147
1882
|
for (const delegation of inspection.delegations) {
|
|
1148
1883
|
lines.push(`- ${delegation.delegationId} ${delegation.status} task=${delegation.taskId} agent=${delegation.agent} artifact=${delegation.expectedArtifact}`);
|
|
1149
1884
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1885
|
+
renderIssues(lines, inspection.issues);
|
|
1886
|
+
return lines.join('\n');
|
|
1887
|
+
}
|
|
1888
|
+
function renderResidentWorkerRuntimeClaimResult(result) {
|
|
1889
|
+
const lines = [`Resident worker runtime ${result.status} for ${result.taskId}`];
|
|
1890
|
+
lines.push(`version=${result.version}`);
|
|
1891
|
+
lines.push(`run=${result.runId} runtime=${result.runtimeId ?? 'n/a'} delegation=${result.delegationId ?? 'n/a'} queue=${result.queueItemId ?? 'n/a'} worker=${result.workerAdapterId}`);
|
|
1892
|
+
lines.push(`artifact=${result.expectedArtifact ?? 'pending'} lease_expires=${result.leaseExpiresAt ?? 'n/a'}`);
|
|
1893
|
+
lines.push(result.message);
|
|
1894
|
+
renderIssues(lines, result.issues);
|
|
1895
|
+
if (result.runtimeId && result.leaseExpiresAt) {
|
|
1896
|
+
lines.push(`next sdd worker-runtime heartbeat ${result.runtimeId} --run ${result.runId}`);
|
|
1897
|
+
lines.push(`inspect sdd worker-runtime inspect ${result.runtimeId} --run ${result.runId}`);
|
|
1898
|
+
}
|
|
1899
|
+
return lines.join('\n');
|
|
1900
|
+
}
|
|
1901
|
+
function renderResidentWorkerRuntimeHeartbeatResult(result) {
|
|
1902
|
+
const lines = [`Resident worker runtime ${result.status}: ${result.runtimeId}`];
|
|
1903
|
+
lines.push(`version=${result.version}`);
|
|
1904
|
+
lines.push(`run=${result.runId} lease_expires=${result.leaseExpiresAt ?? 'n/a'}`);
|
|
1905
|
+
lines.push(result.message);
|
|
1906
|
+
renderIssues(lines, result.issues);
|
|
1907
|
+
if (result.runtime) {
|
|
1908
|
+
lines.push(`next ${result.status === 'terminal' ? `sdd background inspect ${result.runId}` : `sdd worker-runtime inspect ${result.runtimeId} --run ${result.runId}`}`);
|
|
1156
1909
|
}
|
|
1157
1910
|
return lines.join('\n');
|
|
1158
1911
|
}
|
|
1912
|
+
function renderResidentWorkerRuntimeList(result) {
|
|
1913
|
+
const lines = [`Resident worker runtimes for ${result.runId}`];
|
|
1914
|
+
lines.push(`version=${result.version}`);
|
|
1915
|
+
lines.push(`runtimes=${result.runtimes.length} active=${result.activeRuntimes} stale=${result.staleRuntimes} terminal=${result.terminalRuntimes} blocked=${result.blockedRuntimes}`);
|
|
1916
|
+
for (const runtime of result.runtimes) {
|
|
1917
|
+
lines.push(`- ${runtime.runtimeId} ${runtime.status} task=${runtime.taskId} agent=${runtime.agent} delegation=${runtime.delegationId} lease_expires=${runtime.leaseExpiresAt}`);
|
|
1918
|
+
}
|
|
1919
|
+
renderIssues(lines, result.issues);
|
|
1920
|
+
return lines.join('\n');
|
|
1921
|
+
}
|
|
1922
|
+
function renderResidentWorkerRuntimeInspection(inspection) {
|
|
1923
|
+
const lines = [`Resident worker runtime ${inspection.status}: ${inspection.runtimeId}`];
|
|
1924
|
+
lines.push(`version=${inspection.version}`);
|
|
1925
|
+
lines.push(`run=${inspection.runId} valid=${inspection.valid} lease_expired=${inspection.leaseExpired}`);
|
|
1926
|
+
if (inspection.runtime) {
|
|
1927
|
+
lines.push(`task=${inspection.runtime.taskId} agent=${inspection.runtime.agent} worker=${inspection.runtime.workerAdapterId}`);
|
|
1928
|
+
lines.push(`delegation=${inspection.runtime.delegationId} queue=${inspection.runtime.queueItemId} artifact=${inspection.runtime.expectedArtifact}`);
|
|
1929
|
+
lines.push(`claimed=${inspection.runtime.claimedAt} heartbeat=${inspection.runtime.lastHeartbeatAt ?? 'none'} lease_expires=${inspection.runtime.leaseExpiresAt}`);
|
|
1930
|
+
lines.push(`evidence=${inspection.runtime.evidenceSummary}`);
|
|
1931
|
+
}
|
|
1932
|
+
lines.push(`queue_status=${inspection.queueItem?.status ?? 'missing'} adapter=${inspection.workerAdapter?.id ?? 'missing'}`);
|
|
1933
|
+
lines.push(`next ${inspection.recommendedNextCommand}`);
|
|
1934
|
+
renderIssues(lines, inspection.issues);
|
|
1935
|
+
return lines.join('\n');
|
|
1936
|
+
}
|
|
1937
|
+
function renderIssues(lines, issues) {
|
|
1938
|
+
if (issues.length === 0) {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
lines.push('issues');
|
|
1942
|
+
for (const issue of issues) {
|
|
1943
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1944
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
function renderDocumentGaps(lines, gaps) {
|
|
1948
|
+
if (gaps.length === 0) {
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
lines.push('gaps');
|
|
1952
|
+
for (const gap of gaps) {
|
|
1953
|
+
lines.push(`- [${gap.severity}] ${gap.type} ${gap.taskId ?? 'document'} ${gap.field}: ${gap.message}`);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1159
1956
|
function renderWaveExecutorResult(result) {
|
|
1160
1957
|
const lines = [`Wave executor ${result.status} for ${result.branch}`];
|
|
1161
1958
|
lines.push(`version=${result.version}`);
|
|
@@ -1176,13 +1973,7 @@ function renderWaveExecutorResult(result) {
|
|
|
1176
1973
|
lines.push(`- ${gate.taskId}: ${gate.reasons.join(' | ')}`);
|
|
1177
1974
|
}
|
|
1178
1975
|
}
|
|
1179
|
-
|
|
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
|
-
}
|
|
1976
|
+
renderIssues(lines, result.issues);
|
|
1186
1977
|
return lines.join('\n');
|
|
1187
1978
|
}
|
|
1188
1979
|
function renderWaveExecutorInspection(inspection) {
|
|
@@ -1192,13 +1983,7 @@ function renderWaveExecutorInspection(inspection) {
|
|
|
1192
1983
|
for (const event of inspection.waveEvents) {
|
|
1193
1984
|
lines.push(`- ${event.event}: ${event.summary ?? ''}`);
|
|
1194
1985
|
}
|
|
1195
|
-
|
|
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
|
-
}
|
|
1986
|
+
renderIssues(lines, inspection.issues);
|
|
1202
1987
|
return lines.join('\n');
|
|
1203
1988
|
}
|
|
1204
1989
|
function renderWorktreeIsolationDecision(decision) {
|
|
@@ -1237,24 +2022,19 @@ function renderWorktreeLifecycleInspection(inspection) {
|
|
|
1237
2022
|
for (const record of inspection.records) {
|
|
1238
2023
|
lines.push(`- ${record.worktreeId} ${record.status} task=${record.taskId} path=${record.worktreePath} dirty=${record.dirty}`);
|
|
1239
2024
|
}
|
|
1240
|
-
|
|
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
|
-
}
|
|
2025
|
+
renderIssues(lines, inspection.issues);
|
|
1247
2026
|
return lines.join('\n');
|
|
1248
2027
|
}
|
|
1249
2028
|
function renderTaskGraphPlan(graph) {
|
|
1250
2029
|
const lines = [`Task graph ${graph.valid ? 'valid' : 'blocked'} for ${graph.branch}`];
|
|
1251
2030
|
lines.push(`version=${graph.version}`);
|
|
2031
|
+
lines.push(`contract=${graph.contract}`);
|
|
1252
2032
|
lines.push(`tasks=${graph.summary.tasks} dependencies=${graph.summary.dependencies} file_overlaps=${graph.summary.fileOverlaps}`);
|
|
1253
2033
|
lines.push(`high_risk_tasks=${graph.summary.highRiskTasks.length > 0 ? graph.summary.highRiskTasks.join(',') : 'none'}`);
|
|
1254
2034
|
lines.push(`validation=${graph.summary.validationCommands.length > 0 ? graph.summary.validationCommands.join(' | ') : 'none'}`);
|
|
1255
2035
|
lines.push('nodes');
|
|
1256
2036
|
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}`);
|
|
2037
|
+
lines.push(`- ${node.taskId} status=${node.status} wave=${node.wave ?? 'n/a'} deps=${node.dependsOn.join(',') || 'none'} files=${node.affectedFiles.length} agent_fit=${node.agentFit.join(',') || 'none'} verification=${node.verificationAvailability.join(',') || 'none'} autonomy=${node.autonomy ?? 'n/a'}`);
|
|
1258
2038
|
}
|
|
1259
2039
|
if (graph.dependencyEdges.length > 0) {
|
|
1260
2040
|
lines.push('dependency_edges');
|
|
@@ -1309,12 +2089,50 @@ function renderWavePlan(plan) {
|
|
|
1309
2089
|
}
|
|
1310
2090
|
return lines.join('\n');
|
|
1311
2091
|
}
|
|
1312
|
-
function
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
2092
|
+
function readTeamModeActivation(args, fallback) {
|
|
2093
|
+
if (args.includes('--no-team-mode')) {
|
|
2094
|
+
return 'off';
|
|
2095
|
+
}
|
|
2096
|
+
const inline = args.find((item) => item.startsWith('--team-mode='));
|
|
2097
|
+
const inlineValue = inline?.split('=', 2)[1];
|
|
2098
|
+
if (inlineValue === 'auto' || inlineValue === 'force' || inlineValue === 'off') {
|
|
2099
|
+
return inlineValue;
|
|
2100
|
+
}
|
|
2101
|
+
const index = args.indexOf('--team-mode');
|
|
2102
|
+
if (index >= 0) {
|
|
2103
|
+
const value = args[index + 1];
|
|
2104
|
+
if (value === 'auto' || value === 'force' || value === 'off') {
|
|
2105
|
+
return value;
|
|
2106
|
+
}
|
|
2107
|
+
return 'force';
|
|
2108
|
+
}
|
|
2109
|
+
return fallback;
|
|
2110
|
+
}
|
|
2111
|
+
function readBranchContext(args) {
|
|
2112
|
+
const branch = readBranchOption(args);
|
|
2113
|
+
return branch ? { branch, branchSource: 'cli_option' } : {};
|
|
2114
|
+
}
|
|
2115
|
+
function readBranchOption(args) {
|
|
2116
|
+
return readOption(args, '--branch') ?? undefined;
|
|
2117
|
+
}
|
|
2118
|
+
function readOptionalPositionalArgument(args) {
|
|
2119
|
+
const booleanOptions = new Set(['--approved', '--json', '--no-team-mode', '--force', '--check', '--latest-only', '--all-runs', '--scaffold-docs', '--no-scaffold-docs', '--direct-safe', '--external-unknown', '--architecture', '--checkpoint']);
|
|
2120
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
2121
|
+
const item = args[index];
|
|
2122
|
+
if (!item.startsWith('--')) {
|
|
2123
|
+
return item;
|
|
2124
|
+
}
|
|
2125
|
+
if (item.includes('=')) {
|
|
2126
|
+
continue;
|
|
2127
|
+
}
|
|
2128
|
+
if (!booleanOptions.has(item) && args[index + 1] && !args[index + 1].startsWith('--')) {
|
|
2129
|
+
index += 1;
|
|
2130
|
+
}
|
|
1316
2131
|
}
|
|
1317
|
-
return
|
|
2132
|
+
return undefined;
|
|
2133
|
+
}
|
|
2134
|
+
async function readResolvedBranch(projectRoot, args) {
|
|
2135
|
+
return (await resolveSddContext(projectRoot, readBranchContext(args))).branch;
|
|
1318
2136
|
}
|
|
1319
2137
|
function readWaveExecutorStrategy(args, name) {
|
|
1320
2138
|
const value = readOption(args, name) ?? 'fast-stop';
|
|
@@ -1327,15 +2145,6 @@ function readRunStatus(args, name) {
|
|
|
1327
2145
|
function readGovernancePolicyOperation(value) {
|
|
1328
2146
|
return value === 'background_executor' || value === 'wave_executor' || value === 'sync_back_apply' || value === 'destructive_git' || value === 'external_interaction' || value === 'cleanup' ? value : null;
|
|
1329
2147
|
}
|
|
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
2148
|
function readTaskArtifactOptions(args) {
|
|
1340
2149
|
const artifacts = {};
|
|
1341
2150
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -1376,24 +2185,35 @@ function readAiToolSelection(args, allowNone) {
|
|
|
1376
2185
|
}
|
|
1377
2186
|
throw new Error(`Unsupported --ai value: ${value}`);
|
|
1378
2187
|
}
|
|
1379
|
-
function readLifecycleSignalOptions(args) {
|
|
2188
|
+
async function readLifecycleSignalOptions(args) {
|
|
1380
2189
|
const directSafe = args.includes('--direct-safe');
|
|
1381
2190
|
const riskTags = readRepeatedOptions(args, '--risk');
|
|
1382
2191
|
const contracts = readRepeatedOptions(args, '--contract');
|
|
1383
2192
|
const permissions = readRepeatedOptions(args, '--permission');
|
|
1384
|
-
|
|
2193
|
+
const fromText = readOption(args, '--from-text');
|
|
2194
|
+
const fromFile = readOption(args, '--from-file');
|
|
2195
|
+
if (fromText && fromFile) {
|
|
2196
|
+
return { signals: {}, riskExtraction: null, error: 'Usage: sdd lifecycle decide accepts only one of --from-text or --from-file' };
|
|
2197
|
+
}
|
|
2198
|
+
const riskExtraction = fromText
|
|
2199
|
+
? extractLifecycleRiskSignalsFromText(fromText, 'from_text')
|
|
2200
|
+
: fromFile
|
|
2201
|
+
? extractLifecycleRiskSignalsFromText(await readFile(fromFile, 'utf8'), 'from_file')
|
|
2202
|
+
: null;
|
|
2203
|
+
const extracted = riskExtraction?.signals ?? {};
|
|
2204
|
+
const signals = {
|
|
1385
2205
|
intent_clarity: directSafe ? 'high' : readSignalClarity(args, '--intent') ?? 'medium',
|
|
1386
2206
|
acceptance_clarity: directSafe ? 'high' : readSignalClarity(args, '--acceptance') ?? 'medium',
|
|
1387
2207
|
estimated_change_size: directSafe ? 'tiny' : readEstimatedChangeSize(args, '--size') ?? 'small',
|
|
1388
2208
|
task_count_estimate: Number(readOption(args, '--tasks') ?? (directSafe ? '1' : '1')),
|
|
1389
2209
|
file_count_estimate: Number(readOption(args, '--files') ?? (directSafe ? '1' : '1')),
|
|
1390
2210
|
affected_layers: readRepeatedOptions(args, '--layer'),
|
|
1391
|
-
affected_contracts: contracts,
|
|
2211
|
+
affected_contracts: uniqueCliStrings([...contracts, ...(extracted.affected_contracts ?? [])]),
|
|
1392
2212
|
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',
|
|
2213
|
+
impact_confidence: directSafe ? 'high' : extracted.impact_confidence ?? readImpactConfidence(args, '--impact-confidence') ?? 'medium',
|
|
2214
|
+
risk_tags: uniqueCliStrings([...riskTags, ...(extracted.risk_tags ?? [])]),
|
|
2215
|
+
reversibility: directSafe ? 'reversible' : extracted.reversibility ?? readReversibility(args, '--reversibility') ?? 'unknown',
|
|
2216
|
+
validation_clarity: directSafe ? 'clear' : extracted.validation_clarity ?? readValidationClarity(args, '--validation') ?? 'partial',
|
|
1397
2217
|
validation_available: directSafe || args.includes('--validation-available'),
|
|
1398
2218
|
validation_cost: directSafe ? 'cheap' : readValidationCost(args, '--validation-cost') ?? 'unknown',
|
|
1399
2219
|
policy_hits: readRepeatedOptions(args, '--policy'),
|
|
@@ -1405,21 +2225,44 @@ function readLifecycleSignalOptions(args) {
|
|
|
1405
2225
|
orchestration_uncertainty: directSafe ? 'low' : readOrchestrationUncertainty(args, '--orchestration') ?? 'medium',
|
|
1406
2226
|
human_checkpoint_required: args.includes('--checkpoint'),
|
|
1407
2227
|
approval_reason: readRepeatedOptions(args, '--approval-reason'),
|
|
1408
|
-
source_artifacts: readRepeatedOptions(args, '--source-artifact'),
|
|
2228
|
+
source_artifacts: uniqueCliStrings([...readRepeatedOptions(args, '--source-artifact'), ...(fromFile ? [fromFile] : [])]),
|
|
1409
2229
|
can_scout_impact: !args.includes('--cannot-scout-impact'),
|
|
1410
|
-
architecture_decision_required: args.includes('--architecture'),
|
|
1411
|
-
external_unknown: args.includes('--external-unknown')
|
|
2230
|
+
architecture_decision_required: args.includes('--architecture') || Boolean(extracted.architecture_decision_required),
|
|
2231
|
+
external_unknown: args.includes('--external-unknown') || Boolean(extracted.external_unknown)
|
|
1412
2232
|
};
|
|
2233
|
+
return { signals, riskExtraction };
|
|
1413
2234
|
}
|
|
1414
|
-
function
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
2235
|
+
function uniqueCliStrings(values) {
|
|
2236
|
+
return Array.from(new Set(values.filter((value) => value.length > 0)));
|
|
2237
|
+
}
|
|
2238
|
+
function renderLifecycleRiskExtraction(extraction) {
|
|
2239
|
+
if (!extraction) {
|
|
2240
|
+
return '';
|
|
2241
|
+
}
|
|
2242
|
+
const lines = [
|
|
2243
|
+
'Lifecycle Risk Gate',
|
|
2244
|
+
'changed',
|
|
2245
|
+
'- deterministic risk signals extracted',
|
|
2246
|
+
'decision',
|
|
2247
|
+
`- source=${extraction.source}`,
|
|
2248
|
+
`- risk_tags=${extraction.riskTags.join(',') || 'none'}`,
|
|
2249
|
+
`- affected_contracts=${extraction.affectedContracts.join(',') || 'none'}`,
|
|
2250
|
+
`- external_unknown=${extraction.externalUnknown}`,
|
|
2251
|
+
'evidence'
|
|
2252
|
+
];
|
|
2253
|
+
if (extraction.evidence.length === 0) {
|
|
2254
|
+
lines.push('- none');
|
|
2255
|
+
}
|
|
2256
|
+
else {
|
|
2257
|
+
for (const item of extraction.evidence) {
|
|
2258
|
+
lines.push(`- ${item.category}: ${item.matched} -> ${item.riskTag}`);
|
|
1420
2259
|
}
|
|
1421
2260
|
}
|
|
1422
|
-
|
|
2261
|
+
lines.push('gaps');
|
|
2262
|
+
lines.push('- none');
|
|
2263
|
+
lines.push('next');
|
|
2264
|
+
lines.push('- Evaluate extracted signals with lifecycle decision gate.');
|
|
2265
|
+
return `${lines.join('\n')}\n`;
|
|
1423
2266
|
}
|
|
1424
2267
|
function readSignalClarity(args, name) {
|
|
1425
2268
|
const value = readOption(args, name);
|
|
@@ -1460,14 +2303,36 @@ id: T1
|
|
|
1460
2303
|
status: pending
|
|
1461
2304
|
wave: 1
|
|
1462
2305
|
depends_on: []
|
|
2306
|
+
acceptance_refs:
|
|
2307
|
+
- AC-1
|
|
2308
|
+
plan_refs:
|
|
2309
|
+
- "§4 Target Design Overview"
|
|
1463
2310
|
affected_files:
|
|
1464
2311
|
- path/to/file
|
|
1465
2312
|
validation:
|
|
1466
2313
|
- command string
|
|
1467
|
-
risk:
|
|
2314
|
+
risk:
|
|
2315
|
+
- state-machine
|
|
2316
|
+
agent_fit:
|
|
2317
|
+
- scout
|
|
2318
|
+
- implementer
|
|
2319
|
+
- reviewer
|
|
2320
|
+
- validator
|
|
2321
|
+
verification_availability:
|
|
2322
|
+
- unit:command string
|
|
2323
|
+
- build:command string
|
|
2324
|
+
autonomy: full_sdd_with_checkpoint
|
|
2325
|
+
allowed_agents:
|
|
2326
|
+
- scout
|
|
2327
|
+
- implementer
|
|
2328
|
+
- reviewer
|
|
2329
|
+
- validator
|
|
2330
|
+
required_artifacts:
|
|
2331
|
+
- artifacts/review-T1.md
|
|
2332
|
+
- artifacts/validation-T1.md
|
|
1468
2333
|
\`\`\`
|
|
1469
2334
|
|
|
1470
|
-
Companion sections such as #### Boundary, #### Acceptance, and #### Implementation Notes must stay outside the fenced sdd-task metadata block.
|
|
2335
|
+
Put contract metadata inside the fenced block: acceptance_refs, plan_refs, agent_fit, verification_availability, autonomy, allowed_agents, and required_artifacts. Companion sections such as #### Boundary, #### Acceptance, and #### Implementation Notes must stay outside the fenced sdd-task metadata block.
|
|
1471
2336
|
|
|
1472
2337
|
#### Boundary
|
|
1473
2338
|
|