@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-dispatch-readiness.ts
|
|
4
|
-
import { execFile as execFile4, execFileSync as
|
|
4
|
+
import { execFile as execFile4, execFileSync as execFileSync4 } from "node:child_process";
|
|
5
5
|
import { promisify as promisify4 } from "node:util";
|
|
6
6
|
// ../../packages/aeg-forge-state/src/strip-code.ts
|
|
7
7
|
function maskCode(body) {
|
|
@@ -274,6 +274,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
274
274
|
"200"
|
|
275
275
|
];
|
|
276
276
|
}
|
|
277
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
278
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
279
|
+
}
|
|
277
280
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
278
281
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
279
282
|
}
|
|
@@ -289,18 +292,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
289
292
|
return dedupeByNumber(perLabel.flat());
|
|
290
293
|
}
|
|
291
294
|
|
|
292
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
293
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
294
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
295
|
-
const match = milestones.find((m) => m.title === slug);
|
|
296
|
-
if (!match)
|
|
297
|
-
return null;
|
|
298
|
-
return {
|
|
299
|
-
goal: match.description ?? "",
|
|
300
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
295
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
305
296
|
var LABELS = [
|
|
306
297
|
{
|
|
@@ -543,6 +534,66 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
543
534
|
return { trancheSlug, taskId };
|
|
544
535
|
}
|
|
545
536
|
|
|
537
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
538
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
539
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
540
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
541
|
+
function intentGoalForSlug(description, slug) {
|
|
542
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
543
|
+
const start = text.match(INTENTS_HEADING);
|
|
544
|
+
if (!start || start.index === undefined)
|
|
545
|
+
return "";
|
|
546
|
+
const rest = text.slice(start.index + start[0].length);
|
|
547
|
+
const next = rest.match(NEXT_HEADING);
|
|
548
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
549
|
+
for (const line of section.split(`
|
|
550
|
+
`)) {
|
|
551
|
+
const trimmed = line.trim();
|
|
552
|
+
if (trimmed.length === 0)
|
|
553
|
+
continue;
|
|
554
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
555
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
556
|
+
return (m[2] ?? "").trim();
|
|
557
|
+
}
|
|
558
|
+
return "";
|
|
559
|
+
}
|
|
560
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
561
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
562
|
+
}
|
|
563
|
+
function factsFromLegacyMilestone(milestone) {
|
|
564
|
+
return {
|
|
565
|
+
goal: milestone.description ?? "",
|
|
566
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
567
|
+
};
|
|
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
|
+
}
|
|
575
|
+
function lifecycleFromIssues(issues) {
|
|
576
|
+
if (issues.length === 0)
|
|
577
|
+
return "planned";
|
|
578
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
579
|
+
}
|
|
580
|
+
function goalFromMilestones(milestones, slug) {
|
|
581
|
+
for (const m of milestones) {
|
|
582
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
583
|
+
if (goal)
|
|
584
|
+
return goal;
|
|
585
|
+
}
|
|
586
|
+
return "";
|
|
587
|
+
}
|
|
588
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
589
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
590
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
591
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
592
|
+
if (legacy)
|
|
593
|
+
return resolveLegacyFacts(legacy, issues);
|
|
594
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
595
|
+
}
|
|
596
|
+
|
|
546
597
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
547
598
|
function trancheFromIssues(slug, issues, known) {
|
|
548
599
|
return {
|
|
@@ -2726,16 +2777,18 @@ function checkDeadBranchPush(input) {
|
|
|
2726
2777
|
}
|
|
2727
2778
|
// ../../packages/aeg-core/src/reader-resolvable-prose.ts
|
|
2728
2779
|
var SHIPS_PREFIX = "aeg-root/";
|
|
2729
|
-
|
|
2780
|
+
function shipsArchivePrefix(shipsPrefix) {
|
|
2781
|
+
return `${shipsPrefix}tranches/completed/`;
|
|
2782
|
+
}
|
|
2730
2783
|
function isSpecFile2(path) {
|
|
2731
2784
|
return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
|
|
2732
2785
|
}
|
|
2733
2786
|
function isClaudeMdFile(path) {
|
|
2734
2787
|
return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
|
|
2735
2788
|
}
|
|
2736
|
-
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
|
|
2737
|
-
if (path.startsWith(
|
|
2738
|
-
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";
|
|
2739
2792
|
}
|
|
2740
2793
|
if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
|
|
2741
2794
|
return "reader-facing";
|
|
@@ -2770,7 +2823,7 @@ function legacySlugPattern(legacySlugs) {
|
|
|
2770
2823
|
const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2771
2824
|
return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
|
|
2772
2825
|
}
|
|
2773
|
-
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2826
|
+
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2774
2827
|
const findings = [];
|
|
2775
2828
|
const legacyPattern = legacySlugPattern(legacySlugs);
|
|
2776
2829
|
const patterns = [
|
|
@@ -2779,7 +2832,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
|
|
|
2779
2832
|
...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
|
|
2780
2833
|
];
|
|
2781
2834
|
for (const file of files) {
|
|
2782
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2835
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2783
2836
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2784
2837
|
continue;
|
|
2785
2838
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2825,10 +2878,10 @@ function definesOrLinksGlossary(content, term) {
|
|
|
2825
2878
|
return true;
|
|
2826
2879
|
return /docs\/glossary|glossary\.md/i.test(content);
|
|
2827
2880
|
}
|
|
2828
|
-
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
|
|
2881
|
+
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2829
2882
|
const findings = [];
|
|
2830
2883
|
for (const file of files) {
|
|
2831
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2884
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2832
2885
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2833
2886
|
continue;
|
|
2834
2887
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2847,10 +2900,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
|
|
|
2847
2900
|
}
|
|
2848
2901
|
return findings;
|
|
2849
2902
|
}
|
|
2850
|
-
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2903
|
+
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2851
2904
|
return [
|
|
2852
|
-
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
|
|
2853
|
-
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
|
|
2905
|
+
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
|
|
2906
|
+
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
|
|
2854
2907
|
];
|
|
2855
2908
|
}
|
|
2856
2909
|
function parseGlossaryTerms(glossaryContent) {
|
|
@@ -2864,6 +2917,101 @@ function parseGlossaryTerms(glossaryContent) {
|
|
|
2864
2917
|
}
|
|
2865
2918
|
return terms;
|
|
2866
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
|
+
}
|
|
2867
3015
|
// ../../packages/aeg-core/src/dispatch-gate.ts
|
|
2868
3016
|
function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
|
|
2869
3017
|
return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
|
|
@@ -3140,9 +3288,15 @@ function emitCheckError(error) {
|
|
|
3140
3288
|
|
|
3141
3289
|
// src/lib/config.ts
|
|
3142
3290
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
3291
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3143
3292
|
import { homedir } from "node:os";
|
|
3144
3293
|
import { dirname, join } from "node:path";
|
|
3145
3294
|
import { z as z2 } from "zod";
|
|
3295
|
+
|
|
3296
|
+
// src/lib/agent-vendors.ts
|
|
3297
|
+
var AGENT_VENDORS = ["skills", "claude", "gemini"];
|
|
3298
|
+
|
|
3299
|
+
// src/lib/config.ts
|
|
3146
3300
|
var EnvEntrySchema = z2.union([
|
|
3147
3301
|
z2.literal(true),
|
|
3148
3302
|
z2.object({ optional: z2.literal(true) }),
|
|
@@ -3181,6 +3335,11 @@ var CheckEntrySchema = z2.object({
|
|
|
3181
3335
|
}
|
|
3182
3336
|
}
|
|
3183
3337
|
});
|
|
3338
|
+
var RoleEntrySchema = z2.object({
|
|
3339
|
+
contract: z2.string().refine((p) => p.includes("/"), {
|
|
3340
|
+
message: 'must be a path (contain at least one "/"), not a bare filename'
|
|
3341
|
+
})
|
|
3342
|
+
});
|
|
3184
3343
|
var BRIEF_BUILTINS = [
|
|
3185
3344
|
"tier",
|
|
3186
3345
|
"testPlan",
|
|
@@ -3195,7 +3354,8 @@ var BRIEF_BUILTINS = [
|
|
|
3195
3354
|
"for",
|
|
3196
3355
|
"closesN",
|
|
3197
3356
|
"premiseCoverage",
|
|
3198
|
-
"issueRationale"
|
|
3357
|
+
"issueRationale",
|
|
3358
|
+
"milestoneShape"
|
|
3199
3359
|
];
|
|
3200
3360
|
var BriefSectionSchema = z2.union([
|
|
3201
3361
|
z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
|
|
@@ -3206,6 +3366,7 @@ var BriefSectionSchema = z2.union([
|
|
|
3206
3366
|
var BriefSchemaSchema = z2.object({
|
|
3207
3367
|
pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3208
3368
|
issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3369
|
+
milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
|
|
3209
3370
|
ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
|
|
3210
3371
|
});
|
|
3211
3372
|
function isSafeRepoRelPath(p) {
|
|
@@ -3227,7 +3388,8 @@ var ManagedManifestSchema = z2.object({
|
|
|
3227
3388
|
version: z2.number().int().positive(),
|
|
3228
3389
|
files: z2.array(SafeRepoRelPath),
|
|
3229
3390
|
blocks: z2.array(ManagedBlockRecordSchema),
|
|
3230
|
-
labels: z2.array(z2.string())
|
|
3391
|
+
labels: z2.array(z2.string()),
|
|
3392
|
+
agents: z2.array(z2.enum(AGENT_VENDORS)).optional()
|
|
3231
3393
|
});
|
|
3232
3394
|
var VinayaConfigSchema = z2.object({
|
|
3233
3395
|
rings: z2.object({
|
|
@@ -3235,16 +3397,79 @@ var VinayaConfigSchema = z2.object({
|
|
|
3235
3397
|
ring2_asyncAudits: z2.boolean()
|
|
3236
3398
|
}).optional(),
|
|
3237
3399
|
checks: z2.record(z2.string(), CheckEntrySchema).optional(),
|
|
3400
|
+
roles: z2.record(z2.string(), RoleEntrySchema).optional(),
|
|
3238
3401
|
briefSchema: BriefSchemaSchema.optional(),
|
|
3239
3402
|
managed: ManagedManifestSchema.optional(),
|
|
3240
3403
|
principals: z2.array(z2.string()).min(1).optional(),
|
|
3241
3404
|
releaseActor: z2.string().min(1).optional(),
|
|
3242
3405
|
ci: z2.object({ setup: z2.string().min(1) }).optional(),
|
|
3243
|
-
blastRadius: z2.object({ extraDomains: z2.array(z2.string()).optional() }).optional()
|
|
3406
|
+
blastRadius: z2.object({ extraDomains: z2.array(z2.string()).optional() }).optional(),
|
|
3407
|
+
proseGates: z2.object({
|
|
3408
|
+
doctrineRoot: z2.string().min(1).optional(),
|
|
3409
|
+
readerFacingPrefix: z2.string().min(1).optional(),
|
|
3410
|
+
readerFacingSuffix: z2.string().min(1).optional(),
|
|
3411
|
+
legacySlugDir: z2.string().min(1).optional()
|
|
3412
|
+
}).optional()
|
|
3244
3413
|
});
|
|
3245
3414
|
var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
|
|
3246
3415
|
var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
|
|
3247
3416
|
var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
3417
|
+
function findLocalConfig() {
|
|
3418
|
+
let dir = process.cwd();
|
|
3419
|
+
while (true) {
|
|
3420
|
+
const candidate = join(dir, LOCAL_CONFIG_FILENAME);
|
|
3421
|
+
if (existsSync(candidate))
|
|
3422
|
+
return candidate;
|
|
3423
|
+
if (existsSync(join(dir, ".git")))
|
|
3424
|
+
return null;
|
|
3425
|
+
const parent = dirname(dir);
|
|
3426
|
+
if (parent === dir)
|
|
3427
|
+
return null;
|
|
3428
|
+
dir = parent;
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
function configPath() {
|
|
3432
|
+
const local = findLocalConfig();
|
|
3433
|
+
if (local)
|
|
3434
|
+
return local;
|
|
3435
|
+
if (existsSync(GLOBAL_CONFIG_PATH))
|
|
3436
|
+
return GLOBAL_CONFIG_PATH;
|
|
3437
|
+
return null;
|
|
3438
|
+
}
|
|
3439
|
+
function globalChecksIgnoredWarning(path) {
|
|
3440
|
+
return `${path}: "checks" registration in the global config is ignored — checks may only be registered from a repo-local vinaya.config.json.`;
|
|
3441
|
+
}
|
|
3442
|
+
function globalPrincipalsIgnoredWarning(path) {
|
|
3443
|
+
return `${path}: "principals" in the global config is ignored — principals may only be declared from a repo-local vinaya.config.json.`;
|
|
3444
|
+
}
|
|
3445
|
+
function globalRolesIgnoredWarning(path) {
|
|
3446
|
+
return `${path}: "roles" registration in the global config is ignored — roles may only be registered from a repo-local vinaya.config.json.`;
|
|
3447
|
+
}
|
|
3448
|
+
function globalReleaseActorIgnoredWarning(path) {
|
|
3449
|
+
return `${path}: "releaseActor" in the global config is ignored — releaseActor may only be declared from a repo-local vinaya.config.json.`;
|
|
3450
|
+
}
|
|
3451
|
+
function stripGlobalOnlyKeys(config, path) {
|
|
3452
|
+
if (path !== GLOBAL_CONFIG_PATH)
|
|
3453
|
+
return config;
|
|
3454
|
+
let result = config;
|
|
3455
|
+
if (result.checks && Object.keys(result.checks).length > 0) {
|
|
3456
|
+
console.error(`⚠ ${globalChecksIgnoredWarning(path)}`);
|
|
3457
|
+
result = { ...result, checks: undefined };
|
|
3458
|
+
}
|
|
3459
|
+
if (result.roles && Object.keys(result.roles).length > 0) {
|
|
3460
|
+
console.error(`⚠ ${globalRolesIgnoredWarning(path)}`);
|
|
3461
|
+
result = { ...result, roles: undefined };
|
|
3462
|
+
}
|
|
3463
|
+
if (result.principals && result.principals.length > 0) {
|
|
3464
|
+
console.error(`⚠ ${globalPrincipalsIgnoredWarning(path)}`);
|
|
3465
|
+
result = { ...result, principals: undefined };
|
|
3466
|
+
}
|
|
3467
|
+
if (result.releaseActor) {
|
|
3468
|
+
console.error(`⚠ ${globalReleaseActorIgnoredWarning(path)}`);
|
|
3469
|
+
result = { ...result, releaseActor: undefined };
|
|
3470
|
+
}
|
|
3471
|
+
return result;
|
|
3472
|
+
}
|
|
3248
3473
|
function resolvePrincipalAllowlist(config) {
|
|
3249
3474
|
return config?.principals ?? PRINCIPAL_ALLOWLIST;
|
|
3250
3475
|
}
|
|
@@ -3317,13 +3542,87 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3317
3542
|
return null;
|
|
3318
3543
|
}
|
|
3319
3544
|
}
|
|
3545
|
+
function loadConfig() {
|
|
3546
|
+
const path = configPath();
|
|
3547
|
+
if (!path)
|
|
3548
|
+
return null;
|
|
3549
|
+
try {
|
|
3550
|
+
const raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
3551
|
+
return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
|
|
3552
|
+
} catch {
|
|
3553
|
+
return null;
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
// src/checks/edge-resolve.ts
|
|
3558
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3559
|
+
var DIRECT_ISSUE_REF = /#(\d+)/;
|
|
3560
|
+
var issueCache = new Map;
|
|
3561
|
+
function fetchIssueState(num, repo) {
|
|
3562
|
+
const key = `${repo.owner}/${repo.repo}#${num}`;
|
|
3563
|
+
if (issueCache.has(key))
|
|
3564
|
+
return issueCache.get(key) ?? null;
|
|
3565
|
+
let out = null;
|
|
3566
|
+
try {
|
|
3567
|
+
const raw = execFileSync3("gh", [
|
|
3568
|
+
"issue",
|
|
3569
|
+
"view",
|
|
3570
|
+
String(num),
|
|
3571
|
+
"-R",
|
|
3572
|
+
`${repo.owner}/${repo.repo}`,
|
|
3573
|
+
"--json",
|
|
3574
|
+
"state,stateReason,closedByPullRequestsReferences"
|
|
3575
|
+
], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
3576
|
+
out = JSON.parse(raw);
|
|
3577
|
+
} catch {
|
|
3578
|
+
out = null;
|
|
3579
|
+
}
|
|
3580
|
+
issueCache.set(key, out);
|
|
3581
|
+
return out;
|
|
3582
|
+
}
|
|
3583
|
+
function edgeFromIssueJson(num, json) {
|
|
3584
|
+
if (json === null) {
|
|
3585
|
+
return { issue: num, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3586
|
+
}
|
|
3587
|
+
const state = json.state === "CLOSED" ? "closed" : json.state === "OPEN" ? "open" : null;
|
|
3588
|
+
const reason = json.stateReason === "COMPLETED" ? "completed" : json.stateReason === "NOT_PLANNED" ? "not_planned" : null;
|
|
3589
|
+
const closedByMergedPr = (json.closedByPullRequestsReferences ?? []).length > 0;
|
|
3590
|
+
return {
|
|
3591
|
+
issue: num,
|
|
3592
|
+
merged: state === "closed" && closedByMergedPr,
|
|
3593
|
+
open: false,
|
|
3594
|
+
issueState: state,
|
|
3595
|
+
stateReason: reason,
|
|
3596
|
+
closedByActor: null
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
function resolveEdge(id, taskById, factsByTaskId, repo) {
|
|
3600
|
+
const target = taskById.get(id);
|
|
3601
|
+
if (target) {
|
|
3602
|
+
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3603
|
+
return {
|
|
3604
|
+
issue: target.issue,
|
|
3605
|
+
merged: facts?.prState === "merged",
|
|
3606
|
+
open: facts?.prState === "open",
|
|
3607
|
+
issueState: facts?.issueState ?? null,
|
|
3608
|
+
stateReason: facts?.stateReason ?? null,
|
|
3609
|
+
closedByActor: facts?.closedByActor ?? null
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
const direct = id.match(DIRECT_ISSUE_REF);
|
|
3613
|
+
if (direct) {
|
|
3614
|
+
const num = Number(direct[1]);
|
|
3615
|
+
return edgeFromIssueJson(num, fetchIssueState(num, repo));
|
|
3616
|
+
}
|
|
3617
|
+
return { issue: null, merged: false, open: false, issueState: null, stateReason: null, closedByActor: null };
|
|
3618
|
+
}
|
|
3320
3619
|
|
|
3321
3620
|
// src/checks/bin/check-dispatch-readiness.ts
|
|
3322
3621
|
var CHECK_NAME = "dispatch-readiness";
|
|
3323
3622
|
var execFileAsync4 = promisify4(execFile4);
|
|
3324
3623
|
function git(args) {
|
|
3325
3624
|
try {
|
|
3326
|
-
return
|
|
3625
|
+
return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
3327
3626
|
} catch {
|
|
3328
3627
|
return "";
|
|
3329
3628
|
}
|
|
@@ -3370,29 +3669,6 @@ function fail(message, prompt) {
|
|
|
3370
3669
|
});
|
|
3371
3670
|
process.exit(1);
|
|
3372
3671
|
}
|
|
3373
|
-
function resolveEdge(id, taskById, factsByTaskId) {
|
|
3374
|
-
const target = taskById.get(id);
|
|
3375
|
-
if (target) {
|
|
3376
|
-
const facts = target.issue !== null ? factsByTaskId.get(target.id) : undefined;
|
|
3377
|
-
return {
|
|
3378
|
-
issue: target.issue,
|
|
3379
|
-
merged: facts?.prState === "merged",
|
|
3380
|
-
open: facts?.prState === "open",
|
|
3381
|
-
issueState: facts?.issueState ?? null,
|
|
3382
|
-
stateReason: facts?.stateReason ?? null,
|
|
3383
|
-
closedByActor: facts?.closedByActor ?? null
|
|
3384
|
-
};
|
|
3385
|
-
}
|
|
3386
|
-
const direct = id.match(/^#(\d+)$/);
|
|
3387
|
-
return {
|
|
3388
|
-
issue: direct ? Number(direct[1]) : null,
|
|
3389
|
-
merged: false,
|
|
3390
|
-
open: false,
|
|
3391
|
-
issueState: null,
|
|
3392
|
-
stateReason: null,
|
|
3393
|
-
closedByActor: null
|
|
3394
|
-
};
|
|
3395
|
-
}
|
|
3396
3672
|
async function main() {
|
|
3397
3673
|
const branch = currentBranch();
|
|
3398
3674
|
const m = branch.match(/^task\/([^/]+)\/(.+)$/);
|
|
@@ -3433,7 +3709,7 @@ async function main() {
|
|
|
3433
3709
|
const taskById = new Map(tranche.tasks.map((t) => [t.id, t]));
|
|
3434
3710
|
const factsByTaskId = snapshot.facts;
|
|
3435
3711
|
const dependsOn = task.dependsOn.map((dep) => {
|
|
3436
|
-
const r = resolveEdge(dep, taskById, factsByTaskId);
|
|
3712
|
+
const r = resolveEdge(dep, taskById, factsByTaskId, repo);
|
|
3437
3713
|
return {
|
|
3438
3714
|
id: dep,
|
|
3439
3715
|
issue: r.issue,
|
|
@@ -3444,7 +3720,7 @@ async function main() {
|
|
|
3444
3720
|
};
|
|
3445
3721
|
});
|
|
3446
3722
|
const conflictsWith = task.conflictsWith.map((c) => {
|
|
3447
|
-
const r = resolveEdge(c, taskById, factsByTaskId);
|
|
3723
|
+
const r = resolveEdge(c, taskById, factsByTaskId, repo);
|
|
3448
3724
|
return { id: c, issue: r.issue, openOrInFlight: r.open };
|
|
3449
3725
|
});
|
|
3450
3726
|
const priorTrancheArchival = [];
|