@attalabs/vinaya 0.26.0 → 0.27.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 +4 -2
- package/aeg-root/enforcement.md +2 -2
- package/aeg-root/milestone-model.md +2 -0
- package/aeg-root/process.md +1 -1
- package/aeg-root/roles/planner.md +2 -0
- package/aeg-root/roles/principal.md +4 -2
- package/aeg-root/roles/reviewer.md +6 -2
- package/aeg-root/roles/security.md +6 -2
- package/dist/checks/bin/check-body-bare-digits.js +128 -22
- package/dist/checks/bin/check-branch-topology.js +148 -24
- package/dist/checks/bin/check-brief-shape.js +430 -32
- package/dist/checks/bin/check-changeset-coverage.js +148 -24
- package/dist/checks/bin/check-closes-n.js +148 -24
- package/dist/checks/bin/check-coherence.js +148 -24
- package/dist/checks/bin/check-dead-branch-push.js +110 -22
- package/dist/checks/bin/check-dispatch-readiness.js +148 -24
- package/dist/checks/bin/check-doc-coverage-push.js +148 -24
- package/dist/checks/bin/check-doc-coverage.js +148 -24
- package/dist/checks/bin/check-doctrine-no-procedures.js +110 -22
- package/dist/checks/bin/check-doctrine-portability.js +148 -24
- package/dist/checks/bin/check-evidence-fresh.js +650 -63
- package/dist/checks/bin/check-exec-bits.js +148 -24
- package/dist/checks/bin/check-first-push-dispatch.js +148 -24
- package/dist/checks/bin/check-issue-assignment.js +148 -24
- package/dist/checks/bin/check-main-branch-refusal.js +110 -22
- package/dist/checks/bin/check-no-disk-state.js +110 -22
- package/dist/checks/bin/check-pr-premise-reassert.js +110 -22
- package/dist/checks/bin/check-pr-report-density.js +110 -22
- package/dist/checks/bin/check-quoted-command.js +148 -24
- package/dist/checks/bin/check-reader-resolvable-prose.js +148 -24
- package/dist/checks/bin/check-registry-gates.js +110 -22
- package/dist/checks/bin/check-retired-vocabulary.js +148 -24
- package/dist/checks/bin/check-review-gate.js +169 -77
- package/dist/checks/bin/check-single-plan-pr.js +110 -22
- package/dist/checks/bin/check-surface-scope.js +148 -24
- package/dist/checks/bin/check-test-plan.js +110 -22
- package/dist/checks/bin/check-token-collection-wired.js +110 -22
- package/dist/checks/bin/check-token-report.js +110 -22
- package/dist/checks/bin/check-workspace-escape.js +148 -24
- package/dist/index.js +1584 -572
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// src/checks/bin/check-evidence-fresh.ts
|
|
6
|
-
import { execFileSync as
|
|
6
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
7
7
|
// ../../packages/aeg-core/src/gate-audience.ts
|
|
8
8
|
var GATE_AUDIENCE = {
|
|
9
9
|
"check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
|
|
@@ -303,7 +303,7 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
303
303
|
"--state",
|
|
304
304
|
"all",
|
|
305
305
|
"--json",
|
|
306
|
-
"number,title,body,state,labels,milestone",
|
|
306
|
+
"number,title,body,state,labels,milestone,stateReason",
|
|
307
307
|
"--limit",
|
|
308
308
|
"200"
|
|
309
309
|
];
|
|
@@ -649,14 +649,19 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
649
649
|
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
650
650
|
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
651
651
|
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
652
|
-
function
|
|
653
|
-
const text = stripCode(description, { inlineSpans: "keep" });
|
|
652
|
+
function intentsSection(text) {
|
|
654
653
|
const start = text.match(INTENTS_HEADING);
|
|
655
654
|
if (!start || start.index === undefined)
|
|
656
|
-
return
|
|
655
|
+
return null;
|
|
657
656
|
const rest = text.slice(start.index + start[0].length);
|
|
658
657
|
const next = rest.match(NEXT_HEADING);
|
|
659
|
-
|
|
658
|
+
return rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
659
|
+
}
|
|
660
|
+
function intentGoalForSlug(description, slug) {
|
|
661
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
662
|
+
const section = intentsSection(text);
|
|
663
|
+
if (section === null)
|
|
664
|
+
return "";
|
|
660
665
|
for (const line of section.split(`
|
|
661
666
|
`)) {
|
|
662
667
|
const trimmed = line.trim();
|
|
@@ -1948,6 +1953,7 @@ function parseInlineFieldList(section) {
|
|
|
1948
1953
|
// ../../packages/aeg-core/src/verdict-extraction.ts
|
|
1949
1954
|
var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
1950
1955
|
var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
1956
|
+
var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
|
|
1951
1957
|
function firstFiveLines(comment) {
|
|
1952
1958
|
return comment.split(`
|
|
1953
1959
|
`).slice(0, 5).join(`
|
|
@@ -1961,6 +1967,15 @@ function extractObjectivesVersion(comment) {
|
|
|
1961
1967
|
const m = firstFiveLines(comment).match(OBJECTIVES_VERSION_PATTERN);
|
|
1962
1968
|
return m ? m[1].toLowerCase() : null;
|
|
1963
1969
|
}
|
|
1970
|
+
function firstSevenLines(comment) {
|
|
1971
|
+
return comment.split(`
|
|
1972
|
+
`).slice(0, 7).join(`
|
|
1973
|
+
`);
|
|
1974
|
+
}
|
|
1975
|
+
function extractRulingOrdinal(comment) {
|
|
1976
|
+
const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
|
|
1977
|
+
return m ? Number.parseInt(m[1], 10) : null;
|
|
1978
|
+
}
|
|
1964
1979
|
function extractVerdict(comments, valuePattern, missingLabel) {
|
|
1965
1980
|
const candidates = comments.filter((c) => valuePattern.test(c));
|
|
1966
1981
|
if (candidates.length === 0) {
|
|
@@ -1968,6 +1983,7 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1968
1983
|
value: `no ${missingLabel} pass was run before merge — DANGLING, see below`,
|
|
1969
1984
|
headSha: null,
|
|
1970
1985
|
objectivesVersion: null,
|
|
1986
|
+
rulingOrdinal: null,
|
|
1971
1987
|
danglingNote: `no ${missingLabel} verdict comment found on this PR`
|
|
1972
1988
|
};
|
|
1973
1989
|
}
|
|
@@ -1978,6 +1994,7 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1978
1994
|
value: `the most recent ${missingLabel} comment's VERDICT line is not within its first five lines — DANGLING, see below`,
|
|
1979
1995
|
headSha: null,
|
|
1980
1996
|
objectivesVersion: null,
|
|
1997
|
+
rulingOrdinal: null,
|
|
1981
1998
|
danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
|
|
1982
1999
|
};
|
|
1983
2000
|
}
|
|
@@ -1985,6 +2002,7 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1985
2002
|
value: m[1].toUpperCase().replace(/[_-]/g, " "),
|
|
1986
2003
|
headSha: extractHeadSha(latest),
|
|
1987
2004
|
objectivesVersion: extractObjectivesVersion(latest),
|
|
2005
|
+
rulingOrdinal: extractRulingOrdinal(latest),
|
|
1988
2006
|
danglingNote: null
|
|
1989
2007
|
};
|
|
1990
2008
|
}
|
|
@@ -2346,6 +2364,9 @@ import { createHash as createHash2 } from "node:crypto";
|
|
|
2346
2364
|
var HEADING_RE = /^##[ \t]*Objectives[ \t]*$/im;
|
|
2347
2365
|
var NEXT_HEADING_RE = /^##[ \t]/m;
|
|
2348
2366
|
var OBJECTIVE_LINE_RE = /^O(\d+)\.[ \t]*(.*)$/;
|
|
2367
|
+
function maskedForHeadingSearch(body) {
|
|
2368
|
+
return maskDetailsBlocks(maskCode(body));
|
|
2369
|
+
}
|
|
2349
2370
|
function hasBacktickedPath(text) {
|
|
2350
2371
|
let i = 0;
|
|
2351
2372
|
while (i < text.length) {
|
|
@@ -2368,16 +2389,22 @@ function stripObjectiveBackticks(text) {
|
|
|
2368
2389
|
function wordCount(text) {
|
|
2369
2390
|
return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
|
|
2370
2391
|
}
|
|
2371
|
-
function
|
|
2372
|
-
const
|
|
2392
|
+
function objectivesSectionBounds(body) {
|
|
2393
|
+
const masked = maskedForHeadingSearch(body);
|
|
2394
|
+
const heading = HEADING_RE.exec(masked);
|
|
2373
2395
|
if (!heading)
|
|
2374
2396
|
return null;
|
|
2375
|
-
const
|
|
2397
|
+
const start = heading.index + heading[0].length;
|
|
2398
|
+
const afterHeading = masked.slice(start);
|
|
2376
2399
|
const next = NEXT_HEADING_RE.exec(afterHeading);
|
|
2377
|
-
return next ?
|
|
2400
|
+
return { start, end: next ? start + next.index : body.length };
|
|
2401
|
+
}
|
|
2402
|
+
function objectivesSectionText(body) {
|
|
2403
|
+
const bounds = objectivesSectionBounds(body);
|
|
2404
|
+
return bounds === null ? null : body.slice(bounds.start, bounds.end);
|
|
2378
2405
|
}
|
|
2379
2406
|
function hasObjectivesHeading(body) {
|
|
2380
|
-
return HEADING_RE.test(body);
|
|
2407
|
+
return HEADING_RE.test(maskedForHeadingSearch(body));
|
|
2381
2408
|
}
|
|
2382
2409
|
function objectivesOf(body) {
|
|
2383
2410
|
const section = objectivesSectionText(body);
|
|
@@ -2437,6 +2464,15 @@ function isIssueNotFoundError(err) {
|
|
|
2437
2464
|
`);
|
|
2438
2465
|
return /could not resolve to an (?:issue|pull request)|\b404\b|not found/i.test(haystack);
|
|
2439
2466
|
}
|
|
2467
|
+
function resolveObjectivesSource(prBody, issue, cutoverIssue) {
|
|
2468
|
+
if (issue !== null && issue < cutoverIssue)
|
|
2469
|
+
return { kind: "none" };
|
|
2470
|
+
if (issue !== null)
|
|
2471
|
+
return { kind: "issue", issue };
|
|
2472
|
+
if (hasObjectivesHeading(prBody))
|
|
2473
|
+
return { kind: "body" };
|
|
2474
|
+
return { kind: "none" };
|
|
2475
|
+
}
|
|
2440
2476
|
|
|
2441
2477
|
// ../../packages/aeg-core/src/premise-check.ts
|
|
2442
2478
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -2938,17 +2974,40 @@ function checkBriefSections(prBody, readTier, options = {}) {
|
|
|
2938
2974
|
];
|
|
2939
2975
|
return { errors: results.flatMap((r) => r.errors) };
|
|
2940
2976
|
}
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
`
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2977
|
+
function contentAfterNLines(body, n) {
|
|
2978
|
+
let idx = -1;
|
|
2979
|
+
for (let i = 0;i < n; i++) {
|
|
2980
|
+
idx = body.indexOf(`
|
|
2981
|
+
`, idx + 1);
|
|
2982
|
+
if (idx === -1)
|
|
2983
|
+
return "";
|
|
2984
|
+
}
|
|
2985
|
+
return body.slice(idx + 1);
|
|
2986
|
+
}
|
|
2987
|
+
var BRIEF_MARKER_LINE_RE = /^<!-- aeg:brief:v(\d+) -->$/;
|
|
2988
|
+
function parseBriefMarkerVersion(firstLine) {
|
|
2989
|
+
const m = BRIEF_MARKER_LINE_RE.exec(firstLine.trim());
|
|
2990
|
+
if (!m)
|
|
2991
|
+
return null;
|
|
2992
|
+
const version = Number.parseInt(m[1], 10);
|
|
2993
|
+
return Number.isInteger(version) && version >= 1 ? version : null;
|
|
2994
|
+
}
|
|
2995
|
+
function frozenBriefContent(body, version) {
|
|
2996
|
+
return contentAfterNLines(body, version === 1 ? 2 : 3);
|
|
2997
|
+
}
|
|
2998
|
+
function resolveNewestFrozenBrief(comments, allowlist) {
|
|
2999
|
+
let best = null;
|
|
3000
|
+
for (const c of comments) {
|
|
3001
|
+
if (!isPrincipal(c.author, allowlist))
|
|
3002
|
+
continue;
|
|
3003
|
+
const version = parseBriefMarkerVersion(c.body.split(`
|
|
3004
|
+
`)[0] ?? "");
|
|
3005
|
+
if (version === null)
|
|
3006
|
+
continue;
|
|
3007
|
+
if (best === null || version > best.version)
|
|
3008
|
+
best = { ...c, version };
|
|
3009
|
+
}
|
|
3010
|
+
return best === null ? null : { ...best, content: frozenBriefContent(best.body, best.version) };
|
|
2952
3011
|
}
|
|
2953
3012
|
// ../../packages/aeg-core/src/doctrine-portability.ts
|
|
2954
3013
|
var DEFAULT_SHIPS_PREFIX = "aeg-root/";
|
|
@@ -3675,6 +3734,11 @@ function isBoundToObjectives(extraction, currentVersion) {
|
|
|
3675
3734
|
return true;
|
|
3676
3735
|
return extraction.objectivesVersion === currentVersion;
|
|
3677
3736
|
}
|
|
3737
|
+
function isBoundToRulings(extraction, currentOrdinal) {
|
|
3738
|
+
if (extraction.rulingOrdinal === null)
|
|
3739
|
+
return currentOrdinal === 0;
|
|
3740
|
+
return extraction.rulingOrdinal === currentOrdinal;
|
|
3741
|
+
}
|
|
3678
3742
|
function checkReviewGate(input) {
|
|
3679
3743
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
3680
3744
|
const waived = isWaiverLabelActorVerified({
|
|
@@ -3703,7 +3767,9 @@ function checkReviewGate(input) {
|
|
|
3703
3767
|
const securityBound = isBoundToPatch(security, input.headSha, input.patchIdOf);
|
|
3704
3768
|
const codeReviewObjectivesBound = isBoundToObjectives(codeReview, input.objectivesVersion);
|
|
3705
3769
|
const securityObjectivesBound = isBoundToObjectives(security, input.objectivesVersion);
|
|
3706
|
-
|
|
3770
|
+
const codeReviewRulingsBound = isBoundToRulings(codeReview, input.rulingOrdinal);
|
|
3771
|
+
const securityRulingsBound = isBoundToRulings(security, input.rulingOrdinal);
|
|
3772
|
+
if (codeReviewClean && codeReviewBound && codeReviewObjectivesBound && codeReviewRulingsBound && securityClean && securityBound && securityObjectivesBound && securityRulingsBound && mechanicalChecksClean) {
|
|
3707
3773
|
return {
|
|
3708
3774
|
verdict: "pass",
|
|
3709
3775
|
reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}, and every reported mechanical check is green.`,
|
|
@@ -3717,6 +3783,8 @@ function checkReviewGate(input) {
|
|
|
3717
3783
|
problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
3718
3784
|
} else if (!codeReviewObjectivesBound) {
|
|
3719
3785
|
problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
|
|
3786
|
+
} else if (!codeReviewRulingsBound) {
|
|
3787
|
+
problems.push(`the newest code-review verdict was cast against ruling ordinal ${codeReview.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
|
|
3720
3788
|
}
|
|
3721
3789
|
if (!securityClean) {
|
|
3722
3790
|
problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
|
|
@@ -3724,6 +3792,8 @@ function checkReviewGate(input) {
|
|
|
3724
3792
|
problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
3725
3793
|
} else if (!securityObjectivesBound) {
|
|
3726
3794
|
problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
|
|
3795
|
+
} else if (!securityRulingsBound) {
|
|
3796
|
+
problems.push(`the newest security-review verdict was cast against ruling ordinal ${security.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
|
|
3727
3797
|
}
|
|
3728
3798
|
if (!mechanicalChecksClean) {
|
|
3729
3799
|
problems.push(reportedMechanicalChecks.length === 0 ? "no mechanical checks have reported for this head yet" : `mechanical check(s) not green: ${reportedMechanicalChecks.filter((c) => c.bucket !== "pass").map((c) => `${c.name} (${c.bucket})`).join(", ")}`);
|
|
@@ -3740,6 +3810,24 @@ var DEFAULT_RELEASE_ACTOR = "github-actions[bot]";
|
|
|
3740
3810
|
function isChangesetsReleasePr(branch, author, expectedAuthor) {
|
|
3741
3811
|
return branch === CHANGESET_RELEASE_BRANCH && author === expectedAuthor;
|
|
3742
3812
|
}
|
|
3813
|
+
// ../../packages/aeg-core/src/ruling-ordinal.ts
|
|
3814
|
+
var RULING_MARKER_ORDINAL = /^<!-- aeg:principal:ruling:\d+-(\d+) -->$/;
|
|
3815
|
+
function newestPrincipalRulingOrdinal(comments, allowlist) {
|
|
3816
|
+
let best = 0;
|
|
3817
|
+
for (const c of comments) {
|
|
3818
|
+
if (!isPrincipal(c.author, allowlist))
|
|
3819
|
+
continue;
|
|
3820
|
+
const firstLine = (c.body.split(`
|
|
3821
|
+
`)[0] ?? "").trim();
|
|
3822
|
+
const m = RULING_MARKER_ORDINAL.exec(firstLine);
|
|
3823
|
+
if (!m)
|
|
3824
|
+
continue;
|
|
3825
|
+
const k = Number.parseInt(m[1], 10);
|
|
3826
|
+
if (k > best)
|
|
3827
|
+
best = k;
|
|
3828
|
+
}
|
|
3829
|
+
return best;
|
|
3830
|
+
}
|
|
3743
3831
|
// ../../packages/aeg-core/src/markdown-table.ts
|
|
3744
3832
|
function splitRow(line) {
|
|
3745
3833
|
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
@@ -4974,6 +5062,478 @@ var ForgeWriteEventSchema = z.discriminatedUnion("event", [
|
|
|
4974
5062
|
z.object({ ...forgeWriteShared, event: z.literal("written"), comment_ids: z.array(z.string()) }).strict()
|
|
4975
5063
|
]);
|
|
4976
5064
|
var LogEventSchema = z.union([DispatchEventSchema, DevReviewLoopEventSchema, ForgeWriteEventSchema]);
|
|
5065
|
+
// src/checks/registry.ts
|
|
5066
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
5067
|
+
import { join as join2 } from "node:path";
|
|
5068
|
+
|
|
5069
|
+
// src/lib/package-root.ts
|
|
5070
|
+
import { existsSync } from "node:fs";
|
|
5071
|
+
import { dirname, join } from "node:path";
|
|
5072
|
+
import { fileURLToPath } from "node:url";
|
|
5073
|
+
function packageRoot(moduleUrl) {
|
|
5074
|
+
let dir = dirname(fileURLToPath(moduleUrl));
|
|
5075
|
+
while (!existsSync(join(dir, "package.json"))) {
|
|
5076
|
+
if (existsSync(join(dir, ".git")))
|
|
5077
|
+
break;
|
|
5078
|
+
const parent = dirname(dir);
|
|
5079
|
+
if (parent === dir)
|
|
5080
|
+
break;
|
|
5081
|
+
dir = parent;
|
|
5082
|
+
}
|
|
5083
|
+
return dir;
|
|
5084
|
+
}
|
|
5085
|
+
|
|
5086
|
+
// src/checks/registry.ts
|
|
5087
|
+
var DIST_BIN_DIR = join2(packageRoot(import.meta.url), "dist", "checks", "bin");
|
|
5088
|
+
var SRC_BIN_DIR = join2(packageRoot(import.meta.url), "src", "checks", "bin");
|
|
5089
|
+
var BIN_DIR = existsSync2(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
|
|
5090
|
+
var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
|
|
5091
|
+
function bin(name) {
|
|
5092
|
+
return join2(BIN_DIR, `${name}${BIN_EXT}`);
|
|
5093
|
+
}
|
|
5094
|
+
var REGISTRY = [
|
|
5095
|
+
[
|
|
5096
|
+
{
|
|
5097
|
+
name: "brief-shape",
|
|
5098
|
+
run: bin("check-brief-shape"),
|
|
5099
|
+
scope: "diff",
|
|
5100
|
+
timeoutMs: 15000,
|
|
5101
|
+
env: {
|
|
5102
|
+
PR_BODY: { optional: true },
|
|
5103
|
+
BRANCH: { optional: true },
|
|
5104
|
+
PR_NUMBER: { optional: true },
|
|
5105
|
+
GITHUB_TOKEN: { optional: true },
|
|
5106
|
+
GH_TOKEN: { optional: true }
|
|
5107
|
+
}
|
|
5108
|
+
},
|
|
5109
|
+
0
|
|
5110
|
+
],
|
|
5111
|
+
[
|
|
5112
|
+
{
|
|
5113
|
+
name: "pr-report-density",
|
|
5114
|
+
run: bin("check-pr-report-density"),
|
|
5115
|
+
scope: "diff",
|
|
5116
|
+
timeoutMs: 15000,
|
|
5117
|
+
env: {
|
|
5118
|
+
PR_BODY: { optional: true }
|
|
5119
|
+
}
|
|
5120
|
+
},
|
|
5121
|
+
0
|
|
5122
|
+
],
|
|
5123
|
+
[
|
|
5124
|
+
{
|
|
5125
|
+
name: "doc-coverage",
|
|
5126
|
+
run: bin("check-doc-coverage"),
|
|
5127
|
+
scope: "diff",
|
|
5128
|
+
timeoutMs: 15000,
|
|
5129
|
+
env: {
|
|
5130
|
+
BASE_SHA: { optional: true },
|
|
5131
|
+
PR_BODY: { optional: true },
|
|
5132
|
+
PR_BODY_FILE: { optional: true },
|
|
5133
|
+
PR_NUMBER: { optional: true },
|
|
5134
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
5135
|
+
GITHUB_TOKEN: { optional: true },
|
|
5136
|
+
GH_TOKEN: { optional: true }
|
|
5137
|
+
}
|
|
5138
|
+
},
|
|
5139
|
+
0
|
|
5140
|
+
],
|
|
5141
|
+
[
|
|
5142
|
+
{
|
|
5143
|
+
name: "coherence",
|
|
5144
|
+
run: bin("check-coherence"),
|
|
5145
|
+
scope: "full",
|
|
5146
|
+
timeoutMs: 30000,
|
|
5147
|
+
env: {
|
|
5148
|
+
AEG_REPO: { optional: true },
|
|
5149
|
+
BRANCH: { optional: true },
|
|
5150
|
+
GITHUB_TOKEN: { optional: true },
|
|
5151
|
+
GH_TOKEN: { optional: true }
|
|
5152
|
+
}
|
|
5153
|
+
},
|
|
5154
|
+
0
|
|
5155
|
+
],
|
|
5156
|
+
[
|
|
5157
|
+
{
|
|
5158
|
+
name: "pr-premise-reassert",
|
|
5159
|
+
run: bin("check-pr-premise-reassert"),
|
|
5160
|
+
scope: "diff",
|
|
5161
|
+
timeoutMs: 15000,
|
|
5162
|
+
env: {
|
|
5163
|
+
PR_BODY: { optional: true }
|
|
5164
|
+
}
|
|
5165
|
+
},
|
|
5166
|
+
0
|
|
5167
|
+
],
|
|
5168
|
+
[
|
|
5169
|
+
{
|
|
5170
|
+
name: "dispatch-readiness",
|
|
5171
|
+
run: bin("check-dispatch-readiness"),
|
|
5172
|
+
scope: "full",
|
|
5173
|
+
timeoutMs: 30000,
|
|
5174
|
+
env: {
|
|
5175
|
+
AEG_REPO: { optional: true },
|
|
5176
|
+
BRANCH: { optional: true },
|
|
5177
|
+
GITHUB_TOKEN: { optional: true },
|
|
5178
|
+
GH_TOKEN: { optional: true },
|
|
5179
|
+
PREMISE_FILE: { optional: true }
|
|
5180
|
+
}
|
|
5181
|
+
},
|
|
5182
|
+
0
|
|
5183
|
+
],
|
|
5184
|
+
[
|
|
5185
|
+
{
|
|
5186
|
+
name: "closes-n",
|
|
5187
|
+
run: bin("check-closes-n"),
|
|
5188
|
+
scope: "diff",
|
|
5189
|
+
timeoutMs: 15000,
|
|
5190
|
+
requiresOpenPr: true,
|
|
5191
|
+
env: {
|
|
5192
|
+
BRANCH: { optional: true },
|
|
5193
|
+
PR_BODY: { optional: true },
|
|
5194
|
+
AEG_REPO: { optional: true },
|
|
5195
|
+
GITHUB_TOKEN: { optional: true },
|
|
5196
|
+
GH_TOKEN: { optional: true }
|
|
5197
|
+
}
|
|
5198
|
+
},
|
|
5199
|
+
1
|
|
5200
|
+
],
|
|
5201
|
+
[
|
|
5202
|
+
{
|
|
5203
|
+
name: "single-plan-pr",
|
|
5204
|
+
run: bin("check-single-plan-pr"),
|
|
5205
|
+
scope: "diff",
|
|
5206
|
+
timeoutMs: 15000,
|
|
5207
|
+
env: {
|
|
5208
|
+
BASE_SHA: { optional: true },
|
|
5209
|
+
PR_NUMBER: { optional: true },
|
|
5210
|
+
GITHUB_TOKEN: { optional: true },
|
|
5211
|
+
GH_TOKEN: { optional: true }
|
|
5212
|
+
}
|
|
5213
|
+
},
|
|
5214
|
+
0
|
|
5215
|
+
],
|
|
5216
|
+
[
|
|
5217
|
+
{
|
|
5218
|
+
name: "surface-scope",
|
|
5219
|
+
run: bin("check-surface-scope"),
|
|
5220
|
+
scope: "diff",
|
|
5221
|
+
timeoutMs: 15000,
|
|
5222
|
+
env: {
|
|
5223
|
+
AEG_REPO: { optional: true },
|
|
5224
|
+
BASE_SHA: { optional: true },
|
|
5225
|
+
BRANCH: { optional: true },
|
|
5226
|
+
GITHUB_TOKEN: { optional: true },
|
|
5227
|
+
GH_TOKEN: { optional: true }
|
|
5228
|
+
}
|
|
5229
|
+
},
|
|
5230
|
+
0
|
|
5231
|
+
],
|
|
5232
|
+
[
|
|
5233
|
+
{
|
|
5234
|
+
name: "test-plan",
|
|
5235
|
+
run: bin("check-test-plan"),
|
|
5236
|
+
scope: "diff",
|
|
5237
|
+
timeoutMs: 15000,
|
|
5238
|
+
requiresOpenPr: true,
|
|
5239
|
+
env: {
|
|
5240
|
+
PR_BODY: { optional: true },
|
|
5241
|
+
BRANCH: { optional: true }
|
|
5242
|
+
}
|
|
5243
|
+
},
|
|
5244
|
+
1
|
|
5245
|
+
],
|
|
5246
|
+
[
|
|
5247
|
+
{
|
|
5248
|
+
name: "body-bare-digits",
|
|
5249
|
+
run: bin("check-body-bare-digits"),
|
|
5250
|
+
scope: "diff",
|
|
5251
|
+
timeoutMs: 15000,
|
|
5252
|
+
requiresOpenPr: true,
|
|
5253
|
+
ownWorkflow: true,
|
|
5254
|
+
env: {
|
|
5255
|
+
PR_BODY: { optional: true },
|
|
5256
|
+
PR_NUMBER: { optional: true },
|
|
5257
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
5258
|
+
GITHUB_TOKEN: { optional: true },
|
|
5259
|
+
GH_TOKEN: { optional: true }
|
|
5260
|
+
}
|
|
5261
|
+
},
|
|
5262
|
+
1
|
|
5263
|
+
],
|
|
5264
|
+
[
|
|
5265
|
+
{
|
|
5266
|
+
name: "token-report",
|
|
5267
|
+
run: bin("check-token-report"),
|
|
5268
|
+
scope: "diff",
|
|
5269
|
+
timeoutMs: 15000,
|
|
5270
|
+
requiresOpenPr: true,
|
|
5271
|
+
env: {
|
|
5272
|
+
PR_BODY: { optional: true },
|
|
5273
|
+
BRANCH: { optional: true },
|
|
5274
|
+
CLAUDE_PROJECT_DIR: { optional: true },
|
|
5275
|
+
CLAUDE_CODE_SESSION_ID: { optional: true }
|
|
5276
|
+
}
|
|
5277
|
+
},
|
|
5278
|
+
1
|
|
5279
|
+
],
|
|
5280
|
+
[
|
|
5281
|
+
{
|
|
5282
|
+
name: "no-disk-state",
|
|
5283
|
+
run: bin("check-no-disk-state"),
|
|
5284
|
+
scope: "diff",
|
|
5285
|
+
timeoutMs: 15000,
|
|
5286
|
+
env: { BASE_SHA: { optional: true } }
|
|
5287
|
+
},
|
|
5288
|
+
0
|
|
5289
|
+
],
|
|
5290
|
+
[
|
|
5291
|
+
{
|
|
5292
|
+
name: "registry-gates",
|
|
5293
|
+
run: bin("check-registry-gates"),
|
|
5294
|
+
scope: "full",
|
|
5295
|
+
timeoutMs: 30000,
|
|
5296
|
+
env: {
|
|
5297
|
+
AEG_REPO: { optional: true },
|
|
5298
|
+
GITHUB_TOKEN: { optional: true },
|
|
5299
|
+
GH_TOKEN: { optional: true }
|
|
5300
|
+
}
|
|
5301
|
+
},
|
|
5302
|
+
0
|
|
5303
|
+
],
|
|
5304
|
+
[
|
|
5305
|
+
{
|
|
5306
|
+
name: "review-gate",
|
|
5307
|
+
run: bin("check-review-gate"),
|
|
5308
|
+
scope: "full",
|
|
5309
|
+
timeoutMs: 30000,
|
|
5310
|
+
ownWorkflow: true,
|
|
5311
|
+
env: {
|
|
5312
|
+
PR_NUMBER: { optional: true },
|
|
5313
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
5314
|
+
GITHUB_TOKEN: { optional: true },
|
|
5315
|
+
GH_TOKEN: { optional: true }
|
|
5316
|
+
}
|
|
5317
|
+
},
|
|
5318
|
+
1
|
|
5319
|
+
],
|
|
5320
|
+
[
|
|
5321
|
+
{
|
|
5322
|
+
name: "branch-topology",
|
|
5323
|
+
run: bin("check-branch-topology"),
|
|
5324
|
+
scope: "full",
|
|
5325
|
+
timeoutMs: 30000,
|
|
5326
|
+
env: {
|
|
5327
|
+
BRANCH: { optional: true },
|
|
5328
|
+
AEG_REPO: { optional: true },
|
|
5329
|
+
GITHUB_TOKEN: { optional: true },
|
|
5330
|
+
GH_TOKEN: { optional: true }
|
|
5331
|
+
}
|
|
5332
|
+
},
|
|
5333
|
+
0
|
|
5334
|
+
],
|
|
5335
|
+
[
|
|
5336
|
+
{
|
|
5337
|
+
name: "dead-branch-push",
|
|
5338
|
+
run: bin("check-dead-branch-push"),
|
|
5339
|
+
scope: "full",
|
|
5340
|
+
timeoutMs: 30000,
|
|
5341
|
+
env: {
|
|
5342
|
+
BRANCH: { optional: true },
|
|
5343
|
+
GITHUB_TOKEN: { optional: true },
|
|
5344
|
+
GH_TOKEN: { optional: true }
|
|
5345
|
+
}
|
|
5346
|
+
},
|
|
5347
|
+
0
|
|
5348
|
+
],
|
|
5349
|
+
[
|
|
5350
|
+
{
|
|
5351
|
+
name: "first-push-dispatch",
|
|
5352
|
+
run: bin("check-first-push-dispatch"),
|
|
5353
|
+
scope: "full",
|
|
5354
|
+
timeoutMs: 30000,
|
|
5355
|
+
env: {
|
|
5356
|
+
BRANCH: { optional: true },
|
|
5357
|
+
AEG_REPO: { optional: true },
|
|
5358
|
+
GITHUB_TOKEN: { optional: true },
|
|
5359
|
+
GH_TOKEN: { optional: true }
|
|
5360
|
+
}
|
|
5361
|
+
},
|
|
5362
|
+
0
|
|
5363
|
+
],
|
|
5364
|
+
[
|
|
5365
|
+
{
|
|
5366
|
+
name: "doc-coverage-push",
|
|
5367
|
+
run: bin("check-doc-coverage-push"),
|
|
5368
|
+
scope: "diff",
|
|
5369
|
+
timeoutMs: 15000,
|
|
5370
|
+
env: {
|
|
5371
|
+
OVERRIDE_DOCS: { optional: true },
|
|
5372
|
+
BASE_SHA: { optional: true },
|
|
5373
|
+
PR_BODY: { optional: true },
|
|
5374
|
+
PR_BODY_FILE: { optional: true },
|
|
5375
|
+
PR_LABELS: { optional: true },
|
|
5376
|
+
WAIVER_LABEL_ACTOR: { optional: true },
|
|
5377
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
5378
|
+
GITHUB_TOKEN: { optional: true },
|
|
5379
|
+
GH_TOKEN: { optional: true }
|
|
5380
|
+
}
|
|
5381
|
+
},
|
|
5382
|
+
0
|
|
5383
|
+
],
|
|
5384
|
+
[
|
|
5385
|
+
{
|
|
5386
|
+
name: "issue-assignment",
|
|
5387
|
+
run: bin("check-issue-assignment"),
|
|
5388
|
+
scope: "full",
|
|
5389
|
+
timeoutMs: 30000,
|
|
5390
|
+
env: {
|
|
5391
|
+
AEG_REPO: { optional: true },
|
|
5392
|
+
BRANCH: { optional: true },
|
|
5393
|
+
GITHUB_TOKEN: { optional: true },
|
|
5394
|
+
GH_TOKEN: { optional: true }
|
|
5395
|
+
}
|
|
5396
|
+
},
|
|
5397
|
+
0
|
|
5398
|
+
],
|
|
5399
|
+
[
|
|
5400
|
+
{
|
|
5401
|
+
name: "evidence-fresh",
|
|
5402
|
+
run: bin("check-evidence-fresh"),
|
|
5403
|
+
scope: "diff",
|
|
5404
|
+
timeoutMs: 15000,
|
|
5405
|
+
requiresOpenPr: true,
|
|
5406
|
+
env: {
|
|
5407
|
+
PR_NUMBER: { optional: true },
|
|
5408
|
+
PR_BODY: { optional: true },
|
|
5409
|
+
BASE_SHA: { optional: true },
|
|
5410
|
+
GITHUB_TOKEN: { optional: true },
|
|
5411
|
+
GH_TOKEN: { optional: true }
|
|
5412
|
+
}
|
|
5413
|
+
},
|
|
5414
|
+
1
|
|
5415
|
+
],
|
|
5416
|
+
[
|
|
5417
|
+
{
|
|
5418
|
+
name: "reader-resolvable-prose",
|
|
5419
|
+
run: bin("check-reader-resolvable-prose"),
|
|
5420
|
+
scope: "full",
|
|
5421
|
+
timeoutMs: 30000,
|
|
5422
|
+
env: {},
|
|
5423
|
+
include: [
|
|
5424
|
+
"aeg-root/**/*.md",
|
|
5425
|
+
"apps/cli/src/**",
|
|
5426
|
+
".github/workflows/**",
|
|
5427
|
+
".vinaya/**",
|
|
5428
|
+
"apps/cli/README.md",
|
|
5429
|
+
"packages/sources/README.md"
|
|
5430
|
+
]
|
|
5431
|
+
},
|
|
5432
|
+
0
|
|
5433
|
+
],
|
|
5434
|
+
[
|
|
5435
|
+
{
|
|
5436
|
+
name: "retired-vocabulary",
|
|
5437
|
+
run: bin("check-retired-vocabulary"),
|
|
5438
|
+
scope: "full",
|
|
5439
|
+
timeoutMs: 30000,
|
|
5440
|
+
env: {},
|
|
5441
|
+
include: ["aeg-root/**/*.md"]
|
|
5442
|
+
},
|
|
5443
|
+
0
|
|
5444
|
+
],
|
|
5445
|
+
[
|
|
5446
|
+
{
|
|
5447
|
+
name: "doctrine-portability",
|
|
5448
|
+
run: bin("check-doctrine-portability"),
|
|
5449
|
+
scope: "full",
|
|
5450
|
+
timeoutMs: 30000,
|
|
5451
|
+
env: { BASE_SHA: { optional: true } },
|
|
5452
|
+
include: ["aeg-root/**/*.md"]
|
|
5453
|
+
},
|
|
5454
|
+
0
|
|
5455
|
+
],
|
|
5456
|
+
[
|
|
5457
|
+
{
|
|
5458
|
+
name: "doctrine-no-procedures",
|
|
5459
|
+
run: bin("check-doctrine-no-procedures"),
|
|
5460
|
+
scope: "full",
|
|
5461
|
+
timeoutMs: 30000,
|
|
5462
|
+
env: {},
|
|
5463
|
+
include: ["aeg-root/**/*.md"]
|
|
5464
|
+
},
|
|
5465
|
+
0
|
|
5466
|
+
],
|
|
5467
|
+
[
|
|
5468
|
+
{
|
|
5469
|
+
name: "exec-bits",
|
|
5470
|
+
run: bin("check-exec-bits"),
|
|
5471
|
+
scope: "diff",
|
|
5472
|
+
timeoutMs: 30000,
|
|
5473
|
+
env: {}
|
|
5474
|
+
},
|
|
5475
|
+
0
|
|
5476
|
+
],
|
|
5477
|
+
[
|
|
5478
|
+
{
|
|
5479
|
+
name: "workspace-escape",
|
|
5480
|
+
run: bin("check-workspace-escape"),
|
|
5481
|
+
scope: "full",
|
|
5482
|
+
timeoutMs: 30000,
|
|
5483
|
+
env: {},
|
|
5484
|
+
include: ["aeg-root/**/*.md"]
|
|
5485
|
+
},
|
|
5486
|
+
0
|
|
5487
|
+
],
|
|
5488
|
+
[
|
|
5489
|
+
{
|
|
5490
|
+
name: "changeset-coverage",
|
|
5491
|
+
run: bin("check-changeset-coverage"),
|
|
5492
|
+
scope: "diff",
|
|
5493
|
+
timeoutMs: 15000,
|
|
5494
|
+
env: {}
|
|
5495
|
+
},
|
|
5496
|
+
0
|
|
5497
|
+
],
|
|
5498
|
+
[
|
|
5499
|
+
{
|
|
5500
|
+
name: "quoted-command",
|
|
5501
|
+
run: bin("check-quoted-command"),
|
|
5502
|
+
scope: "diff",
|
|
5503
|
+
timeoutMs: 15000,
|
|
5504
|
+
env: {}
|
|
5505
|
+
},
|
|
5506
|
+
0
|
|
5507
|
+
],
|
|
5508
|
+
[
|
|
5509
|
+
{
|
|
5510
|
+
name: "main-branch-refusal",
|
|
5511
|
+
run: bin("check-main-branch-refusal"),
|
|
5512
|
+
scope: "full",
|
|
5513
|
+
timeoutMs: 15000,
|
|
5514
|
+
env: { VINAYA_PUSH_REFS: { optional: true } }
|
|
5515
|
+
},
|
|
5516
|
+
0
|
|
5517
|
+
],
|
|
5518
|
+
[
|
|
5519
|
+
{
|
|
5520
|
+
name: "token-collection-wired",
|
|
5521
|
+
run: bin("check-token-collection-wired"),
|
|
5522
|
+
scope: "full",
|
|
5523
|
+
timeoutMs: 15000,
|
|
5524
|
+
env: {
|
|
5525
|
+
CLAUDE_PROJECT_DIR: { optional: true },
|
|
5526
|
+
CLAUDE_CODE_SESSION_ID: { optional: true }
|
|
5527
|
+
}
|
|
5528
|
+
},
|
|
5529
|
+
0
|
|
5530
|
+
]
|
|
5531
|
+
];
|
|
5532
|
+
function coreCheckRegistry() {
|
|
5533
|
+
return REGISTRY.map(([spec]) => spec);
|
|
5534
|
+
}
|
|
5535
|
+
var CORE_CHECK_RING = Object.fromEntries(REGISTRY.map(([spec, ring]) => [spec.name, ring]));
|
|
5536
|
+
|
|
4977
5537
|
// src/checks/contract.ts
|
|
4978
5538
|
var CHECK_SCHEMA_VERSION = 1;
|
|
4979
5539
|
function emitCheckError(error) {
|
|
@@ -5001,8 +5561,8 @@ function summariseNumstat(numstat) {
|
|
|
5001
5561
|
deleted += Number(d) || 0;
|
|
5002
5562
|
}
|
|
5003
5563
|
const files = `${rows.length} file${rows.length === 1 ? "" : "s"} changed`;
|
|
5004
|
-
const
|
|
5005
|
-
return `${files}, ${added} insertion${added === 1 ? "" : "s"}(+), ${deleted} deletion${deleted === 1 ? "" : "s"}(-)${
|
|
5564
|
+
const bin2 = binary > 0 ? `, ${binary} binary` : "";
|
|
5565
|
+
return `${files}, ${added} insertion${added === 1 ? "" : "s"}(+), ${deleted} deletion${deleted === 1 ? "" : "s"}(-)${bin2}`;
|
|
5006
5566
|
}
|
|
5007
5567
|
var EVIDENCE_SUMMARY_PREFIX = "Summary: ";
|
|
5008
5568
|
|
|
@@ -5059,28 +5619,11 @@ function summaryLineIndex(maskedRegion) {
|
|
|
5059
5619
|
return index === -1 ? null : index;
|
|
5060
5620
|
}
|
|
5061
5621
|
|
|
5062
|
-
// src/lib/package-root.ts
|
|
5063
|
-
import { existsSync } from "node:fs";
|
|
5064
|
-
import { dirname, join } from "node:path";
|
|
5065
|
-
import { fileURLToPath } from "node:url";
|
|
5066
|
-
function packageRoot(moduleUrl) {
|
|
5067
|
-
let dir = dirname(fileURLToPath(moduleUrl));
|
|
5068
|
-
while (!existsSync(join(dir, "package.json"))) {
|
|
5069
|
-
if (existsSync(join(dir, ".git")))
|
|
5070
|
-
break;
|
|
5071
|
-
const parent = dirname(dir);
|
|
5072
|
-
if (parent === dir)
|
|
5073
|
-
break;
|
|
5074
|
-
dir = parent;
|
|
5075
|
-
}
|
|
5076
|
-
return dir;
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
5622
|
// src/lib/config.ts
|
|
5080
5623
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
5081
|
-
import { existsSync as
|
|
5624
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "node:fs";
|
|
5082
5625
|
import { homedir } from "node:os";
|
|
5083
|
-
import { dirname as dirname2, join as
|
|
5626
|
+
import { dirname as dirname2, join as join3, resolve } from "node:path";
|
|
5084
5627
|
import { z as z2 } from "zod";
|
|
5085
5628
|
|
|
5086
5629
|
// src/lib/agent-vendors.ts
|
|
@@ -5234,16 +5777,16 @@ var VinayaConfigSchema = z2.object({
|
|
|
5234
5777
|
agent: z2.enum(["claude", "codex", "gemini"]).optional()
|
|
5235
5778
|
}).optional()
|
|
5236
5779
|
});
|
|
5237
|
-
var GLOBAL_VINAYA_HOME =
|
|
5238
|
-
var GLOBAL_CONFIG_PATH =
|
|
5780
|
+
var GLOBAL_VINAYA_HOME = join3(homedir(), ".vinaya");
|
|
5781
|
+
var GLOBAL_CONFIG_PATH = join3(GLOBAL_VINAYA_HOME, "config.json");
|
|
5239
5782
|
var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
5240
5783
|
function findLocalConfig() {
|
|
5241
5784
|
let dir = process.cwd();
|
|
5242
5785
|
while (true) {
|
|
5243
|
-
const candidate =
|
|
5244
|
-
if (
|
|
5786
|
+
const candidate = join3(dir, LOCAL_CONFIG_FILENAME);
|
|
5787
|
+
if (existsSync3(candidate))
|
|
5245
5788
|
return candidate;
|
|
5246
|
-
if (
|
|
5789
|
+
if (existsSync3(join3(dir, ".git")))
|
|
5247
5790
|
return null;
|
|
5248
5791
|
const parent = dirname2(dir);
|
|
5249
5792
|
if (parent === dir)
|
|
@@ -5255,7 +5798,7 @@ function configPath() {
|
|
|
5255
5798
|
const local = findLocalConfig();
|
|
5256
5799
|
if (local)
|
|
5257
5800
|
return local;
|
|
5258
|
-
if (
|
|
5801
|
+
if (existsSync3(GLOBAL_CONFIG_PATH))
|
|
5259
5802
|
return GLOBAL_CONFIG_PATH;
|
|
5260
5803
|
return null;
|
|
5261
5804
|
}
|
|
@@ -5383,7 +5926,7 @@ function loadConfig() {
|
|
|
5383
5926
|
return null;
|
|
5384
5927
|
}
|
|
5385
5928
|
}
|
|
5386
|
-
var TOKENS_COLLECT_TRUST_PATH =
|
|
5929
|
+
var TOKENS_COLLECT_TRUST_PATH = join3(GLOBAL_VINAYA_HOME, "tokens-collect-trust.json");
|
|
5387
5930
|
|
|
5388
5931
|
// src/commands/tokens.ts
|
|
5389
5932
|
var USAGE = [
|
|
@@ -5406,6 +5949,10 @@ var USAGE = [
|
|
|
5406
5949
|
`);
|
|
5407
5950
|
|
|
5408
5951
|
// src/commands/pr-report.ts
|
|
5952
|
+
var BODY_READING_CHECK_NAMES = new Set(coreCheckRegistry().filter((spec) => {
|
|
5953
|
+
const decl = spec.env?.PR_BODY;
|
|
5954
|
+
return decl === true || typeof decl === "object" && decl !== null && "optional" in decl;
|
|
5955
|
+
}).map((spec) => spec.name));
|
|
5409
5956
|
var FAILING_STATUSES = new Set(["fail", "error", "timeout"]);
|
|
5410
5957
|
function extractAgentCommandLines(prBody) {
|
|
5411
5958
|
const located = locateTestPlanSection(prBody);
|
|
@@ -5441,10 +5988,36 @@ var TOKEN_ROW_REMEDY = [
|
|
|
5441
5988
|
`);
|
|
5442
5989
|
var USAGE2 = "Usage: vinaya pr report [--write <body-file> | --push <pr>] [--phase <phase>] [--role <role>] " + "[--model <id>] [--transcript <path>]";
|
|
5443
5990
|
|
|
5991
|
+
// src/lib/patch-id.ts
|
|
5992
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
5993
|
+
function patchIdAt(base, sha) {
|
|
5994
|
+
try {
|
|
5995
|
+
execFileSync3("git", ["fetch", "--quiet", "origin", sha], { stdio: ["ignore", "ignore", "ignore"] });
|
|
5996
|
+
} catch {}
|
|
5997
|
+
try {
|
|
5998
|
+
const diff = execFileSync3("git", ["diff", `origin/${base}...${sha}`], {
|
|
5999
|
+
encoding: "utf8",
|
|
6000
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
6001
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
6002
|
+
});
|
|
6003
|
+
if (diff === "")
|
|
6004
|
+
return null;
|
|
6005
|
+
const out = execFileSync3("git", ["patch-id", "--stable"], {
|
|
6006
|
+
input: diff,
|
|
6007
|
+
encoding: "utf8",
|
|
6008
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
6009
|
+
}).trim();
|
|
6010
|
+
const id = out.split(/\s+/)[0] ?? "";
|
|
6011
|
+
return id === "" ? null : id;
|
|
6012
|
+
} catch {
|
|
6013
|
+
return null;
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
|
|
5444
6017
|
// src/checks/evidence-fresh-logic.ts
|
|
5445
6018
|
var HEAD_LINE = /^Head:\s*([0-9a-f]{7,40})\s*$/m;
|
|
5446
6019
|
var FENCE = /```[^\n]*\n?([\s\S]*?)```/g;
|
|
5447
|
-
function compareEvidenceBlock(resolved, resolvedHead, actualNumstat, expectedGroupCCommandLines) {
|
|
6020
|
+
function compareEvidenceBlock(resolved, resolvedHead, actualNumstat, expectedGroupCCommandLines, patchIdOf) {
|
|
5448
6021
|
const region = resolved.region;
|
|
5449
6022
|
const headMatch = region.match(HEAD_LINE);
|
|
5450
6023
|
const fences = [...region.matchAll(FENCE)].map((m) => (m[1] ?? "").trim());
|
|
@@ -5461,7 +6034,16 @@ function compareEvidenceBlock(resolved, resolvedHead, actualNumstat, expectedGro
|
|
|
5461
6034
|
const actual = actualNumstat.trim();
|
|
5462
6035
|
const errors = [];
|
|
5463
6036
|
if (storedHead !== resolvedHead) {
|
|
5464
|
-
|
|
6037
|
+
let samePatch = false;
|
|
6038
|
+
if (patchIdOf) {
|
|
6039
|
+
const storedPatchId = patchIdOf(storedHead);
|
|
6040
|
+
const resolvedPatchId = patchIdOf(resolvedHead);
|
|
6041
|
+
samePatch = storedPatchId !== null && resolvedPatchId !== null && storedPatchId === resolvedPatchId;
|
|
6042
|
+
}
|
|
6043
|
+
if (!samePatch) {
|
|
6044
|
+
const patchNote = patchIdOf ? ", and the patch changed" : "";
|
|
6045
|
+
errors.push(`evidence-fresh: Group B is stale — the block's Head (${storedHead}) does not match the PR's real head (${resolvedHead})${patchNote}. Re-run \`vinaya pr report --write\` against the current head, commit, and push again.`);
|
|
6046
|
+
}
|
|
5465
6047
|
}
|
|
5466
6048
|
if (storedNumstat !== actual) {
|
|
5467
6049
|
errors.push([
|
|
@@ -5519,7 +6101,7 @@ function compareEvidenceBlock(resolved, resolvedHead, actualNumstat, expectedGro
|
|
|
5519
6101
|
var CHECK_NAME = "evidence-fresh";
|
|
5520
6102
|
function git(args) {
|
|
5521
6103
|
try {
|
|
5522
|
-
return
|
|
6104
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
5523
6105
|
} catch {
|
|
5524
6106
|
return "";
|
|
5525
6107
|
}
|
|
@@ -5538,7 +6120,7 @@ class GitCommandError extends Error {
|
|
|
5538
6120
|
}
|
|
5539
6121
|
function gitStrict(args) {
|
|
5540
6122
|
try {
|
|
5541
|
-
return
|
|
6123
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
5542
6124
|
} catch (err) {
|
|
5543
6125
|
const stderr = err.stderr;
|
|
5544
6126
|
throw new GitCommandError(args, String(stderr ?? err.message).trim() || "non-zero exit");
|
|
@@ -5554,13 +6136,16 @@ function resolveMergeBase(head) {
|
|
|
5554
6136
|
}
|
|
5555
6137
|
throw new UnresolvableMergeBaseError(tried);
|
|
5556
6138
|
}
|
|
5557
|
-
function
|
|
6139
|
+
function fetchPrRefs(prNumber) {
|
|
5558
6140
|
try {
|
|
5559
|
-
const out =
|
|
6141
|
+
const out = execFileSync4("gh", ["pr", "view", String(prNumber), "--json", "headRefOid,baseRefName"], {
|
|
5560
6142
|
encoding: "utf8",
|
|
5561
6143
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5562
|
-
})
|
|
5563
|
-
|
|
6144
|
+
});
|
|
6145
|
+
const parsed = JSON.parse(out);
|
|
6146
|
+
if (!parsed.headRefOid || !parsed.baseRefName)
|
|
6147
|
+
return null;
|
|
6148
|
+
return { head: parsed.headRefOid, base: parsed.baseRefName };
|
|
5564
6149
|
} catch {
|
|
5565
6150
|
return null;
|
|
5566
6151
|
}
|
|
@@ -5588,17 +6173,18 @@ function main() {
|
|
|
5588
6173
|
if (!prNumberStr) {
|
|
5589
6174
|
process.exit(0);
|
|
5590
6175
|
}
|
|
5591
|
-
const
|
|
5592
|
-
if (
|
|
6176
|
+
const prRefs = fetchPrRefs(Number(prNumberStr));
|
|
6177
|
+
if (prRefs === null) {
|
|
5593
6178
|
emitCheckError({
|
|
5594
6179
|
schema: CHECK_SCHEMA_VERSION,
|
|
5595
6180
|
check: CHECK_NAME,
|
|
5596
6181
|
severity: "error",
|
|
5597
|
-
message: `evidence-fresh: could not resolve PR #${prNumberStr}'s head via \`gh pr view --json headRefOid\`.`,
|
|
6182
|
+
message: `evidence-fresh: could not resolve PR #${prNumberStr}'s head and base via \`gh pr view --json headRefOid,baseRefName\`.`,
|
|
5598
6183
|
agent_recovery_prompt: "Confirm `gh auth status` passes and PR_NUMBER is correct, then re-run `vinaya check evidence-fresh`."
|
|
5599
6184
|
});
|
|
5600
6185
|
process.exit(1);
|
|
5601
6186
|
}
|
|
6187
|
+
const resolvedHead = prRefs.head;
|
|
5602
6188
|
let base;
|
|
5603
6189
|
let actualNumstat;
|
|
5604
6190
|
try {
|
|
@@ -5615,7 +6201,8 @@ function main() {
|
|
|
5615
6201
|
process.exit(1);
|
|
5616
6202
|
}
|
|
5617
6203
|
const expectedGroupCCommandLines = extractAgentCommandLines(body).map(agentCommandText);
|
|
5618
|
-
const
|
|
6204
|
+
const patchIdOf = (sha) => patchIdAt(prRefs.base, sha);
|
|
6205
|
+
const result = compareEvidenceBlock(resolved, resolvedHead, actualNumstat, expectedGroupCCommandLines, patchIdOf);
|
|
5619
6206
|
if (result.status === "fail") {
|
|
5620
6207
|
for (const message of result.errors) {
|
|
5621
6208
|
emitCheckError({
|