@sabaiway/agent-workflow-kit 1.37.1 → 1.39.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/CHANGELOG.md +113 -0
- package/README.md +3 -3
- package/SKILL.md +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/fold-completeness.md +7 -3
- package/references/modes/gates.md +5 -3
- package/references/modes/review-ledger.md +12 -7
- package/references/modes/velocity.md +1 -1
- package/tools/changed-surface.mjs +294 -0
- package/tools/commands.mjs +3 -3
- package/tools/fold-completeness-run.mjs +310 -139
- package/tools/fold-completeness.mjs +292 -77
- package/tools/procedures.mjs +1 -1
- package/tools/review-ledger-write.mjs +241 -43
- package/tools/review-ledger.mjs +425 -43
- package/tools/run-gates.mjs +58 -7
- package/tools/seed-gates.mjs +2 -2
package/tools/run-gates.mjs
CHANGED
|
@@ -18,16 +18,25 @@
|
|
|
18
18
|
// Honest outcomes — each distinct, never a silent green (the exit-code table + the summary-line
|
|
19
19
|
// schema are pinned by run-gates.test.mjs):
|
|
20
20
|
// 0 ok · 1 gate failure · 2 usage · 3 missing declaration · 4 empty gates list ·
|
|
21
|
-
// 5 malformed/invalid declaration · 6 bash unavailable
|
|
22
|
-
//
|
|
23
|
-
// never a silent reinterpretation
|
|
21
|
+
// 5 malformed/invalid declaration · 6 bash unavailable · 7 --record asked but the gate-run
|
|
22
|
+
// record could not be written. Gate `cmd` lines are BASH command lines (brace/glob expansion);
|
|
23
|
+
// a host without bash gets the loud exit-6 preflight error, never a silent reinterpretation
|
|
24
|
+
// under another shell.
|
|
24
25
|
//
|
|
25
|
-
// The runner itself WRITES NOTHING
|
|
26
|
+
// The runner itself WRITES NOTHING by default. `--record` (BUGFREE-2 / AD-048, D5) mints ONE
|
|
27
|
+
// v4 `gate-run` record — the green-baseline receipt the review-ledger writer's D5 tooth consumes —
|
|
28
|
+
// by DELEGATING to the ledger's sole writer (recordGateRun in review-ledger-write.mjs): this
|
|
29
|
+
// runner never opens the ledger file itself (an import/structure pin holds the boundary). The
|
|
30
|
+
// record carries the FULL declaration + exactly what ran (a --only subset records honestly as a
|
|
31
|
+
// subset — it never satisfies quality-green) + the tree fingerprint BEFORE and AFTER the run (a
|
|
32
|
+
// mutating gate attests no particular tree). Dependency-free, Node >= 18. No side effects on import.
|
|
26
33
|
|
|
27
34
|
import { readFileSync, lstatSync } from 'node:fs';
|
|
28
35
|
import { join } from 'node:path';
|
|
29
36
|
import { spawnSync } from 'node:child_process';
|
|
30
37
|
import { pathToFileURL } from 'node:url';
|
|
38
|
+
import { computeTreeFingerprint } from './review-state.mjs';
|
|
39
|
+
import { recordGateRun } from './review-ledger-write.mjs';
|
|
31
40
|
|
|
32
41
|
// The per-project declaration (strict JSON, hand-editable). cwd-relative — errors show a path the
|
|
33
42
|
// user can open (the orchestration-config CONFIG_REL idiom).
|
|
@@ -42,6 +51,10 @@ export const EXIT = Object.freeze({
|
|
|
42
51
|
empty: 4,
|
|
43
52
|
malformed: 5,
|
|
44
53
|
noBash: 6,
|
|
54
|
+
// --record was asked for but the gate-run record could not be written (no in-flight loop, a
|
|
55
|
+
// malformed ledger, an fs refusal): the invocation's contract included a ledger receipt — not
|
|
56
|
+
// delivering it is its own loud outcome, never folded into ok/fail.
|
|
57
|
+
recordFailed: 7,
|
|
45
58
|
});
|
|
46
59
|
|
|
47
60
|
// A tagged failure carrying its process exit code (the shared orchestration-config idiom).
|
|
@@ -54,12 +67,15 @@ const SPAWN_FAILED_CODE = -1;
|
|
|
54
67
|
const MAX_GATE_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
55
68
|
|
|
56
69
|
const USAGE = [
|
|
57
|
-
'usage: run-gates.mjs [--cwd <dir>] [--only <id>]... [--help]',
|
|
70
|
+
'usage: run-gates.mjs [--cwd <dir>] [--only <id>]... [--record] [--help]',
|
|
58
71
|
'',
|
|
59
72
|
`Runs the gates declared in <cwd>/${GATES_REL} (one bash command line each, project root as cwd).`,
|
|
60
73
|
'Prints a per-gate PASS/FAIL table + one machine-readable summary line; exit 0 iff all green.',
|
|
74
|
+
'--record additionally mints ONE v4 gate-run record into the review ledger via its sole writer',
|
|
75
|
+
'(the D5 green-baseline receipt; needs a single in-flight plan): the full declaration + what ran',
|
|
76
|
+
'+ the pre/post tree fingerprints. A red run records honestly; a --only subset records as a subset.',
|
|
61
77
|
`Exit codes: 0 ok · 1 gate failure · 2 usage · 3 missing declaration · 4 empty gates list ·`,
|
|
62
|
-
'5 malformed/invalid declaration · 6 bash unavailable.',
|
|
78
|
+
'5 malformed/invalid declaration · 6 bash unavailable · 7 --record asked but the record failed.',
|
|
63
79
|
].join('\n');
|
|
64
80
|
|
|
65
81
|
// ── declaration validation (malformed → exit 5, loud `path: reason`) ─────────────────
|
|
@@ -218,7 +234,7 @@ export const composeSummaryLine = ({ status, results = [] }) => {
|
|
|
218
234
|
// ── CLI ───────────────────────────────────────────────────────────────────────────────
|
|
219
235
|
|
|
220
236
|
const parseArgs = (argv) => {
|
|
221
|
-
const opts = { cwd: null, only: [], help: false };
|
|
237
|
+
const opts = { cwd: null, only: [], record: false, help: false };
|
|
222
238
|
for (let i = 0; i < argv.length; i += 1) {
|
|
223
239
|
const arg = argv[i];
|
|
224
240
|
if (arg === '--help' || arg === '-h') {
|
|
@@ -231,6 +247,8 @@ const parseArgs = (argv) => {
|
|
|
231
247
|
i += 1;
|
|
232
248
|
if (argv[i] === undefined) throw fail(EXIT.usage, '--only requires a gate id argument');
|
|
233
249
|
opts.only.push(argv[i]);
|
|
250
|
+
} else if (arg === '--record') {
|
|
251
|
+
opts.record = true;
|
|
234
252
|
} else {
|
|
235
253
|
throw fail(EXIT.usage, `unknown argument "${arg}"\n${USAGE}`);
|
|
236
254
|
}
|
|
@@ -244,12 +262,15 @@ const parseArgs = (argv) => {
|
|
|
244
262
|
export const runCli = (argv, deps = {}) => {
|
|
245
263
|
const {
|
|
246
264
|
cwd = process.cwd(),
|
|
265
|
+
env = process.env,
|
|
247
266
|
log = console.log,
|
|
248
267
|
logError = console.error,
|
|
249
268
|
spawn = spawnGateViaBash,
|
|
250
269
|
readFile,
|
|
251
270
|
lstat,
|
|
252
271
|
now,
|
|
272
|
+
record = recordGateRun,
|
|
273
|
+
fingerprint = computeTreeFingerprint,
|
|
253
274
|
} = deps;
|
|
254
275
|
try {
|
|
255
276
|
const opts = parseArgs(argv);
|
|
@@ -283,10 +304,40 @@ export const runCli = (argv, deps = {}) => {
|
|
|
283
304
|
log(composeSummaryLine({ status: 'no-bash' }));
|
|
284
305
|
return EXIT.noBash;
|
|
285
306
|
}
|
|
307
|
+
const fingerprintBefore = opts.record ? fingerprint(projectDir) : null;
|
|
286
308
|
const results = runGates(selected, { cwd: projectDir, spawn, log, now });
|
|
287
309
|
for (const line of formatTable(results)) log(line);
|
|
288
310
|
const allGreen = results.every((result) => result.ok);
|
|
311
|
+
// The gate-run record (D5): minted for green AND red runs alike (an honest red is telemetry
|
|
312
|
+
// fuel), via the ledger's sole writer. Emitted BEFORE the summary line — the machine summary
|
|
313
|
+
// stays the LAST line of every non-usage outcome (pinned).
|
|
314
|
+
let recordError = null;
|
|
315
|
+
if (opts.record) {
|
|
316
|
+
const failing = results.filter((result) => !result.ok);
|
|
317
|
+
try {
|
|
318
|
+
const { writtenPath } = record({
|
|
319
|
+
cwd: projectDir,
|
|
320
|
+
env,
|
|
321
|
+
declared: declaration.gates.map(({ id, cmd }) => ({ id, cmd })),
|
|
322
|
+
results: results.map(({ id, ok, code }) => ({ id, ok, code })),
|
|
323
|
+
summary: {
|
|
324
|
+
status: allGreen ? 'ok' : 'fail',
|
|
325
|
+
gates: results.length,
|
|
326
|
+
passed: results.length - failing.length,
|
|
327
|
+
failed: failing.length,
|
|
328
|
+
failedIds: failing.map((result) => result.id),
|
|
329
|
+
},
|
|
330
|
+
fingerprintBefore,
|
|
331
|
+
fingerprintAfter: fingerprint(projectDir),
|
|
332
|
+
});
|
|
333
|
+
log(`[run-gates] gate-run recorded → ${writtenPath}`);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
recordError = err;
|
|
336
|
+
logError(`[run-gates] --record failed: ${err.message}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
289
339
|
log(composeSummaryLine({ status: allGreen ? 'ok' : 'fail', results }));
|
|
340
|
+
if (recordError) return EXIT.recordFailed;
|
|
290
341
|
return allGreen ? EXIT.ok : EXIT.fail;
|
|
291
342
|
} catch (err) {
|
|
292
343
|
logError(`[run-gates] ${err.message}`);
|
package/tools/seed-gates.mjs
CHANGED
|
@@ -208,7 +208,7 @@ export const reviewStateCandidate = (cwd, deps = {}) => {
|
|
|
208
208
|
|
|
209
209
|
// The conditional review-LEDGER candidate (AD-045) — the SAME consent + conditional rule as the
|
|
210
210
|
// review-state candidate (offered ONLY when plan-execution.review is reviewed/council), keyed on the
|
|
211
|
-
// same slot, path resolved + QUOTED. It gates the review-ROUND ledger (converged /
|
|
211
|
+
// same slot, path resolved + QUOTED. It gates the review-ROUND ledger (converged / resolved-residual);
|
|
212
212
|
// review-state gates receipt PRESENCE. Both may be offered together — distinct axes.
|
|
213
213
|
export const reviewLedgerCandidate = (cwd, deps = {}) => {
|
|
214
214
|
const toolPath = deps.reviewLedgerTool ?? REVIEW_LEDGER_TOOL;
|
|
@@ -228,7 +228,7 @@ export const reviewLedgerCandidate = (cwd, deps = {}) => {
|
|
|
228
228
|
return {
|
|
229
229
|
candidate: {
|
|
230
230
|
id: 'review-ledger',
|
|
231
|
-
title: 'Review-round ledger: the in-flight loop is converged or
|
|
231
|
+
title: 'Review-round ledger: the in-flight loop is converged or resolved-residual',
|
|
232
232
|
cmd: `node "${toolPath}" --check`,
|
|
233
233
|
},
|
|
234
234
|
note: null,
|