@deftai/directive-core 0.100.0 → 0.101.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/classify.js +100 -23
- package/dist/authz/decompose-apply.d.ts +14 -0
- package/dist/authz/decompose-apply.js +93 -18
- package/dist/check/cached-orchestrator.d.ts +26 -5
- package/dist/check/cached-orchestrator.js +228 -6
- package/dist/check/gate-lists.d.ts +10 -4
- package/dist/check/gate-lists.js +19 -5
- package/dist/check/index.d.ts +3 -2
- package/dist/check/index.js +2 -1
- package/dist/check/named-cause.d.ts +45 -0
- package/dist/check/named-cause.js +121 -0
- package/dist/check/orchestrator.js +6 -1
- package/dist/doctor/help.d.ts +5 -0
- package/dist/doctor/help.js +31 -0
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.js +2 -0
- package/dist/doctor/main.js +58 -0
- package/dist/doctor/session-coda.d.ts +82 -0
- package/dist/doctor/session-coda.js +151 -0
- package/dist/doctor/types.d.ts +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/gitignore.js +2 -0
- package/dist/intake/issue-ingest.js +7 -0
- package/dist/policy/ac-pass-banking.d.ts +58 -0
- package/dist/policy/ac-pass-banking.js +150 -0
- package/dist/policy/ceremony-dial.d.ts +29 -0
- package/dist/policy/ceremony-dial.js +76 -0
- package/dist/policy/index.d.ts +1 -0
- package/dist/policy/index.js +15 -1
- package/dist/preflight-cache/evaluate.d.ts +3 -0
- package/dist/preflight-cache/evaluate.js +3 -0
- package/dist/product-first-done-gate/acceptance.d.ts +25 -0
- package/dist/product-first-done-gate/acceptance.js +247 -0
- package/dist/product-first-done-gate/check-mode.d.ts +45 -0
- package/dist/product-first-done-gate/check-mode.js +148 -0
- package/dist/product-first-done-gate/evaluate.d.ts +50 -0
- package/dist/product-first-done-gate/evaluate.js +255 -0
- package/dist/product-first-done-gate/index.d.ts +11 -0
- package/dist/product-first-done-gate/index.js +11 -0
- package/dist/product-first-done-gate/types.d.ts +64 -0
- package/dist/product-first-done-gate/types.js +61 -0
- package/dist/run-summary/emit.d.ts +56 -0
- package/dist/run-summary/emit.js +171 -0
- package/dist/run-summary/index.d.ts +4 -0
- package/dist/run-summary/index.js +4 -0
- package/dist/run-summary/path.d.ts +25 -0
- package/dist/run-summary/path.js +78 -0
- package/dist/run-summary/types.d.ts +76 -0
- package/dist/run-summary/types.js +21 -0
- package/dist/scope/acceptance-evidence.d.ts +34 -0
- package/dist/scope/acceptance-evidence.js +84 -10
- package/dist/scope/decompose.d.ts +5 -0
- package/dist/scope/decompose.js +11 -2
- package/dist/session/ac-pass-banking.d.ts +221 -0
- package/dist/session/ac-pass-banking.js +761 -0
- package/dist/session/deposit-sha.d.ts +49 -0
- package/dist/session/deposit-sha.js +121 -0
- package/dist/session/effort-budget.d.ts +6 -0
- package/dist/session/effort-budget.js +21 -3
- package/dist/session/index.d.ts +5 -0
- package/dist/session/index.js +5 -0
- package/dist/session/orientation-compression.d.ts +127 -0
- package/dist/session/orientation-compression.js +425 -0
- package/dist/session/orientation-state.d.ts +29 -0
- package/dist/session/orientation-state.js +85 -0
- package/dist/session/session-start.d.ts +25 -0
- package/dist/session/session-start.js +175 -0
- package/dist/session/toolchain-preflight.d.ts +64 -0
- package/dist/session/toolchain-preflight.js +151 -0
- package/dist/triage/bootstrap/gitignore.d.ts +1 -1
- package/dist/triage/bootstrap/gitignore.js +8 -2
- package/dist/triage/bootstrap/index.js +15 -3
- package/dist/triage/classify/index.d.ts +1 -0
- package/dist/triage/classify/index.js +2 -0
- package/dist/triage/classify/label-mirror.js +16 -0
- package/dist/triage/classify/mirror-discovery-tip.d.ts +95 -0
- package/dist/triage/classify/mirror-discovery-tip.js +234 -0
- package/dist/triage/reconcile/reconcile.js +28 -6
- package/dist/triage/summary/index.js +12 -4
- package/dist/triage/welcome/default-mode.js +16 -0
- package/dist/ts-check-lane/run-lane.js +21 -4
- package/dist/vbrief-validate/conformance.js +7 -0
- package/dist/vitest-runner/coverage-debt-teardown.js +16 -4
- package/package.json +11 -3
package/dist/authz/classify.js
CHANGED
|
@@ -204,11 +204,25 @@ const DOWNLOADER_DECODER_BINS = new Set([
|
|
|
204
204
|
"fetch",
|
|
205
205
|
"socat",
|
|
206
206
|
"lftp",
|
|
207
|
+
// #3288 residual after #3245: crypto / alt-download / pipe / archive bins.
|
|
208
|
+
"gpg",
|
|
209
|
+
"age",
|
|
210
|
+
"zstd",
|
|
211
|
+
"unzstd",
|
|
212
|
+
"sftp",
|
|
213
|
+
"wget2",
|
|
214
|
+
"http",
|
|
215
|
+
"https",
|
|
216
|
+
"yt-dlp",
|
|
217
|
+
"ytdlp",
|
|
218
|
+
"aria2",
|
|
219
|
+
"mbuffer",
|
|
220
|
+
"cpio",
|
|
207
221
|
]);
|
|
208
222
|
/**
|
|
209
223
|
* Archive extractors / alt writers that can plant via pathish operands without
|
|
210
|
-
* shell redirects (#3245). Used for pathish authz/kill scans (prefer deny)
|
|
211
|
-
* write-shape residual under UAT — not bare curl-class URL fetches.
|
|
224
|
+
* shell redirects (#3245 / #3288). Used for pathish authz/kill scans (prefer deny)
|
|
225
|
+
* and write-shape residual under UAT — not bare curl-class URL fetches.
|
|
212
226
|
*/
|
|
213
227
|
const ARCHIVE_ALT_WRITE_BINS = new Set([
|
|
214
228
|
"tar",
|
|
@@ -222,7 +236,54 @@ const ARCHIVE_ALT_WRITE_BINS = new Set([
|
|
|
222
236
|
"fetch",
|
|
223
237
|
"socat",
|
|
224
238
|
"lftp",
|
|
239
|
+
// #3288 residual after #3245.
|
|
240
|
+
"gpg",
|
|
241
|
+
"age",
|
|
242
|
+
"zstd",
|
|
243
|
+
"unzstd",
|
|
244
|
+
"sftp",
|
|
245
|
+
"wget2",
|
|
246
|
+
"http",
|
|
247
|
+
"https",
|
|
248
|
+
"yt-dlp",
|
|
249
|
+
"ytdlp",
|
|
250
|
+
"aria2",
|
|
251
|
+
"mbuffer",
|
|
252
|
+
"cpio",
|
|
225
253
|
]);
|
|
254
|
+
/**
|
|
255
|
+
* Bins whose pathish operands are scanned for authz/kill destinations (#3213 / #3245 / #3288).
|
|
256
|
+
* Prefer a Set over a long `||` chain so coverage counts one membership check, not N branches.
|
|
257
|
+
*/
|
|
258
|
+
const PROTECTED_POSITIONAL_BINS = new Set([
|
|
259
|
+
"scp",
|
|
260
|
+
"certutil",
|
|
261
|
+
"rclone",
|
|
262
|
+
"tar",
|
|
263
|
+
"bsdtar",
|
|
264
|
+
"unzip",
|
|
265
|
+
"7z",
|
|
266
|
+
"7za",
|
|
267
|
+
"7zr",
|
|
268
|
+
"socat",
|
|
269
|
+
"lftp",
|
|
270
|
+
// #3288 residual.
|
|
271
|
+
"sftp",
|
|
272
|
+
"cpio",
|
|
273
|
+
"gpg",
|
|
274
|
+
"age",
|
|
275
|
+
"zstd",
|
|
276
|
+
"unzstd",
|
|
277
|
+
"mbuffer",
|
|
278
|
+
]);
|
|
279
|
+
/** wget family (directory-prefix dest flags). */
|
|
280
|
+
const WGET_FAMILY_BINS = new Set(["wget", "wget2"]);
|
|
281
|
+
/** aria2 family (dir dest flags). */
|
|
282
|
+
const ARIA2_FAMILY_BINS = new Set(["aria2c", "aria2"]);
|
|
283
|
+
/** 7z family (attached -oDIR only). */
|
|
284
|
+
const SEVEN_Z_FAMILY_BINS = new Set(["7z", "7za", "7zr"]);
|
|
285
|
+
/** tar family (chdir -C / --directory). */
|
|
286
|
+
const TAR_FAMILY_BINS = new Set(["tar", "bsdtar"]);
|
|
226
287
|
/**
|
|
227
288
|
* File destination flags for downloaders/decoders (#3206).
|
|
228
289
|
* normalizeToken lowercases, so wget `-O` and curl `-o` share `-o`.
|
|
@@ -248,6 +309,13 @@ const TAR_DIR_DEST_FLAGS_EXACT = new Set(["-C"]);
|
|
|
248
309
|
const TAR_DIR_DEST_FLAGS_LOWER = new Set(["--directory"]);
|
|
249
310
|
/** unzip extract directory (#3245). */
|
|
250
311
|
const UNZIP_DIR_DEST_FLAGS = new Set(["-d"]);
|
|
312
|
+
/**
|
|
313
|
+
* cpio chdir before extract/create (#3288).
|
|
314
|
+
* Case-sensitive short form: POSIX cpio uses capital `-D`; lower `-d` is a create option bit.
|
|
315
|
+
* Long form `--directory` is accepted lowercased.
|
|
316
|
+
*/
|
|
317
|
+
const CPIO_DIR_DEST_FLAGS_EXACT = new Set(["-D"]);
|
|
318
|
+
const CPIO_DIR_DEST_FLAGS_LOWER = new Set(["--directory"]);
|
|
251
319
|
/**
|
|
252
320
|
* Symlink / hard-link plant bins (#3213). Absent from prior killWriteBins →
|
|
253
321
|
* `ln -sf … .deft-directive-disable` classified empty → UAT fail-open.
|
|
@@ -285,18 +353,27 @@ function isDownloaderDestFlag(flag, bin, rawFlag) {
|
|
|
285
353
|
if (bin === "scp")
|
|
286
354
|
return false;
|
|
287
355
|
// 7z family: only attached `-oDIR` (parsed in attached-short branch), not separate `-o PATH`.
|
|
288
|
-
if (bin
|
|
356
|
+
if (SEVEN_Z_FAMILY_BINS.has(bin)) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
// #3288: cpio `-o` is copy-out (create archive), not a file dest; dest is `-D` / `--directory`.
|
|
360
|
+
if (bin === "cpio") {
|
|
361
|
+
if (rawFlag !== undefined && CPIO_DIR_DEST_FLAGS_EXACT.has(rawFlag))
|
|
362
|
+
return true;
|
|
363
|
+
// Long form is case-insensitive via normalizeToken (`flag` already lowercased).
|
|
364
|
+
if (CPIO_DIR_DEST_FLAGS_LOWER.has(flag))
|
|
365
|
+
return true;
|
|
289
366
|
return false;
|
|
290
367
|
}
|
|
291
368
|
if (DOWNLOADER_FILE_DEST_FLAGS.has(flag))
|
|
292
369
|
return true;
|
|
293
370
|
if (bin === "curl" && CURL_DIR_DEST_FLAGS.has(flag))
|
|
294
371
|
return true;
|
|
295
|
-
if (bin
|
|
372
|
+
if (WGET_FAMILY_BINS.has(bin) && WGET_DIR_DEST_FLAGS.has(flag))
|
|
296
373
|
return true;
|
|
297
|
-
if (bin
|
|
374
|
+
if (ARIA2_FAMILY_BINS.has(bin) && ARIA2C_DIR_DEST_FLAGS.has(flag))
|
|
298
375
|
return true;
|
|
299
|
-
if (bin
|
|
376
|
+
if (TAR_FAMILY_BINS.has(bin)) {
|
|
300
377
|
if (rawFlag !== undefined && TAR_DIR_DEST_FLAGS_EXACT.has(rawFlag))
|
|
301
378
|
return true;
|
|
302
379
|
if (TAR_DIR_DEST_FLAGS_LOWER.has(flag))
|
|
@@ -386,17 +463,7 @@ function downloaderDecoderDestinations(tokens) {
|
|
|
386
463
|
// Segment breaks (`;`/`\n`/glued ops) prevent following-command overwrite.
|
|
387
464
|
let lastPositionalPath = null;
|
|
388
465
|
const protectedPathish = [];
|
|
389
|
-
const collectsProtectedPositionals = bin
|
|
390
|
-
bin === "certutil" ||
|
|
391
|
-
bin === "rclone" ||
|
|
392
|
-
bin === "tar" ||
|
|
393
|
-
bin === "bsdtar" ||
|
|
394
|
-
bin === "unzip" ||
|
|
395
|
-
bin === "7z" ||
|
|
396
|
-
bin === "7za" ||
|
|
397
|
-
bin === "7zr" ||
|
|
398
|
-
bin === "socat" ||
|
|
399
|
-
bin === "lftp";
|
|
466
|
+
const collectsProtectedPositionals = PROTECTED_POSITIONAL_BINS.has(bin);
|
|
400
467
|
while (i < tokens.length) {
|
|
401
468
|
const raw = tokens[i];
|
|
402
469
|
const n = normalizeToken(raw);
|
|
@@ -463,19 +530,23 @@ function downloaderDecoderDestinations(tokens) {
|
|
|
463
530
|
i++;
|
|
464
531
|
continue;
|
|
465
532
|
}
|
|
466
|
-
|
|
533
|
+
// cpio `-o` is copy-out create mode, not a file dest (#3288).
|
|
534
|
+
if (bin !== "cpio" && n.startsWith("-o") && !n.startsWith("-out") && n.length > 2) {
|
|
467
535
|
dests.push(pathishToken(raw.slice(2)));
|
|
468
536
|
i++;
|
|
469
537
|
continue;
|
|
470
538
|
}
|
|
471
|
-
// wget attached -Pdir
|
|
472
|
-
if (
|
|
539
|
+
// wget / wget2 attached -Pdir
|
|
540
|
+
if (WGET_FAMILY_BINS.has(bin) &&
|
|
541
|
+
n.startsWith("-p") &&
|
|
542
|
+
n.length > 2 &&
|
|
543
|
+
!n.startsWith("-proxy")) {
|
|
473
544
|
dests.push(pathishToken(raw.slice(2)));
|
|
474
545
|
i++;
|
|
475
546
|
continue;
|
|
476
547
|
}
|
|
477
|
-
// aria2c attached -dDIR (#3213)
|
|
478
|
-
if (bin
|
|
548
|
+
// aria2c / aria2 attached -dDIR (#3213 / #3288)
|
|
549
|
+
if (ARIA2_FAMILY_BINS.has(bin) && n.startsWith("-d") && n.length > 2) {
|
|
479
550
|
dests.push(pathishToken(raw.slice(2)));
|
|
480
551
|
i++;
|
|
481
552
|
continue;
|
|
@@ -487,7 +558,13 @@ function downloaderDecoderDestinations(tokens) {
|
|
|
487
558
|
continue;
|
|
488
559
|
}
|
|
489
560
|
// tar attached -CDIR (rare; capital C required)
|
|
490
|
-
if ((bin
|
|
561
|
+
if (TAR_FAMILY_BINS.has(bin) && raw.startsWith("-C") && raw.length > 2) {
|
|
562
|
+
dests.push(pathishToken(raw.slice(2)));
|
|
563
|
+
i++;
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
// cpio attached -DDIR (#3288; capital D required)
|
|
567
|
+
if (bin === "cpio" && raw.startsWith("-D") && raw.length > 2) {
|
|
491
568
|
dests.push(pathishToken(raw.slice(2)));
|
|
492
569
|
i++;
|
|
493
570
|
continue;
|
|
@@ -34,6 +34,20 @@ export interface EvaluateDecomposeStructuralApplyInput {
|
|
|
34
34
|
export declare function sha256Hex(data: Buffer | string): string;
|
|
35
35
|
/** SHA-256 hex of file bytes at path (exact on-disk digest). */
|
|
36
36
|
export declare function sha256FileHex(path: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Exact operator CLI mint command for a structural decompose apply grant (#3291).
|
|
39
|
+
* Paths are project-relative POSIX when inside projectRoot; otherwise as provided.
|
|
40
|
+
* Parent / draft / repo tokens are shell-quoted when they contain whitespace or
|
|
41
|
+
* shell metacharacters. When POSIX and PowerShell apostrophe escapes differ,
|
|
42
|
+
* both forms are emitted on separate labeled lines (`bash:` / `pwsh:`) so each
|
|
43
|
+
* is independently copy-pasteable. Paths containing newline or NUL are refused
|
|
44
|
+
* (no rewritten fake path) so the operator renames before minting. Does not
|
|
45
|
+
* include agent/CI/TTY gates — those remain on the CLI multi-factor path.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatDecomposeStructuralMintCommand(parentPath: string, draftPath: string, options?: {
|
|
48
|
+
readonly projectRoot?: string;
|
|
49
|
+
readonly repo?: string | null;
|
|
50
|
+
}): string;
|
|
37
51
|
/**
|
|
38
52
|
* Normalize a path to project-relative POSIX form for grant binding compare.
|
|
39
53
|
* Returns null when the path escapes the project root.
|
|
@@ -23,6 +23,69 @@ export function sha256Hex(data) {
|
|
|
23
23
|
export function sha256FileHex(path) {
|
|
24
24
|
return sha256Hex(readFileSync(path));
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Quote a CLI token for operator copy-paste when it has whitespace or shell
|
|
28
|
+
* metacharacters (Greptile #3291 / PR #3300). Safe bare tokens stay unquoted
|
|
29
|
+
* so deny-reason mint hints match the common path shape.
|
|
30
|
+
*
|
|
31
|
+
* Single quotes keep `$()`, backticks, and `!` inert. Apostrophe escape differs
|
|
32
|
+
* by shell: POSIX uses `'\''`; PowerShell uses `''`. Callers that need both
|
|
33
|
+
* pass dialect `"posix"` or `"pwsh"`. Does not rewrite path bytes (no newline
|
|
34
|
+
* flattening) — callers must refuse control chars before quoting.
|
|
35
|
+
*/
|
|
36
|
+
function shellQuoteCliArg(value, dialect) {
|
|
37
|
+
// Allowlist: alnum + common path/repo chars without whitespace or shell meta.
|
|
38
|
+
if (value.length > 0 && /^[A-Za-z0-9_./:@+=,-]+$/.test(value)) {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
if (dialect === "pwsh") {
|
|
42
|
+
// PowerShell single-quoted string: only ' is special, doubled as ''.
|
|
43
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
44
|
+
}
|
|
45
|
+
// POSIX single-quote; only ' needs escaping as '\''
|
|
46
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
47
|
+
}
|
|
48
|
+
function mintCommandWithDialect(parent, draft, repo, dialect) {
|
|
49
|
+
return (`deft authz:grant -- --parent ${shellQuoteCliArg(parent, dialect)} --draft ${shellQuoteCliArg(draft, dialect)}` +
|
|
50
|
+
(repo ? ` --repo ${shellQuoteCliArg(repo, dialect)}` : "") +
|
|
51
|
+
" --confirm");
|
|
52
|
+
}
|
|
53
|
+
/** True when a path/repo token cannot be represented as an exact shell mint arg. */
|
|
54
|
+
function hasUnsafeMintControlChars(value) {
|
|
55
|
+
return /[\r\n\0]/.test(value);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Exact operator CLI mint command for a structural decompose apply grant (#3291).
|
|
59
|
+
* Paths are project-relative POSIX when inside projectRoot; otherwise as provided.
|
|
60
|
+
* Parent / draft / repo tokens are shell-quoted when they contain whitespace or
|
|
61
|
+
* shell metacharacters. When POSIX and PowerShell apostrophe escapes differ,
|
|
62
|
+
* both forms are emitted on separate labeled lines (`bash:` / `pwsh:`) so each
|
|
63
|
+
* is independently copy-pasteable. Paths containing newline or NUL are refused
|
|
64
|
+
* (no rewritten fake path) so the operator renames before minting. Does not
|
|
65
|
+
* include agent/CI/TTY gates — those remain on the CLI multi-factor path.
|
|
66
|
+
*/
|
|
67
|
+
export function formatDecomposeStructuralMintCommand(parentPath, draftPath, options) {
|
|
68
|
+
let parent = parentPath.replace(/\\/g, "/");
|
|
69
|
+
let draft = draftPath.replace(/\\/g, "/");
|
|
70
|
+
const root = options?.projectRoot;
|
|
71
|
+
if (root) {
|
|
72
|
+
parent = toProjectRelativePosix(root, parentPath) ?? parent;
|
|
73
|
+
draft = toProjectRelativePosix(root, draftPath) ?? draft;
|
|
74
|
+
}
|
|
75
|
+
const repo = (options?.repo ?? "").trim();
|
|
76
|
+
if (hasUnsafeMintControlChars(parent) ||
|
|
77
|
+
hasUnsafeMintControlChars(draft) ||
|
|
78
|
+
hasUnsafeMintControlChars(repo)) {
|
|
79
|
+
return ("rename parent/draft/repo to remove newline or NUL characters, then run: " +
|
|
80
|
+
"deft authz:grant -- --parent <parent.xbrief.json> --draft <draft.json> [--repo owner/name] --confirm");
|
|
81
|
+
}
|
|
82
|
+
const posix = mintCommandWithDialect(parent, draft, repo, "posix");
|
|
83
|
+
const pwsh = mintCommandWithDialect(parent, draft, repo, "pwsh");
|
|
84
|
+
// Labels on their own lines so the executable command is independently pasteable.
|
|
85
|
+
if (posix === pwsh)
|
|
86
|
+
return posix;
|
|
87
|
+
return `bash:\n${posix}\npwsh:\n${pwsh}`;
|
|
88
|
+
}
|
|
26
89
|
/**
|
|
27
90
|
* Normalize a path to project-relative POSIX form for grant binding compare.
|
|
28
91
|
* Returns null when the path escapes the project root.
|
|
@@ -56,7 +119,7 @@ function normalizeDigest(raw) {
|
|
|
56
119
|
function pathsEqual(a, b) {
|
|
57
120
|
return a.replace(/\\/g, "/") === b.replace(/\\/g, "/");
|
|
58
121
|
}
|
|
59
|
-
function grantValidity(grant, now) {
|
|
122
|
+
function grantValidity(grant, now, mintHint) {
|
|
60
123
|
if (!isHumanOriginGrant(grant)) {
|
|
61
124
|
const kind = grant.origin.kind;
|
|
62
125
|
if (isRejectedOriginKind(kind)) {
|
|
@@ -65,14 +128,14 @@ function grantValidity(grant, now) {
|
|
|
65
128
|
code: "authz-grant-origin-reject",
|
|
66
129
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} origin.kind=${kind} is ` +
|
|
67
130
|
"agent/self-authored and cannot approve a decomposition draft. " +
|
|
68
|
-
|
|
131
|
+
`Human action required: \`${mintHint}\`.`,
|
|
69
132
|
};
|
|
70
133
|
}
|
|
71
134
|
return {
|
|
72
135
|
ok: false,
|
|
73
136
|
code: "authz-grant-origin-reject",
|
|
74
137
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} lacks human-origin provenance. ` +
|
|
75
|
-
|
|
138
|
+
`Human action required: \`${mintHint}\`.`,
|
|
76
139
|
};
|
|
77
140
|
}
|
|
78
141
|
if (grant.semantics.revokedAt !== null) {
|
|
@@ -86,7 +149,8 @@ function grantValidity(grant, now) {
|
|
|
86
149
|
return {
|
|
87
150
|
ok: false,
|
|
88
151
|
code: "authz-grant-single-use-spent",
|
|
89
|
-
reason: `Directive denied scope:decompose apply: single-use grant ${grant.id} already spent at ${grant.semantics.usedAt}
|
|
152
|
+
reason: `Directive denied scope:decompose apply: single-use grant ${grant.id} already spent at ${grant.semantics.usedAt}. ` +
|
|
153
|
+
`Human action required: \`${mintHint}\`.`,
|
|
90
154
|
};
|
|
91
155
|
}
|
|
92
156
|
if (grant.semantics.expiresAt !== null) {
|
|
@@ -96,7 +160,7 @@ function grantValidity(grant, now) {
|
|
|
96
160
|
ok: false,
|
|
97
161
|
code: "authz-grant-expired",
|
|
98
162
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} expired at ${grant.semantics.expiresAt}. ` +
|
|
99
|
-
|
|
163
|
+
`Human action required: \`${mintHint}\`.`,
|
|
100
164
|
};
|
|
101
165
|
}
|
|
102
166
|
}
|
|
@@ -116,11 +180,16 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
116
180
|
const targetRel = toProjectRelativePosix(input.projectRoot, input.draftPath);
|
|
117
181
|
const projectAbs = resolve(input.projectRoot);
|
|
118
182
|
const grants = input.grants ?? listGrants(input.projectRoot);
|
|
183
|
+
const mintHint = formatDecomposeStructuralMintCommand(input.parentPath, input.draftPath, {
|
|
184
|
+
projectRoot: input.projectRoot,
|
|
185
|
+
repo: input.repo,
|
|
186
|
+
});
|
|
119
187
|
if (parentRel === null || targetRel === null) {
|
|
120
188
|
return {
|
|
121
189
|
allowed: false,
|
|
122
190
|
code: "authz-grant-scope-deny",
|
|
123
|
-
reason: "Directive denied scope:decompose apply: parent or draft path is outside the project root."
|
|
191
|
+
reason: "Directive denied scope:decompose apply: parent or draft path is outside the project root. " +
|
|
192
|
+
`Human action required: \`${mintHint}\` with paths inside the project root.`,
|
|
124
193
|
humanApprovalRef: null,
|
|
125
194
|
draftDigest: digest,
|
|
126
195
|
};
|
|
@@ -128,7 +197,7 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
128
197
|
let lastReject = null;
|
|
129
198
|
for (const grant of grants) {
|
|
130
199
|
if (!evidenceSatisfiesImplementationApproval({ grant })) {
|
|
131
|
-
const validity = grantValidity(grant, now);
|
|
200
|
+
const validity = grantValidity(grant, now, mintHint);
|
|
132
201
|
if (!validity.ok) {
|
|
133
202
|
lastReject = { code: validity.code, reason: validity.reason, grantId: grant.id };
|
|
134
203
|
continue;
|
|
@@ -136,12 +205,12 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
136
205
|
lastReject = {
|
|
137
206
|
code: "authz-grant-origin-reject",
|
|
138
207
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} does not satisfy ` +
|
|
139
|
-
|
|
208
|
+
`human-origin implementation approval. Human action required: \`${mintHint}\`.`,
|
|
140
209
|
grantId: grant.id,
|
|
141
210
|
};
|
|
142
211
|
continue;
|
|
143
212
|
}
|
|
144
|
-
const validity = grantValidity(grant, now);
|
|
213
|
+
const validity = grantValidity(grant, now, mintHint);
|
|
145
214
|
if (!validity.ok) {
|
|
146
215
|
lastReject = { code: validity.code, reason: validity.reason, grantId: grant.id };
|
|
147
216
|
continue;
|
|
@@ -150,7 +219,7 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
150
219
|
lastReject = {
|
|
151
220
|
code: "authz-grant-scope-deny",
|
|
152
221
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} does not include operation ` +
|
|
153
|
-
`'${SCOPE_DECOMPOSE_APPLY_STRUCTURAL}'. Human action required:
|
|
222
|
+
`'${SCOPE_DECOMPOSE_APPLY_STRUCTURAL}'. Human action required: \`${mintHint}\`.`,
|
|
154
223
|
grantId: grant.id,
|
|
155
224
|
};
|
|
156
225
|
continue;
|
|
@@ -165,7 +234,7 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
165
234
|
code: "authz-grant-binding-incomplete",
|
|
166
235
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} is missing required ` +
|
|
167
236
|
"structural bindings (contentDigest, parentPath, targetPath). " +
|
|
168
|
-
|
|
237
|
+
`Human action required: \`${mintHint}\`.`,
|
|
169
238
|
grantId: grant.id,
|
|
170
239
|
};
|
|
171
240
|
continue;
|
|
@@ -174,7 +243,8 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
174
243
|
lastReject = {
|
|
175
244
|
code: "authz-grant-binding-incomplete",
|
|
176
245
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} does not bind project ` +
|
|
177
|
-
"identity (repo and/or worktree).
|
|
246
|
+
"identity (repo and/or worktree). " +
|
|
247
|
+
`Human action required: \`${mintHint}\`.`,
|
|
178
248
|
grantId: grant.id,
|
|
179
249
|
};
|
|
180
250
|
continue;
|
|
@@ -184,7 +254,8 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
184
254
|
code: "authz-grant-digest-mismatch",
|
|
185
255
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} is bound to draft digest ` +
|
|
186
256
|
`${boundDigest.slice(0, 12)}… but the draft bytes hash to ${digest.slice(0, 12)}…. ` +
|
|
187
|
-
"Any content change after approval invalidates the grant.
|
|
257
|
+
"Any content change after approval invalidates the grant. " +
|
|
258
|
+
`Human action required: \`${mintHint}\`.`,
|
|
188
259
|
grantId: grant.id,
|
|
189
260
|
};
|
|
190
261
|
continue;
|
|
@@ -193,7 +264,8 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
193
264
|
lastReject = {
|
|
194
265
|
code: "authz-grant-parent-mismatch",
|
|
195
266
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} is bound to parent ` +
|
|
196
|
-
`'${boundParent}' but apply targets '${parentRel}'
|
|
267
|
+
`'${boundParent}' but apply targets '${parentRel}'. ` +
|
|
268
|
+
`Human action required: \`${mintHint}\`.`,
|
|
197
269
|
grantId: grant.id,
|
|
198
270
|
};
|
|
199
271
|
continue;
|
|
@@ -202,7 +274,8 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
202
274
|
lastReject = {
|
|
203
275
|
code: "authz-grant-target-mismatch",
|
|
204
276
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} is bound to draft path ` +
|
|
205
|
-
`'${boundTarget}' but apply uses '${targetRel}'
|
|
277
|
+
`'${boundTarget}' but apply uses '${targetRel}'. ` +
|
|
278
|
+
`Human action required: \`${mintHint}\`.`,
|
|
206
279
|
grantId: grant.id,
|
|
207
280
|
};
|
|
208
281
|
continue;
|
|
@@ -214,7 +287,8 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
214
287
|
lastReject = {
|
|
215
288
|
code: "authz-grant-project-mismatch",
|
|
216
289
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} is bound to repo ` +
|
|
217
|
-
`'${boundRepo}' which does not match the apply context
|
|
290
|
+
`'${boundRepo}' which does not match the apply context. ` +
|
|
291
|
+
`Human action required: \`${mintHint}\`.`,
|
|
218
292
|
grantId: grant.id,
|
|
219
293
|
};
|
|
220
294
|
continue;
|
|
@@ -228,7 +302,8 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
228
302
|
lastReject = {
|
|
229
303
|
code: "authz-grant-project-mismatch",
|
|
230
304
|
reason: `Directive denied scope:decompose apply: grant ${grant.id} is bound to worktree ` +
|
|
231
|
-
`'${boundWorktree}' which does not match project root '${projectAbs}'
|
|
305
|
+
`'${boundWorktree}' which does not match project root '${projectAbs}'. ` +
|
|
306
|
+
`Human action required: \`${mintHint}\`.`,
|
|
232
307
|
grantId: grant.id,
|
|
233
308
|
};
|
|
234
309
|
continue;
|
|
@@ -257,7 +332,7 @@ export function evaluateDecomposeStructuralApply(input) {
|
|
|
257
332
|
code: "authz-grant-missing",
|
|
258
333
|
reason: "Directive denied scope:decompose apply: no human-origin grant covers " +
|
|
259
334
|
`'${SCOPE_DECOMPOSE_APPLY_STRUCTURAL}' for this draft digest. ` +
|
|
260
|
-
|
|
335
|
+
`Human action required: \`${mintHint}\` ` +
|
|
261
336
|
"(self-authored lifecycle/dispatch tokens do not count). --check remains ungated.",
|
|
262
337
|
humanApprovalRef: null,
|
|
263
338
|
draftDigest: digest,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TaskRunResult } from "../cache/task-cache/types.js";
|
|
2
|
+
import { type ToolchainPreflightResult } from "../session/toolchain-preflight.js";
|
|
2
3
|
import { type CheckOrchestratorSeams } from "./context.js";
|
|
3
4
|
export interface CachedCheckOptions extends CheckOrchestratorSeams {
|
|
4
5
|
readonly onGateStart?: (gateId: string) => void;
|
|
@@ -6,16 +7,36 @@ export interface CachedCheckOptions extends CheckOrchestratorSeams {
|
|
|
6
7
|
readonly gateSpawnFn?: (gateId: string, taskBin: string, taskArgs: string[], opts: {
|
|
7
8
|
cwd: string;
|
|
8
9
|
env?: NodeJS.ProcessEnv;
|
|
9
|
-
}) => Pick<TaskRunResult, "exitCode" | "stdout" | "stderr"
|
|
10
|
+
}) => Pick<TaskRunResult, "exitCode" | "stdout" | "stderr"> & {
|
|
11
|
+
spawnError?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* #3282: inject preflight (tests). When omitted, runs live toolchain preflight.
|
|
15
|
+
* Pass `null` to skip preflight entirely (legacy test paths).
|
|
16
|
+
*/
|
|
17
|
+
readonly preflight?: ToolchainPreflightResult | null;
|
|
18
|
+
/** #3282: session id for run-summary lines (default: new UUID). */
|
|
19
|
+
readonly sessionId?: string;
|
|
20
|
+
/** #3282: disable run-summary emission (tests). */
|
|
21
|
+
readonly emitRunSummary?: boolean;
|
|
10
22
|
}
|
|
11
23
|
/**
|
|
12
24
|
* Run check gates sequentially with content-hash caching (#1713).
|
|
13
25
|
* Falls back to fail-open execution for undeclared / non-cacheable gates.
|
|
14
26
|
*
|
|
15
|
-
* Gate order
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
27
|
+
* Gate order (#3284 / #3188):
|
|
28
|
+
* 1. Product AC (`verify:ac`) first — fail-fast; never skippable when commands exist
|
|
29
|
+
* 2. Hygiene preflight (may be advisory under pressure / degraded)
|
|
30
|
+
* 3. Suite last (`ts:check-lane`)
|
|
31
|
+
*
|
|
32
|
+
* Modes (env / ceremony dial / hard budget — see resolveProductFirstCheckMode):
|
|
33
|
+
* - full: AC hard → hygiene hard → suite
|
|
34
|
+
* - pressure: AC hard → hygiene advisory → suite
|
|
35
|
+
* - rapid: AC only (ceremony dial rapid/minimal positive content)
|
|
36
|
+
*
|
|
37
|
+
* #3282: toolchain preflight enables degraded skip report when go-task/pnpm
|
|
38
|
+
* are missing; gate failures print named cause + remedy; run-summary JSONL
|
|
39
|
+
* is appended when DEFT_RUN_SUMMARY_PATH is set (fail-open).
|
|
19
40
|
*/
|
|
20
41
|
export declare function dispatchCachedTaskCheck(frameworkRoot: string, projectRoot: string, options?: CachedCheckOptions): number;
|
|
21
42
|
//# sourceMappingURL=cached-orchestrator.d.ts.map
|