sdd-agent-platform 0.1.0 → 0.3.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 +1336 -313
- 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 +114 -22
- package/dist/packages/core/src/ai-tools.js.map +1 -1
- package/dist/packages/core/src/index.d.ts +975 -5
- package/dist/packages/core/src/index.js +5267 -369
- 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 +2 -2
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { writeArtifact, archiveRun, applyAiToolEntries, applySyncBack, createWorktreeLifecycle, createRun, doctor, buildContextBuildPackage, buildEvidenceSummaryProjection, 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, parseContextProfile, 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';
|
|
7
|
+
import { readOption, readPositiveIntegerOption, readRepeatedOption, readRepeatedOptions } from './options.js';
|
|
3
8
|
async function main(args) {
|
|
4
9
|
const projectRoot = process.cwd();
|
|
5
10
|
const [command, subcommand, ...rest] = args;
|
|
@@ -9,22 +14,30 @@ async function main(args) {
|
|
|
9
14
|
output: helpText()
|
|
10
15
|
};
|
|
11
16
|
}
|
|
12
|
-
if (command === '
|
|
17
|
+
if (command === 'help') {
|
|
13
18
|
return {
|
|
14
19
|
exitCode: 0,
|
|
15
|
-
output:
|
|
20
|
+
output: helpText(subcommand)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (command === '--version' || command === '-v' || command === 'version') {
|
|
24
|
+
const identity = getCliIdentity();
|
|
25
|
+
return {
|
|
26
|
+
exitCode: 0,
|
|
27
|
+
output: wantsJson(args) ? jsonOutput(identity, args) : identity.version
|
|
16
28
|
};
|
|
17
29
|
}
|
|
18
30
|
if (command === 'init') {
|
|
19
31
|
const initArgs = [subcommand, ...rest].filter(Boolean);
|
|
20
32
|
const force = initArgs.includes('--force');
|
|
21
33
|
const aiTool = readAiToolSelection(initArgs, true);
|
|
22
|
-
const branch = readOption(initArgs, '--branch') ??
|
|
23
|
-
const scaffoldDocuments =
|
|
34
|
+
const branch = readOption(initArgs, '--branch') ?? undefined;
|
|
35
|
+
const scaffoldDocuments = initArgs.includes('--no-scaffold-docs') ? false : initArgs.includes('--scaffold-docs') || branch !== undefined;
|
|
24
36
|
const result = await initProject(projectRoot, { force, aiTool, branch, scaffoldDocuments });
|
|
37
|
+
const json = wantsJson(initArgs);
|
|
25
38
|
return {
|
|
26
39
|
exitCode: 0,
|
|
27
|
-
output:
|
|
40
|
+
output: json ? jsonOutput({ command: 'init', ...result }, initArgs) : renderInitResult(result)
|
|
28
41
|
};
|
|
29
42
|
}
|
|
30
43
|
if (command === 'update') {
|
|
@@ -42,10 +55,9 @@ async function main(args) {
|
|
|
42
55
|
const instructionArgs = [subcommand, ...rest].filter(Boolean);
|
|
43
56
|
const action = instructionArgs.find((item) => !item.startsWith('--')) ?? 'overview';
|
|
44
57
|
const payload = getSddInstructions(action);
|
|
45
|
-
const json = instructionArgs.includes('--json');
|
|
46
58
|
return {
|
|
47
59
|
exitCode: 0,
|
|
48
|
-
output:
|
|
60
|
+
output: renderTextOrJson(instructionArgs, payload, renderSddInstructions)
|
|
49
61
|
};
|
|
50
62
|
}
|
|
51
63
|
if (command === 'doctor') {
|
|
@@ -53,25 +65,27 @@ async function main(args) {
|
|
|
53
65
|
if (doctorArgs.includes('--latest-only') && doctorArgs.includes('--all-runs')) {
|
|
54
66
|
return {
|
|
55
67
|
exitCode: 2,
|
|
56
|
-
error: 'Usage: sdd doctor [--latest-only] [--all-runs] (choose only one scope flag)'
|
|
68
|
+
error: 'Usage: sdd doctor [--latest-only] [--all-runs] [--branch <branch>] (choose only one scope flag)'
|
|
57
69
|
};
|
|
58
70
|
}
|
|
59
71
|
const report = await doctor(projectRoot, {
|
|
60
72
|
latestOnly: doctorArgs.includes('--latest-only'),
|
|
61
|
-
allRuns: doctorArgs.includes('--all-runs')
|
|
73
|
+
allRuns: doctorArgs.includes('--all-runs'),
|
|
74
|
+
branch: readBranchOption(doctorArgs)
|
|
62
75
|
});
|
|
76
|
+
const json = wantsJson(doctorArgs);
|
|
63
77
|
return {
|
|
64
78
|
exitCode: report.status === 'FAIL' ? 1 : 0,
|
|
65
|
-
output: renderDoctorReport(report)
|
|
79
|
+
output: json ? jsonOutput(report, doctorArgs) : renderDoctorReport(report)
|
|
66
80
|
};
|
|
67
81
|
}
|
|
68
82
|
if (command === 'status') {
|
|
69
83
|
const statusArgs = [subcommand, ...rest].filter(Boolean);
|
|
70
|
-
const result = await getProjectStatus(projectRoot,
|
|
71
|
-
const json = statusArgs
|
|
84
|
+
const result = await getProjectStatus(projectRoot, readBranchContext(statusArgs));
|
|
85
|
+
const json = wantsJson(statusArgs);
|
|
72
86
|
return {
|
|
73
87
|
exitCode: result.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
74
|
-
output: json ?
|
|
88
|
+
output: json ? jsonOutput(result, statusArgs) : renderProjectStatus(result)
|
|
75
89
|
};
|
|
76
90
|
}
|
|
77
91
|
if (command === 'run' && subcommand === 'create') {
|
|
@@ -105,19 +119,19 @@ async function main(args) {
|
|
|
105
119
|
}
|
|
106
120
|
if (command === 'run' && subcommand === 'index') {
|
|
107
121
|
const action = rest[0];
|
|
108
|
-
const json = rest
|
|
122
|
+
const json = wantsJson(rest);
|
|
109
123
|
if (action === 'rebuild') {
|
|
110
124
|
const index = await rebuildLocalRunIndex(projectRoot);
|
|
111
125
|
return {
|
|
112
126
|
exitCode: 0,
|
|
113
|
-
output: json ?
|
|
127
|
+
output: json ? jsonOutput(index, rest) : renderLocalRunIndex(index)
|
|
114
128
|
};
|
|
115
129
|
}
|
|
116
130
|
if (action === 'inspect') {
|
|
117
131
|
const inspection = await inspectLocalRunIndex(projectRoot);
|
|
118
132
|
return {
|
|
119
133
|
exitCode: inspection.valid ? 0 : 1,
|
|
120
|
-
output: json ?
|
|
134
|
+
output: json ? jsonOutput(inspection, rest) : renderLocalRunIndexInspection(inspection)
|
|
121
135
|
};
|
|
122
136
|
}
|
|
123
137
|
if (action === 'query') {
|
|
@@ -125,7 +139,7 @@ async function main(args) {
|
|
|
125
139
|
if (readOption(rest, '--status') && !status) {
|
|
126
140
|
return {
|
|
127
141
|
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]'
|
|
142
|
+
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
143
|
};
|
|
130
144
|
}
|
|
131
145
|
const index = await queryLocalRunIndex(projectRoot, {
|
|
@@ -136,7 +150,7 @@ async function main(args) {
|
|
|
136
150
|
});
|
|
137
151
|
return {
|
|
138
152
|
exitCode: 0,
|
|
139
|
-
output: json ?
|
|
153
|
+
output: json ? jsonOutput(index, rest) : renderLocalRunIndex(index)
|
|
140
154
|
};
|
|
141
155
|
}
|
|
142
156
|
return {
|
|
@@ -153,10 +167,10 @@ async function main(args) {
|
|
|
153
167
|
};
|
|
154
168
|
}
|
|
155
169
|
const result = await inspectRun(projectRoot, runId);
|
|
156
|
-
const json = rest
|
|
170
|
+
const json = wantsJson(rest);
|
|
157
171
|
return {
|
|
158
172
|
exitCode: 0,
|
|
159
|
-
output: json ?
|
|
173
|
+
output: json ? jsonOutput(result, rest) : renderRunInspection(result)
|
|
160
174
|
};
|
|
161
175
|
}
|
|
162
176
|
if (command === 'run' && subcommand === 'archive') {
|
|
@@ -173,43 +187,85 @@ async function main(args) {
|
|
|
173
187
|
output: JSON.stringify({ runId: state.runId, status: state.status, updatedAt: state.updatedAt }, null, 2)
|
|
174
188
|
};
|
|
175
189
|
}
|
|
176
|
-
if (command === '
|
|
177
|
-
const runId = rest
|
|
190
|
+
if (command === 'evidence' && subcommand === 'summary') {
|
|
191
|
+
const runId = rest.find((item) => !item.startsWith('--'));
|
|
178
192
|
if (!runId) {
|
|
179
193
|
return {
|
|
180
194
|
exitCode: 2,
|
|
181
|
-
error: 'Usage: sdd
|
|
195
|
+
error: 'Usage: sdd evidence summary <run_id> [--task <task_id>] [--json|--compact-json]'
|
|
182
196
|
};
|
|
183
197
|
}
|
|
184
|
-
const
|
|
198
|
+
const summary = await buildEvidenceSummaryProjection(projectRoot, {
|
|
185
199
|
runId,
|
|
186
|
-
branch: readOption(rest, '--branch') ?? 'master',
|
|
187
200
|
taskId: readOption(rest, '--task') ?? undefined
|
|
188
201
|
});
|
|
189
|
-
const json = rest
|
|
202
|
+
const json = wantsJson(rest);
|
|
203
|
+
return {
|
|
204
|
+
exitCode: 0,
|
|
205
|
+
output: json ? jsonOutput(summary, rest) : renderEvidenceSummaryProjection(summary)
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
if (command === 'context' && subcommand === 'build') {
|
|
209
|
+
const taskId = readOption(rest, '--task') ?? undefined;
|
|
210
|
+
const mode = readContextBuildMode(rest, '--mode');
|
|
211
|
+
if (!taskId || !mode) {
|
|
212
|
+
return {
|
|
213
|
+
exitCode: 2,
|
|
214
|
+
error: 'Usage: sdd context build --task <task_id> --mode do|verify|sync-back|doctor [--agent <agent>] [--branch <branch>] [--profile brief|normal|forensic] [--json|--compact-json]'
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const contextPackage = await buildContextBuildPackage(projectRoot, {
|
|
218
|
+
taskId,
|
|
219
|
+
branch: readBranchOption(rest),
|
|
220
|
+
mode,
|
|
221
|
+
agent: readOption(rest, '--agent') ?? undefined,
|
|
222
|
+
profile: parseContextProfile(readOption(rest, '--profile'))
|
|
223
|
+
});
|
|
224
|
+
const json = wantsJson(rest);
|
|
225
|
+
return {
|
|
226
|
+
exitCode: 0,
|
|
227
|
+
output: json ? jsonOutput(contextPackage, rest) : renderContextBuildPackage(contextPackage)
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (command === 'sync-back' && subcommand === 'inspect') {
|
|
231
|
+
const runId = readOptionalPositionalArgument(rest);
|
|
232
|
+
const taskId = readOption(rest, '--task') ?? undefined;
|
|
233
|
+
if (!runId && !taskId) {
|
|
234
|
+
return {
|
|
235
|
+
exitCode: 2,
|
|
236
|
+
error: 'Usage: sdd sync-back inspect [<run_id>] [--branch <branch>] --task <task_id> [--json|--compact-json]'
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const result = await inspectSyncBack(projectRoot, {
|
|
240
|
+
runId,
|
|
241
|
+
branch: readBranchOption(rest),
|
|
242
|
+
taskId
|
|
243
|
+
});
|
|
244
|
+
const json = wantsJson(rest);
|
|
190
245
|
return {
|
|
191
246
|
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
192
|
-
output: json ?
|
|
247
|
+
output: json ? jsonOutput(result, rest) : renderSyncBackInspection(result)
|
|
193
248
|
};
|
|
194
249
|
}
|
|
195
250
|
if (command === 'sync-back' && subcommand === 'apply') {
|
|
196
|
-
const runId = rest
|
|
197
|
-
|
|
251
|
+
const runId = readOptionalPositionalArgument(rest);
|
|
252
|
+
const taskId = readOption(rest, '--task') ?? undefined;
|
|
253
|
+
if (!runId && !taskId) {
|
|
198
254
|
return {
|
|
199
255
|
exitCode: 2,
|
|
200
|
-
error: 'Usage: sdd sync-back apply <run_id> [--branch <branch>]
|
|
256
|
+
error: 'Usage: sdd sync-back apply [<run_id>] [--branch <branch>] --task <task_id> [--approved] [--json|--compact-json]'
|
|
201
257
|
};
|
|
202
258
|
}
|
|
203
259
|
const result = await applySyncBack(projectRoot, {
|
|
204
260
|
runId,
|
|
205
|
-
branch:
|
|
206
|
-
taskId
|
|
261
|
+
branch: readBranchOption(rest),
|
|
262
|
+
taskId,
|
|
207
263
|
approved: rest.includes('--approved')
|
|
208
264
|
});
|
|
209
|
-
const json = rest
|
|
265
|
+
const json = wantsJson(rest);
|
|
210
266
|
return {
|
|
211
267
|
exitCode: 0,
|
|
212
|
-
output: json ?
|
|
268
|
+
output: json ? jsonOutput(result, rest) : renderSyncBackApplyResult(result)
|
|
213
269
|
};
|
|
214
270
|
}
|
|
215
271
|
if (command === 'tasks' && subcommand === 'format') {
|
|
@@ -219,7 +275,7 @@ async function main(args) {
|
|
|
219
275
|
};
|
|
220
276
|
}
|
|
221
277
|
if (command === 'tasks' && subcommand === 'list') {
|
|
222
|
-
const model = await parseSddBranch(projectRoot,
|
|
278
|
+
const model = await parseSddBranch(projectRoot, await readResolvedBranch(projectRoot, rest));
|
|
223
279
|
return {
|
|
224
280
|
exitCode: model.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
225
281
|
output: renderTaskList(model)
|
|
@@ -230,10 +286,10 @@ async function main(args) {
|
|
|
230
286
|
if (!taskId) {
|
|
231
287
|
return {
|
|
232
288
|
exitCode: 2,
|
|
233
|
-
error: 'Usage: sdd tasks inspect <task_id> [--branch <branch>]'
|
|
289
|
+
error: 'Usage: sdd tasks inspect <task_id> [--branch <branch>] [--json]'
|
|
234
290
|
};
|
|
235
291
|
}
|
|
236
|
-
const model = await parseSddBranch(projectRoot,
|
|
292
|
+
const model = await parseSddBranch(projectRoot, await readResolvedBranch(projectRoot, rest));
|
|
237
293
|
const result = inspectSddTask(model, taskId);
|
|
238
294
|
if (!result.task && result.gaps.length === 0) {
|
|
239
295
|
return {
|
|
@@ -241,20 +297,48 @@ async function main(args) {
|
|
|
241
297
|
error: `Task not found: ${taskId}`
|
|
242
298
|
};
|
|
243
299
|
}
|
|
300
|
+
const json = wantsJson(rest);
|
|
244
301
|
return {
|
|
245
302
|
exitCode: result.task === null || result.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
246
|
-
output: renderTaskInspect(result.task, result.gaps)
|
|
303
|
+
output: json ? jsonOutput(result, rest) : renderTaskInspect(result.task, result.gaps)
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
if (command === 'tasks' && subcommand === 'route') {
|
|
307
|
+
const taskId = rest.find((item) => !item.startsWith('--'));
|
|
308
|
+
if (!taskId) {
|
|
309
|
+
return {
|
|
310
|
+
exitCode: 2,
|
|
311
|
+
error: 'Usage: sdd tasks route <task_id> [--branch <branch>] [--team-mode [auto|force|off]] [--no-team-mode] [--profile] [--cache] [--json]'
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
const decision = await routeSddTask(projectRoot, {
|
|
315
|
+
taskId,
|
|
316
|
+
branch: readBranchOption(rest),
|
|
317
|
+
teamModeActivation: readTeamModeActivation(rest),
|
|
318
|
+
profile: rest.includes('--profile'),
|
|
319
|
+
cache: rest.includes('--cache'),
|
|
320
|
+
});
|
|
321
|
+
return {
|
|
322
|
+
exitCode: decision.blockedReason ? 1 : 0,
|
|
323
|
+
output: wantsJson(rest) ? jsonOutput(decision, rest) : renderAgentRouterDecision(decision)
|
|
247
324
|
};
|
|
248
325
|
}
|
|
249
326
|
if (command === 'tasks' && subcommand === 'gaps') {
|
|
250
|
-
const model = await parseSddBranch(projectRoot,
|
|
327
|
+
const model = await parseSddBranch(projectRoot, await readResolvedBranch(projectRoot, rest));
|
|
251
328
|
return {
|
|
252
329
|
exitCode: model.gaps.some((gap) => gap.severity === 'blocking') ? 1 : 0,
|
|
253
330
|
output: renderTaskGapReport(model)
|
|
254
331
|
};
|
|
255
332
|
}
|
|
256
333
|
if (command === 'lifecycle' && subcommand === 'decide') {
|
|
257
|
-
const
|
|
334
|
+
const lifecycleInput = await readLifecycleSignalOptions(rest);
|
|
335
|
+
if (lifecycleInput.error) {
|
|
336
|
+
return {
|
|
337
|
+
exitCode: 2,
|
|
338
|
+
error: lifecycleInput.error
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
const result = evaluateLifecycleDecisionGate(lifecycleInput.signals);
|
|
258
342
|
const runId = readOption(rest, '--run');
|
|
259
343
|
if (runId) {
|
|
260
344
|
await recordLifecycleDecision(projectRoot, runId, result.record);
|
|
@@ -262,7 +346,9 @@ async function main(args) {
|
|
|
262
346
|
const json = rest.includes('--json');
|
|
263
347
|
return {
|
|
264
348
|
exitCode: 0,
|
|
265
|
-
output: json
|
|
349
|
+
output: json
|
|
350
|
+
? JSON.stringify({ riskExtraction: lifecycleInput.riskExtraction, ...result, recordedRunId: runId ?? null }, null, 2)
|
|
351
|
+
: `${renderLifecycleRiskExtraction(lifecycleInput.riskExtraction)}${renderLifecycleDecisionGate(result)}${runId ? `\nrecorded_run=${runId}` : ''}`
|
|
266
352
|
};
|
|
267
353
|
}
|
|
268
354
|
if (command === 'do' && subcommand === 'task') {
|
|
@@ -270,42 +356,45 @@ async function main(args) {
|
|
|
270
356
|
if (!taskId) {
|
|
271
357
|
return {
|
|
272
358
|
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]'
|
|
359
|
+
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
360
|
};
|
|
275
361
|
}
|
|
276
362
|
const result = await runSingleTaskLoop(projectRoot, {
|
|
277
363
|
taskId,
|
|
278
|
-
branch:
|
|
364
|
+
branch: readBranchOption(rest),
|
|
279
365
|
runId: readOption(rest, '--run') ?? undefined,
|
|
280
366
|
implementArtifact: readOption(rest, '--implement-artifact') ?? undefined,
|
|
281
367
|
reviewArtifact: readOption(rest, '--review-artifact') ?? undefined,
|
|
282
368
|
debugArtifact: readOption(rest, '--debug-artifact') ?? undefined,
|
|
283
|
-
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined
|
|
369
|
+
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined,
|
|
370
|
+
teamModeActivation: readTeamModeActivation(rest)
|
|
284
371
|
});
|
|
372
|
+
const json = wantsJson(rest);
|
|
285
373
|
return {
|
|
286
374
|
exitCode: result.status === 'completed' ? 0 : 1,
|
|
287
|
-
output: renderSingleTaskLoopResult(result)
|
|
375
|
+
output: json ? jsonOutput(result, rest) : renderSingleTaskLoopResult(result)
|
|
288
376
|
};
|
|
289
377
|
}
|
|
290
378
|
if (command === 'verify' && subcommand === 'task') {
|
|
291
|
-
const taskId = rest
|
|
379
|
+
const taskId = readOptionalPositionalArgument(rest);
|
|
292
380
|
const runId = readOption(rest, '--run');
|
|
293
|
-
if (!taskId
|
|
381
|
+
if (!taskId) {
|
|
294
382
|
return {
|
|
295
383
|
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]'
|
|
384
|
+
error: 'Usage: sdd verify task <task_id> [--run <run_id>] [--branch <branch>] [--review-artifact artifacts/path.md] [--validation-artifact artifacts/path.md] [--json]'
|
|
297
385
|
};
|
|
298
386
|
}
|
|
299
387
|
const result = await runGoalVerify(projectRoot, {
|
|
300
388
|
taskId,
|
|
301
|
-
runId,
|
|
302
|
-
branch:
|
|
389
|
+
runId: runId ?? undefined,
|
|
390
|
+
branch: readBranchOption(rest),
|
|
303
391
|
reviewArtifact: readOption(rest, '--review-artifact') ?? undefined,
|
|
304
392
|
validationArtifact: readOption(rest, '--validation-artifact') ?? undefined
|
|
305
393
|
});
|
|
394
|
+
const json = wantsJson(rest);
|
|
306
395
|
return {
|
|
307
396
|
exitCode: result.status === 'PASS' ? 0 : 1,
|
|
308
|
-
output: renderGoalVerifyResult(result)
|
|
397
|
+
output: json ? jsonOutput(result, rest) : renderGoalVerifyResult(result)
|
|
309
398
|
};
|
|
310
399
|
}
|
|
311
400
|
if (command === 'governance' && subcommand === 'inspect') {
|
|
@@ -334,6 +423,217 @@ async function main(args) {
|
|
|
334
423
|
output: rest.includes('--json') ? JSON.stringify(decision, null, 2) : renderGovernancePolicyDecision(decision)
|
|
335
424
|
};
|
|
336
425
|
}
|
|
426
|
+
if (command === 'workflow' && subcommand === 'list') {
|
|
427
|
+
const registry = await listWorkflowGates(projectRoot);
|
|
428
|
+
return {
|
|
429
|
+
exitCode: 0,
|
|
430
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderWorkflowGateList(registry.workflows)
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
if (command === 'workflow' && subcommand === 'inspect') {
|
|
434
|
+
const workflowId = rest.find((item) => !item.startsWith('--'));
|
|
435
|
+
if (!workflowId) {
|
|
436
|
+
return {
|
|
437
|
+
exitCode: 2,
|
|
438
|
+
error: 'Usage: sdd workflow inspect <workflow_id> [--json]'
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
const workflow = await inspectWorkflowGate(projectRoot, workflowId);
|
|
442
|
+
if (!workflow) {
|
|
443
|
+
return {
|
|
444
|
+
exitCode: 1,
|
|
445
|
+
error: `Unknown workflow: ${workflowId}`
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
exitCode: 0,
|
|
450
|
+
output: rest.includes('--json') ? JSON.stringify(workflow, null, 2) : renderWorkflowGateInspect(workflow)
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
if (command === 'workflow' && subcommand === 'validate') {
|
|
454
|
+
const result = await validateWorkflowGates(projectRoot);
|
|
455
|
+
return {
|
|
456
|
+
exitCode: result.valid ? 0 : 1,
|
|
457
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderWorkflowGateValidation(result)
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
if (command === 'agents' && subcommand === 'list') {
|
|
461
|
+
const registry = await listAgentRegistry(projectRoot);
|
|
462
|
+
return {
|
|
463
|
+
exitCode: 0,
|
|
464
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderAgentRegistryList(registry.agents)
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
if (command === 'agents' && subcommand === 'inspect') {
|
|
468
|
+
const agentId = rest.find((item) => !item.startsWith('--'));
|
|
469
|
+
if (!agentId) {
|
|
470
|
+
return {
|
|
471
|
+
exitCode: 2,
|
|
472
|
+
error: 'Usage: sdd agents inspect <agent_id> [--json]'
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
const agent = await inspectAgentRegistryEntry(projectRoot, agentId);
|
|
476
|
+
if (!agent) {
|
|
477
|
+
return {
|
|
478
|
+
exitCode: 1,
|
|
479
|
+
error: `Unknown agent: ${agentId}`
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
exitCode: 0,
|
|
484
|
+
output: rest.includes('--json') ? JSON.stringify(agent, null, 2) : renderAgentRegistryInspect(agent)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
if (command === 'agents' && subcommand === 'validate') {
|
|
488
|
+
const result = await validateAgentRegistry(projectRoot);
|
|
489
|
+
return {
|
|
490
|
+
exitCode: result.valid ? 0 : 1,
|
|
491
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderAgentRegistryValidation(result)
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
if (command === 'agent-runtime' && subcommand === 'inspect') {
|
|
495
|
+
const inspection = await inspectAgentSkillTeamRuntime(projectRoot);
|
|
496
|
+
return {
|
|
497
|
+
exitCode: 0,
|
|
498
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderAgentSkillTeamRuntimeInspection(inspection)
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (command === 'agent-runtime' && subcommand === 'validate') {
|
|
502
|
+
const result = await validateAgentSkillTeamRuntime(projectRoot);
|
|
503
|
+
return {
|
|
504
|
+
exitCode: result.valid ? 0 : 1,
|
|
505
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderAgentSkillTeamRuntimeValidation(result)
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (command === 'skill-capabilities' && subcommand === 'list') {
|
|
509
|
+
const registry = await listSkillCapabilities(projectRoot);
|
|
510
|
+
return {
|
|
511
|
+
exitCode: 0,
|
|
512
|
+
output: rest.includes('--json') ? JSON.stringify(registry, null, 2) : renderSkillCapabilityList(registry.capabilities, registry.registrySources)
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (command === 'skill-capabilities' && subcommand === 'inspect') {
|
|
516
|
+
const capabilityId = rest.find((item) => !item.startsWith('--'));
|
|
517
|
+
if (!capabilityId) {
|
|
518
|
+
return {
|
|
519
|
+
exitCode: 2,
|
|
520
|
+
error: 'Usage: sdd skill-capabilities inspect <capability_id> [--json]'
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
const capability = await inspectSkillCapability(projectRoot, capabilityId);
|
|
524
|
+
if (!capability) {
|
|
525
|
+
return { exitCode: 1, error: `Unknown skill capability: ${capabilityId}` };
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
exitCode: 0,
|
|
529
|
+
output: rest.includes('--json') ? JSON.stringify(capability, null, 2) : renderSkillCapabilityInspect(capability)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
if (command === 'capability-sources' && subcommand === 'list') {
|
|
533
|
+
const catalog = await listCapabilitySources(projectRoot);
|
|
534
|
+
return {
|
|
535
|
+
exitCode: 0,
|
|
536
|
+
output: rest.includes('--json') ? JSON.stringify(catalog, null, 2) : renderCapabilitySourceList(catalog.sources, catalog.registrySources)
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
if (command === 'capability-sources' && subcommand === 'inspect') {
|
|
540
|
+
const sourceId = rest.find((item) => !item.startsWith('--'));
|
|
541
|
+
if (!sourceId) {
|
|
542
|
+
return {
|
|
543
|
+
exitCode: 2,
|
|
544
|
+
error: 'Usage: sdd capability-sources inspect <source_id> [--json]'
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const source = await inspectCapabilitySource(projectRoot, sourceId);
|
|
548
|
+
if (!source) {
|
|
549
|
+
return { exitCode: 1, error: `Unknown capability source: ${sourceId}` };
|
|
550
|
+
}
|
|
551
|
+
return {
|
|
552
|
+
exitCode: 0,
|
|
553
|
+
output: rest.includes('--json') ? JSON.stringify(source, null, 2) : renderCapabilitySourceInspect(source)
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (command === 'external-packs' && subcommand === 'inspect') {
|
|
557
|
+
const sourceId = rest.find((item) => !item.startsWith('--'));
|
|
558
|
+
if (!sourceId) {
|
|
559
|
+
return {
|
|
560
|
+
exitCode: 2,
|
|
561
|
+
error: 'Usage: sdd external-packs inspect <source_id> [--json]'
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
const inspection = await inspectExternalAgentPackImport(projectRoot, sourceId);
|
|
565
|
+
return {
|
|
566
|
+
exitCode: inspection.status === 'denied' ? 1 : 0,
|
|
567
|
+
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderExternalAgentPackImportInspection(inspection)
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
if (command === 'team-mode' && subcommand === 'inspect') {
|
|
571
|
+
const policy = await inspectTeamModePolicy(projectRoot, {
|
|
572
|
+
taskId: readOption(rest, '--task') ?? undefined,
|
|
573
|
+
branch: readBranchOption(rest),
|
|
574
|
+
teamModeActivation: readTeamModeActivation(rest, rest.includes('--enabled') ? 'force' : undefined)
|
|
575
|
+
});
|
|
576
|
+
return {
|
|
577
|
+
exitCode: policy.decision === 'blocked' ? 1 : 0,
|
|
578
|
+
output: rest.includes('--json') ? JSON.stringify(policy, null, 2) : renderTeamModePolicy(policy)
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
if (command === 'query-status' && subcommand === 'inspect') {
|
|
582
|
+
const contract = await inspectQueryStatusContract(projectRoot);
|
|
583
|
+
return {
|
|
584
|
+
exitCode: 0,
|
|
585
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderQueryStatusContract(contract)
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
if (command === 'query-status' && subcommand === 'validate') {
|
|
589
|
+
const result = await validateQueryStatusContract(projectRoot);
|
|
590
|
+
return {
|
|
591
|
+
exitCode: result.valid ? 0 : 1,
|
|
592
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderQueryStatusValidation(result)
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
if (command === 'eval' && subcommand === 'inspect') {
|
|
596
|
+
const contract = await inspectSkillAgentEvalContract(projectRoot);
|
|
597
|
+
return {
|
|
598
|
+
exitCode: 0,
|
|
599
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderSkillAgentEvalContract(contract)
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (command === 'eval' && subcommand === 'validate') {
|
|
603
|
+
const result = await validateSkillAgentEvalContract(projectRoot);
|
|
604
|
+
return {
|
|
605
|
+
exitCode: result.valid ? 0 : 1,
|
|
606
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderSkillAgentEvalValidation(result)
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
if (command === 'learning' && subcommand === 'inspect') {
|
|
610
|
+
const contract = await inspectHarnessLearningContract(projectRoot);
|
|
611
|
+
return {
|
|
612
|
+
exitCode: 0,
|
|
613
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderHarnessLearningContract(contract)
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
if (command === 'learning' && subcommand === 'validate') {
|
|
617
|
+
const result = await validateHarnessLearningContract(projectRoot);
|
|
618
|
+
return {
|
|
619
|
+
exitCode: result.valid ? 0 : 1,
|
|
620
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderHarnessLearningValidation(result)
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
if (command === 'context-pack' && subcommand === 'inspect') {
|
|
624
|
+
const contract = await inspectProjectContextPackContract(projectRoot);
|
|
625
|
+
return {
|
|
626
|
+
exitCode: 0,
|
|
627
|
+
output: rest.includes('--json') ? JSON.stringify(contract, null, 2) : renderProjectContextPackContract(contract)
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
if (command === 'context-pack' && subcommand === 'validate') {
|
|
631
|
+
const result = await validateProjectContextPackContract(projectRoot);
|
|
632
|
+
return {
|
|
633
|
+
exitCode: result.valid ? 0 : 1,
|
|
634
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderProjectContextPackValidation(result)
|
|
635
|
+
};
|
|
636
|
+
}
|
|
337
637
|
if (command === 'capabilities' && subcommand === 'list') {
|
|
338
638
|
const registry = await listToolCapabilities(projectRoot);
|
|
339
639
|
return {
|
|
@@ -432,7 +732,7 @@ async function main(args) {
|
|
|
432
732
|
}
|
|
433
733
|
const decision = await inspectWorktreeIsolation(projectRoot, {
|
|
434
734
|
taskId,
|
|
435
|
-
branch:
|
|
735
|
+
branch: readBranchOption(rest),
|
|
436
736
|
capabilityId: readOption(rest, '--capability') ?? undefined,
|
|
437
737
|
peerTaskIds: readRepeatedOptions(rest, '--peer-task')
|
|
438
738
|
});
|
|
@@ -442,7 +742,7 @@ async function main(args) {
|
|
|
442
742
|
};
|
|
443
743
|
}
|
|
444
744
|
if (command === 'graph' && subcommand === 'inspect') {
|
|
445
|
-
const graph = await inspectTaskGraph(projectRoot, { branch:
|
|
745
|
+
const graph = await inspectTaskGraph(projectRoot, { branch: readBranchOption(rest) });
|
|
446
746
|
return {
|
|
447
747
|
exitCode: graph.valid ? 0 : 1,
|
|
448
748
|
output: rest.includes('--json') ? JSON.stringify(graph, null, 2) : renderTaskGraphPlan(graph)
|
|
@@ -450,7 +750,7 @@ async function main(args) {
|
|
|
450
750
|
}
|
|
451
751
|
if (command === 'wave' && subcommand === 'inspect') {
|
|
452
752
|
const wavePlan = await inspectWavePlan(projectRoot, {
|
|
453
|
-
branch:
|
|
753
|
+
branch: readBranchOption(rest),
|
|
454
754
|
capabilityId: readOption(rest, '--capability') ?? undefined
|
|
455
755
|
});
|
|
456
756
|
return {
|
|
@@ -467,7 +767,7 @@ async function main(args) {
|
|
|
467
767
|
};
|
|
468
768
|
}
|
|
469
769
|
const result = await runWaveExecutor(projectRoot, {
|
|
470
|
-
branch:
|
|
770
|
+
branch: readBranchOption(rest),
|
|
471
771
|
runId: readOption(rest, '--run') ?? undefined,
|
|
472
772
|
capabilityId: readOption(rest, '--capability') ?? undefined,
|
|
473
773
|
agent: readOption(rest, '--agent') ?? undefined,
|
|
@@ -503,7 +803,7 @@ async function main(args) {
|
|
|
503
803
|
};
|
|
504
804
|
}
|
|
505
805
|
const result = await runBackgroundExecutor(projectRoot, {
|
|
506
|
-
branch:
|
|
806
|
+
branch: readBranchOption(rest),
|
|
507
807
|
runId: readOption(rest, '--run') ?? undefined,
|
|
508
808
|
taskId,
|
|
509
809
|
agent: readOption(rest, '--agent') ?? undefined,
|
|
@@ -530,6 +830,78 @@ async function main(args) {
|
|
|
530
830
|
output: rest.includes('--json') ? JSON.stringify(inspection, null, 2) : renderBackgroundExecutorInspection(inspection)
|
|
531
831
|
};
|
|
532
832
|
}
|
|
833
|
+
if (command === 'worker-runtime' && subcommand === 'claim') {
|
|
834
|
+
const taskId = rest[0];
|
|
835
|
+
if (!taskId) {
|
|
836
|
+
return {
|
|
837
|
+
exitCode: 2,
|
|
838
|
+
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]'
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
const result = await claimResidentWorkerRuntime(projectRoot, {
|
|
842
|
+
branch: readBranchOption(rest),
|
|
843
|
+
runId: readOption(rest, '--run') ?? undefined,
|
|
844
|
+
taskId,
|
|
845
|
+
runtimeId: readOption(rest, '--runtime') ?? undefined,
|
|
846
|
+
agent: readOption(rest, '--agent') ?? undefined,
|
|
847
|
+
workerAdapterId: readOption(rest, '--worker') ?? undefined,
|
|
848
|
+
delegationId: readOption(rest, '--delegation') ?? undefined,
|
|
849
|
+
leaseSeconds: readPositiveIntegerOption(rest, '--lease-seconds') ?? undefined
|
|
850
|
+
});
|
|
851
|
+
return {
|
|
852
|
+
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
853
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeClaimResult(result)
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
if (command === 'worker-runtime' && subcommand === 'heartbeat') {
|
|
857
|
+
const runtimeId = rest[0];
|
|
858
|
+
const runId = readOption(rest, '--run');
|
|
859
|
+
if (!runtimeId || !runId) {
|
|
860
|
+
return {
|
|
861
|
+
exitCode: 2,
|
|
862
|
+
error: 'Usage: sdd worker-runtime heartbeat <runtime_id> --run <run_id> [--lease-seconds <n>] [--json]'
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
const result = await heartbeatResidentWorkerRuntime(projectRoot, {
|
|
866
|
+
runId,
|
|
867
|
+
runtimeId,
|
|
868
|
+
leaseSeconds: readPositiveIntegerOption(rest, '--lease-seconds') ?? undefined
|
|
869
|
+
});
|
|
870
|
+
return {
|
|
871
|
+
exitCode: result.status === 'blocked' ? 1 : 0,
|
|
872
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeHeartbeatResult(result)
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
if (command === 'worker-runtime' && subcommand === 'status') {
|
|
876
|
+
const positionalRunId = rest[0] && !rest[0].startsWith('--') ? rest[0] : null;
|
|
877
|
+
const runId = readOption(rest, '--run') ?? positionalRunId;
|
|
878
|
+
if (!runId) {
|
|
879
|
+
return {
|
|
880
|
+
exitCode: 2,
|
|
881
|
+
error: 'Usage: sdd worker-runtime status --run <run_id> [--json]'
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
const result = await listResidentWorkerRuntimes(projectRoot, { runId });
|
|
885
|
+
return {
|
|
886
|
+
exitCode: result.valid ? 0 : 1,
|
|
887
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeList(result)
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
if (command === 'worker-runtime' && subcommand === 'inspect') {
|
|
891
|
+
const runtimeId = rest[0];
|
|
892
|
+
const runId = readOption(rest, '--run');
|
|
893
|
+
if (!runtimeId || !runId) {
|
|
894
|
+
return {
|
|
895
|
+
exitCode: 2,
|
|
896
|
+
error: 'Usage: sdd worker-runtime inspect <runtime_id> --run <run_id> [--json]'
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
const result = await inspectResidentWorkerRuntime(projectRoot, { runId, runtimeId });
|
|
900
|
+
return {
|
|
901
|
+
exitCode: result.valid ? 0 : 1,
|
|
902
|
+
output: rest.includes('--json') ? JSON.stringify(result, null, 2) : renderResidentWorkerRuntimeInspection(result)
|
|
903
|
+
};
|
|
904
|
+
}
|
|
533
905
|
if (command === 'worktree' && subcommand === 'create') {
|
|
534
906
|
const runId = rest[0];
|
|
535
907
|
const taskId = rest[1];
|
|
@@ -627,18 +999,34 @@ async function main(args) {
|
|
|
627
999
|
if (!artifactPath || !taskId || !agent) {
|
|
628
1000
|
return {
|
|
629
1001
|
exitCode: 2,
|
|
630
|
-
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> [--branch <branch>] [--status <status>]'
|
|
1002
|
+
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> [--run <run_id> --write] [--branch <branch>] [--status <status>]'
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
const runId = readOption(rest, '--run');
|
|
1006
|
+
const template = await renderSddResultArtifactTemplate(projectRoot, {
|
|
1007
|
+
artifactPath,
|
|
1008
|
+
taskId,
|
|
1009
|
+
agent,
|
|
1010
|
+
branch: readBranchOption(rest),
|
|
1011
|
+
runId: runId ?? undefined,
|
|
1012
|
+
status: readSddResultStatus(rest, '--status') ?? 'PASS'
|
|
1013
|
+
});
|
|
1014
|
+
if (rest.includes('--write')) {
|
|
1015
|
+
if (!runId) {
|
|
1016
|
+
return {
|
|
1017
|
+
exitCode: 2,
|
|
1018
|
+
error: 'Usage: sdd artifact template <artifacts/path.md> --task <task_id> --agent <agent> --run <run_id> --write'
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
const written = await writeArtifact(projectRoot, runId, toArtifactRootRelativePath(artifactPath), template);
|
|
1022
|
+
return {
|
|
1023
|
+
exitCode: 0,
|
|
1024
|
+
output: `Artifact template written: ${written.runRelativePath}\nphysical_path=${written.absolutePath}`
|
|
631
1025
|
};
|
|
632
1026
|
}
|
|
633
1027
|
return {
|
|
634
1028
|
exitCode: 0,
|
|
635
|
-
output:
|
|
636
|
-
artifactPath,
|
|
637
|
-
taskId,
|
|
638
|
-
agent,
|
|
639
|
-
branch: readOption(rest, '--branch') ?? 'master',
|
|
640
|
-
status: readSddResultStatus(rest, '--status') ?? 'PASS'
|
|
641
|
-
})
|
|
1029
|
+
output: template
|
|
642
1030
|
};
|
|
643
1031
|
}
|
|
644
1032
|
if (command === 'artifact' && subcommand === 'validate') {
|
|
@@ -647,7 +1035,7 @@ async function main(args) {
|
|
|
647
1035
|
if (!runId || !artifactPath) {
|
|
648
1036
|
return {
|
|
649
1037
|
exitCode: 2,
|
|
650
|
-
error: 'Usage: sdd artifact validate <run_id> <artifacts/path.md> [--task <task_id>] [--agent <agent>] [--json]'
|
|
1038
|
+
error: 'Usage: sdd artifact validate <run_id> <artifacts/path.md> [--task <task_id>] [--agent <agent>] [--json|--compact-json]'
|
|
651
1039
|
};
|
|
652
1040
|
}
|
|
653
1041
|
const expectedTask = readOption(rest, '--task') ?? undefined;
|
|
@@ -658,7 +1046,7 @@ async function main(args) {
|
|
|
658
1046
|
});
|
|
659
1047
|
return {
|
|
660
1048
|
exitCode: report.valid ? 0 : 1,
|
|
661
|
-
output: rest
|
|
1049
|
+
output: renderTextOrJson(rest, report, (value) => renderArtifactValidationReport(artifactPath, value, expectedTask, expectedAgent))
|
|
662
1050
|
};
|
|
663
1051
|
}
|
|
664
1052
|
if (command === 'artifact' && subcommand === 'ingest') {
|
|
@@ -696,175 +1084,290 @@ async function main(args) {
|
|
|
696
1084
|
error: `Unknown command: ${args.join(' ')}\n\n${helpText()}`
|
|
697
1085
|
};
|
|
698
1086
|
}
|
|
699
|
-
function helpText() {
|
|
1087
|
+
function helpText(topic) {
|
|
1088
|
+
if (topic === 'advanced') {
|
|
1089
|
+
return advancedHelpText();
|
|
1090
|
+
}
|
|
1091
|
+
if (topic === 'workflow') {
|
|
1092
|
+
return workflowHelpText();
|
|
1093
|
+
}
|
|
700
1094
|
return `sdd Phase 2 platform CLI
|
|
701
1095
|
|
|
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
|
|
750
|
-
|
|
751
|
-
AI options:
|
|
752
|
-
--ai auto Project Claude Code entries when supported
|
|
753
|
-
--ai claude-code Project Claude Code entries explicitly
|
|
754
|
-
--ai none Skip AI entry projection during init
|
|
755
|
-
|
|
756
|
-
Init options:
|
|
757
|
-
--branch <branch> Create starter docs under specs/<branch>; default master
|
|
758
|
-
--no-scaffold-docs Skip starter spec.md/plan.md/tasks.md creation
|
|
759
|
-
|
|
760
|
-
Doctor options:
|
|
761
|
-
--latest-only Inspect only the newest non-archived run evidence
|
|
762
|
-
--all-runs Inspect every run, including archived runs
|
|
763
|
-
|
|
764
|
-
Run index options:
|
|
765
|
-
--run <run_id> Filter local run index query by run id
|
|
766
|
-
--task <task_id> Filter local run index query by task id
|
|
767
|
-
--status <status> Filter query by run status
|
|
768
|
-
--artifact <path> Filter query by indexed artifact path
|
|
769
|
-
--json Print machine-readable local run index output
|
|
770
|
-
|
|
771
|
-
Artifact options:
|
|
772
|
-
--task <task_id> Expected artifact task id
|
|
773
|
-
--agent <agent> Expected producing agent name
|
|
774
|
-
--branch <branch> Branch used to copy validator Acceptance mapping
|
|
775
|
-
--status <status> Template status; default PASS
|
|
776
|
-
--json Print machine-readable validation result
|
|
1096
|
+
Common workflow:
|
|
1097
|
+
sdd init [--force] [--ai <mode>] [--scaffold-docs] [--json]
|
|
1098
|
+
sdd status [--branch <branch>] [--json|--compact-json]
|
|
1099
|
+
sdd tasks inspect <task_id> [--branch <branch>] [--json|--compact-json]
|
|
1100
|
+
sdd tasks route <task_id> [--branch <branch>] [--json|--compact-json]
|
|
1101
|
+
sdd do task <task_id> [options]
|
|
1102
|
+
sdd verify task <task_id> [--branch <branch>] [--run <run_id>] [--json|--compact-json]
|
|
1103
|
+
sdd sync-back inspect [<run_id>] [--task <task_id>] [--branch <branch>] [--json|--compact-json]
|
|
1104
|
+
sdd sync-back apply [<run_id>] [--task <task_id>] [--branch <branch>] [--approved] [--json|--compact-json]
|
|
1105
|
+
sdd doctor [--latest-only] [--all-runs] [--json|--compact-json]
|
|
777
1106
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
--json
|
|
1107
|
+
Evidence helpers:
|
|
1108
|
+
sdd run create
|
|
1109
|
+
sdd run list [--json]
|
|
1110
|
+
sdd run inspect <run_id> [--json|--compact-json]
|
|
1111
|
+
sdd run index rebuild|inspect|query [options] [--json|--compact-json]
|
|
1112
|
+
sdd artifact template <path> --task <task_id> --agent <agent> [--run <run_id> --write]
|
|
1113
|
+
sdd artifact validate <run_id> <path> [--task <task_id>] [--agent <agent>] [--json|--compact-json]
|
|
1114
|
+
sdd evidence summary <run_id> [--task <task_id>] [--json|--compact-json]
|
|
1115
|
+
sdd context build --task <task_id> --mode do|verify|sync-back|doctor [--agent <agent>] [--branch <branch>] [--profile brief|normal|forensic] [--json|--compact-json]
|
|
783
1116
|
|
|
784
|
-
|
|
785
|
-
--
|
|
786
|
-
|
|
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
|
|
1117
|
+
Generated AI entries:
|
|
1118
|
+
sdd update [--check] [--ai <mode>]
|
|
1119
|
+
sdd instructions [action] [--json|--compact-json]
|
|
790
1120
|
|
|
791
|
-
|
|
792
|
-
|
|
1121
|
+
More help:
|
|
1122
|
+
sdd help workflow Show core workflow options.
|
|
1123
|
+
sdd help advanced Show platform/agent/runtime commands.
|
|
793
1124
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
--
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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
|
|
1125
|
+
Notes:
|
|
1126
|
+
/sdd:spec owns workflow partition docs after project init.
|
|
1127
|
+
init --branch is legacy starter-doc scaffolding; prefer sdd status --branch or /sdd:spec --branch for workflow partitions.
|
|
1128
|
+
`;
|
|
1129
|
+
}
|
|
1130
|
+
function workflowHelpText() {
|
|
1131
|
+
return `sdd workflow help
|
|
807
1132
|
|
|
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
|
|
1133
|
+
Core path:
|
|
1134
|
+
1. sdd status [--branch <branch>]
|
|
1135
|
+
2. sdd tasks inspect <task_id> [--branch <branch>]
|
|
1136
|
+
3. sdd tasks route <task_id> [--branch <branch>]
|
|
1137
|
+
4. sdd artifact template artifacts/<agent>-<task_id>.md --task <task_id> --agent <agent> --run <run_id> --write
|
|
1138
|
+
5. sdd do task <task_id> --run <run_id> --implement-artifact <path> --review-artifact <path> --validation-artifact <path>
|
|
1139
|
+
6. sdd verify task <task_id> [--branch <branch>]
|
|
1140
|
+
7. sdd sync-back inspect --task <task_id> [--branch <branch>]
|
|
1141
|
+
8. sdd sync-back apply --task <task_id> [--branch <branch>]
|
|
821
1142
|
|
|
822
|
-
|
|
823
|
-
--
|
|
824
|
-
|
|
825
|
-
|
|
1143
|
+
JSON:
|
|
1144
|
+
--json prints readable JSON; --compact-json prints one-line JSON for logs and scripts.
|
|
1145
|
+
`;
|
|
1146
|
+
}
|
|
1147
|
+
function advancedHelpText() {
|
|
1148
|
+
return `sdd advanced help
|
|
826
1149
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1150
|
+
Runtime/catalog:
|
|
1151
|
+
sdd agent-runtime inspect|validate [--json]
|
|
1152
|
+
sdd skill-capabilities list|inspect [--json]
|
|
1153
|
+
sdd capability-sources list|inspect [--json]
|
|
1154
|
+
sdd external-packs inspect <source_id> [--json]
|
|
1155
|
+
sdd team-mode inspect [--task <id>] [--team-mode [auto|force|off]] [--no-team-mode] [--json]
|
|
831
1156
|
|
|
832
|
-
|
|
833
|
-
|
|
1157
|
+
Harness/platform:
|
|
1158
|
+
sdd workflow list|inspect|validate [--json]
|
|
1159
|
+
sdd agents list|inspect|validate [--json]
|
|
1160
|
+
sdd query-status inspect|validate [--json]
|
|
1161
|
+
sdd eval inspect|validate [--json]
|
|
1162
|
+
sdd learning inspect|validate [--json]
|
|
1163
|
+
sdd context-pack inspect|validate [--json]
|
|
1164
|
+
sdd capabilities list|inspect [--json]
|
|
1165
|
+
sdd governance inspect|evaluate [options]
|
|
1166
|
+
sdd plugins list|inspect [--json]
|
|
1167
|
+
sdd queue list|inspect [options]
|
|
1168
|
+
sdd state-machine inspect [--json]
|
|
1169
|
+
sdd workers list|inspect [--json]
|
|
834
1170
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1171
|
+
Execution/isolation:
|
|
1172
|
+
sdd background run|inspect [options]
|
|
1173
|
+
sdd worker-runtime claim|heartbeat|status|inspect [options]
|
|
1174
|
+
sdd isolation inspect <task_id> [options]
|
|
1175
|
+
sdd graph inspect [--branch <branch>] [--json]
|
|
1176
|
+
sdd wave inspect|run|executor [options]
|
|
1177
|
+
sdd worktree create|inspect|keep|remove [options]
|
|
838
1178
|
|
|
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
|
-
`;
|
|
1179
|
+
Legacy init partition option:
|
|
1180
|
+
sdd init --branch <branch> creates starter docs for that branch, but normal workflow partitioning belongs to /sdd:spec and sdd status --branch.
|
|
1181
|
+
`;
|
|
851
1182
|
}
|
|
852
|
-
function
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1183
|
+
function wantsJson(args) {
|
|
1184
|
+
return args.includes('--json') || args.includes('--compact-json');
|
|
1185
|
+
}
|
|
1186
|
+
function jsonOutput(value, args) {
|
|
1187
|
+
return JSON.stringify(value, null, args.includes('--compact-json') ? 0 : 2);
|
|
1188
|
+
}
|
|
1189
|
+
function getCliIdentity() {
|
|
1190
|
+
const cliEntryPath = fileURLToPath(import.meta.url);
|
|
1191
|
+
const packageRoot = findPackageRoot(path.dirname(cliEntryPath));
|
|
1192
|
+
const packageJsonPath = packageRoot ? path.join(packageRoot, 'package.json') : null;
|
|
1193
|
+
return {
|
|
1194
|
+
version: readPackageVersion(packageJsonPath) ?? SDD_VERSION,
|
|
1195
|
+
cliEntryPath,
|
|
1196
|
+
packageRoot,
|
|
1197
|
+
packageJsonPath
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
function findPackageRoot(startDir) {
|
|
1201
|
+
let current = startDir;
|
|
1202
|
+
while (true) {
|
|
1203
|
+
const packageJsonPath = path.join(current, 'package.json');
|
|
1204
|
+
if (existsSync(packageJsonPath) && isCliPackageRoot(packageJsonPath)) {
|
|
1205
|
+
return current;
|
|
1206
|
+
}
|
|
1207
|
+
const parent = path.dirname(current);
|
|
1208
|
+
if (parent === current) {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
current = parent;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
function isCliPackageRoot(packageJsonPath) {
|
|
1215
|
+
try {
|
|
1216
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
1217
|
+
return parsed.name === '@sdd-agent-platform/cli' || parsed.name === 'sdd-agent-platform';
|
|
1218
|
+
}
|
|
1219
|
+
catch {
|
|
1220
|
+
return false;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
function readPackageVersion(packageJsonPath) {
|
|
1224
|
+
if (!packageJsonPath) {
|
|
1225
|
+
return null;
|
|
1226
|
+
}
|
|
1227
|
+
try {
|
|
1228
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
1229
|
+
return typeof parsed.version === 'string' ? parsed.version : null;
|
|
1230
|
+
}
|
|
1231
|
+
catch {
|
|
1232
|
+
return null;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
function readContextBuildMode(args, name) {
|
|
1236
|
+
const value = readOption(args, name);
|
|
1237
|
+
return value === 'do' || value === 'verify' || value === 'sync-back' || value === 'doctor' ? value : null;
|
|
1238
|
+
}
|
|
1239
|
+
function renderEvidenceSummaryProjection(summary) {
|
|
1240
|
+
const lines = [`Evidence summary ${summary.runId}`];
|
|
1241
|
+
lines.push(`task=${summary.taskId ?? 'none'} authoritative=${summary.authoritative} usable_for_pass=${summary.usableForPass}`);
|
|
1242
|
+
lines.push(`pass=${summary.passCount} blocked=${summary.blockedCount} fail=${summary.failCount} issues=${summary.issueCodes.join(',') || 'none'}`);
|
|
1243
|
+
lines.push('highlights');
|
|
1244
|
+
for (const highlight of summary.highlights.slice(0, 8)) {
|
|
1245
|
+
lines.push(`- ${highlight}`);
|
|
1246
|
+
}
|
|
1247
|
+
lines.push('sources');
|
|
1248
|
+
for (const source of summary.sources.slice(0, 12)) {
|
|
1249
|
+
lines.push(`- ${source.kind}:${source.path} hash=${source.hash.slice(0, 12)}`);
|
|
1250
|
+
}
|
|
1251
|
+
if (summary.sources.length > 12) {
|
|
1252
|
+
lines.push(`- omitted_sources=${summary.sources.length - 12}`);
|
|
1253
|
+
}
|
|
1254
|
+
return lines.join('\n');
|
|
1255
|
+
}
|
|
1256
|
+
function renderContextBuildPackage(contextPackage) {
|
|
1257
|
+
const lines = [`Context package ${contextPackage.taskId}`];
|
|
1258
|
+
lines.push(`mode=${contextPackage.mode} agent=${contextPackage.agent ?? 'none'} profile=${contextPackage.profile} branch=${contextPackage.branch}`);
|
|
1259
|
+
lines.push(`authoritative=${contextPackage.authoritative} usable_for_pass=${contextPackage.usableForPass}`);
|
|
1260
|
+
renderContextRefs(lines, 'must_read', contextPackage.mustRead, 10);
|
|
1261
|
+
renderContextRefs(lines, 'optional_read', contextPackage.optionalRead, 8);
|
|
1262
|
+
renderContextRefs(lines, 'deferred', contextPackage.doNotReadUnlessNeeded, 6);
|
|
1263
|
+
lines.push('next_commands');
|
|
1264
|
+
for (const command of contextPackage.nextCommands) {
|
|
1265
|
+
lines.push(`- ${command}`);
|
|
1266
|
+
}
|
|
1267
|
+
if (contextPackage.warnings.length > 0) {
|
|
1268
|
+
lines.push('warnings');
|
|
1269
|
+
for (const warning of contextPackage.warnings.slice(0, 6)) {
|
|
1270
|
+
lines.push(`- ${warning}`);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
return lines.join('\n');
|
|
1274
|
+
}
|
|
1275
|
+
function renderContextRefs(lines, label, refs, limit) {
|
|
1276
|
+
lines.push(label);
|
|
1277
|
+
for (const ref of refs.slice(0, limit)) {
|
|
1278
|
+
lines.push(`- ${ref.kind}:${ref.path} hash=${ref.hash.slice(0, 12)}`);
|
|
1279
|
+
}
|
|
1280
|
+
if (refs.length > limit) {
|
|
1281
|
+
lines.push(`- omitted_${label}=${refs.length - limit}`);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function renderTextOrJson(args, value, renderText) {
|
|
1285
|
+
return wantsJson(args) ? jsonOutput(value, args) : renderText(value);
|
|
1286
|
+
}
|
|
1287
|
+
function renderInitResult(result) {
|
|
1288
|
+
const aiEntries = result.aiTools.flatMap((tool) => tool.entries);
|
|
1289
|
+
const aiCounts = new Map();
|
|
1290
|
+
for (const entry of aiEntries) {
|
|
1291
|
+
aiCounts.set(entry.status, (aiCounts.get(entry.status) ?? 0) + 1);
|
|
1292
|
+
}
|
|
1293
|
+
const aiSummary = Array.from(aiCounts.entries()).map(([status, count]) => `${status}=${count}`).join(' ') || 'none';
|
|
1294
|
+
const scaffoldedDocuments = result.documents.documents.filter((document) => document.status !== 'skipped');
|
|
1295
|
+
const lines = ['SDD init', 'changed'];
|
|
1296
|
+
lines.push(`- config ${result.created ? 'created/updated' : 'unchanged'} at ${result.configPath}`);
|
|
1297
|
+
lines.push(`- semantic docs ${scaffoldedDocuments.map((document) => `${document.status}:${document.relativePath}`).join(', ') || 'none'}`);
|
|
1298
|
+
lines.push(`- ai entries ${aiSummary}`);
|
|
1299
|
+
lines.push('decision');
|
|
1300
|
+
if (scaffoldedDocuments.length > 0) {
|
|
1301
|
+
lines.push(`- legacy_scaffold_branch=${result.documents.branch}`);
|
|
1302
|
+
lines.push(`- legacy_spec_dir=${result.documents.root}`);
|
|
1303
|
+
}
|
|
1304
|
+
lines.push('- sdd init is project-level setup; /sdd:spec is the workflow partition/spec entry');
|
|
1305
|
+
lines.push('evidence');
|
|
1306
|
+
for (const document of scaffoldedDocuments) {
|
|
1307
|
+
lines.push(`- [${document.status}] ${document.relativePath}: ${document.message}`);
|
|
1308
|
+
}
|
|
1309
|
+
if (aiEntries.length === 0) {
|
|
1310
|
+
lines.push('- ai entries skipped');
|
|
858
1311
|
}
|
|
859
1312
|
else {
|
|
860
|
-
lines.push(
|
|
1313
|
+
lines.push(`- ${aiEntries.length} managed AI entry projection(s) checked/applied`);
|
|
861
1314
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1315
|
+
lines.push('- doctor checks git repository health; run git init first in fresh temporary projects before relying on doctor/run-index checks');
|
|
1316
|
+
lines.push('gaps');
|
|
1317
|
+
const driftEntries = aiEntries.filter((entry) => entry.status === 'drifted' || entry.status === 'user-modified' || entry.status === 'foreign' || entry.status === 'conflict');
|
|
1318
|
+
if (driftEntries.length === 0) {
|
|
1319
|
+
lines.push('- none');
|
|
1320
|
+
}
|
|
1321
|
+
else {
|
|
1322
|
+
for (const entry of driftEntries) {
|
|
1323
|
+
lines.push(`- [${entry.status}] ${entry.relativePath}: ${entry.action ?? entry.message}`);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
lines.push('next');
|
|
1327
|
+
lines.push('- /sdd:spec');
|
|
1328
|
+
return lines.join('\n');
|
|
1329
|
+
}
|
|
1330
|
+
function renderProjectStatus(status) {
|
|
1331
|
+
const lines = [`SDD status for ${status.branch}`];
|
|
1332
|
+
const staleDocuments = [
|
|
1333
|
+
status.documents.planStale ? 'plan' : null,
|
|
1334
|
+
status.documents.tasksStale ? 'tasks' : null
|
|
1335
|
+
].filter((item) => item !== null);
|
|
1336
|
+
const hasDocumentHashes = Boolean(status.documents.specHash
|
|
1337
|
+
|| status.documents.planHash
|
|
1338
|
+
|| status.documents.tasksHash
|
|
1339
|
+
|| status.documents.planBasedOnSpecHash
|
|
1340
|
+
|| status.documents.tasksBasedOnPlanHash);
|
|
1341
|
+
lines.push('decision');
|
|
1342
|
+
lines.push(`- workflow_status=${status.workflowStatus}`);
|
|
1343
|
+
lines.push(`- context raw_branch=${status.context.rawBranch} partition=${status.context.partition} source=${status.context.branchSource} spec_dir=${status.context.specDir}`);
|
|
1344
|
+
lines.push(`- git current_branch=${status.context.currentGitBranch ?? 'none'} working_tree_matched=${status.context.workingTreeMatched ?? 'unknown'}`);
|
|
1345
|
+
lines.push(`- documents spec=${status.documents.specExists} plan=${status.documents.planExists} tasks=${status.documents.tasksExists} stale=${staleDocuments.join(',') || 'none'}`);
|
|
1346
|
+
if (hasDocumentHashes) {
|
|
1347
|
+
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'}`);
|
|
1348
|
+
}
|
|
1349
|
+
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}`);
|
|
1350
|
+
if (status.latestRun) {
|
|
1351
|
+
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}`);
|
|
1352
|
+
if (status.latestRunEvidence) {
|
|
1353
|
+
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}`);
|
|
1354
|
+
if (status.latestRunEvidence.tasksChangedAfterRun && status.latestRun.syncBackStatus !== 'applied') {
|
|
1355
|
+
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.');
|
|
1356
|
+
}
|
|
1357
|
+
else if (status.latestRunEvidence.tasksChangedAfterRun) {
|
|
1358
|
+
lines.push('- latest_run_evidence tasks.md changed after sync-back apply; task completion state is already recorded.');
|
|
1359
|
+
}
|
|
866
1360
|
}
|
|
867
1361
|
}
|
|
1362
|
+
else {
|
|
1363
|
+
lines.push('- latest_run none');
|
|
1364
|
+
}
|
|
1365
|
+
lines.push('evidence');
|
|
1366
|
+
lines.push(`- branch documents loaded from ${status.context.specDir}`);
|
|
1367
|
+
lines.push(status.gitRoot
|
|
1368
|
+
? `- git repository detected at ${status.gitRoot}; doctor and run-index checks can use Git repository context`
|
|
1369
|
+
: '- doctor and run-index checks expect Git repository context; run git init first in fresh temporary projects');
|
|
1370
|
+
renderDocumentGaps(lines, status.gaps);
|
|
868
1371
|
lines.push(`next ${status.recommendedNextCommand}`);
|
|
869
1372
|
return lines.join('\n');
|
|
870
1373
|
}
|
|
@@ -892,13 +1395,7 @@ function renderLocalRunIndexInspection(inspection) {
|
|
|
892
1395
|
if (inspection.index) {
|
|
893
1396
|
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
1397
|
}
|
|
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
|
-
}
|
|
1398
|
+
renderIssues(lines, inspection.issues);
|
|
902
1399
|
return lines.join('\n');
|
|
903
1400
|
}
|
|
904
1401
|
function renderGovernancePolicy(policy) {
|
|
@@ -919,13 +1416,7 @@ function renderGovernancePolicyDecision(decision) {
|
|
|
919
1416
|
for (const reason of decision.reasons) {
|
|
920
1417
|
lines.push(`- ${reason}`);
|
|
921
1418
|
}
|
|
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
|
-
}
|
|
1419
|
+
renderIssues(lines, decision.issues);
|
|
929
1420
|
return lines.join('\n');
|
|
930
1421
|
}
|
|
931
1422
|
function renderRunInspection(inspection) {
|
|
@@ -933,6 +1424,7 @@ function renderRunInspection(inspection) {
|
|
|
933
1424
|
lines.push(`status=${inspection.summary.status} phase=${inspection.summary.phase ?? 'n/a'} task=${inspection.summary.currentTask ?? 'n/a'} updated=${inspection.summary.updatedAt}`);
|
|
934
1425
|
lines.push(`validation=${inspection.validation.status} evidence=${inspection.validation.evidence.join(',') || 'none'}`);
|
|
935
1426
|
lines.push(`sync_back=${inspection.syncBack.status} proposal=${inspection.syncBack.proposalPath ?? 'none'}`);
|
|
1427
|
+
lines.push(`task_run_evidence=${inspection.taskRunEvidence.version} gaps=${inspection.taskRunEvidence.gaps.length} sync_back=${inspection.taskRunEvidence.syncBackProposal ?? 'none'}`);
|
|
936
1428
|
lines.push(`artifacts=${inspection.artifacts.length}`);
|
|
937
1429
|
for (const artifact of inspection.artifacts) {
|
|
938
1430
|
lines.push(`- ${artifact.path} kind=${artifact.kind} task=${artifact.task ?? 'n/a'} agent=${artifact.agent ?? 'n/a'}`);
|
|
@@ -941,6 +1433,18 @@ function renderRunInspection(inspection) {
|
|
|
941
1433
|
for (const ingestion of inspection.artifactIngestions) {
|
|
942
1434
|
lines.push(`- ${ingestion.delegationId} ${ingestion.status} artifact=${ingestion.artifactPath} result=${ingestion.resultStatus ?? 'n/a'} delegation=${ingestion.delegationStatus ?? 'n/a'}`);
|
|
943
1435
|
}
|
|
1436
|
+
lines.push(`agent_executions=${inspection.agentExecutions.length}`);
|
|
1437
|
+
for (const execution of inspection.agentExecutions) {
|
|
1438
|
+
lines.push(`- ${execution.executionId} profile=${execution.profile} status=${execution.status} task=${execution.taskId} artifacts=${execution.artifacts.join(',') || 'none'}`);
|
|
1439
|
+
}
|
|
1440
|
+
lines.push(`team_sessions=${inspection.teamSessions.length}`);
|
|
1441
|
+
for (const session of inspection.teamSessions) {
|
|
1442
|
+
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'}`);
|
|
1443
|
+
}
|
|
1444
|
+
lines.push(`worker_runtimes=${inspection.workerRuntimes.length}`);
|
|
1445
|
+
for (const runtime of inspection.workerRuntimes) {
|
|
1446
|
+
lines.push(`- ${runtime.runtimeId} status=${runtime.status} task=${runtime.taskId} agent=${runtime.agent} delegation=${runtime.delegationId} lease_expires=${runtime.leaseExpiresAt}`);
|
|
1447
|
+
}
|
|
944
1448
|
lines.push(`events=${inspection.eventCount}`);
|
|
945
1449
|
for (const event of inspection.recentEvents) {
|
|
946
1450
|
lines.push(`- ${event.time} ${event.event}${event.summary ? `: ${event.summary}` : ''}`);
|
|
@@ -958,12 +1462,7 @@ function renderSyncBackInspection(inspection) {
|
|
|
958
1462
|
lines.push(`- ${reason}`);
|
|
959
1463
|
}
|
|
960
1464
|
}
|
|
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
|
-
}
|
|
1465
|
+
renderDocumentGaps(lines, inspection.gaps);
|
|
967
1466
|
lines.push(`apply_policy=${inspection.applyPolicy.mode} approval_required=${inspection.applyPolicy.requiresApproval}`);
|
|
968
1467
|
for (const reason of inspection.applyPolicy.reasons) {
|
|
969
1468
|
lines.push(`- policy: ${reason}`);
|
|
@@ -981,6 +1480,412 @@ function renderSyncBackApplyResult(result) {
|
|
|
981
1480
|
lines.push(`sync_back=${result.inspection.status}`);
|
|
982
1481
|
return lines.join('\n');
|
|
983
1482
|
}
|
|
1483
|
+
function renderWorkflowGateList(workflows) {
|
|
1484
|
+
const lines = ['SDD workflow gates'];
|
|
1485
|
+
for (const workflow of workflows) {
|
|
1486
|
+
lines.push(`- ${workflow.id} command=${workflow.command} agents=${workflow.allowedAgents.join(',') || 'none'}`);
|
|
1487
|
+
}
|
|
1488
|
+
return lines.join('\n');
|
|
1489
|
+
}
|
|
1490
|
+
function renderWorkflowGateInspect(workflow) {
|
|
1491
|
+
const lines = [`Workflow gate ${workflow.id}`];
|
|
1492
|
+
lines.push(`version=${workflow.version}`);
|
|
1493
|
+
lines.push(`command=${workflow.command}`);
|
|
1494
|
+
lines.push(`agents=${workflow.allowedAgents.join(',') || 'none'}`);
|
|
1495
|
+
lines.push('required_inputs');
|
|
1496
|
+
for (const input of workflow.requiredInputs) {
|
|
1497
|
+
lines.push(`- ${input}`);
|
|
1498
|
+
}
|
|
1499
|
+
lines.push('required_artifacts');
|
|
1500
|
+
for (const artifact of workflow.requiredArtifacts) {
|
|
1501
|
+
lines.push(`- ${artifact}`);
|
|
1502
|
+
}
|
|
1503
|
+
lines.push('gate_conditions');
|
|
1504
|
+
for (const condition of workflow.gateConditions) {
|
|
1505
|
+
lines.push(`- ${condition}`);
|
|
1506
|
+
}
|
|
1507
|
+
lines.push(`gap_closure=${workflow.gapClosureBehavior}`);
|
|
1508
|
+
lines.push(`next=${workflow.nextAction}`);
|
|
1509
|
+
return lines.join('\n');
|
|
1510
|
+
}
|
|
1511
|
+
function renderWorkflowGateValidation(result) {
|
|
1512
|
+
const lines = ['SDD workflow gate validation'];
|
|
1513
|
+
lines.push(`valid=${result.valid}`);
|
|
1514
|
+
lines.push(`workflows=${result.workflows.length}`);
|
|
1515
|
+
lines.push('issues');
|
|
1516
|
+
if (result.issues.length === 0) {
|
|
1517
|
+
lines.push('- none');
|
|
1518
|
+
}
|
|
1519
|
+
else {
|
|
1520
|
+
for (const issue of result.issues) {
|
|
1521
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
return lines.join('\n');
|
|
1525
|
+
}
|
|
1526
|
+
function renderAgentRegistryList(agents) {
|
|
1527
|
+
const lines = ['SDD agent registry'];
|
|
1528
|
+
for (const agent of agents) {
|
|
1529
|
+
lines.push(`- ${agent.id} stages=${agent.allowedStages.join(',')} autonomy=${agent.autonomyCeiling}`);
|
|
1530
|
+
}
|
|
1531
|
+
return lines.join('\n');
|
|
1532
|
+
}
|
|
1533
|
+
function renderAgentRegistryInspect(agent) {
|
|
1534
|
+
const lines = [`Agent ${agent.id}`];
|
|
1535
|
+
lines.push(`version=${agent.version}`);
|
|
1536
|
+
lines.push(`role=${agent.role}`);
|
|
1537
|
+
lines.push(`allowed_stages=${agent.allowedStages.join(',')}`);
|
|
1538
|
+
lines.push(`autonomy_ceiling=${agent.autonomyCeiling}`);
|
|
1539
|
+
lines.push(`required_artifact=${agent.requiredArtifact}`);
|
|
1540
|
+
lines.push(`verification=${agent.verificationExpectation}`);
|
|
1541
|
+
lines.push('capabilities');
|
|
1542
|
+
for (const capability of agent.capabilities) {
|
|
1543
|
+
lines.push(`- ${capability}`);
|
|
1544
|
+
}
|
|
1545
|
+
lines.push('read_boundary');
|
|
1546
|
+
for (const item of agent.readBoundary) {
|
|
1547
|
+
lines.push(`- ${item}`);
|
|
1548
|
+
}
|
|
1549
|
+
lines.push('write_boundary');
|
|
1550
|
+
for (const item of agent.writeBoundary) {
|
|
1551
|
+
lines.push(`- ${item}`);
|
|
1552
|
+
}
|
|
1553
|
+
lines.push('tool_allowlist');
|
|
1554
|
+
for (const tool of agent.toolAllowlist) {
|
|
1555
|
+
lines.push(`- ${tool}`);
|
|
1556
|
+
}
|
|
1557
|
+
lines.push(`stop_condition=${agent.stopCondition}`);
|
|
1558
|
+
return lines.join('\n');
|
|
1559
|
+
}
|
|
1560
|
+
function renderAgentRegistryValidation(result) {
|
|
1561
|
+
const lines = ['SDD agent registry validation'];
|
|
1562
|
+
lines.push(`valid=${result.valid}`);
|
|
1563
|
+
lines.push(`agents=${result.agents.length}`);
|
|
1564
|
+
lines.push('issues');
|
|
1565
|
+
if (result.issues.length === 0) {
|
|
1566
|
+
lines.push('- none');
|
|
1567
|
+
}
|
|
1568
|
+
else {
|
|
1569
|
+
for (const issue of result.issues) {
|
|
1570
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
return lines.join('\n');
|
|
1574
|
+
}
|
|
1575
|
+
function renderRegistryOriginCounts(sources) {
|
|
1576
|
+
if (!sources || sources.length === 0) {
|
|
1577
|
+
return 'none';
|
|
1578
|
+
}
|
|
1579
|
+
const counts = new Map();
|
|
1580
|
+
for (const source of sources) {
|
|
1581
|
+
counts.set(source.origin, (counts.get(source.origin) ?? 0) + 1);
|
|
1582
|
+
}
|
|
1583
|
+
return [...counts.entries()].map(([origin, count]) => `${origin}:${count}`).join(',');
|
|
1584
|
+
}
|
|
1585
|
+
function idsByOrigin(sources, kind, origin) {
|
|
1586
|
+
const ids = sources?.filter((source) => source.kind === kind && source.origin === origin).map((source) => source.id) ?? [];
|
|
1587
|
+
return ids.join(',') || 'none';
|
|
1588
|
+
}
|
|
1589
|
+
function renderAgentRouterDecision(decision) {
|
|
1590
|
+
const lines = [`Agent router decision ${decision.taskId}`];
|
|
1591
|
+
lines.push(`version=${decision.version}`);
|
|
1592
|
+
lines.push(`branch=${decision.branch} category=${decision.category}`);
|
|
1593
|
+
lines.push(`recommended_profile=${decision.recommendedProfile ?? 'none'} autonomy_ceiling=${decision.autonomyCeiling}`);
|
|
1594
|
+
lines.push(`allowed_profiles=${decision.allowedProfiles.join(',') || 'none'}`);
|
|
1595
|
+
lines.push(`required_capabilities=${decision.requiredCapabilities.join(',') || 'none'}`);
|
|
1596
|
+
lines.push(`source_capability=${decision.sourceCapability ?? 'none'} reuse=${decision.reuseDecision ?? 'none'}`);
|
|
1597
|
+
if (decision.registrySources && decision.registrySources.length > 0) {
|
|
1598
|
+
lines.push(`registry_sources=${decision.registrySources.map((source) => `${source.kind}:${source.id}:${source.origin}`).join(',')}`);
|
|
1599
|
+
}
|
|
1600
|
+
if (decision.resolvedAliases && decision.resolvedAliases.length > 0) {
|
|
1601
|
+
lines.push(`alias_resolutions=${decision.resolvedAliases.map((alias) => `${alias.input}->${alias.resolved}:${alias.source}`).join(',')}`);
|
|
1602
|
+
}
|
|
1603
|
+
if (decision.routingRuleHits && decision.routingRuleHits.length > 0) {
|
|
1604
|
+
lines.push(`routing_rule_hits=${decision.routingRuleHits.join(',')}`);
|
|
1605
|
+
}
|
|
1606
|
+
if (decision.quarantineWarnings && decision.quarantineWarnings.length > 0) {
|
|
1607
|
+
lines.push('quarantine_warnings');
|
|
1608
|
+
for (const warning of decision.quarantineWarnings) {
|
|
1609
|
+
lines.push(`- ${warning}`);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
if (decision.adapterMapping) {
|
|
1613
|
+
lines.push(`adapter_mapping profile=${decision.adapterMapping.profile} host=${decision.adapterMapping.hostAdapter} projection=${decision.adapterMapping.projection}`);
|
|
1614
|
+
}
|
|
1615
|
+
if (decision.toolPermission) {
|
|
1616
|
+
lines.push(`tool_permission profile=${decision.toolPermission.profile} policy=${decision.toolPermission.policy} groups=${decision.toolPermission.toolGroups.join(',')}`);
|
|
1617
|
+
lines.push(`approval=${decision.toolPermission.approvalPolicy}`);
|
|
1618
|
+
}
|
|
1619
|
+
lines.push(`model_policy=${decision.modelPolicy.id} category=${decision.modelPolicy.category}`);
|
|
1620
|
+
lines.push(`team_mode=${decision.teamMode.decision} mode=${decision.teamMode.mode} activation=${decision.teamMode.activation} cost=${decision.teamMode.costClass} cost_route=${decision.teamMode.costRoute} waves=${decision.teamMode.waveRecommendation.join(',') || 'none'}`);
|
|
1621
|
+
lines.push(`team_mode_reason=${decision.teamMode.reason}`);
|
|
1622
|
+
if (decision.teamMode.downgradeReason) {
|
|
1623
|
+
lines.push(`team_mode_downgrade=${decision.teamMode.downgradeReason}`);
|
|
1624
|
+
}
|
|
1625
|
+
lines.push(`trust_policy_enforced=${decision.teamMode.trustPolicyEnforced}`);
|
|
1626
|
+
if (decision.cache) {
|
|
1627
|
+
lines.push(`route_cache=${decision.cache.status} key=${decision.cache.key} authoritative=${decision.cache.authoritative}`);
|
|
1628
|
+
}
|
|
1629
|
+
if (decision.profile && decision.profile.length > 0) {
|
|
1630
|
+
lines.push('profile');
|
|
1631
|
+
for (const span of decision.profile) {
|
|
1632
|
+
lines.push(`- ${span.name}: ${span.durationMs}ms`);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
lines.push(`required_artifacts=${decision.requiredArtifacts.join(',') || 'none'}`);
|
|
1636
|
+
if (decision.blockedReason) {
|
|
1637
|
+
lines.push(`blocked_reason=${decision.blockedReason}`);
|
|
1638
|
+
}
|
|
1639
|
+
lines.push(`next=${decision.nextAction}`);
|
|
1640
|
+
return lines.join('\n');
|
|
1641
|
+
}
|
|
1642
|
+
function renderAgentSkillTeamRuntimeInspection(inspection) {
|
|
1643
|
+
const lines = ['SDD agent/skill/team runtime'];
|
|
1644
|
+
lines.push(`version=${inspection.version}`);
|
|
1645
|
+
lines.push(`profiles=${inspection.profiles.length} skill_capabilities=${inspection.skillCapabilities.length} capability_sources=${inspection.capabilitySources.length}`);
|
|
1646
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(inspection.registrySources)}`);
|
|
1647
|
+
lines.push(`project_profiles=${idsByOrigin(inspection.registrySources, 'profile', 'project_config')}`);
|
|
1648
|
+
lines.push(`project_capabilities=${idsByOrigin(inspection.registrySources, 'skill_capability', 'project_config')}`);
|
|
1649
|
+
lines.push(`project_sources=${idsByOrigin(inspection.registrySources, 'capability_source', 'project_config')}`);
|
|
1650
|
+
if (inspection.aliases && Object.keys(inspection.aliases).length > 0) {
|
|
1651
|
+
lines.push(`aliases=${Object.entries(inspection.aliases).map(([alias, target]) => `${alias}->${target}`).join(',')}`);
|
|
1652
|
+
}
|
|
1653
|
+
if (inspection.routingRules && inspection.routingRules.length > 0) {
|
|
1654
|
+
lines.push(`routing_rules=${inspection.routingRules.map((rule) => rule.id).join(',')}`);
|
|
1655
|
+
}
|
|
1656
|
+
if (inspection.adapterMappings && inspection.adapterMappings.length > 0) {
|
|
1657
|
+
lines.push(`adapter_mappings=${inspection.adapterMappings.map((mapping) => `${mapping.profile}:${mapping.hostAdapter}`).join(',')}`);
|
|
1658
|
+
}
|
|
1659
|
+
lines.push(`host_adapter=${inspection.hostAdapter.id} host=${inspection.hostAdapter.host}`);
|
|
1660
|
+
lines.push(`team_mode_default=${inspection.teamMode.decision}`);
|
|
1661
|
+
lines.push(`reuse_policy=${inspection.reusePolicy}`);
|
|
1662
|
+
lines.push('profiles');
|
|
1663
|
+
for (const profile of inspection.profiles) {
|
|
1664
|
+
lines.push(`- ${profile.id} stages=${profile.stageScope.join(',')} risk_ceiling=${profile.riskCeiling}`);
|
|
1665
|
+
}
|
|
1666
|
+
lines.push('capabilities');
|
|
1667
|
+
for (const capability of inspection.skillCapabilities) {
|
|
1668
|
+
lines.push(`- ${capability.id} reuse=${capability.reuseDecision} evidence=${capability.evidenceType}`);
|
|
1669
|
+
}
|
|
1670
|
+
return lines.join('\n');
|
|
1671
|
+
}
|
|
1672
|
+
function renderAgentSkillTeamRuntimeValidation(result) {
|
|
1673
|
+
const lines = ['SDD agent/skill/team runtime validation'];
|
|
1674
|
+
lines.push(`valid=${result.valid}`);
|
|
1675
|
+
lines.push(`profiles=${result.inspection.profiles.length}`);
|
|
1676
|
+
lines.push(`capabilities=${result.inspection.skillCapabilities.length}`);
|
|
1677
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(result.inspection.registrySources)}`);
|
|
1678
|
+
lines.push('issues');
|
|
1679
|
+
if (result.issues.length === 0) {
|
|
1680
|
+
lines.push('- none');
|
|
1681
|
+
}
|
|
1682
|
+
else {
|
|
1683
|
+
for (const issue of result.issues) {
|
|
1684
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
return lines.join('\n');
|
|
1688
|
+
}
|
|
1689
|
+
function renderSkillCapabilityList(capabilities, registrySources) {
|
|
1690
|
+
const lines = ['SDD skill capabilities'];
|
|
1691
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(registrySources)}`);
|
|
1692
|
+
for (const capability of capabilities) {
|
|
1693
|
+
const source = registrySources?.find((candidate) => candidate.kind === 'skill_capability' && candidate.id === capability.id);
|
|
1694
|
+
lines.push(`- ${capability.id} domain=${capability.capabilityDomain.join(',')} reuse=${capability.reuseDecision} evidence=${capability.evidenceType} origin=${source?.origin ?? 'unknown'}`);
|
|
1695
|
+
}
|
|
1696
|
+
return lines.join('\n');
|
|
1697
|
+
}
|
|
1698
|
+
function renderSkillCapabilityInspect(capability) {
|
|
1699
|
+
const lines = [`Skill capability ${capability.id}`];
|
|
1700
|
+
lines.push(`version=${capability.version}`);
|
|
1701
|
+
lines.push(`name=${capability.name}`);
|
|
1702
|
+
lines.push(`kind=${capability.kind} source=${capability.source} source_ref=${capability.sourceRef}`);
|
|
1703
|
+
lines.push(`domain=${capability.capabilityDomain.join(',')}`);
|
|
1704
|
+
lines.push(`allowed_stages=${capability.allowedStages.join(',')}`);
|
|
1705
|
+
lines.push(`risk_ceiling=${capability.requiredRiskCeiling}`);
|
|
1706
|
+
lines.push(`evidence_type=${capability.evidenceType}`);
|
|
1707
|
+
lines.push(`reuse_decision=${capability.reuseDecision}`);
|
|
1708
|
+
if (capability.buildExceptionReason) {
|
|
1709
|
+
lines.push(`build_exception=${capability.buildExceptionReason}`);
|
|
1710
|
+
}
|
|
1711
|
+
return lines.join('\n');
|
|
1712
|
+
}
|
|
1713
|
+
function renderCapabilitySourceList(sources, registrySources) {
|
|
1714
|
+
const lines = ['SDD capability sources'];
|
|
1715
|
+
lines.push(`registry_origins=${renderRegistryOriginCounts(registrySources)}`);
|
|
1716
|
+
for (const source of sources) {
|
|
1717
|
+
const registrySource = registrySources?.find((candidate) => candidate.kind === 'capability_source' && candidate.id === source.id);
|
|
1718
|
+
lines.push(`- ${source.id} kind=${source.kind} reuse=${source.reuseDecision} quarantine=${source.quarantineRequired} origin=${registrySource?.origin ?? 'unknown'}`);
|
|
1719
|
+
}
|
|
1720
|
+
return lines.join('\n');
|
|
1721
|
+
}
|
|
1722
|
+
function renderCapabilitySourceInspect(source) {
|
|
1723
|
+
const lines = [`Capability source ${source.id}`];
|
|
1724
|
+
lines.push(`version=${source.version}`);
|
|
1725
|
+
lines.push(`name=${source.name}`);
|
|
1726
|
+
lines.push(`kind=${source.kind} reuse=${source.reuseDecision} quarantine=${source.quarantineRequired}`);
|
|
1727
|
+
lines.push(`source_ref=${source.sourceRef}`);
|
|
1728
|
+
lines.push(`allowed_use=${source.allowedUse}`);
|
|
1729
|
+
lines.push(`attribution=${source.attribution}`);
|
|
1730
|
+
lines.push(`rationale=${source.rationale}`);
|
|
1731
|
+
return lines.join('\n');
|
|
1732
|
+
}
|
|
1733
|
+
function renderExternalAgentPackImportInspection(inspection) {
|
|
1734
|
+
const lines = [`External pack import ${inspection.sourceId}`];
|
|
1735
|
+
lines.push(`version=${inspection.version}`);
|
|
1736
|
+
lines.push(`status=${inspection.status} risk_ceiling=${inspection.riskCeiling}`);
|
|
1737
|
+
lines.push(`allowed_profiles=${inspection.allowedProfiles.join(',') || 'none'}`);
|
|
1738
|
+
lines.push(`mapping=${inspection.mappingResult}`);
|
|
1739
|
+
lines.push(`reason=${inspection.reason}`);
|
|
1740
|
+
lines.push('checks');
|
|
1741
|
+
for (const check of inspection.checks) {
|
|
1742
|
+
lines.push(`- ${check.check} status=${check.status} evidence=${check.evidence}`);
|
|
1743
|
+
}
|
|
1744
|
+
return lines.join('\n');
|
|
1745
|
+
}
|
|
1746
|
+
function renderTeamModePolicy(policy) {
|
|
1747
|
+
const lines = ['SDD team-mode policy'];
|
|
1748
|
+
lines.push(`version=${policy.version}`);
|
|
1749
|
+
lines.push(`enabled=${policy.enabled} decision=${policy.decision} mode=${policy.mode} activation=${policy.activation} cost=${policy.costClass}`);
|
|
1750
|
+
lines.push(`reason=${policy.reason}`);
|
|
1751
|
+
lines.push(`chief=${policy.chiefProfile} members=${policy.memberProfiles.join(',') || 'none'} max_members=${policy.maxMembers}`);
|
|
1752
|
+
lines.push(`require_artifacts=${policy.requireArtifacts}`);
|
|
1753
|
+
lines.push(`waves=${policy.waveRecommendation.join(',') || 'none'}`);
|
|
1754
|
+
if (policy.blockedReason) {
|
|
1755
|
+
lines.push(`blocked_reason=${policy.blockedReason}`);
|
|
1756
|
+
}
|
|
1757
|
+
for (const wave of policy.allowedWaves) {
|
|
1758
|
+
lines.push(`- ${wave.id} kind=${wave.waveKind} members=${wave.memberProfiles.join(',')} merge_gate=${wave.mergeGate}`);
|
|
1759
|
+
}
|
|
1760
|
+
return lines.join('\n');
|
|
1761
|
+
}
|
|
1762
|
+
function renderQueryStatusContract(contract) {
|
|
1763
|
+
const lines = ['SDD query status contract'];
|
|
1764
|
+
lines.push(`version=${contract.version}`);
|
|
1765
|
+
lines.push(`source=${contract.sourceDocument}`);
|
|
1766
|
+
for (const surface of contract.surfaces) {
|
|
1767
|
+
lines.push(`- ${surface.id} command=${surface.command}`);
|
|
1768
|
+
lines.push(` responsibility=${surface.responsibility}`);
|
|
1769
|
+
lines.push(` includes=${surface.includes.join(',')}`);
|
|
1770
|
+
lines.push(` excludes=${surface.excludes.join(',')}`);
|
|
1771
|
+
lines.push(` next=${surface.nextActionRule}`);
|
|
1772
|
+
}
|
|
1773
|
+
return lines.join('\n');
|
|
1774
|
+
}
|
|
1775
|
+
function renderQueryStatusValidation(result) {
|
|
1776
|
+
const lines = ['SDD query status validation'];
|
|
1777
|
+
lines.push(`valid=${result.valid}`);
|
|
1778
|
+
lines.push(`surfaces=${result.surfaces.length}`);
|
|
1779
|
+
lines.push('issues');
|
|
1780
|
+
if (result.issues.length === 0) {
|
|
1781
|
+
lines.push('- none');
|
|
1782
|
+
}
|
|
1783
|
+
else {
|
|
1784
|
+
for (const issue of result.issues) {
|
|
1785
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
return lines.join('\n');
|
|
1789
|
+
}
|
|
1790
|
+
function renderSkillAgentEvalContract(contract) {
|
|
1791
|
+
const lines = ['SDD skill/agent eval contract'];
|
|
1792
|
+
lines.push(`version=${contract.version}`);
|
|
1793
|
+
lines.push(`source=${contract.sourceReport}`);
|
|
1794
|
+
lines.push(`corpus=${contract.corpus.length}`);
|
|
1795
|
+
lines.push('dimensions');
|
|
1796
|
+
for (const dimension of contract.dimensions) {
|
|
1797
|
+
lines.push(`- ${dimension.id} threshold=${dimension.passThreshold}`);
|
|
1798
|
+
lines.push(` expectation=${dimension.expectation}`);
|
|
1799
|
+
lines.push(` baseline=${dimension.baselineFinding}`);
|
|
1800
|
+
}
|
|
1801
|
+
lines.push('regression_assertions');
|
|
1802
|
+
for (const assertion of contract.regressionAssertions) {
|
|
1803
|
+
lines.push(`- ${assertion}`);
|
|
1804
|
+
}
|
|
1805
|
+
return lines.join('\n');
|
|
1806
|
+
}
|
|
1807
|
+
function renderSkillAgentEvalValidation(result) {
|
|
1808
|
+
const lines = ['SDD skill/agent eval validation'];
|
|
1809
|
+
lines.push(`valid=${result.valid}`);
|
|
1810
|
+
lines.push(`dimensions=${result.contract.dimensions.length}`);
|
|
1811
|
+
lines.push(`corpus=${result.contract.corpus.length}`);
|
|
1812
|
+
lines.push('issues');
|
|
1813
|
+
if (result.issues.length === 0) {
|
|
1814
|
+
lines.push('- none');
|
|
1815
|
+
}
|
|
1816
|
+
else {
|
|
1817
|
+
for (const issue of result.issues) {
|
|
1818
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
return lines.join('\n');
|
|
1822
|
+
}
|
|
1823
|
+
function renderHarnessLearningContract(contract) {
|
|
1824
|
+
const lines = ['SDD harness learning contract'];
|
|
1825
|
+
lines.push(`version=${contract.version}`);
|
|
1826
|
+
lines.push(`source=${contract.sourceTrial}`);
|
|
1827
|
+
lines.push(`promotion=${contract.promotionRule}`);
|
|
1828
|
+
lines.push('allowed_sinks');
|
|
1829
|
+
for (const sink of contract.allowedSinks) {
|
|
1830
|
+
lines.push(`- ${sink.id}: ${sink.output}`);
|
|
1831
|
+
lines.push(` boundary=${sink.boundary}`);
|
|
1832
|
+
}
|
|
1833
|
+
lines.push('forbidden_outputs');
|
|
1834
|
+
for (const output of contract.forbiddenOutputs) {
|
|
1835
|
+
lines.push(`- ${output}`);
|
|
1836
|
+
}
|
|
1837
|
+
return lines.join('\n');
|
|
1838
|
+
}
|
|
1839
|
+
function renderHarnessLearningValidation(result) {
|
|
1840
|
+
const lines = ['SDD harness learning validation'];
|
|
1841
|
+
lines.push(`valid=${result.valid}`);
|
|
1842
|
+
lines.push(`allowed_sinks=${result.contract.allowedSinks.length}`);
|
|
1843
|
+
lines.push(`forbidden_outputs=${result.contract.forbiddenOutputs.length}`);
|
|
1844
|
+
lines.push('issues');
|
|
1845
|
+
if (result.issues.length === 0) {
|
|
1846
|
+
lines.push('- none');
|
|
1847
|
+
}
|
|
1848
|
+
else {
|
|
1849
|
+
for (const issue of result.issues) {
|
|
1850
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
return lines.join('\n');
|
|
1854
|
+
}
|
|
1855
|
+
function renderProjectContextPackContract(contract) {
|
|
1856
|
+
const lines = ['SDD project context pack contract'];
|
|
1857
|
+
lines.push(`version=${contract.version}`);
|
|
1858
|
+
lines.push(`entry=${contract.entryPoint}`);
|
|
1859
|
+
lines.push('durable_context');
|
|
1860
|
+
for (const item of contract.durableContext) {
|
|
1861
|
+
lines.push(`- ${item}`);
|
|
1862
|
+
}
|
|
1863
|
+
lines.push('runtime_sources_of_truth');
|
|
1864
|
+
for (const source of contract.runtimeSourcesOfTruth) {
|
|
1865
|
+
lines.push(`- ${source}`);
|
|
1866
|
+
}
|
|
1867
|
+
lines.push('boundaries');
|
|
1868
|
+
for (const boundary of contract.boundaries) {
|
|
1869
|
+
lines.push(`- ${boundary}`);
|
|
1870
|
+
}
|
|
1871
|
+
return lines.join('\n');
|
|
1872
|
+
}
|
|
1873
|
+
function renderProjectContextPackValidation(result) {
|
|
1874
|
+
const lines = ['SDD project context pack validation'];
|
|
1875
|
+
lines.push(`valid=${result.valid}`);
|
|
1876
|
+
lines.push(`entry=${result.contract.entryPoint}`);
|
|
1877
|
+
lines.push(`runtime_sources=${result.contract.runtimeSourcesOfTruth.length}`);
|
|
1878
|
+
lines.push('issues');
|
|
1879
|
+
if (result.issues.length === 0) {
|
|
1880
|
+
lines.push('- none');
|
|
1881
|
+
}
|
|
1882
|
+
else {
|
|
1883
|
+
for (const issue of result.issues) {
|
|
1884
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
return lines.join('\n');
|
|
1888
|
+
}
|
|
984
1889
|
function renderCapabilityList(capabilities) {
|
|
985
1890
|
const lines = ['SDD tool capabilities'];
|
|
986
1891
|
for (const capability of capabilities) {
|
|
@@ -1116,13 +2021,7 @@ function renderArtifactIngestionInspection(inspection) {
|
|
|
1116
2021
|
for (const record of inspection.records) {
|
|
1117
2022
|
lines.push(`- ${record.delegationId} ${record.status} artifact=${record.artifactPath} result=${record.resultStatus ?? 'n/a'} delegation=${record.delegationStatus ?? 'n/a'}`);
|
|
1118
2023
|
}
|
|
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
|
-
}
|
|
2024
|
+
renderIssues(lines, inspection.issues);
|
|
1126
2025
|
return lines.join('\n');
|
|
1127
2026
|
}
|
|
1128
2027
|
function renderBackgroundExecutorResult(result) {
|
|
@@ -1131,13 +2030,7 @@ function renderBackgroundExecutorResult(result) {
|
|
|
1131
2030
|
lines.push(`run=${result.runId} delegation=${result.delegationId ?? 'n/a'} queue=${result.queueItemId ?? 'n/a'} worker=${result.workerAdapterId}`);
|
|
1132
2031
|
lines.push(`artifact=${result.artifactPath ?? 'pending'}`);
|
|
1133
2032
|
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
|
-
}
|
|
2033
|
+
renderIssues(lines, result.issues);
|
|
1141
2034
|
return lines.join('\n');
|
|
1142
2035
|
}
|
|
1143
2036
|
function renderBackgroundExecutorInspection(inspection) {
|
|
@@ -1147,15 +2040,77 @@ function renderBackgroundExecutorInspection(inspection) {
|
|
|
1147
2040
|
for (const delegation of inspection.delegations) {
|
|
1148
2041
|
lines.push(`- ${delegation.delegationId} ${delegation.status} task=${delegation.taskId} agent=${delegation.agent} artifact=${delegation.expectedArtifact}`);
|
|
1149
2042
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
2043
|
+
renderIssues(lines, inspection.issues);
|
|
2044
|
+
return lines.join('\n');
|
|
2045
|
+
}
|
|
2046
|
+
function renderResidentWorkerRuntimeClaimResult(result) {
|
|
2047
|
+
const lines = [`Resident worker runtime ${result.status} for ${result.taskId}`];
|
|
2048
|
+
lines.push(`version=${result.version}`);
|
|
2049
|
+
lines.push(`run=${result.runId} runtime=${result.runtimeId ?? 'n/a'} delegation=${result.delegationId ?? 'n/a'} queue=${result.queueItemId ?? 'n/a'} worker=${result.workerAdapterId}`);
|
|
2050
|
+
lines.push(`artifact=${result.expectedArtifact ?? 'pending'} lease_expires=${result.leaseExpiresAt ?? 'n/a'}`);
|
|
2051
|
+
lines.push(result.message);
|
|
2052
|
+
renderIssues(lines, result.issues);
|
|
2053
|
+
if (result.runtimeId && result.leaseExpiresAt) {
|
|
2054
|
+
lines.push(`next sdd worker-runtime heartbeat ${result.runtimeId} --run ${result.runId}`);
|
|
2055
|
+
lines.push(`inspect sdd worker-runtime inspect ${result.runtimeId} --run ${result.runId}`);
|
|
2056
|
+
}
|
|
2057
|
+
return lines.join('\n');
|
|
2058
|
+
}
|
|
2059
|
+
function renderResidentWorkerRuntimeHeartbeatResult(result) {
|
|
2060
|
+
const lines = [`Resident worker runtime ${result.status}: ${result.runtimeId}`];
|
|
2061
|
+
lines.push(`version=${result.version}`);
|
|
2062
|
+
lines.push(`run=${result.runId} lease_expires=${result.leaseExpiresAt ?? 'n/a'}`);
|
|
2063
|
+
lines.push(result.message);
|
|
2064
|
+
renderIssues(lines, result.issues);
|
|
2065
|
+
if (result.runtime) {
|
|
2066
|
+
lines.push(`next ${result.status === 'terminal' ? `sdd background inspect ${result.runId}` : `sdd worker-runtime inspect ${result.runtimeId} --run ${result.runId}`}`);
|
|
2067
|
+
}
|
|
2068
|
+
return lines.join('\n');
|
|
2069
|
+
}
|
|
2070
|
+
function renderResidentWorkerRuntimeList(result) {
|
|
2071
|
+
const lines = [`Resident worker runtimes for ${result.runId}`];
|
|
2072
|
+
lines.push(`version=${result.version}`);
|
|
2073
|
+
lines.push(`runtimes=${result.runtimes.length} active=${result.activeRuntimes} stale=${result.staleRuntimes} terminal=${result.terminalRuntimes} blocked=${result.blockedRuntimes}`);
|
|
2074
|
+
for (const runtime of result.runtimes) {
|
|
2075
|
+
lines.push(`- ${runtime.runtimeId} ${runtime.status} task=${runtime.taskId} agent=${runtime.agent} delegation=${runtime.delegationId} lease_expires=${runtime.leaseExpiresAt}`);
|
|
1156
2076
|
}
|
|
2077
|
+
renderIssues(lines, result.issues);
|
|
2078
|
+
return lines.join('\n');
|
|
2079
|
+
}
|
|
2080
|
+
function renderResidentWorkerRuntimeInspection(inspection) {
|
|
2081
|
+
const lines = [`Resident worker runtime ${inspection.status}: ${inspection.runtimeId}`];
|
|
2082
|
+
lines.push(`version=${inspection.version}`);
|
|
2083
|
+
lines.push(`run=${inspection.runId} valid=${inspection.valid} lease_expired=${inspection.leaseExpired}`);
|
|
2084
|
+
if (inspection.runtime) {
|
|
2085
|
+
lines.push(`task=${inspection.runtime.taskId} agent=${inspection.runtime.agent} worker=${inspection.runtime.workerAdapterId}`);
|
|
2086
|
+
lines.push(`delegation=${inspection.runtime.delegationId} queue=${inspection.runtime.queueItemId} artifact=${inspection.runtime.expectedArtifact}`);
|
|
2087
|
+
lines.push(`claimed=${inspection.runtime.claimedAt} heartbeat=${inspection.runtime.lastHeartbeatAt ?? 'none'} lease_expires=${inspection.runtime.leaseExpiresAt}`);
|
|
2088
|
+
lines.push(`evidence=${inspection.runtime.evidenceSummary}`);
|
|
2089
|
+
}
|
|
2090
|
+
lines.push(`queue_status=${inspection.queueItem?.status ?? 'missing'} adapter=${inspection.workerAdapter?.id ?? 'missing'}`);
|
|
2091
|
+
lines.push(`next ${inspection.recommendedNextCommand}`);
|
|
2092
|
+
renderIssues(lines, inspection.issues);
|
|
1157
2093
|
return lines.join('\n');
|
|
1158
2094
|
}
|
|
2095
|
+
function renderIssues(lines, issues) {
|
|
2096
|
+
if (issues.length === 0) {
|
|
2097
|
+
return;
|
|
2098
|
+
}
|
|
2099
|
+
lines.push('issues');
|
|
2100
|
+
for (const issue of issues) {
|
|
2101
|
+
lines.push(`- ${issue.field}: ${issue.message}`);
|
|
2102
|
+
lines.push(` recommendation: ${issue.recommendation}`);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
function renderDocumentGaps(lines, gaps) {
|
|
2106
|
+
if (gaps.length === 0) {
|
|
2107
|
+
return;
|
|
2108
|
+
}
|
|
2109
|
+
lines.push('gaps');
|
|
2110
|
+
for (const gap of gaps) {
|
|
2111
|
+
lines.push(`- [${gap.severity}] ${gap.type} ${gap.taskId ?? 'document'} ${gap.field}: ${gap.message}`);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
1159
2114
|
function renderWaveExecutorResult(result) {
|
|
1160
2115
|
const lines = [`Wave executor ${result.status} for ${result.branch}`];
|
|
1161
2116
|
lines.push(`version=${result.version}`);
|
|
@@ -1176,13 +2131,7 @@ function renderWaveExecutorResult(result) {
|
|
|
1176
2131
|
lines.push(`- ${gate.taskId}: ${gate.reasons.join(' | ')}`);
|
|
1177
2132
|
}
|
|
1178
2133
|
}
|
|
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
|
-
}
|
|
2134
|
+
renderIssues(lines, result.issues);
|
|
1186
2135
|
return lines.join('\n');
|
|
1187
2136
|
}
|
|
1188
2137
|
function renderWaveExecutorInspection(inspection) {
|
|
@@ -1192,13 +2141,7 @@ function renderWaveExecutorInspection(inspection) {
|
|
|
1192
2141
|
for (const event of inspection.waveEvents) {
|
|
1193
2142
|
lines.push(`- ${event.event}: ${event.summary ?? ''}`);
|
|
1194
2143
|
}
|
|
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
|
-
}
|
|
2144
|
+
renderIssues(lines, inspection.issues);
|
|
1202
2145
|
return lines.join('\n');
|
|
1203
2146
|
}
|
|
1204
2147
|
function renderWorktreeIsolationDecision(decision) {
|
|
@@ -1237,24 +2180,19 @@ function renderWorktreeLifecycleInspection(inspection) {
|
|
|
1237
2180
|
for (const record of inspection.records) {
|
|
1238
2181
|
lines.push(`- ${record.worktreeId} ${record.status} task=${record.taskId} path=${record.worktreePath} dirty=${record.dirty}`);
|
|
1239
2182
|
}
|
|
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
|
-
}
|
|
2183
|
+
renderIssues(lines, inspection.issues);
|
|
1247
2184
|
return lines.join('\n');
|
|
1248
2185
|
}
|
|
1249
2186
|
function renderTaskGraphPlan(graph) {
|
|
1250
2187
|
const lines = [`Task graph ${graph.valid ? 'valid' : 'blocked'} for ${graph.branch}`];
|
|
1251
2188
|
lines.push(`version=${graph.version}`);
|
|
2189
|
+
lines.push(`contract=${graph.contract}`);
|
|
1252
2190
|
lines.push(`tasks=${graph.summary.tasks} dependencies=${graph.summary.dependencies} file_overlaps=${graph.summary.fileOverlaps}`);
|
|
1253
2191
|
lines.push(`high_risk_tasks=${graph.summary.highRiskTasks.length > 0 ? graph.summary.highRiskTasks.join(',') : 'none'}`);
|
|
1254
2192
|
lines.push(`validation=${graph.summary.validationCommands.length > 0 ? graph.summary.validationCommands.join(' | ') : 'none'}`);
|
|
1255
2193
|
lines.push('nodes');
|
|
1256
2194
|
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}`);
|
|
2195
|
+
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
2196
|
}
|
|
1259
2197
|
if (graph.dependencyEdges.length > 0) {
|
|
1260
2198
|
lines.push('dependency_edges');
|
|
@@ -1309,12 +2247,50 @@ function renderWavePlan(plan) {
|
|
|
1309
2247
|
}
|
|
1310
2248
|
return lines.join('\n');
|
|
1311
2249
|
}
|
|
1312
|
-
function
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
2250
|
+
function readTeamModeActivation(args, fallback) {
|
|
2251
|
+
if (args.includes('--no-team-mode')) {
|
|
2252
|
+
return 'off';
|
|
2253
|
+
}
|
|
2254
|
+
const inline = args.find((item) => item.startsWith('--team-mode='));
|
|
2255
|
+
const inlineValue = inline?.split('=', 2)[1];
|
|
2256
|
+
if (inlineValue === 'auto' || inlineValue === 'force' || inlineValue === 'off') {
|
|
2257
|
+
return inlineValue;
|
|
2258
|
+
}
|
|
2259
|
+
const index = args.indexOf('--team-mode');
|
|
2260
|
+
if (index >= 0) {
|
|
2261
|
+
const value = args[index + 1];
|
|
2262
|
+
if (value === 'auto' || value === 'force' || value === 'off') {
|
|
2263
|
+
return value;
|
|
2264
|
+
}
|
|
2265
|
+
return 'force';
|
|
1316
2266
|
}
|
|
1317
|
-
return
|
|
2267
|
+
return fallback;
|
|
2268
|
+
}
|
|
2269
|
+
function readBranchContext(args) {
|
|
2270
|
+
const branch = readBranchOption(args);
|
|
2271
|
+
return branch ? { branch, branchSource: 'cli_option' } : {};
|
|
2272
|
+
}
|
|
2273
|
+
function readBranchOption(args) {
|
|
2274
|
+
return readOption(args, '--branch') ?? undefined;
|
|
2275
|
+
}
|
|
2276
|
+
function readOptionalPositionalArgument(args) {
|
|
2277
|
+
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']);
|
|
2278
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
2279
|
+
const item = args[index];
|
|
2280
|
+
if (!item.startsWith('--')) {
|
|
2281
|
+
return item;
|
|
2282
|
+
}
|
|
2283
|
+
if (item.includes('=')) {
|
|
2284
|
+
continue;
|
|
2285
|
+
}
|
|
2286
|
+
if (!booleanOptions.has(item) && args[index + 1] && !args[index + 1].startsWith('--')) {
|
|
2287
|
+
index += 1;
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
return undefined;
|
|
2291
|
+
}
|
|
2292
|
+
async function readResolvedBranch(projectRoot, args) {
|
|
2293
|
+
return (await resolveSddContext(projectRoot, readBranchContext(args))).branch;
|
|
1318
2294
|
}
|
|
1319
2295
|
function readWaveExecutorStrategy(args, name) {
|
|
1320
2296
|
const value = readOption(args, name) ?? 'fast-stop';
|
|
@@ -1327,15 +2303,6 @@ function readRunStatus(args, name) {
|
|
|
1327
2303
|
function readGovernancePolicyOperation(value) {
|
|
1328
2304
|
return value === 'background_executor' || value === 'wave_executor' || value === 'sync_back_apply' || value === 'destructive_git' || value === 'external_interaction' || value === 'cleanup' ? value : null;
|
|
1329
2305
|
}
|
|
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
2306
|
function readTaskArtifactOptions(args) {
|
|
1340
2307
|
const artifacts = {};
|
|
1341
2308
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -1376,24 +2343,35 @@ function readAiToolSelection(args, allowNone) {
|
|
|
1376
2343
|
}
|
|
1377
2344
|
throw new Error(`Unsupported --ai value: ${value}`);
|
|
1378
2345
|
}
|
|
1379
|
-
function readLifecycleSignalOptions(args) {
|
|
2346
|
+
async function readLifecycleSignalOptions(args) {
|
|
1380
2347
|
const directSafe = args.includes('--direct-safe');
|
|
1381
2348
|
const riskTags = readRepeatedOptions(args, '--risk');
|
|
1382
2349
|
const contracts = readRepeatedOptions(args, '--contract');
|
|
1383
2350
|
const permissions = readRepeatedOptions(args, '--permission');
|
|
1384
|
-
|
|
2351
|
+
const fromText = readOption(args, '--from-text');
|
|
2352
|
+
const fromFile = readOption(args, '--from-file');
|
|
2353
|
+
if (fromText && fromFile) {
|
|
2354
|
+
return { signals: {}, riskExtraction: null, error: 'Usage: sdd lifecycle decide accepts only one of --from-text or --from-file' };
|
|
2355
|
+
}
|
|
2356
|
+
const riskExtraction = fromText
|
|
2357
|
+
? extractLifecycleRiskSignalsFromText(fromText, 'from_text')
|
|
2358
|
+
: fromFile
|
|
2359
|
+
? extractLifecycleRiskSignalsFromText(await readFile(fromFile, 'utf8'), 'from_file')
|
|
2360
|
+
: null;
|
|
2361
|
+
const extracted = riskExtraction?.signals ?? {};
|
|
2362
|
+
const signals = {
|
|
1385
2363
|
intent_clarity: directSafe ? 'high' : readSignalClarity(args, '--intent') ?? 'medium',
|
|
1386
2364
|
acceptance_clarity: directSafe ? 'high' : readSignalClarity(args, '--acceptance') ?? 'medium',
|
|
1387
2365
|
estimated_change_size: directSafe ? 'tiny' : readEstimatedChangeSize(args, '--size') ?? 'small',
|
|
1388
2366
|
task_count_estimate: Number(readOption(args, '--tasks') ?? (directSafe ? '1' : '1')),
|
|
1389
2367
|
file_count_estimate: Number(readOption(args, '--files') ?? (directSafe ? '1' : '1')),
|
|
1390
2368
|
affected_layers: readRepeatedOptions(args, '--layer'),
|
|
1391
|
-
affected_contracts: contracts,
|
|
2369
|
+
affected_contracts: uniqueCliStrings([...contracts, ...(extracted.affected_contracts ?? [])]),
|
|
1392
2370
|
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',
|
|
2371
|
+
impact_confidence: directSafe ? 'high' : extracted.impact_confidence ?? readImpactConfidence(args, '--impact-confidence') ?? 'medium',
|
|
2372
|
+
risk_tags: uniqueCliStrings([...riskTags, ...(extracted.risk_tags ?? [])]),
|
|
2373
|
+
reversibility: directSafe ? 'reversible' : extracted.reversibility ?? readReversibility(args, '--reversibility') ?? 'unknown',
|
|
2374
|
+
validation_clarity: directSafe ? 'clear' : extracted.validation_clarity ?? readValidationClarity(args, '--validation') ?? 'partial',
|
|
1397
2375
|
validation_available: directSafe || args.includes('--validation-available'),
|
|
1398
2376
|
validation_cost: directSafe ? 'cheap' : readValidationCost(args, '--validation-cost') ?? 'unknown',
|
|
1399
2377
|
policy_hits: readRepeatedOptions(args, '--policy'),
|
|
@@ -1405,21 +2383,44 @@ function readLifecycleSignalOptions(args) {
|
|
|
1405
2383
|
orchestration_uncertainty: directSafe ? 'low' : readOrchestrationUncertainty(args, '--orchestration') ?? 'medium',
|
|
1406
2384
|
human_checkpoint_required: args.includes('--checkpoint'),
|
|
1407
2385
|
approval_reason: readRepeatedOptions(args, '--approval-reason'),
|
|
1408
|
-
source_artifacts: readRepeatedOptions(args, '--source-artifact'),
|
|
2386
|
+
source_artifacts: uniqueCliStrings([...readRepeatedOptions(args, '--source-artifact'), ...(fromFile ? [fromFile] : [])]),
|
|
1409
2387
|
can_scout_impact: !args.includes('--cannot-scout-impact'),
|
|
1410
|
-
architecture_decision_required: args.includes('--architecture'),
|
|
1411
|
-
external_unknown: args.includes('--external-unknown')
|
|
2388
|
+
architecture_decision_required: args.includes('--architecture') || Boolean(extracted.architecture_decision_required),
|
|
2389
|
+
external_unknown: args.includes('--external-unknown') || Boolean(extracted.external_unknown)
|
|
1412
2390
|
};
|
|
2391
|
+
return { signals, riskExtraction };
|
|
1413
2392
|
}
|
|
1414
|
-
function
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
2393
|
+
function uniqueCliStrings(values) {
|
|
2394
|
+
return Array.from(new Set(values.filter((value) => value.length > 0)));
|
|
2395
|
+
}
|
|
2396
|
+
function renderLifecycleRiskExtraction(extraction) {
|
|
2397
|
+
if (!extraction) {
|
|
2398
|
+
return '';
|
|
2399
|
+
}
|
|
2400
|
+
const lines = [
|
|
2401
|
+
'Lifecycle Risk Gate',
|
|
2402
|
+
'changed',
|
|
2403
|
+
'- deterministic risk signals extracted',
|
|
2404
|
+
'decision',
|
|
2405
|
+
`- source=${extraction.source}`,
|
|
2406
|
+
`- risk_tags=${extraction.riskTags.join(',') || 'none'}`,
|
|
2407
|
+
`- affected_contracts=${extraction.affectedContracts.join(',') || 'none'}`,
|
|
2408
|
+
`- external_unknown=${extraction.externalUnknown}`,
|
|
2409
|
+
'evidence'
|
|
2410
|
+
];
|
|
2411
|
+
if (extraction.evidence.length === 0) {
|
|
2412
|
+
lines.push('- none');
|
|
2413
|
+
}
|
|
2414
|
+
else {
|
|
2415
|
+
for (const item of extraction.evidence) {
|
|
2416
|
+
lines.push(`- ${item.category}: ${item.matched} -> ${item.riskTag}`);
|
|
1420
2417
|
}
|
|
1421
2418
|
}
|
|
1422
|
-
|
|
2419
|
+
lines.push('gaps');
|
|
2420
|
+
lines.push('- none');
|
|
2421
|
+
lines.push('next');
|
|
2422
|
+
lines.push('- Evaluate extracted signals with lifecycle decision gate.');
|
|
2423
|
+
return `${lines.join('\n')}\n`;
|
|
1423
2424
|
}
|
|
1424
2425
|
function readSignalClarity(args, name) {
|
|
1425
2426
|
const value = readOption(args, name);
|
|
@@ -1460,14 +2461,36 @@ id: T1
|
|
|
1460
2461
|
status: pending
|
|
1461
2462
|
wave: 1
|
|
1462
2463
|
depends_on: []
|
|
2464
|
+
acceptance_refs:
|
|
2465
|
+
- AC-1
|
|
2466
|
+
plan_refs:
|
|
2467
|
+
- "§4 Target Design Overview"
|
|
1463
2468
|
affected_files:
|
|
1464
2469
|
- path/to/file
|
|
1465
2470
|
validation:
|
|
1466
2471
|
- command string
|
|
1467
|
-
risk:
|
|
2472
|
+
risk:
|
|
2473
|
+
- state-machine
|
|
2474
|
+
agent_fit:
|
|
2475
|
+
- scout
|
|
2476
|
+
- implementer
|
|
2477
|
+
- reviewer
|
|
2478
|
+
- validator
|
|
2479
|
+
verification_availability:
|
|
2480
|
+
- unit:command string
|
|
2481
|
+
- build:command string
|
|
2482
|
+
autonomy: full_sdd_with_checkpoint
|
|
2483
|
+
allowed_agents:
|
|
2484
|
+
- scout
|
|
2485
|
+
- implementer
|
|
2486
|
+
- reviewer
|
|
2487
|
+
- validator
|
|
2488
|
+
required_artifacts:
|
|
2489
|
+
- artifacts/review-T1.md
|
|
2490
|
+
- artifacts/validation-T1.md
|
|
1468
2491
|
\`\`\`
|
|
1469
2492
|
|
|
1470
|
-
Companion sections such as #### Boundary, #### Acceptance, and #### Implementation Notes must stay outside the fenced sdd-task metadata block.
|
|
2493
|
+
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
2494
|
|
|
1472
2495
|
#### Boundary
|
|
1473
2496
|
|