@attalabs/vinaya 0.19.0 → 0.19.2
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 +1 -1
- package/aeg-root/enforcement.md +3 -2
- package/aeg-root/milestone-model.md +75 -0
- package/aeg-root/roles/architect.md +4 -4
- package/aeg-root/skills/aeg/SKILL.md +1 -1
- package/aeg-root/task-model.md +45 -0
- package/aeg-root/tranche-model.md +16 -11
- package/dist/checks/bin/check-body-bare-digits.js +204 -15
- package/dist/checks/bin/check-branch-topology.js +116 -13
- package/dist/checks/bin/check-brief-shape.js +116 -13
- package/dist/checks/bin/check-closes-n.js +116 -13
- package/dist/checks/bin/check-coherence.js +207 -18
- package/dist/checks/bin/check-dead-branch-push.js +116 -13
- package/dist/checks/bin/check-dispatch-readiness.js +204 -15
- package/dist/checks/bin/check-doc-coverage-push.js +208 -19
- package/dist/checks/bin/check-doc-coverage.js +208 -19
- package/dist/checks/bin/check-evidence-fresh.js +116 -13
- package/dist/checks/bin/check-first-push-dispatch.js +204 -15
- package/dist/checks/bin/check-issue-assignment.js +116 -13
- package/dist/checks/bin/check-no-disk-state.js +116 -13
- package/dist/checks/bin/check-reader-resolvable-prose.js +410 -36
- package/dist/checks/bin/check-registry-gates.js +116 -13
- package/dist/checks/bin/check-retired-vocabulary.js +3595 -0
- package/dist/checks/bin/check-review-gate.js +204 -15
- package/dist/checks/bin/check-single-plan-pr.js +116 -13
- package/dist/checks/bin/check-test-plan.js +116 -13
- package/dist/index.js +2362 -1602
- 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]__0ulzsom._.js → [root-of-the-server]__0h3web3._.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]__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/{2r36w820aqwb9.js → 1hko4y648-9sa.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3ocvtlhgckh81.js → 20f41k165euzy.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2xoclb4g7d9n7.js → 3mhcu_-shkfgs.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/{RISz5nirLr1mUfMqzSaFS → Ye7cOzO7rtvyiBouNOFES}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{RISz5nirLr1mUfMqzSaFS → Ye7cOzO7rtvyiBouNOFES}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{RISz5nirLr1mUfMqzSaFS → Ye7cOzO7rtvyiBouNOFES}/_ssgManifest.js +0 -0
|
@@ -566,6 +566,12 @@ function factsFromLegacyMilestone(milestone) {
|
|
|
566
566
|
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
567
567
|
};
|
|
568
568
|
}
|
|
569
|
+
function resolveLegacyFacts(milestone, labelIssues) {
|
|
570
|
+
if (milestone.state === "closed" && labelIssues.length > 0) {
|
|
571
|
+
return { goal: milestone.description ?? "", lifecycle: lifecycleFromIssues(labelIssues) };
|
|
572
|
+
}
|
|
573
|
+
return factsFromLegacyMilestone(milestone);
|
|
574
|
+
}
|
|
569
575
|
function lifecycleFromIssues(issues) {
|
|
570
576
|
if (issues.length === 0)
|
|
571
577
|
return "planned";
|
|
@@ -582,9 +588,9 @@ function goalFromMilestones(milestones, slug) {
|
|
|
582
588
|
function findMilestoneForSlug(owner, repo, slug) {
|
|
583
589
|
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
584
590
|
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
585
|
-
if (legacy)
|
|
586
|
-
return factsFromLegacyMilestone(legacy);
|
|
587
591
|
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
592
|
+
if (legacy)
|
|
593
|
+
return resolveLegacyFacts(legacy, issues);
|
|
588
594
|
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
589
595
|
}
|
|
590
596
|
|
|
@@ -2771,16 +2777,18 @@ function checkDeadBranchPush(input) {
|
|
|
2771
2777
|
}
|
|
2772
2778
|
// ../../packages/aeg-core/src/reader-resolvable-prose.ts
|
|
2773
2779
|
var SHIPS_PREFIX = "aeg-root/";
|
|
2774
|
-
|
|
2780
|
+
function shipsArchivePrefix(shipsPrefix) {
|
|
2781
|
+
return `${shipsPrefix}tranches/completed/`;
|
|
2782
|
+
}
|
|
2775
2783
|
function isSpecFile2(path) {
|
|
2776
2784
|
return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
|
|
2777
2785
|
}
|
|
2778
2786
|
function isClaudeMdFile(path) {
|
|
2779
2787
|
return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
|
|
2780
2788
|
}
|
|
2781
|
-
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
|
|
2782
|
-
if (path.startsWith(
|
|
2783
|
-
return path.startsWith(
|
|
2789
|
+
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2790
|
+
if (path.startsWith(shipsPrefix)) {
|
|
2791
|
+
return path.startsWith(shipsArchivePrefix(shipsPrefix)) ? "internal" : "ships";
|
|
2784
2792
|
}
|
|
2785
2793
|
if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
|
|
2786
2794
|
return "reader-facing";
|
|
@@ -2815,7 +2823,7 @@ function legacySlugPattern(legacySlugs) {
|
|
|
2815
2823
|
const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2816
2824
|
return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
|
|
2817
2825
|
}
|
|
2818
|
-
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2826
|
+
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2819
2827
|
const findings = [];
|
|
2820
2828
|
const legacyPattern = legacySlugPattern(legacySlugs);
|
|
2821
2829
|
const patterns = [
|
|
@@ -2824,7 +2832,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
|
|
|
2824
2832
|
...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
|
|
2825
2833
|
];
|
|
2826
2834
|
for (const file of files) {
|
|
2827
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2835
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2828
2836
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2829
2837
|
continue;
|
|
2830
2838
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2870,10 +2878,10 @@ function definesOrLinksGlossary(content, term) {
|
|
|
2870
2878
|
return true;
|
|
2871
2879
|
return /docs\/glossary|glossary\.md/i.test(content);
|
|
2872
2880
|
}
|
|
2873
|
-
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
|
|
2881
|
+
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2874
2882
|
const findings = [];
|
|
2875
2883
|
for (const file of files) {
|
|
2876
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2884
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2877
2885
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2878
2886
|
continue;
|
|
2879
2887
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2892,10 +2900,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
|
|
|
2892
2900
|
}
|
|
2893
2901
|
return findings;
|
|
2894
2902
|
}
|
|
2895
|
-
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2903
|
+
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2896
2904
|
return [
|
|
2897
|
-
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
|
|
2898
|
-
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
|
|
2905
|
+
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
|
|
2906
|
+
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
|
|
2899
2907
|
];
|
|
2900
2908
|
}
|
|
2901
2909
|
function parseGlossaryTerms(glossaryContent) {
|
|
@@ -2909,6 +2917,101 @@ function parseGlossaryTerms(glossaryContent) {
|
|
|
2909
2917
|
}
|
|
2910
2918
|
return terms;
|
|
2911
2919
|
}
|
|
2920
|
+
// ../../packages/aeg-core/src/retired-vocabulary.ts
|
|
2921
|
+
var RETIRED_PATTERNS = [
|
|
2922
|
+
String.raw`\bD-[0-9]{3}\b`,
|
|
2923
|
+
"D-(###|NNN|nnn|xxx)",
|
|
2924
|
+
"decision (entry|logged)",
|
|
2925
|
+
"decision-log entry",
|
|
2926
|
+
"decision log entry",
|
|
2927
|
+
"decision log(s|ged|ging)?([^a-z]|$)",
|
|
2928
|
+
"decision-log",
|
|
2929
|
+
"decision entr",
|
|
2930
|
+
"decisions? (are |is )?logged",
|
|
2931
|
+
"log entries",
|
|
2932
|
+
String.raw`decisions\.md`,
|
|
2933
|
+
"decisions-legacy",
|
|
2934
|
+
"CONTRADICTION",
|
|
2935
|
+
"assumes Tier 3",
|
|
2936
|
+
"Lock: ?YES",
|
|
2937
|
+
"Lock: ?NO",
|
|
2938
|
+
"lock approvals?",
|
|
2939
|
+
"approves locks",
|
|
2940
|
+
"Conforms to lock",
|
|
2941
|
+
"Challenges lock",
|
|
2942
|
+
"checkDecisionNumbersFresh",
|
|
2943
|
+
String.raw`roles/team-leader\.md`,
|
|
2944
|
+
String.raw`\(,`,
|
|
2945
|
+
String.raw`,\)`,
|
|
2946
|
+
String.raw`\(\.\)`
|
|
2947
|
+
];
|
|
2948
|
+
var RETIRED_EXEMPT_SUBSTRINGS = [
|
|
2949
|
+
"docs/decisions-legacy.md",
|
|
2950
|
+
"apps/herald-ai/docs/",
|
|
2951
|
+
"apps/vada-ai/docs/",
|
|
2952
|
+
"aeg-root/tranches/completed/",
|
|
2953
|
+
"packages/aeg-core/src/docs/published-prose",
|
|
2954
|
+
"packages/aeg-core/src/retired-vocabulary.test.ts",
|
|
2955
|
+
"packages/aeg-core/src/retired-vocabulary.ts",
|
|
2956
|
+
"/fixtures/",
|
|
2957
|
+
"/node_modules/",
|
|
2958
|
+
"/.next/",
|
|
2959
|
+
"/.turbo/"
|
|
2960
|
+
];
|
|
2961
|
+
var PATTERN_EXEMPT = {
|
|
2962
|
+
[String.raw`\bD-[0-9]{3}\b`]: ["./CLAUDE.md"],
|
|
2963
|
+
[String.raw`decisions\.md`]: [
|
|
2964
|
+
"docs-index.md",
|
|
2965
|
+
"apps/vada-ai/specs/legacy/README.md",
|
|
2966
|
+
"apps/vada-ai/specs/vada-product-spec.md",
|
|
2967
|
+
"apps/vada-ai/web/CLAUDE.md",
|
|
2968
|
+
"apps/vada-ai/CLAUDE.md"
|
|
2969
|
+
],
|
|
2970
|
+
"decisions-legacy": [
|
|
2971
|
+
"packages/aeg-core/src/file-classify.ts",
|
|
2972
|
+
"packages/aeg-core/src/file-classify.test.ts",
|
|
2973
|
+
"packages/aeg-core/src/pr-tier.test.ts",
|
|
2974
|
+
"docs-index.md",
|
|
2975
|
+
".claude/skills/database/SKILL.md",
|
|
2976
|
+
".claude/skills/vada-architecture/SKILL.md",
|
|
2977
|
+
"apps/vada-ai/specs/vada-byok-principles.md",
|
|
2978
|
+
"apps/vada-ai/web/CLAUDE.md",
|
|
2979
|
+
"apps/vada-ai/CLAUDE.md"
|
|
2980
|
+
],
|
|
2981
|
+
CONTRADICTION: ["apps/vada-ai/specs/vada-reviewers-spec.md"]
|
|
2982
|
+
};
|
|
2983
|
+
function lineNumbers(content, pattern) {
|
|
2984
|
+
const out = [];
|
|
2985
|
+
const lines = content.split(`
|
|
2986
|
+
`);
|
|
2987
|
+
for (let i = 0;i < lines.length; i++) {
|
|
2988
|
+
if (pattern.test(lines[i] ?? ""))
|
|
2989
|
+
out.push(i + 1);
|
|
2990
|
+
}
|
|
2991
|
+
return out;
|
|
2992
|
+
}
|
|
2993
|
+
function scanRetiredVocabulary(files) {
|
|
2994
|
+
const findings = [];
|
|
2995
|
+
for (const file of files) {
|
|
2996
|
+
if (RETIRED_EXEMPT_SUBSTRINGS.some((e) => file.path.includes(e)))
|
|
2997
|
+
continue;
|
|
2998
|
+
for (const pattern of RETIRED_PATTERNS) {
|
|
2999
|
+
const patternExempt = PATTERN_EXEMPT[pattern] ?? [];
|
|
3000
|
+
if (patternExempt.some((e) => file.path.includes(e)))
|
|
3001
|
+
continue;
|
|
3002
|
+
const re = new RegExp(pattern);
|
|
3003
|
+
for (const line of lineNumbers(file.content, re)) {
|
|
3004
|
+
findings.push({
|
|
3005
|
+
file: file.path,
|
|
3006
|
+
line,
|
|
3007
|
+
pattern,
|
|
3008
|
+
message: `claims a retired AEG mechanism is still live (matches /${pattern}/)`
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
return findings;
|
|
3014
|
+
}
|
|
2912
3015
|
// ../../packages/aeg-core/src/dispatch-gate.ts
|
|
2913
3016
|
function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
|
|
2914
3017
|
return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
|
|
@@ -3164,9 +3267,15 @@ function evaluateTestPlanGate(body, branch) {
|
|
|
3164
3267
|
}
|
|
3165
3268
|
// src/lib/config.ts
|
|
3166
3269
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
3270
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3167
3271
|
import { homedir } from "node:os";
|
|
3168
3272
|
import { dirname, join } from "node:path";
|
|
3169
3273
|
import { z } from "zod";
|
|
3274
|
+
|
|
3275
|
+
// src/lib/agent-vendors.ts
|
|
3276
|
+
var AGENT_VENDORS = ["skills", "claude", "gemini"];
|
|
3277
|
+
|
|
3278
|
+
// src/lib/config.ts
|
|
3170
3279
|
var EnvEntrySchema = z.union([
|
|
3171
3280
|
z.literal(true),
|
|
3172
3281
|
z.object({ optional: z.literal(true) }),
|
|
@@ -3205,6 +3314,11 @@ var CheckEntrySchema = z.object({
|
|
|
3205
3314
|
}
|
|
3206
3315
|
}
|
|
3207
3316
|
});
|
|
3317
|
+
var RoleEntrySchema = z.object({
|
|
3318
|
+
contract: z.string().refine((p) => p.includes("/"), {
|
|
3319
|
+
message: 'must be a path (contain at least one "/"), not a bare filename'
|
|
3320
|
+
})
|
|
3321
|
+
});
|
|
3208
3322
|
var BRIEF_BUILTINS = [
|
|
3209
3323
|
"tier",
|
|
3210
3324
|
"testPlan",
|
|
@@ -3253,7 +3367,8 @@ var ManagedManifestSchema = z.object({
|
|
|
3253
3367
|
version: z.number().int().positive(),
|
|
3254
3368
|
files: z.array(SafeRepoRelPath),
|
|
3255
3369
|
blocks: z.array(ManagedBlockRecordSchema),
|
|
3256
|
-
labels: z.array(z.string())
|
|
3370
|
+
labels: z.array(z.string()),
|
|
3371
|
+
agents: z.array(z.enum(AGENT_VENDORS)).optional()
|
|
3257
3372
|
});
|
|
3258
3373
|
var VinayaConfigSchema = z.object({
|
|
3259
3374
|
rings: z.object({
|
|
@@ -3261,16 +3376,79 @@ var VinayaConfigSchema = z.object({
|
|
|
3261
3376
|
ring2_asyncAudits: z.boolean()
|
|
3262
3377
|
}).optional(),
|
|
3263
3378
|
checks: z.record(z.string(), CheckEntrySchema).optional(),
|
|
3379
|
+
roles: z.record(z.string(), RoleEntrySchema).optional(),
|
|
3264
3380
|
briefSchema: BriefSchemaSchema.optional(),
|
|
3265
3381
|
managed: ManagedManifestSchema.optional(),
|
|
3266
3382
|
principals: z.array(z.string()).min(1).optional(),
|
|
3267
3383
|
releaseActor: z.string().min(1).optional(),
|
|
3268
3384
|
ci: z.object({ setup: z.string().min(1) }).optional(),
|
|
3269
|
-
blastRadius: z.object({ extraDomains: z.array(z.string()).optional() }).optional()
|
|
3385
|
+
blastRadius: z.object({ extraDomains: z.array(z.string()).optional() }).optional(),
|
|
3386
|
+
proseGates: z.object({
|
|
3387
|
+
doctrineRoot: z.string().min(1).optional(),
|
|
3388
|
+
readerFacingPrefix: z.string().min(1).optional(),
|
|
3389
|
+
readerFacingSuffix: z.string().min(1).optional(),
|
|
3390
|
+
legacySlugDir: z.string().min(1).optional()
|
|
3391
|
+
}).optional()
|
|
3270
3392
|
});
|
|
3271
3393
|
var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
|
|
3272
3394
|
var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
|
|
3273
3395
|
var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
3396
|
+
function findLocalConfig() {
|
|
3397
|
+
let dir = process.cwd();
|
|
3398
|
+
while (true) {
|
|
3399
|
+
const candidate = join(dir, LOCAL_CONFIG_FILENAME);
|
|
3400
|
+
if (existsSync(candidate))
|
|
3401
|
+
return candidate;
|
|
3402
|
+
if (existsSync(join(dir, ".git")))
|
|
3403
|
+
return null;
|
|
3404
|
+
const parent = dirname(dir);
|
|
3405
|
+
if (parent === dir)
|
|
3406
|
+
return null;
|
|
3407
|
+
dir = parent;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
function configPath() {
|
|
3411
|
+
const local = findLocalConfig();
|
|
3412
|
+
if (local)
|
|
3413
|
+
return local;
|
|
3414
|
+
if (existsSync(GLOBAL_CONFIG_PATH))
|
|
3415
|
+
return GLOBAL_CONFIG_PATH;
|
|
3416
|
+
return null;
|
|
3417
|
+
}
|
|
3418
|
+
function globalChecksIgnoredWarning(path) {
|
|
3419
|
+
return `${path}: "checks" registration in the global config is ignored — checks may only be registered from a repo-local vinaya.config.json.`;
|
|
3420
|
+
}
|
|
3421
|
+
function globalPrincipalsIgnoredWarning(path) {
|
|
3422
|
+
return `${path}: "principals" in the global config is ignored — principals may only be declared from a repo-local vinaya.config.json.`;
|
|
3423
|
+
}
|
|
3424
|
+
function globalRolesIgnoredWarning(path) {
|
|
3425
|
+
return `${path}: "roles" registration in the global config is ignored — roles may only be registered from a repo-local vinaya.config.json.`;
|
|
3426
|
+
}
|
|
3427
|
+
function globalReleaseActorIgnoredWarning(path) {
|
|
3428
|
+
return `${path}: "releaseActor" in the global config is ignored — releaseActor may only be declared from a repo-local vinaya.config.json.`;
|
|
3429
|
+
}
|
|
3430
|
+
function stripGlobalOnlyKeys(config, path) {
|
|
3431
|
+
if (path !== GLOBAL_CONFIG_PATH)
|
|
3432
|
+
return config;
|
|
3433
|
+
let result = config;
|
|
3434
|
+
if (result.checks && Object.keys(result.checks).length > 0) {
|
|
3435
|
+
console.error(`⚠ ${globalChecksIgnoredWarning(path)}`);
|
|
3436
|
+
result = { ...result, checks: undefined };
|
|
3437
|
+
}
|
|
3438
|
+
if (result.roles && Object.keys(result.roles).length > 0) {
|
|
3439
|
+
console.error(`⚠ ${globalRolesIgnoredWarning(path)}`);
|
|
3440
|
+
result = { ...result, roles: undefined };
|
|
3441
|
+
}
|
|
3442
|
+
if (result.principals && result.principals.length > 0) {
|
|
3443
|
+
console.error(`⚠ ${globalPrincipalsIgnoredWarning(path)}`);
|
|
3444
|
+
result = { ...result, principals: undefined };
|
|
3445
|
+
}
|
|
3446
|
+
if (result.releaseActor) {
|
|
3447
|
+
console.error(`⚠ ${globalReleaseActorIgnoredWarning(path)}`);
|
|
3448
|
+
result = { ...result, releaseActor: undefined };
|
|
3449
|
+
}
|
|
3450
|
+
return result;
|
|
3451
|
+
}
|
|
3274
3452
|
function resolvePrincipalAllowlist(config) {
|
|
3275
3453
|
return config?.principals ?? PRINCIPAL_ALLOWLIST;
|
|
3276
3454
|
}
|
|
@@ -3343,6 +3521,17 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3343
3521
|
return null;
|
|
3344
3522
|
}
|
|
3345
3523
|
}
|
|
3524
|
+
function loadConfig() {
|
|
3525
|
+
const path = configPath();
|
|
3526
|
+
if (!path)
|
|
3527
|
+
return null;
|
|
3528
|
+
try {
|
|
3529
|
+
const raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
3530
|
+
return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
|
|
3531
|
+
} catch {
|
|
3532
|
+
return null;
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3346
3535
|
|
|
3347
3536
|
// src/checks/contract.ts
|
|
3348
3537
|
var CHECK_SCHEMA_VERSION = 1;
|
|
@@ -565,6 +565,12 @@ function factsFromLegacyMilestone(milestone) {
|
|
|
565
565
|
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
566
566
|
};
|
|
567
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
|
+
}
|
|
568
574
|
function lifecycleFromIssues(issues) {
|
|
569
575
|
if (issues.length === 0)
|
|
570
576
|
return "planned";
|
|
@@ -581,9 +587,9 @@ function goalFromMilestones(milestones, slug) {
|
|
|
581
587
|
function findMilestoneForSlug(owner, repo, slug) {
|
|
582
588
|
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
583
589
|
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
584
|
-
if (legacy)
|
|
585
|
-
return factsFromLegacyMilestone(legacy);
|
|
586
590
|
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
591
|
+
if (legacy)
|
|
592
|
+
return resolveLegacyFacts(legacy, issues);
|
|
587
593
|
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
588
594
|
}
|
|
589
595
|
|
|
@@ -2770,16 +2776,18 @@ function checkDeadBranchPush(input) {
|
|
|
2770
2776
|
}
|
|
2771
2777
|
// ../../packages/aeg-core/src/reader-resolvable-prose.ts
|
|
2772
2778
|
var SHIPS_PREFIX = "aeg-root/";
|
|
2773
|
-
|
|
2779
|
+
function shipsArchivePrefix(shipsPrefix) {
|
|
2780
|
+
return `${shipsPrefix}tranches/completed/`;
|
|
2781
|
+
}
|
|
2774
2782
|
function isSpecFile2(path) {
|
|
2775
2783
|
return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
|
|
2776
2784
|
}
|
|
2777
2785
|
function isClaudeMdFile(path) {
|
|
2778
2786
|
return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
|
|
2779
2787
|
}
|
|
2780
|
-
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
|
|
2781
|
-
if (path.startsWith(
|
|
2782
|
-
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";
|
|
2783
2791
|
}
|
|
2784
2792
|
if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
|
|
2785
2793
|
return "reader-facing";
|
|
@@ -2814,7 +2822,7 @@ function legacySlugPattern(legacySlugs) {
|
|
|
2814
2822
|
const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2815
2823
|
return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
|
|
2816
2824
|
}
|
|
2817
|
-
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2825
|
+
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2818
2826
|
const findings = [];
|
|
2819
2827
|
const legacyPattern = legacySlugPattern(legacySlugs);
|
|
2820
2828
|
const patterns = [
|
|
@@ -2823,7 +2831,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
|
|
|
2823
2831
|
...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
|
|
2824
2832
|
];
|
|
2825
2833
|
for (const file of files) {
|
|
2826
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2834
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2827
2835
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2828
2836
|
continue;
|
|
2829
2837
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2869,10 +2877,10 @@ function definesOrLinksGlossary(content, term) {
|
|
|
2869
2877
|
return true;
|
|
2870
2878
|
return /docs\/glossary|glossary\.md/i.test(content);
|
|
2871
2879
|
}
|
|
2872
|
-
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
|
|
2880
|
+
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2873
2881
|
const findings = [];
|
|
2874
2882
|
for (const file of files) {
|
|
2875
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2883
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2876
2884
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2877
2885
|
continue;
|
|
2878
2886
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2891,10 +2899,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
|
|
|
2891
2899
|
}
|
|
2892
2900
|
return findings;
|
|
2893
2901
|
}
|
|
2894
|
-
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2902
|
+
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2895
2903
|
return [
|
|
2896
|
-
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
|
|
2897
|
-
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
|
|
2904
|
+
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
|
|
2905
|
+
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
|
|
2898
2906
|
];
|
|
2899
2907
|
}
|
|
2900
2908
|
function parseGlossaryTerms(glossaryContent) {
|
|
@@ -2908,6 +2916,101 @@ function parseGlossaryTerms(glossaryContent) {
|
|
|
2908
2916
|
}
|
|
2909
2917
|
return terms;
|
|
2910
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
|
+
}
|
|
2911
3014
|
// ../../packages/aeg-core/src/dispatch-gate.ts
|
|
2912
3015
|
function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
|
|
2913
3016
|
return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
|