@deftai/directive 0.119.13 → 0.121.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/dist/authz.js +41 -7
- package/dist/changelog-check.js +14 -6
- package/dist/dispatch.d.ts +2 -2
- package/dist/dispatch.js +17 -0
- package/dist/hook-dispatch.js +4 -0
- package/dist/pre-pr-run.d.ts +39 -0
- package/dist/pre-pr-run.js +514 -0
- package/dist/render-cli/spec-reconstruct-cli.d.ts +3 -0
- package/dist/render-cli/spec-reconstruct-cli.js +15 -0
- package/dist/subagent-pre-cancel.d.ts +21 -0
- package/dist/subagent-pre-cancel.js +240 -0
- package/dist/subagent-steer-write.d.ts +41 -0
- package/dist/subagent-steer-write.js +333 -0
- package/dist/verify-cohort-review-monitors.d.ts +5 -0
- package/dist/verify-cohort-review-monitors.js +11 -0
- package/dist/verify-completed-tracked.d.ts +4 -1
- package/dist/verify-completed-tracked.js +60 -9
- package/dist/verify-review-monitor.d.ts +2 -0
- package/dist/verify-review-monitor.js +66 -1
- package/dist/verify-source-cli/verify-spec-drift.d.ts +3 -0
- package/dist/verify-source-cli/verify-spec-drift.js +15 -0
- package/dist/verify-story-ready.js +5 -2
- package/dist/verify-subagent-alive.js +17 -1
- package/package.json +3 -3
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent-facing pre-PR controller entry (#4912 Limb 3).
|
|
4
|
+
* `deft pre-pr:run` starts the prescribed workflow. Opening the skill file
|
|
5
|
+
* is not completion. Generic mark-complete cannot mint a pass.
|
|
6
|
+
*/
|
|
7
|
+
import { completeRun, computeControllerObservedHash, controllerPublisher, digestApprovedCriteria, evaluateLivePrePrCheck, getDefaultPrePrStore, markComplete, noteSkillFileOpen, observeCommandPhase, PRE_PR_PHASE_IDS, phaseSpec, resolveRecordFromStore, startControllerRun, submitReviewerReport, } from "@deftai/directive-core/pre-pr-controller";
|
|
8
|
+
import { isDirectEntrypoint } from "./entrypoint.js";
|
|
9
|
+
const USAGE = `Usage: deft pre-pr:run [options]
|
|
10
|
+
|
|
11
|
+
Start the repository-controlled pre-PR workflow. Opening the skill file is
|
|
12
|
+
not completion. A generic mark-complete cannot mint a pass.
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--repo <owner/name>
|
|
16
|
+
--base-sha <sha>
|
|
17
|
+
--head-sha <sha>
|
|
18
|
+
--tree-hash <sha>
|
|
19
|
+
--pr-body-hash <hex>
|
|
20
|
+
--pr-node-id <id>
|
|
21
|
+
--approved-revision <sha>
|
|
22
|
+
--scope <path> (repeatable)
|
|
23
|
+
--acceptance <text>
|
|
24
|
+
--generation <n>
|
|
25
|
+
--skill-version <ver>
|
|
26
|
+
--policy-version <ver>
|
|
27
|
+
--run-id <id> lookup hint only
|
|
28
|
+
--complete publisher-backed complete (fails without observables)
|
|
29
|
+
--observe-command record a command-observable phase before --complete
|
|
30
|
+
--observe-semantic record semantic / final-no-change evidence
|
|
31
|
+
--phase <id>
|
|
32
|
+
--command <text>
|
|
33
|
+
--exit-code <n> required with --observe-command; omit is a parse error
|
|
34
|
+
--input-hash <hex>
|
|
35
|
+
--skip-reason <text> skip also requires a non-zero --exit-code
|
|
36
|
+
--supplied-contents-hash <hex>
|
|
37
|
+
--controller-observed-hash <hex>
|
|
38
|
+
optional; must match independently hashed reviewed files
|
|
39
|
+
--criteria-digest <hex>
|
|
40
|
+
--reviewed-file <path> (repeatable)
|
|
41
|
+
--reviewer-report-ref <ref>
|
|
42
|
+
--mark-complete always refuses; cannot mint a pass
|
|
43
|
+
--skill-open always refuses; opening the skill is not completion
|
|
44
|
+
--evaluate evaluate live binding against the private store
|
|
45
|
+
--json
|
|
46
|
+
--help
|
|
47
|
+
`;
|
|
48
|
+
export function parseArgs(argv) {
|
|
49
|
+
const parsed = {
|
|
50
|
+
repo: "",
|
|
51
|
+
baseSha: "",
|
|
52
|
+
headSha: "",
|
|
53
|
+
treeHash: "",
|
|
54
|
+
prBodyHash: "",
|
|
55
|
+
prNodeId: null,
|
|
56
|
+
approvedRevision: "",
|
|
57
|
+
scope: [],
|
|
58
|
+
acceptance: "",
|
|
59
|
+
generation: 1,
|
|
60
|
+
skillVersion: "0.1",
|
|
61
|
+
policyVersion: "1",
|
|
62
|
+
runId: null,
|
|
63
|
+
complete: false,
|
|
64
|
+
observeCommand: false,
|
|
65
|
+
observeSemantic: false,
|
|
66
|
+
phase: null,
|
|
67
|
+
command: "",
|
|
68
|
+
exitCode: null,
|
|
69
|
+
inputHash: null,
|
|
70
|
+
skipReason: null,
|
|
71
|
+
suppliedContentsHash: "",
|
|
72
|
+
controllerObservedHash: "",
|
|
73
|
+
criteriaDigest: null,
|
|
74
|
+
reviewedFiles: [],
|
|
75
|
+
reviewerReportRef: null,
|
|
76
|
+
markComplete: false,
|
|
77
|
+
skillOpen: false,
|
|
78
|
+
evaluate: false,
|
|
79
|
+
json: false,
|
|
80
|
+
help: false,
|
|
81
|
+
};
|
|
82
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
83
|
+
const arg = argv[i];
|
|
84
|
+
if (arg === "--help" || arg === "-h") {
|
|
85
|
+
parsed.help = true;
|
|
86
|
+
}
|
|
87
|
+
else if (arg === "--json") {
|
|
88
|
+
parsed.json = true;
|
|
89
|
+
}
|
|
90
|
+
else if (arg === "--complete") {
|
|
91
|
+
parsed.complete = true;
|
|
92
|
+
}
|
|
93
|
+
else if (arg === "--observe-command") {
|
|
94
|
+
parsed.observeCommand = true;
|
|
95
|
+
}
|
|
96
|
+
else if (arg === "--observe-semantic") {
|
|
97
|
+
parsed.observeSemantic = true;
|
|
98
|
+
}
|
|
99
|
+
else if (arg === "--phase" || arg?.startsWith("--phase=")) {
|
|
100
|
+
const value = arg === "--phase" ? argv[i + 1] : arg.slice("--phase=".length);
|
|
101
|
+
if (value === undefined)
|
|
102
|
+
return { ...parsed, error: "argument --phase: expected one argument" };
|
|
103
|
+
parsed.phase = value;
|
|
104
|
+
if (arg === "--phase")
|
|
105
|
+
i += 1;
|
|
106
|
+
}
|
|
107
|
+
else if (arg === "--command" || arg?.startsWith("--command=")) {
|
|
108
|
+
const value = arg === "--command" ? argv[i + 1] : arg.slice("--command=".length);
|
|
109
|
+
if (value === undefined)
|
|
110
|
+
return { ...parsed, error: "argument --command: expected one argument" };
|
|
111
|
+
parsed.command = value;
|
|
112
|
+
if (arg === "--command")
|
|
113
|
+
i += 1;
|
|
114
|
+
}
|
|
115
|
+
else if (arg === "--exit-code" || arg?.startsWith("--exit-code=")) {
|
|
116
|
+
const value = arg === "--exit-code" ? argv[i + 1] : arg.slice("--exit-code=".length);
|
|
117
|
+
if (value === undefined) {
|
|
118
|
+
return { ...parsed, error: "argument --exit-code: expected one argument" };
|
|
119
|
+
}
|
|
120
|
+
const n = Number.parseInt(value, 10);
|
|
121
|
+
if (!Number.isFinite(n)) {
|
|
122
|
+
return { ...parsed, error: "argument --exit-code: expected an integer" };
|
|
123
|
+
}
|
|
124
|
+
parsed.exitCode = n;
|
|
125
|
+
if (arg === "--exit-code")
|
|
126
|
+
i += 1;
|
|
127
|
+
}
|
|
128
|
+
else if (arg === "--input-hash" || arg?.startsWith("--input-hash=")) {
|
|
129
|
+
const value = arg === "--input-hash" ? argv[i + 1] : arg.slice("--input-hash=".length);
|
|
130
|
+
if (value === undefined) {
|
|
131
|
+
return { ...parsed, error: "argument --input-hash: expected one argument" };
|
|
132
|
+
}
|
|
133
|
+
parsed.inputHash = value;
|
|
134
|
+
if (arg === "--input-hash")
|
|
135
|
+
i += 1;
|
|
136
|
+
}
|
|
137
|
+
else if (arg === "--skip-reason" || arg?.startsWith("--skip-reason=")) {
|
|
138
|
+
const value = arg === "--skip-reason" ? argv[i + 1] : arg.slice("--skip-reason=".length);
|
|
139
|
+
if (value === undefined) {
|
|
140
|
+
return { ...parsed, error: "argument --skip-reason: expected one argument" };
|
|
141
|
+
}
|
|
142
|
+
parsed.skipReason = value;
|
|
143
|
+
if (arg === "--skip-reason")
|
|
144
|
+
i += 1;
|
|
145
|
+
}
|
|
146
|
+
else if (arg === "--supplied-contents-hash" || arg?.startsWith("--supplied-contents-hash=")) {
|
|
147
|
+
const value = arg === "--supplied-contents-hash"
|
|
148
|
+
? argv[i + 1]
|
|
149
|
+
: arg.slice("--supplied-contents-hash=".length);
|
|
150
|
+
if (value === undefined) {
|
|
151
|
+
return { ...parsed, error: "argument --supplied-contents-hash: expected one argument" };
|
|
152
|
+
}
|
|
153
|
+
parsed.suppliedContentsHash = value;
|
|
154
|
+
if (arg === "--supplied-contents-hash")
|
|
155
|
+
i += 1;
|
|
156
|
+
}
|
|
157
|
+
else if (arg === "--controller-observed-hash" ||
|
|
158
|
+
arg?.startsWith("--controller-observed-hash=")) {
|
|
159
|
+
const value = arg === "--controller-observed-hash"
|
|
160
|
+
? argv[i + 1]
|
|
161
|
+
: arg.slice("--controller-observed-hash=".length);
|
|
162
|
+
if (value === undefined) {
|
|
163
|
+
return {
|
|
164
|
+
...parsed,
|
|
165
|
+
error: "argument --controller-observed-hash: expected one argument",
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
parsed.controllerObservedHash = value;
|
|
169
|
+
if (arg === "--controller-observed-hash")
|
|
170
|
+
i += 1;
|
|
171
|
+
}
|
|
172
|
+
else if (arg === "--criteria-digest" || arg?.startsWith("--criteria-digest=")) {
|
|
173
|
+
const value = arg === "--criteria-digest" ? argv[i + 1] : arg.slice("--criteria-digest=".length);
|
|
174
|
+
if (value === undefined) {
|
|
175
|
+
return { ...parsed, error: "argument --criteria-digest: expected one argument" };
|
|
176
|
+
}
|
|
177
|
+
parsed.criteriaDigest = value;
|
|
178
|
+
if (arg === "--criteria-digest")
|
|
179
|
+
i += 1;
|
|
180
|
+
}
|
|
181
|
+
else if (arg === "--reviewed-file" || arg?.startsWith("--reviewed-file=")) {
|
|
182
|
+
const value = arg === "--reviewed-file" ? argv[i + 1] : arg.slice("--reviewed-file=".length);
|
|
183
|
+
if (value === undefined) {
|
|
184
|
+
return { ...parsed, error: "argument --reviewed-file: expected one argument" };
|
|
185
|
+
}
|
|
186
|
+
parsed.reviewedFiles.push(value);
|
|
187
|
+
if (arg === "--reviewed-file")
|
|
188
|
+
i += 1;
|
|
189
|
+
}
|
|
190
|
+
else if (arg === "--reviewer-report-ref" || arg?.startsWith("--reviewer-report-ref=")) {
|
|
191
|
+
const value = arg === "--reviewer-report-ref" ? argv[i + 1] : arg.slice("--reviewer-report-ref=".length);
|
|
192
|
+
if (value === undefined) {
|
|
193
|
+
return { ...parsed, error: "argument --reviewer-report-ref: expected one argument" };
|
|
194
|
+
}
|
|
195
|
+
parsed.reviewerReportRef = value;
|
|
196
|
+
if (arg === "--reviewer-report-ref")
|
|
197
|
+
i += 1;
|
|
198
|
+
}
|
|
199
|
+
else if (arg === "--mark-complete") {
|
|
200
|
+
parsed.markComplete = true;
|
|
201
|
+
}
|
|
202
|
+
else if (arg === "--skill-open") {
|
|
203
|
+
parsed.skillOpen = true;
|
|
204
|
+
}
|
|
205
|
+
else if (arg === "--evaluate") {
|
|
206
|
+
parsed.evaluate = true;
|
|
207
|
+
}
|
|
208
|
+
else if (arg === "--repo" || arg?.startsWith("--repo=")) {
|
|
209
|
+
const value = arg === "--repo" ? argv[i + 1] : arg.slice("--repo=".length);
|
|
210
|
+
if (value === undefined)
|
|
211
|
+
return { ...parsed, error: "argument --repo: expected one argument" };
|
|
212
|
+
parsed.repo = value;
|
|
213
|
+
if (arg === "--repo")
|
|
214
|
+
i += 1;
|
|
215
|
+
}
|
|
216
|
+
else if (arg === "--base-sha" || arg?.startsWith("--base-sha=")) {
|
|
217
|
+
const value = arg === "--base-sha" ? argv[i + 1] : arg.slice("--base-sha=".length);
|
|
218
|
+
if (value === undefined)
|
|
219
|
+
return { ...parsed, error: "argument --base-sha: expected one argument" };
|
|
220
|
+
parsed.baseSha = value;
|
|
221
|
+
if (arg === "--base-sha")
|
|
222
|
+
i += 1;
|
|
223
|
+
}
|
|
224
|
+
else if (arg === "--head-sha" || arg?.startsWith("--head-sha=")) {
|
|
225
|
+
const value = arg === "--head-sha" ? argv[i + 1] : arg.slice("--head-sha=".length);
|
|
226
|
+
if (value === undefined)
|
|
227
|
+
return { ...parsed, error: "argument --head-sha: expected one argument" };
|
|
228
|
+
parsed.headSha = value;
|
|
229
|
+
if (arg === "--head-sha")
|
|
230
|
+
i += 1;
|
|
231
|
+
}
|
|
232
|
+
else if (arg === "--tree-hash" || arg?.startsWith("--tree-hash=")) {
|
|
233
|
+
const value = arg === "--tree-hash" ? argv[i + 1] : arg.slice("--tree-hash=".length);
|
|
234
|
+
if (value === undefined)
|
|
235
|
+
return { ...parsed, error: "argument --tree-hash: expected one argument" };
|
|
236
|
+
parsed.treeHash = value;
|
|
237
|
+
if (arg === "--tree-hash")
|
|
238
|
+
i += 1;
|
|
239
|
+
}
|
|
240
|
+
else if (arg === "--pr-body-hash" || arg?.startsWith("--pr-body-hash=")) {
|
|
241
|
+
const value = arg === "--pr-body-hash" ? argv[i + 1] : arg.slice("--pr-body-hash=".length);
|
|
242
|
+
if (value === undefined) {
|
|
243
|
+
return { ...parsed, error: "argument --pr-body-hash: expected one argument" };
|
|
244
|
+
}
|
|
245
|
+
parsed.prBodyHash = value;
|
|
246
|
+
if (arg === "--pr-body-hash")
|
|
247
|
+
i += 1;
|
|
248
|
+
}
|
|
249
|
+
else if (arg === "--pr-node-id" || arg?.startsWith("--pr-node-id=")) {
|
|
250
|
+
const value = arg === "--pr-node-id" ? argv[i + 1] : arg.slice("--pr-node-id=".length);
|
|
251
|
+
if (value === undefined) {
|
|
252
|
+
return { ...parsed, error: "argument --pr-node-id: expected one argument" };
|
|
253
|
+
}
|
|
254
|
+
parsed.prNodeId = value;
|
|
255
|
+
if (arg === "--pr-node-id")
|
|
256
|
+
i += 1;
|
|
257
|
+
}
|
|
258
|
+
else if (arg === "--approved-revision" || arg?.startsWith("--approved-revision=")) {
|
|
259
|
+
const value = arg === "--approved-revision" ? argv[i + 1] : arg.slice("--approved-revision=".length);
|
|
260
|
+
if (value === undefined) {
|
|
261
|
+
return { ...parsed, error: "argument --approved-revision: expected one argument" };
|
|
262
|
+
}
|
|
263
|
+
parsed.approvedRevision = value;
|
|
264
|
+
if (arg === "--approved-revision")
|
|
265
|
+
i += 1;
|
|
266
|
+
}
|
|
267
|
+
else if (arg === "--scope" || arg?.startsWith("--scope=")) {
|
|
268
|
+
const value = arg === "--scope" ? argv[i + 1] : arg.slice("--scope=".length);
|
|
269
|
+
if (value === undefined)
|
|
270
|
+
return { ...parsed, error: "argument --scope: expected one argument" };
|
|
271
|
+
parsed.scope.push(value);
|
|
272
|
+
if (arg === "--scope")
|
|
273
|
+
i += 1;
|
|
274
|
+
}
|
|
275
|
+
else if (arg === "--acceptance" || arg?.startsWith("--acceptance=")) {
|
|
276
|
+
const value = arg === "--acceptance" ? argv[i + 1] : arg.slice("--acceptance=".length);
|
|
277
|
+
if (value === undefined) {
|
|
278
|
+
return { ...parsed, error: "argument --acceptance: expected one argument" };
|
|
279
|
+
}
|
|
280
|
+
parsed.acceptance = value;
|
|
281
|
+
if (arg === "--acceptance")
|
|
282
|
+
i += 1;
|
|
283
|
+
}
|
|
284
|
+
else if (arg === "--generation" || arg?.startsWith("--generation=")) {
|
|
285
|
+
const value = arg === "--generation" ? argv[i + 1] : arg.slice("--generation=".length);
|
|
286
|
+
if (value === undefined) {
|
|
287
|
+
return { ...parsed, error: "argument --generation: expected one argument" };
|
|
288
|
+
}
|
|
289
|
+
const n = Number.parseInt(value, 10);
|
|
290
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
291
|
+
return { ...parsed, error: "argument --generation: expected a positive integer" };
|
|
292
|
+
}
|
|
293
|
+
parsed.generation = n;
|
|
294
|
+
if (arg === "--generation")
|
|
295
|
+
i += 1;
|
|
296
|
+
}
|
|
297
|
+
else if (arg === "--skill-version" || arg?.startsWith("--skill-version=")) {
|
|
298
|
+
const value = arg === "--skill-version" ? argv[i + 1] : arg.slice("--skill-version=".length);
|
|
299
|
+
if (value === undefined) {
|
|
300
|
+
return { ...parsed, error: "argument --skill-version: expected one argument" };
|
|
301
|
+
}
|
|
302
|
+
parsed.skillVersion = value;
|
|
303
|
+
if (arg === "--skill-version")
|
|
304
|
+
i += 1;
|
|
305
|
+
}
|
|
306
|
+
else if (arg === "--policy-version" || arg?.startsWith("--policy-version=")) {
|
|
307
|
+
const value = arg === "--policy-version" ? argv[i + 1] : arg.slice("--policy-version=".length);
|
|
308
|
+
if (value === undefined) {
|
|
309
|
+
return { ...parsed, error: "argument --policy-version: expected one argument" };
|
|
310
|
+
}
|
|
311
|
+
parsed.policyVersion = value;
|
|
312
|
+
if (arg === "--policy-version")
|
|
313
|
+
i += 1;
|
|
314
|
+
}
|
|
315
|
+
else if (arg === "--run-id" || arg?.startsWith("--run-id=")) {
|
|
316
|
+
const value = arg === "--run-id" ? argv[i + 1] : arg.slice("--run-id=".length);
|
|
317
|
+
if (value === undefined)
|
|
318
|
+
return { ...parsed, error: "argument --run-id: expected one argument" };
|
|
319
|
+
parsed.runId = value;
|
|
320
|
+
if (arg === "--run-id")
|
|
321
|
+
i += 1;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return parsed;
|
|
328
|
+
}
|
|
329
|
+
function emit(json, payload, text, err) {
|
|
330
|
+
const line = json ? `${JSON.stringify(payload)}\n` : `${text}\n`;
|
|
331
|
+
if (err)
|
|
332
|
+
process.stderr.write(line);
|
|
333
|
+
else
|
|
334
|
+
process.stdout.write(line);
|
|
335
|
+
}
|
|
336
|
+
function asPhaseId(value) {
|
|
337
|
+
return PRE_PR_PHASE_IDS.includes(value) ? value : null;
|
|
338
|
+
}
|
|
339
|
+
export function run(argv) {
|
|
340
|
+
const args = parseArgs(argv);
|
|
341
|
+
if (args.help) {
|
|
342
|
+
process.stdout.write(USAGE);
|
|
343
|
+
return 0;
|
|
344
|
+
}
|
|
345
|
+
if (args.error !== undefined) {
|
|
346
|
+
process.stderr.write(`pre_pr_run: ${args.error}\n`);
|
|
347
|
+
return 2;
|
|
348
|
+
}
|
|
349
|
+
if (args.skillOpen) {
|
|
350
|
+
const d = noteSkillFileOpen();
|
|
351
|
+
emit(args.json, d, d.message, true);
|
|
352
|
+
return 1;
|
|
353
|
+
}
|
|
354
|
+
const store = getDefaultPrePrStore();
|
|
355
|
+
if (args.markComplete) {
|
|
356
|
+
const d = markComplete(store, args.runId ?? "");
|
|
357
|
+
emit(args.json, d, d.message, true);
|
|
358
|
+
return 1;
|
|
359
|
+
}
|
|
360
|
+
if (args.observeCommand || args.observeSemantic) {
|
|
361
|
+
if (args.runId === null || args.runId.length === 0) {
|
|
362
|
+
process.stderr.write("pre_pr_run: observe requires --run-id\n");
|
|
363
|
+
return 2;
|
|
364
|
+
}
|
|
365
|
+
if (args.phase === null || args.phase.length === 0) {
|
|
366
|
+
process.stderr.write("pre_pr_run: observe requires --phase\n");
|
|
367
|
+
return 2;
|
|
368
|
+
}
|
|
369
|
+
const phase = asPhaseId(args.phase);
|
|
370
|
+
if (phase === null) {
|
|
371
|
+
process.stderr.write(`pre_pr_run: unknown phase ${args.phase}\n`);
|
|
372
|
+
return 2;
|
|
373
|
+
}
|
|
374
|
+
const rec = store.getById(args.runId);
|
|
375
|
+
if (args.observeCommand) {
|
|
376
|
+
if (args.exitCode === null) {
|
|
377
|
+
process.stderr.write("pre_pr_run: --observe-command requires --exit-code\n");
|
|
378
|
+
return 2;
|
|
379
|
+
}
|
|
380
|
+
if (args.skipReason !== null && args.skipReason.length > 0 && args.exitCode === 0) {
|
|
381
|
+
process.stderr.write("pre_pr_run: skip requires a non-zero --exit-code plus --skip-reason\n");
|
|
382
|
+
return 2;
|
|
383
|
+
}
|
|
384
|
+
const spec = phaseSpec(phase);
|
|
385
|
+
const d = observeCommandPhase(store, args.runId, {
|
|
386
|
+
phaseId: phase,
|
|
387
|
+
command: args.command.length > 0 ? args.command : (spec.command ?? ""),
|
|
388
|
+
exitCode: args.exitCode,
|
|
389
|
+
inputHash: args.inputHash ?? rec?.inputHash ?? "",
|
|
390
|
+
skipReason: args.skipReason,
|
|
391
|
+
});
|
|
392
|
+
emit(args.json, d, d.message, !d.ok);
|
|
393
|
+
return d.ok ? 0 : 1;
|
|
394
|
+
}
|
|
395
|
+
if (args.suppliedContentsHash.length === 0) {
|
|
396
|
+
process.stderr.write("pre_pr_run: --observe-semantic requires --supplied-contents-hash\n");
|
|
397
|
+
return 2;
|
|
398
|
+
}
|
|
399
|
+
if (args.reviewedFiles.length === 0) {
|
|
400
|
+
process.stderr.write("pre_pr_run: --observe-semantic requires --reviewed-file\n");
|
|
401
|
+
return 2;
|
|
402
|
+
}
|
|
403
|
+
const observed = computeControllerObservedHash({ reviewedFiles: args.reviewedFiles });
|
|
404
|
+
if (observed === null) {
|
|
405
|
+
process.stderr.write("pre_pr_run: --observe-semantic could not hash reviewed-file contents\n");
|
|
406
|
+
return 2;
|
|
407
|
+
}
|
|
408
|
+
if (args.controllerObservedHash.length > 0 && args.controllerObservedHash !== observed) {
|
|
409
|
+
process.stderr.write("pre_pr_run: --controller-observed-hash does not match independently hashed reviewed-file contents\n");
|
|
410
|
+
return 1;
|
|
411
|
+
}
|
|
412
|
+
if (args.suppliedContentsHash !== observed) {
|
|
413
|
+
process.stderr.write("pre_pr_run: --supplied-contents-hash does not match independently hashed reviewed-file contents\n");
|
|
414
|
+
return 1;
|
|
415
|
+
}
|
|
416
|
+
const d = submitReviewerReport(store, args.runId, {
|
|
417
|
+
phaseId: phase,
|
|
418
|
+
reviewedFileManifest: args.reviewedFiles,
|
|
419
|
+
suppliedContentsHash: args.suppliedContentsHash,
|
|
420
|
+
criteriaDigest: args.criteriaDigest ?? rec?.criteria.digest ?? "",
|
|
421
|
+
reviewerReportRef: args.reviewerReportRef,
|
|
422
|
+
controllerObservedHash: observed,
|
|
423
|
+
});
|
|
424
|
+
emit(args.json, d, d.message, !d.ok);
|
|
425
|
+
return d.ok ? 0 : 1;
|
|
426
|
+
}
|
|
427
|
+
if (args.evaluate) {
|
|
428
|
+
if (args.repo.length === 0 || args.baseSha.length === 0 || args.headSha.length === 0) {
|
|
429
|
+
process.stderr.write("pre_pr_run: --evaluate requires --repo --base-sha --head-sha\n");
|
|
430
|
+
return 2;
|
|
431
|
+
}
|
|
432
|
+
if (args.prBodyHash.length === 0) {
|
|
433
|
+
process.stderr.write("pre_pr_run: --evaluate requires --pr-body-hash\n");
|
|
434
|
+
return 2;
|
|
435
|
+
}
|
|
436
|
+
const record = resolveRecordFromStore(store, {
|
|
437
|
+
id: args.runId,
|
|
438
|
+
prNodeId: args.prNodeId,
|
|
439
|
+
});
|
|
440
|
+
const headSource = args.approvedRevision.length > 0
|
|
441
|
+
? args.approvedRevision
|
|
442
|
+
: (record?.criteria.sourceRevisionSha ?? args.headSha);
|
|
443
|
+
const liveApproved = digestApprovedCriteria({
|
|
444
|
+
sourceRevisionSha: headSource,
|
|
445
|
+
scopePaths: args.scope,
|
|
446
|
+
acceptanceText: args.acceptance,
|
|
447
|
+
generation: args.generation,
|
|
448
|
+
});
|
|
449
|
+
const d = evaluateLivePrePrCheck({
|
|
450
|
+
store,
|
|
451
|
+
liveBinding: {
|
|
452
|
+
repo: args.repo,
|
|
453
|
+
baseSha: args.baseSha,
|
|
454
|
+
headSha: args.headSha,
|
|
455
|
+
prNodeId: args.prNodeId,
|
|
456
|
+
prBodyHash: args.prBodyHash,
|
|
457
|
+
},
|
|
458
|
+
presentedRunId: args.runId,
|
|
459
|
+
approvedCriteria: liveApproved,
|
|
460
|
+
currentGeneration: args.generation,
|
|
461
|
+
headCriteria: liveApproved,
|
|
462
|
+
});
|
|
463
|
+
emit(args.json, d, d.message, !d.ok);
|
|
464
|
+
return d.ok ? 0 : 1;
|
|
465
|
+
}
|
|
466
|
+
if (args.complete) {
|
|
467
|
+
if (args.runId === null || args.runId.length === 0) {
|
|
468
|
+
process.stderr.write("pre_pr_run: --complete requires --run-id\n");
|
|
469
|
+
return 2;
|
|
470
|
+
}
|
|
471
|
+
const d = completeRun(store, controllerPublisher(), args.runId);
|
|
472
|
+
emit(args.json, d, d.message, !d.ok);
|
|
473
|
+
return d.ok ? 0 : 1;
|
|
474
|
+
}
|
|
475
|
+
if (args.repo.length === 0 ||
|
|
476
|
+
args.baseSha.length === 0 ||
|
|
477
|
+
args.headSha.length === 0 ||
|
|
478
|
+
args.treeHash.length === 0 ||
|
|
479
|
+
args.prBodyHash.length === 0 ||
|
|
480
|
+
args.approvedRevision.length === 0) {
|
|
481
|
+
process.stderr.write("pre_pr_run: start requires --repo --base-sha --head-sha --tree-hash --pr-body-hash --approved-revision\n");
|
|
482
|
+
return 2;
|
|
483
|
+
}
|
|
484
|
+
const criteria = digestApprovedCriteria({
|
|
485
|
+
sourceRevisionSha: args.approvedRevision,
|
|
486
|
+
scopePaths: args.scope,
|
|
487
|
+
acceptanceText: args.acceptance,
|
|
488
|
+
generation: args.generation,
|
|
489
|
+
});
|
|
490
|
+
const started = startControllerRun(store, {
|
|
491
|
+
repo: args.repo,
|
|
492
|
+
baseSha: args.baseSha,
|
|
493
|
+
headSha: args.headSha,
|
|
494
|
+
treeHash: args.treeHash,
|
|
495
|
+
prBodyHash: args.prBodyHash,
|
|
496
|
+
prNodeId: args.prNodeId,
|
|
497
|
+
criteria,
|
|
498
|
+
skillVersion: args.skillVersion,
|
|
499
|
+
policyVersion: args.policyVersion,
|
|
500
|
+
approvedRevisionSha: args.approvedRevision,
|
|
501
|
+
runId: args.runId ?? undefined,
|
|
502
|
+
});
|
|
503
|
+
if (!started.ok) {
|
|
504
|
+
emit(args.json, started.decision, started.decision.message, true);
|
|
505
|
+
return 1;
|
|
506
|
+
}
|
|
507
|
+
const payload = { ok: started.ok, runId: started.runId, hint: "run id is a lookup hint only" };
|
|
508
|
+
emit(args.json, payload, `started ${started.runId} (lookup hint only; private store is authoritative)`, false);
|
|
509
|
+
return 0;
|
|
510
|
+
}
|
|
511
|
+
if (isDirectEntrypoint(import.meta.url)) {
|
|
512
|
+
process.exit(run(process.argv.slice(2)));
|
|
513
|
+
}
|
|
514
|
+
//# sourceMappingURL=pre-pr-run.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { runSpecReconstructCli } from "@deftai/directive-core/spec-reconstruct";
|
|
4
|
+
export function runSpecReconstructCliEntry(argv) {
|
|
5
|
+
const result = runSpecReconstructCli(argv);
|
|
6
|
+
if (result.stdout.length > 0)
|
|
7
|
+
process.stdout.write(result.stdout);
|
|
8
|
+
if (result.stderr.length > 0)
|
|
9
|
+
process.stderr.write(result.stderr);
|
|
10
|
+
return result.exitCode;
|
|
11
|
+
}
|
|
12
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
13
|
+
process.exit(runSpecReconstructCliEntry(process.argv.slice(2)));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=spec-reconstruct-cli.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export declare const SUBAGENT_PRE_CANCEL_HELP = "subagent:pre-cancel \u2014 query-before-cancel gate (#5278)\n\nUsage:\n task subagent:pre-cancel -- --agent <id> --canceller-id <id> [options]\n\nExit 0 only when one ordered branch clears:\n (a) canceller-authored status steer (kind note|correction) + matching ack\n OR observed first-seen window (default 3 minutes; PA-18 forward skew only)\n (b) heartbeat STALE/missing under startup grace from --dispatch-started-at\n (c) --force --reason <text>\n\nOptions:\n --agent ID Target child agent_id (required)\n --canceller-id ID Canceller identity; must match steer writer_id for (a)\n --target-id PATH Worktree root (resolves steer/scratch/first-seen under it)\n --steer-dir PATH Steer inbox dir (default: <cwd|target>/.deft-scratch/subagent-steer)\n --scratch-dir PATH Heartbeat dir (default: <cwd|target>/.deft-scratch/subagent-status)\n --first-seen-dir PATH First-seen stamps (default: .../subagent-steer-firstseen)\n --dispatch-started-at ISO DeliveryAttemptRecord.startedAt for grace path (b)\n --expected-worker-id ID Refuse when agent does not match current attempt worker\n --observed-window-seconds N Default 180\n --force Explicit force clear (requires --reason)\n --reason TEXT Printed force reason\n --json Machine-readable verdict\n\nExit codes:\n 0 Pre-cancel green\n 1 Refused (gate red)\n 2 Config / usage error\n";
|
|
3
|
+
export interface SubagentPreCancelArgs {
|
|
4
|
+
agentId: string | null;
|
|
5
|
+
cancellerId: string | null;
|
|
6
|
+
targetId: string | null;
|
|
7
|
+
steerDir: string | null;
|
|
8
|
+
scratchDir: string | null;
|
|
9
|
+
firstSeenDir: string | null;
|
|
10
|
+
dispatchStartedAt: string | null;
|
|
11
|
+
expectedWorkerId: string | null;
|
|
12
|
+
observedWindowSeconds: number | null;
|
|
13
|
+
force: boolean;
|
|
14
|
+
forceReason: string | null;
|
|
15
|
+
emitJson: boolean;
|
|
16
|
+
help: boolean;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function parseSubagentPreCancelArgs(argv: readonly string[]): SubagentPreCancelArgs;
|
|
20
|
+
export declare function run(argv: readonly string[], cwd?: string): number;
|
|
21
|
+
//# sourceMappingURL=subagent-pre-cancel.d.ts.map
|