@attalabs/vinaya 0.18.0 → 0.19.1
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 +37 -1
- package/aeg-root/contracts/architect-planner.md +72 -0
- package/aeg-root/enforcement.md +3 -2
- package/aeg-root/roles/architect.md +91 -0
- package/aeg-root/roles/planner.md +14 -15
- package/aeg-root/tranche-model.md +9 -1
- package/dist/checks/bin/check-body-bare-digits.js +262 -26
- package/dist/checks/bin/check-branch-topology.js +171 -23
- package/dist/checks/bin/check-brief-shape.js +171 -23
- package/dist/checks/bin/check-closes-n.js +171 -23
- package/dist/checks/bin/check-coherence.js +265 -29
- package/dist/checks/bin/check-dead-branch-push.js +171 -23
- package/dist/checks/bin/check-dispatch-readiness.js +329 -53
- package/dist/checks/bin/check-doc-coverage-push.js +266 -30
- package/dist/checks/bin/check-doc-coverage.js +266 -30
- package/dist/checks/bin/check-evidence-fresh.js +171 -23
- package/dist/checks/bin/check-first-push-dispatch.js +330 -54
- package/dist/checks/bin/check-issue-assignment.js +171 -23
- package/dist/checks/bin/check-no-disk-state.js +171 -23
- package/dist/checks/bin/check-reader-resolvable-prose.js +465 -46
- package/dist/checks/bin/check-registry-gates.js +171 -23
- package/dist/checks/bin/check-retired-vocabulary.js +3595 -0
- package/dist/checks/bin/check-review-gate.js +262 -26
- package/dist/checks/bin/check-single-plan-pr.js +171 -23
- package/dist/checks/bin/check-test-plan.js +171 -23
- package/dist/index.js +2959 -1581
- package/package.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__0e95dv5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__029-1ch._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0q56ohl._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0z47hfl._.js → [root-of-the-server]__0xdkvod._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1_ojzp1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1d_8nm4._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1zkwtx8._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__210ehg9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_00yjcv1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0rix02i._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_18-d2be._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +5 -5
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1gw6vc9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2myi4phnshkfw.js → 1zaotsjjq5o6o.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{415k4k1rf3swg.js → 295mri9sjante.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3z3a3gb6he23i.js → 2opd70pfbc5yx.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- package/templates/noop-check.template.ts +18 -0
- package/templates/role.template.md +20 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → SG6gXRhit12wl-8HLX9d3}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → SG6gXRhit12wl-8HLX9d3}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → SG6gXRhit12wl-8HLX9d3}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/checks/bin/check-first-push-dispatch.ts
|
|
4
|
-
import { execFileSync as
|
|
4
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
5
5
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
6
6
|
function maskCode(body) {
|
|
7
7
|
const fill = (line) => " ".repeat(line.length);
|
|
@@ -273,6 +273,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
273
273
|
"200"
|
|
274
274
|
];
|
|
275
275
|
}
|
|
276
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
277
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
278
|
+
}
|
|
276
279
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
277
280
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
278
281
|
}
|
|
@@ -288,18 +291,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
288
291
|
return dedupeByNumber(perLabel.flat());
|
|
289
292
|
}
|
|
290
293
|
|
|
291
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
292
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
293
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
294
|
-
const match = milestones.find((m) => m.title === slug);
|
|
295
|
-
if (!match)
|
|
296
|
-
return null;
|
|
297
|
-
return {
|
|
298
|
-
goal: match.description ?? "",
|
|
299
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
294
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
304
295
|
var LABELS = [
|
|
305
296
|
{
|
|
@@ -542,6 +533,66 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
542
533
|
return { trancheSlug, taskId };
|
|
543
534
|
}
|
|
544
535
|
|
|
536
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
537
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
538
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
539
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
540
|
+
function intentGoalForSlug(description, slug) {
|
|
541
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
542
|
+
const start = text.match(INTENTS_HEADING);
|
|
543
|
+
if (!start || start.index === undefined)
|
|
544
|
+
return "";
|
|
545
|
+
const rest = text.slice(start.index + start[0].length);
|
|
546
|
+
const next = rest.match(NEXT_HEADING);
|
|
547
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
548
|
+
for (const line of section.split(`
|
|
549
|
+
`)) {
|
|
550
|
+
const trimmed = line.trim();
|
|
551
|
+
if (trimmed.length === 0)
|
|
552
|
+
continue;
|
|
553
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
554
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
555
|
+
return (m[2] ?? "").trim();
|
|
556
|
+
}
|
|
557
|
+
return "";
|
|
558
|
+
}
|
|
559
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
560
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
561
|
+
}
|
|
562
|
+
function factsFromLegacyMilestone(milestone) {
|
|
563
|
+
return {
|
|
564
|
+
goal: milestone.description ?? "",
|
|
565
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function resolveLegacyFacts(milestone, labelIssues) {
|
|
569
|
+
if (milestone.state === "closed" && labelIssues.length > 0) {
|
|
570
|
+
return { goal: milestone.description ?? "", lifecycle: lifecycleFromIssues(labelIssues) };
|
|
571
|
+
}
|
|
572
|
+
return factsFromLegacyMilestone(milestone);
|
|
573
|
+
}
|
|
574
|
+
function lifecycleFromIssues(issues) {
|
|
575
|
+
if (issues.length === 0)
|
|
576
|
+
return "planned";
|
|
577
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
578
|
+
}
|
|
579
|
+
function goalFromMilestones(milestones, slug) {
|
|
580
|
+
for (const m of milestones) {
|
|
581
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
582
|
+
if (goal)
|
|
583
|
+
return goal;
|
|
584
|
+
}
|
|
585
|
+
return "";
|
|
586
|
+
}
|
|
587
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
588
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
589
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
590
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
591
|
+
if (legacy)
|
|
592
|
+
return resolveLegacyFacts(legacy, issues);
|
|
593
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
594
|
+
}
|
|
595
|
+
|
|
545
596
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
546
597
|
function trancheFromIssues(slug, issues, known) {
|
|
547
598
|
return {
|
|
@@ -2725,16 +2776,18 @@ function checkDeadBranchPush(input) {
|
|
|
2725
2776
|
}
|
|
2726
2777
|
// ../../packages/aeg-core/src/reader-resolvable-prose.ts
|
|
2727
2778
|
var SHIPS_PREFIX = "aeg-root/";
|
|
2728
|
-
|
|
2779
|
+
function shipsArchivePrefix(shipsPrefix) {
|
|
2780
|
+
return `${shipsPrefix}tranches/completed/`;
|
|
2781
|
+
}
|
|
2729
2782
|
function isSpecFile2(path) {
|
|
2730
2783
|
return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
|
|
2731
2784
|
}
|
|
2732
2785
|
function isClaudeMdFile(path) {
|
|
2733
2786
|
return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
|
|
2734
2787
|
}
|
|
2735
|
-
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
|
|
2736
|
-
if (path.startsWith(
|
|
2737
|
-
return path.startsWith(
|
|
2788
|
+
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2789
|
+
if (path.startsWith(shipsPrefix)) {
|
|
2790
|
+
return path.startsWith(shipsArchivePrefix(shipsPrefix)) ? "internal" : "ships";
|
|
2738
2791
|
}
|
|
2739
2792
|
if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
|
|
2740
2793
|
return "reader-facing";
|
|
@@ -2769,7 +2822,7 @@ function legacySlugPattern(legacySlugs) {
|
|
|
2769
2822
|
const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2770
2823
|
return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
|
|
2771
2824
|
}
|
|
2772
|
-
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2825
|
+
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2773
2826
|
const findings = [];
|
|
2774
2827
|
const legacyPattern = legacySlugPattern(legacySlugs);
|
|
2775
2828
|
const patterns = [
|
|
@@ -2778,7 +2831,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
|
|
|
2778
2831
|
...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
|
|
2779
2832
|
];
|
|
2780
2833
|
for (const file of files) {
|
|
2781
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2834
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2782
2835
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2783
2836
|
continue;
|
|
2784
2837
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2824,10 +2877,10 @@ function definesOrLinksGlossary(content, term) {
|
|
|
2824
2877
|
return true;
|
|
2825
2878
|
return /docs\/glossary|glossary\.md/i.test(content);
|
|
2826
2879
|
}
|
|
2827
|
-
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
|
|
2880
|
+
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2828
2881
|
const findings = [];
|
|
2829
2882
|
for (const file of files) {
|
|
2830
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2883
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2831
2884
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2832
2885
|
continue;
|
|
2833
2886
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2846,10 +2899,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
|
|
|
2846
2899
|
}
|
|
2847
2900
|
return findings;
|
|
2848
2901
|
}
|
|
2849
|
-
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2902
|
+
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2850
2903
|
return [
|
|
2851
|
-
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
|
|
2852
|
-
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
|
|
2904
|
+
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
|
|
2905
|
+
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
|
|
2853
2906
|
];
|
|
2854
2907
|
}
|
|
2855
2908
|
function parseGlossaryTerms(glossaryContent) {
|
|
@@ -2863,6 +2916,101 @@ function parseGlossaryTerms(glossaryContent) {
|
|
|
2863
2916
|
}
|
|
2864
2917
|
return terms;
|
|
2865
2918
|
}
|
|
2919
|
+
// ../../packages/aeg-core/src/retired-vocabulary.ts
|
|
2920
|
+
var RETIRED_PATTERNS = [
|
|
2921
|
+
String.raw`\bD-[0-9]{3}\b`,
|
|
2922
|
+
"D-(###|NNN|nnn|xxx)",
|
|
2923
|
+
"decision (entry|logged)",
|
|
2924
|
+
"decision-log entry",
|
|
2925
|
+
"decision log entry",
|
|
2926
|
+
"decision log(s|ged|ging)?([^a-z]|$)",
|
|
2927
|
+
"decision-log",
|
|
2928
|
+
"decision entr",
|
|
2929
|
+
"decisions? (are |is )?logged",
|
|
2930
|
+
"log entries",
|
|
2931
|
+
String.raw`decisions\.md`,
|
|
2932
|
+
"decisions-legacy",
|
|
2933
|
+
"CONTRADICTION",
|
|
2934
|
+
"assumes Tier 3",
|
|
2935
|
+
"Lock: ?YES",
|
|
2936
|
+
"Lock: ?NO",
|
|
2937
|
+
"lock approvals?",
|
|
2938
|
+
"approves locks",
|
|
2939
|
+
"Conforms to lock",
|
|
2940
|
+
"Challenges lock",
|
|
2941
|
+
"checkDecisionNumbersFresh",
|
|
2942
|
+
String.raw`roles/team-leader\.md`,
|
|
2943
|
+
String.raw`\(,`,
|
|
2944
|
+
String.raw`,\)`,
|
|
2945
|
+
String.raw`\(\.\)`
|
|
2946
|
+
];
|
|
2947
|
+
var RETIRED_EXEMPT_SUBSTRINGS = [
|
|
2948
|
+
"docs/decisions-legacy.md",
|
|
2949
|
+
"apps/herald-ai/docs/",
|
|
2950
|
+
"apps/vada-ai/docs/",
|
|
2951
|
+
"aeg-root/tranches/completed/",
|
|
2952
|
+
"packages/aeg-core/src/docs/published-prose",
|
|
2953
|
+
"packages/aeg-core/src/retired-vocabulary.test.ts",
|
|
2954
|
+
"packages/aeg-core/src/retired-vocabulary.ts",
|
|
2955
|
+
"/fixtures/",
|
|
2956
|
+
"/node_modules/",
|
|
2957
|
+
"/.next/",
|
|
2958
|
+
"/.turbo/"
|
|
2959
|
+
];
|
|
2960
|
+
var PATTERN_EXEMPT = {
|
|
2961
|
+
[String.raw`\bD-[0-9]{3}\b`]: ["./CLAUDE.md"],
|
|
2962
|
+
[String.raw`decisions\.md`]: [
|
|
2963
|
+
"docs-index.md",
|
|
2964
|
+
"apps/vada-ai/specs/legacy/README.md",
|
|
2965
|
+
"apps/vada-ai/specs/vada-product-spec.md",
|
|
2966
|
+
"apps/vada-ai/web/CLAUDE.md",
|
|
2967
|
+
"apps/vada-ai/CLAUDE.md"
|
|
2968
|
+
],
|
|
2969
|
+
"decisions-legacy": [
|
|
2970
|
+
"packages/aeg-core/src/file-classify.ts",
|
|
2971
|
+
"packages/aeg-core/src/file-classify.test.ts",
|
|
2972
|
+
"packages/aeg-core/src/pr-tier.test.ts",
|
|
2973
|
+
"docs-index.md",
|
|
2974
|
+
".claude/skills/database/SKILL.md",
|
|
2975
|
+
".claude/skills/vada-architecture/SKILL.md",
|
|
2976
|
+
"apps/vada-ai/specs/vada-byok-principles.md",
|
|
2977
|
+
"apps/vada-ai/web/CLAUDE.md",
|
|
2978
|
+
"apps/vada-ai/CLAUDE.md"
|
|
2979
|
+
],
|
|
2980
|
+
CONTRADICTION: ["apps/vada-ai/specs/vada-reviewers-spec.md"]
|
|
2981
|
+
};
|
|
2982
|
+
function lineNumbers(content, pattern) {
|
|
2983
|
+
const out = [];
|
|
2984
|
+
const lines = content.split(`
|
|
2985
|
+
`);
|
|
2986
|
+
for (let i = 0;i < lines.length; i++) {
|
|
2987
|
+
if (pattern.test(lines[i] ?? ""))
|
|
2988
|
+
out.push(i + 1);
|
|
2989
|
+
}
|
|
2990
|
+
return out;
|
|
2991
|
+
}
|
|
2992
|
+
function scanRetiredVocabulary(files) {
|
|
2993
|
+
const findings = [];
|
|
2994
|
+
for (const file of files) {
|
|
2995
|
+
if (RETIRED_EXEMPT_SUBSTRINGS.some((e) => file.path.includes(e)))
|
|
2996
|
+
continue;
|
|
2997
|
+
for (const pattern of RETIRED_PATTERNS) {
|
|
2998
|
+
const patternExempt = PATTERN_EXEMPT[pattern] ?? [];
|
|
2999
|
+
if (patternExempt.some((e) => file.path.includes(e)))
|
|
3000
|
+
continue;
|
|
3001
|
+
const re = new RegExp(pattern);
|
|
3002
|
+
for (const line of lineNumbers(file.content, re)) {
|
|
3003
|
+
findings.push({
|
|
3004
|
+
file: file.path,
|
|
3005
|
+
line,
|
|
3006
|
+
pattern,
|
|
3007
|
+
message: `claims a retired AEG mechanism is still live (matches /${pattern}/)`
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
return findings;
|
|
3013
|
+
}
|
|
2866
3014
|
// ../../packages/aeg-core/src/dispatch-gate.ts
|
|
2867
3015
|
function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
|
|
2868
3016
|
return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
|
|
@@ -3139,9 +3287,15 @@ function emitCheckError(error) {
|
|
|
3139
3287
|
|
|
3140
3288
|
// src/lib/config.ts
|
|
3141
3289
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
3290
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3142
3291
|
import { homedir } from "node:os";
|
|
3143
3292
|
import { dirname, join } from "node:path";
|
|
3144
3293
|
import { z as z2 } from "zod";
|
|
3294
|
+
|
|
3295
|
+
// src/lib/agent-vendors.ts
|
|
3296
|
+
var AGENT_VENDORS = ["skills", "claude", "gemini"];
|
|
3297
|
+
|
|
3298
|
+
// src/lib/config.ts
|
|
3145
3299
|
var EnvEntrySchema = z2.union([
|
|
3146
3300
|
z2.literal(true),
|
|
3147
3301
|
z2.object({ optional: z2.literal(true) }),
|
|
@@ -3180,6 +3334,11 @@ var CheckEntrySchema = z2.object({
|
|
|
3180
3334
|
}
|
|
3181
3335
|
}
|
|
3182
3336
|
});
|
|
3337
|
+
var RoleEntrySchema = z2.object({
|
|
3338
|
+
contract: z2.string().refine((p) => p.includes("/"), {
|
|
3339
|
+
message: 'must be a path (contain at least one "/"), not a bare filename'
|
|
3340
|
+
})
|
|
3341
|
+
});
|
|
3183
3342
|
var BRIEF_BUILTINS = [
|
|
3184
3343
|
"tier",
|
|
3185
3344
|
"testPlan",
|
|
@@ -3194,7 +3353,8 @@ var BRIEF_BUILTINS = [
|
|
|
3194
3353
|
"for",
|
|
3195
3354
|
"closesN",
|
|
3196
3355
|
"premiseCoverage",
|
|
3197
|
-
"issueRationale"
|
|
3356
|
+
"issueRationale",
|
|
3357
|
+
"milestoneShape"
|
|
3198
3358
|
];
|
|
3199
3359
|
var BriefSectionSchema = z2.union([
|
|
3200
3360
|
z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
|
|
@@ -3205,6 +3365,7 @@ var BriefSectionSchema = z2.union([
|
|
|
3205
3365
|
var BriefSchemaSchema = z2.object({
|
|
3206
3366
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3207
3367
|
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3368
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3208
3369
|
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3209
3370
|
});
|
|
3210
3371
|
function isSafeRepoRelPath(p) {
|
|
@@ -3226,7 +3387,8 @@ var ManagedManifestSchema = z2.object({
|
|
|
3226
3387
|
version: z2.number().int().positive(),
|
|
3227
3388
|
files: z2.array(SafeRepoRelPath),
|
|
3228
3389
|
blocks: z2.array(ManagedBlockRecordSchema),
|
|
3229
|
-
labels: z2.array(z2.string())
|
|
3390
|
+
labels: z2.array(z2.string()),
|
|
3391
|
+
agents: z2.array(z2.enum(AGENT_VENDORS)).optional()
|
|
3230
3392
|
});
|
|
3231
3393
|
var VinayaConfigSchema = z2.object({
|
|
3232
3394
|
rings: z2.object({
|
|
@@ -3234,16 +3396,79 @@ var VinayaConfigSchema = z2.object({
|
|
|
3234
3396
|
ring2_asyncAudits: z2.boolean()
|
|
3235
3397
|
}).optional(),
|
|
3236
3398
|
checks: z2.record(z2.string(), CheckEntrySchema).optional(),
|
|
3399
|
+
roles: z2.record(z2.string(), RoleEntrySchema).optional(),
|
|
3237
3400
|
briefSchema: BriefSchemaSchema.optional(),
|
|
3238
3401
|
managed: ManagedManifestSchema.optional(),
|
|
3239
3402
|
principals: z2.array(z2.string()).min(1).optional(),
|
|
3240
3403
|
releaseActor: z2.string().min(1).optional(),
|
|
3241
3404
|
ci: z2.object({ setup: z2.string().min(1) }).optional(),
|
|
3242
|
-
blastRadius: z2.object({ extraDomains: z2.array(z2.string()).optional() }).optional()
|
|
3405
|
+
blastRadius: z2.object({ extraDomains: z2.array(z2.string()).optional() }).optional(),
|
|
3406
|
+
proseGates: z2.object({
|
|
3407
|
+
doctrineRoot: z2.string().min(1).optional(),
|
|
3408
|
+
readerFacingPrefix: z2.string().min(1).optional(),
|
|
3409
|
+
readerFacingSuffix: z2.string().min(1).optional(),
|
|
3410
|
+
legacySlugDir: z2.string().min(1).optional()
|
|
3411
|
+
}).optional()
|
|
3243
3412
|
});
|
|
3244
3413
|
var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
|
|
3245
3414
|
var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
|
|
3246
3415
|
var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
3416
|
+
function findLocalConfig() {
|
|
3417
|
+
let dir = process.cwd();
|
|
3418
|
+
while (true) {
|
|
3419
|
+
const candidate = join(dir, LOCAL_CONFIG_FILENAME);
|
|
3420
|
+
if (existsSync(candidate))
|
|
3421
|
+
return candidate;
|
|
3422
|
+
if (existsSync(join(dir, ".git")))
|
|
3423
|
+
return null;
|
|
3424
|
+
const parent = dirname(dir);
|
|
3425
|
+
if (parent === dir)
|
|
3426
|
+
return null;
|
|
3427
|
+
dir = parent;
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
function configPath() {
|
|
3431
|
+
const local = findLocalConfig();
|
|
3432
|
+
if (local)
|
|
3433
|
+
return local;
|
|
3434
|
+
if (existsSync(GLOBAL_CONFIG_PATH))
|
|
3435
|
+
return GLOBAL_CONFIG_PATH;
|
|
3436
|
+
return null;
|
|
3437
|
+
}
|
|
3438
|
+
function globalChecksIgnoredWarning(path) {
|
|
3439
|
+
return `${path}: "checks" registration in the global config is ignored — checks may only be registered from a repo-local vinaya.config.json.`;
|
|
3440
|
+
}
|
|
3441
|
+
function globalPrincipalsIgnoredWarning(path) {
|
|
3442
|
+
return `${path}: "principals" in the global config is ignored — principals may only be declared from a repo-local vinaya.config.json.`;
|
|
3443
|
+
}
|
|
3444
|
+
function globalRolesIgnoredWarning(path) {
|
|
3445
|
+
return `${path}: "roles" registration in the global config is ignored — roles may only be registered from a repo-local vinaya.config.json.`;
|
|
3446
|
+
}
|
|
3447
|
+
function globalReleaseActorIgnoredWarning(path) {
|
|
3448
|
+
return `${path}: "releaseActor" in the global config is ignored — releaseActor may only be declared from a repo-local vinaya.config.json.`;
|
|
3449
|
+
}
|
|
3450
|
+
function stripGlobalOnlyKeys(config, path) {
|
|
3451
|
+
if (path !== GLOBAL_CONFIG_PATH)
|
|
3452
|
+
return config;
|
|
3453
|
+
let result = config;
|
|
3454
|
+
if (result.checks && Object.keys(result.checks).length > 0) {
|
|
3455
|
+
console.error(`⚠ ${globalChecksIgnoredWarning(path)}`);
|
|
3456
|
+
result = { ...result, checks: undefined };
|
|
3457
|
+
}
|
|
3458
|
+
if (result.roles && Object.keys(result.roles).length > 0) {
|
|
3459
|
+
console.error(`⚠ ${globalRolesIgnoredWarning(path)}`);
|
|
3460
|
+
result = { ...result, roles: undefined };
|
|
3461
|
+
}
|
|
3462
|
+
if (result.principals && result.principals.length > 0) {
|
|
3463
|
+
console.error(`⚠ ${globalPrincipalsIgnoredWarning(path)}`);
|
|
3464
|
+
result = { ...result, principals: undefined };
|
|
3465
|
+
}
|
|
3466
|
+
if (result.releaseActor) {
|
|
3467
|
+
console.error(`⚠ ${globalReleaseActorIgnoredWarning(path)}`);
|
|
3468
|
+
result = { ...result, releaseActor: undefined };
|
|
3469
|
+
}
|
|
3470
|
+
return result;
|
|
3471
|
+
}
|
|
3247
3472
|
function resolvePrincipalAllowlist(config) {
|
|
3248
3473
|
return config?.principals ?? PRINCIPAL_ALLOWLIST;
|
|
3249
3474
|
}
|
|
@@ -3316,12 +3541,86 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3316
3541
|
return null;
|
|
3317
3542
|
}
|
|
3318
3543
|
}
|
|
3544
|
+
function loadConfig() {
|
|
3545
|
+
const path = configPath();
|
|
3546
|
+
if (!path)
|
|
3547
|
+
return null;
|
|
3548
|
+
try {
|
|
3549
|
+
const raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
3550
|
+
return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
|
|
3551
|
+
} catch {
|
|
3552
|
+
return null;
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
// src/checks/edge-resolve.ts
|
|
3557
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3558
|
+
var DIRECT_ISSUE_REF = /#(\d+)/;
|
|
3559
|
+
var issueCache = new Map;
|
|
3560
|
+
function fetchIssueState(num, repo) {
|
|
3561
|
+
const key = `${repo.owner}/${repo.repo}#${num}`;
|
|
3562
|
+
if (issueCache.has(key))
|
|
3563
|
+
return issueCache.get(key) ?? null;
|
|
3564
|
+
let out = null;
|
|
3565
|
+
try {
|
|
3566
|
+
const raw = execFileSync3("gh", [
|
|
3567
|
+
"issue",
|
|
3568
|
+
"view",
|
|
3569
|
+
String(num),
|
|
3570
|
+
"-R",
|
|
3571
|
+
`${repo.owner}/${repo.repo}`,
|
|
3572
|
+
"--json",
|
|
3573
|
+
"state,stateReason,closedByPullRequestsReferences"
|
|
3574
|
+
], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
3575
|
+
out = JSON.parse(raw);
|
|
3576
|
+
} catch {
|
|
3577
|
+
out = null;
|
|
3578
|
+
}
|
|
3579
|
+
issueCache.set(key, out);
|
|
3580
|
+
return out;
|
|
3581
|
+
}
|
|
3582
|
+
function edgeFromIssueJson(num, json) {
|
|
3583
|
+
if (json === null) {
|
|
3584
|
+
return { issue: num, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3585
|
+
}
|
|
3586
|
+
const state = json.state === "CLOSED" ? "closed" : json.state === "OPEN" ? "open" : null;
|
|
3587
|
+
const reason = json.stateReason === "COMPLETED" ? "completed" : json.stateReason === "NOT_PLANNED" ? "not_planned" : null;
|
|
3588
|
+
const closedByMergedPr = (json.closedByPullRequestsReferences ?? []).length > 0;
|
|
3589
|
+
return {
|
|
3590
|
+
issue: num,
|
|
3591
|
+
merged: state === "closed" && closedByMergedPr,
|
|
3592
|
+
open: false,
|
|
3593
|
+
issueState: state,
|
|
3594
|
+
stateReason: reason,
|
|
3595
|
+
closedByActor: null
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
function resolveEdge(id, taskById, factsByTaskId, repo) {
|
|
3599
|
+
const target = taskById.get(id);
|
|
3600
|
+
if (target) {
|
|
3601
|
+
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3602
|
+
return {
|
|
3603
|
+
issue: target.issue,
|
|
3604
|
+
merged: facts?.prState === "merged",
|
|
3605
|
+
open: facts?.prState === "open",
|
|
3606
|
+
issueState: facts?.issueState ?? null,
|
|
3607
|
+
stateReason: facts?.stateReason ?? null,
|
|
3608
|
+
closedByActor: facts?.closedByActor ?? null
|
|
3609
|
+
};
|
|
3610
|
+
}
|
|
3611
|
+
const direct = id.match(DIRECT_ISSUE_REF);
|
|
3612
|
+
if (direct) {
|
|
3613
|
+
const num = Number(direct[1]);
|
|
3614
|
+
return edgeFromIssueJson(num, fetchIssueState(num, repo));
|
|
3615
|
+
}
|
|
3616
|
+
return { issue: null, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3617
|
+
}
|
|
3319
3618
|
|
|
3320
3619
|
// src/checks/bin/check-first-push-dispatch.ts
|
|
3321
3620
|
var CHECK_NAME = "first-push-dispatch";
|
|
3322
3621
|
function git(args) {
|
|
3323
3622
|
try {
|
|
3324
|
-
return
|
|
3623
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3325
3624
|
} catch {
|
|
3326
3625
|
return "";
|
|
3327
3626
|
}
|
|
@@ -3344,7 +3643,7 @@ function resolveRepo2() {
|
|
|
3344
3643
|
}
|
|
3345
3644
|
function prExistsFor(branch) {
|
|
3346
3645
|
try {
|
|
3347
|
-
const out =
|
|
3646
|
+
const out = execFileSync4("gh", ["pr", "list", "--head", branch, "--state", "all", "--json", "number", "--limit", "1"], {
|
|
3348
3647
|
encoding: "utf8",
|
|
3349
3648
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3350
3649
|
});
|
|
@@ -3354,29 +3653,6 @@ function prExistsFor(branch) {
|
|
|
3354
3653
|
return false;
|
|
3355
3654
|
}
|
|
3356
3655
|
}
|
|
3357
|
-
function resolveEdge(id, taskById, factsByTaskId) {
|
|
3358
|
-
const target = taskById.get(id);
|
|
3359
|
-
if (target) {
|
|
3360
|
-
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3361
|
-
return {
|
|
3362
|
-
issue: target.issue,
|
|
3363
|
-
merged: facts?.prState === "merged",
|
|
3364
|
-
open: facts?.prState === "open",
|
|
3365
|
-
issueState: facts?.issueState ?? null,
|
|
3366
|
-
stateReason: facts?.stateReason ?? null,
|
|
3367
|
-
closedByActor: facts?.closedByActor ?? null
|
|
3368
|
-
};
|
|
3369
|
-
}
|
|
3370
|
-
const direct = id.match(/^#(\d+)$/);
|
|
3371
|
-
return {
|
|
3372
|
-
issue: direct ? Number(direct[1]) : null,
|
|
3373
|
-
merged: false,
|
|
3374
|
-
open: false,
|
|
3375
|
-
issueState: null,
|
|
3376
|
-
stateReason: null,
|
|
3377
|
-
closedByActor: null
|
|
3378
|
-
};
|
|
3379
|
-
}
|
|
3380
3656
|
async function classifyReadiness(trancheSlug, taskId) {
|
|
3381
3657
|
const repo = resolveRepo2();
|
|
3382
3658
|
if (!repo)
|
|
@@ -3404,7 +3680,7 @@ async function classifyReadiness(trancheSlug, taskId) {
|
|
|
3404
3680
|
const taskById = new Map(tranche.tasks.map((t) => [t.id, t]));
|
|
3405
3681
|
const factsByTaskId = snapshot.facts;
|
|
3406
3682
|
const dependsOn = task.dependsOn.map((dep) => {
|
|
3407
|
-
const r = resolveEdge(dep, taskById, factsByTaskId);
|
|
3683
|
+
const r = resolveEdge(dep, taskById, factsByTaskId, repo);
|
|
3408
3684
|
return {
|
|
3409
3685
|
id: dep,
|
|
3410
3686
|
issue: r.issue,
|
|
@@ -3415,7 +3691,7 @@ async function classifyReadiness(trancheSlug, taskId) {
|
|
|
3415
3691
|
};
|
|
3416
3692
|
});
|
|
3417
3693
|
const conflictsWith = task.conflictsWith.map((c) => {
|
|
3418
|
-
const r = resolveEdge(c, taskById, factsByTaskId);
|
|
3694
|
+
const r = resolveEdge(c, taskById, factsByTaskId, repo);
|
|
3419
3695
|
return { id: c, issue: r.issue, openOrInFlight: r.open };
|
|
3420
3696
|
});
|
|
3421
3697
|
const input = {
|