@attalabs/vinaya 0.4.3 → 0.4.4
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/aeg-root/enforcement.md +1 -1
- package/aeg-root/state-machine.md +1 -1
- package/dist/checks/bin/check-branch-topology.js +44 -31
- package/dist/checks/bin/check-brief-shape.js +44 -31
- package/dist/checks/bin/check-closes-n.js +44 -31
- package/dist/checks/bin/check-coherence.js +44 -31
- package/dist/checks/bin/check-dead-branch-push.js +44 -31
- package/dist/checks/bin/check-dispatch-readiness.js +44 -31
- package/dist/checks/bin/check-doc-coverage-push.js +221 -34
- package/dist/checks/bin/check-doc-coverage.js +221 -34
- package/dist/checks/bin/check-first-push-dispatch.js +44 -31
- package/dist/checks/bin/check-issue-assignment.js +44 -31
- package/dist/checks/bin/check-no-disk-state.js +44 -31
- package/dist/checks/bin/check-reader-resolvable-prose.js +44 -31
- package/dist/checks/bin/check-registry-gates.js +44 -31
- package/dist/checks/bin/check-review-gate.js +222 -36
- package/dist/checks/bin/check-single-plan-pr.js +44 -31
- package/dist/checks/bin/check-test-plan.js +44 -31
- package/dist/index.js +116 -34
- package/package.json +1 -1
- package/studio-standalone/.worktrees/fix/bump-0.4.4/.vinaya/projects.md +63 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/aeg-manual-flow.md +216 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/brief-developer.md +140 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/developer-reviewer.md +106 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/planner-brief.md +130 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/reviewer-archivist.md +96 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/tranche-archivist-planner.md +116 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/coordination.md +293 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/documentation-coherence.md +65 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/enforcement.md +161 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/glossary.md +36 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/process.md +371 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/reviewer-prompt.md +68 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/archivist.md +167 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/brief-author.md +108 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/developer.md +429 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/planner.md +285 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/principal.md +107 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/reviewer.md +130 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/security.md +121 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/tranche-archivist.md +257 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/aeg/SKILL.md +90 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/aeg-roles/SKILL.md +58 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/brief-authoring/SKILL.md +497 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/state-machine.md +656 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/brief-template.md +103 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/issue-rationale-template.md +35 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/pr-report-template.md +68 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranche-model.md +306 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-coherence-v1.md +55 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-coherence-v1.tokens.md +13 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-consolidation.md +28 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-hardening.md +80 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-ui-v2.md +168 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-ui-v2.tokens.md +18 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-studio-cleanup.md +37 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-ui-v1.md +176 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-ui-v1.tokens.md +17 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-agents-v2.md +35 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-agents-v2.tokens.md +11 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-onto-engine.md +99 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/vada-agents-v2.md +220 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/apps/vinaya/cli/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/node_modules/@attalabs/vinaya/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/bump-0.4.4/vinaya.config.json +36 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/.vinaya/projects.md +63 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/aeg-manual-flow.md +216 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/brief-developer.md +140 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/developer-reviewer.md +106 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/planner-brief.md +130 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/reviewer-archivist.md +96 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/tranche-archivist-planner.md +116 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/coordination.md +293 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/documentation-coherence.md +65 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/enforcement.md +161 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/glossary.md +36 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/process.md +371 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/reviewer-prompt.md +68 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/archivist.md +167 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/brief-author.md +108 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/developer.md +429 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/planner.md +285 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/principal.md +107 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/reviewer.md +130 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/security.md +121 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/tranche-archivist.md +257 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/aeg/SKILL.md +90 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/aeg-roles/SKILL.md +58 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/brief-authoring/SKILL.md +497 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/state-machine.md +656 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/brief-template.md +103 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/issue-rationale-template.md +35 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/pr-report-template.md +68 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranche-model.md +306 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-coherence-v1.md +55 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-coherence-v1.tokens.md +13 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-consolidation.md +28 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-hardening.md +80 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-ui-v2.md +168 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-ui-v2.tokens.md +18 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-studio-cleanup.md +37 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-ui-v1.md +176 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-ui-v1.tokens.md +17 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-agents-v2.md +35 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-agents-v2.tokens.md +11 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-onto-engine.md +99 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/vada-agents-v2.md +220 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/apps/vinaya/cli/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/node_modules/@attalabs/vinaya/tests/fixtures/checks/vinaya.config.json +9 -0
- package/studio-standalone/.worktrees/fix/check-lifecycle-phase/vinaya.config.json +36 -0
- package/studio-standalone/_node_modules/@atta/vinaya-cli/aeg-root/enforcement.md +1 -1
- package/studio-standalone/_node_modules/@atta/vinaya-cli/aeg-root/state-machine.md +1 -1
- package/studio-standalone/_node_modules/@attalabs/vinaya/aeg-root/enforcement.md +1 -1
- package/studio-standalone/_node_modules/@attalabs/vinaya/aeg-root/state-machine.md +1 -1
- package/studio-standalone/apps/vinaya/cli/aeg-root/enforcement.md +1 -1
- package/studio-standalone/apps/vinaya/cli/aeg-root/state-machine.md +1 -1
- package/studio-standalone/apps/vinaya/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/cli/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/config/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/cli/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/harness/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/state-machine/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(with-sidebar)/[...slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(with-sidebar)/reference/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/install/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/roadmap/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/archive/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/brief/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/develop/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/overview/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/plan/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/quick/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/review/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/security/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/wrap-up/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/state-machine/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/the-harness/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/the-studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/docs/[...slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/docs/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/chunks/ssr/[root-of-the-server]__0kqmrho._.js +1 -1
- package/studio-standalone/apps/vinaya/web/.next/server/chunks/ssr/[root-of-the-server]__1dxaovd._.js +2 -2
- package/studio-standalone/apps/vinaya/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya/web/.next/server/pages/500.html +1 -1
- /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -532,6 +532,27 @@ function parsePremiseBlock(prBody) {
|
|
|
532
532
|
return assertions;
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
+
// ../../../packages/aeg-core/src/test-plan-section.ts
|
|
536
|
+
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
537
|
+
var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
|
|
538
|
+
var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
|
|
539
|
+
function locateTestPlanSection(body) {
|
|
540
|
+
const region = anchoredRegion(body, "TEST-PLAN");
|
|
541
|
+
if (region !== null)
|
|
542
|
+
return { found: true, section: region };
|
|
543
|
+
const headingMatch = HEADING_FORM_RE.exec(body);
|
|
544
|
+
const match = headingMatch ?? INLINE_FORM_RE.exec(body);
|
|
545
|
+
if (!match || match.index === undefined)
|
|
546
|
+
return { found: false };
|
|
547
|
+
const sectionBody = body.slice(match.index);
|
|
548
|
+
const firstLineEnd = sectionBody.indexOf(`
|
|
549
|
+
`);
|
|
550
|
+
const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
|
|
551
|
+
const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
|
|
552
|
+
const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
|
|
553
|
+
return { found: true, section: sectionBody.slice(0, sectionEnd) };
|
|
554
|
+
}
|
|
555
|
+
|
|
535
556
|
// ../../../packages/aeg-core/src/brief-validation.ts
|
|
536
557
|
function headerRegion(prBody) {
|
|
537
558
|
const m = prBody.match(/^##\s/m);
|
|
@@ -570,10 +591,15 @@ function checkTierField(prBody, readTier) {
|
|
|
570
591
|
};
|
|
571
592
|
}
|
|
572
593
|
var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
|
|
594
|
+
function testPlanRegion(prBody) {
|
|
595
|
+
const located = locateTestPlanSection(prBody);
|
|
596
|
+
return located.found ? located.section : prBody;
|
|
597
|
+
}
|
|
573
598
|
function checkTestPlan(prBody) {
|
|
574
|
-
|
|
599
|
+
const region = testPlanRegion(prBody);
|
|
600
|
+
if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
575
601
|
return { status: "pass", errors: [] };
|
|
576
|
-
if (/\*\*\[(?:agent|principal)\]\*\*/.test(
|
|
602
|
+
if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
|
|
577
603
|
return { status: "pass", errors: [] };
|
|
578
604
|
return {
|
|
579
605
|
status: "fail",
|
|
@@ -583,9 +609,10 @@ function checkTestPlan(prBody) {
|
|
|
583
609
|
};
|
|
584
610
|
}
|
|
585
611
|
function checkTestPlanExclusivity(prBody) {
|
|
586
|
-
|
|
612
|
+
const region = testPlanRegion(prBody);
|
|
613
|
+
if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
|
|
587
614
|
return { status: "pass", errors: [] };
|
|
588
|
-
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(
|
|
615
|
+
if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
|
|
589
616
|
return {
|
|
590
617
|
status: "fail",
|
|
591
618
|
errors: [
|
|
@@ -596,8 +623,9 @@ function checkTestPlanExclusivity(prBody) {
|
|
|
596
623
|
return { status: "pass", errors: [] };
|
|
597
624
|
}
|
|
598
625
|
function checkPrincipalPlaceholder(prBody) {
|
|
626
|
+
const region = testPlanRegion(prBody);
|
|
599
627
|
const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
|
|
600
|
-
for (const m of
|
|
628
|
+
for (const m of region.matchAll(lineRe)) {
|
|
601
629
|
const content = m[1] ?? "";
|
|
602
630
|
if (/^\s*None\b/i.test(content)) {
|
|
603
631
|
return {
|
|
@@ -1543,7 +1571,10 @@ function coreCheckRegistry() {
|
|
|
1543
1571
|
PR_BODY: { optional: true },
|
|
1544
1572
|
PR_BODY_FILE: { optional: true },
|
|
1545
1573
|
PR_LABELS: { optional: true },
|
|
1546
|
-
WAIVER_LABEL_ACTOR: { optional: true }
|
|
1574
|
+
WAIVER_LABEL_ACTOR: { optional: true },
|
|
1575
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
1576
|
+
GITHUB_TOKEN: { optional: true },
|
|
1577
|
+
GH_TOKEN: { optional: true }
|
|
1547
1578
|
}
|
|
1548
1579
|
},
|
|
1549
1580
|
{
|
|
@@ -1575,6 +1606,7 @@ function coreCheckRegistry() {
|
|
|
1575
1606
|
run: bin("check-closes-n"),
|
|
1576
1607
|
scope: "diff",
|
|
1577
1608
|
timeoutMs: 15000,
|
|
1609
|
+
requiresOpenPr: true,
|
|
1578
1610
|
env: {
|
|
1579
1611
|
BRANCH: { optional: true },
|
|
1580
1612
|
PR_BODY: { optional: true },
|
|
@@ -1600,6 +1632,7 @@ function coreCheckRegistry() {
|
|
|
1600
1632
|
run: bin("check-test-plan"),
|
|
1601
1633
|
scope: "diff",
|
|
1602
1634
|
timeoutMs: 15000,
|
|
1635
|
+
requiresOpenPr: true,
|
|
1603
1636
|
env: {
|
|
1604
1637
|
PR_BODY: { optional: true },
|
|
1605
1638
|
BRANCH: { optional: true }
|
|
@@ -1631,6 +1664,7 @@ function coreCheckRegistry() {
|
|
|
1631
1664
|
env: {
|
|
1632
1665
|
BRANCH: { optional: true },
|
|
1633
1666
|
PR_NUMBER: { optional: true },
|
|
1667
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
1634
1668
|
GITHUB_TOKEN: { optional: true },
|
|
1635
1669
|
GH_TOKEN: { optional: true }
|
|
1636
1670
|
}
|
|
@@ -1681,7 +1715,10 @@ function coreCheckRegistry() {
|
|
|
1681
1715
|
PR_BODY: { optional: true },
|
|
1682
1716
|
PR_BODY_FILE: { optional: true },
|
|
1683
1717
|
PR_LABELS: { optional: true },
|
|
1684
|
-
WAIVER_LABEL_ACTOR: { optional: true }
|
|
1718
|
+
WAIVER_LABEL_ACTOR: { optional: true },
|
|
1719
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
1720
|
+
GITHUB_TOKEN: { optional: true },
|
|
1721
|
+
GH_TOKEN: { optional: true }
|
|
1685
1722
|
}
|
|
1686
1723
|
},
|
|
1687
1724
|
{
|
|
@@ -1760,6 +1797,8 @@ function isCheckError(value) {
|
|
|
1760
1797
|
return v.schema === CHECK_SCHEMA_VERSION && typeof v.check === "string" && (v.severity === "error" || v.severity === "warning") && typeof v.message === "string" && typeof v.agent_recovery_prompt === "string";
|
|
1761
1798
|
}
|
|
1762
1799
|
function shouldSkip(spec, opts) {
|
|
1800
|
+
if (opts.localOnly && spec.requiresOpenPr)
|
|
1801
|
+
return true;
|
|
1763
1802
|
if (spec.scope !== "diff")
|
|
1764
1803
|
return false;
|
|
1765
1804
|
if (!opts.diffOnly)
|
|
@@ -2020,7 +2059,8 @@ var CheckEntrySchema = z.object({
|
|
|
2020
2059
|
include: z.array(z.string()).optional(),
|
|
2021
2060
|
args: z.array(z.string()).optional(),
|
|
2022
2061
|
timeoutMs: z.number().optional(),
|
|
2023
|
-
env: z.record(z.string(), EnvEntrySchema).optional()
|
|
2062
|
+
env: z.record(z.string(), EnvEntrySchema).optional(),
|
|
2063
|
+
requiresOpenPr: z.boolean().optional()
|
|
2024
2064
|
}).superRefine((entry2, ctx) => {
|
|
2025
2065
|
if (!entry2.env)
|
|
2026
2066
|
return;
|
|
@@ -2127,7 +2167,8 @@ var VinayaConfigSchema = z.object({
|
|
|
2127
2167
|
}).optional(),
|
|
2128
2168
|
checks: z.record(z.string(), CheckEntrySchema).optional(),
|
|
2129
2169
|
briefSchema: BriefSchemaSchema.optional(),
|
|
2130
|
-
managed: ManagedManifestSchema.optional()
|
|
2170
|
+
managed: ManagedManifestSchema.optional(),
|
|
2171
|
+
principals: z.array(z.string()).min(1).optional()
|
|
2131
2172
|
});
|
|
2132
2173
|
var GLOBAL_VINAYA_HOME = join4(homedir(), ".vinaya");
|
|
2133
2174
|
var GLOBAL_CONFIG_PATH = join4(GLOBAL_VINAYA_HOME, "config.json");
|
|
@@ -2155,11 +2196,22 @@ function configPath() {
|
|
|
2155
2196
|
function globalChecksIgnoredWarning(path) {
|
|
2156
2197
|
return `${path}: "checks" registration in the global config is ignored — checks may only be registered from a repo-local vinaya.config.json.`;
|
|
2157
2198
|
}
|
|
2158
|
-
function
|
|
2159
|
-
|
|
2199
|
+
function globalPrincipalsIgnoredWarning(path) {
|
|
2200
|
+
return `${path}: "principals" in the global config is ignored — principals may only be declared from a repo-local vinaya.config.json.`;
|
|
2201
|
+
}
|
|
2202
|
+
function stripGlobalOnlyKeys(config, path) {
|
|
2203
|
+
if (path !== GLOBAL_CONFIG_PATH)
|
|
2160
2204
|
return config;
|
|
2161
|
-
|
|
2162
|
-
|
|
2205
|
+
let result = config;
|
|
2206
|
+
if (result.checks && Object.keys(result.checks).length > 0) {
|
|
2207
|
+
console.error(`⚠ ${globalChecksIgnoredWarning(path)}`);
|
|
2208
|
+
result = { ...result, checks: undefined };
|
|
2209
|
+
}
|
|
2210
|
+
if (result.principals && result.principals.length > 0) {
|
|
2211
|
+
console.error(`⚠ ${globalPrincipalsIgnoredWarning(path)}`);
|
|
2212
|
+
result = { ...result, principals: undefined };
|
|
2213
|
+
}
|
|
2214
|
+
return result;
|
|
2163
2215
|
}
|
|
2164
2216
|
function loadConfigChecked() {
|
|
2165
2217
|
const path = configPath();
|
|
@@ -2176,7 +2228,7 @@ function loadConfigChecked() {
|
|
|
2176
2228
|
const detail = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
2177
2229
|
return { ok: false, path, error: detail };
|
|
2178
2230
|
}
|
|
2179
|
-
return { ok: true, config:
|
|
2231
|
+
return { ok: true, config: stripGlobalOnlyKeys(parsed.data, path) };
|
|
2180
2232
|
}
|
|
2181
2233
|
|
|
2182
2234
|
// src/commands/check.ts
|
|
@@ -2301,6 +2353,7 @@ function printClassificationWarnings(configChecks) {
|
|
|
2301
2353
|
async function checkCommand(args) {
|
|
2302
2354
|
const jsonOutput = args.includes("--json");
|
|
2303
2355
|
const diffOnly = args.includes("--diff-only");
|
|
2356
|
+
const localOnly = args.includes("--local");
|
|
2304
2357
|
const requestedParallel = parseParallel(args);
|
|
2305
2358
|
const allRequested = args.includes("--all");
|
|
2306
2359
|
const planRequested = args.includes("--plan");
|
|
@@ -2318,7 +2371,7 @@ async function checkCommand(args) {
|
|
|
2318
2371
|
process.exit(result.failures.length > 0 ? 1 : 0);
|
|
2319
2372
|
}
|
|
2320
2373
|
if (!allRequested && !requestedName) {
|
|
2321
|
-
console.error("Usage: vinaya check <name> | --all | --plan [--json] [--diff-only] [--parallel[=n]]");
|
|
2374
|
+
console.error("Usage: vinaya check <name> | --all | --plan [--json] [--diff-only] [--local] [--parallel[=n]]");
|
|
2322
2375
|
process.exit(2);
|
|
2323
2376
|
}
|
|
2324
2377
|
const { specs: customSpecs, errorOutcome, checks: configChecks } = customSpecsFromConfig();
|
|
@@ -2333,7 +2386,8 @@ async function checkCommand(args) {
|
|
|
2333
2386
|
parallel: requestedParallel ?? defaultParallelism(),
|
|
2334
2387
|
diffOnly,
|
|
2335
2388
|
changedFiles: changed,
|
|
2336
|
-
defaultTimeoutMs: 30000
|
|
2389
|
+
defaultTimeoutMs: 30000,
|
|
2390
|
+
localOnly
|
|
2337
2391
|
}) : [];
|
|
2338
2392
|
const allOutcomes = errorOutcome ? [...outcomes, errorOutcome] : outcomes;
|
|
2339
2393
|
for (const o of allOutcomes) {
|
|
@@ -2566,8 +2620,9 @@ async function demoBreakCommand(args) {
|
|
|
2566
2620
|
}
|
|
2567
2621
|
|
|
2568
2622
|
// src/commands/doctor.ts
|
|
2623
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
2569
2624
|
import { existsSync as existsSync8, readFileSync as readFileSync6, statSync } from "node:fs";
|
|
2570
|
-
import { join as join8 } from "node:path";
|
|
2625
|
+
import { isAbsolute as isAbsolute2, join as join8 } from "node:path";
|
|
2571
2626
|
|
|
2572
2627
|
// src/lib/artifacts.ts
|
|
2573
2628
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
@@ -2629,6 +2684,11 @@ jobs:
|
|
|
2629
2684
|
env:
|
|
2630
2685
|
GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
2631
2686
|
PR_NUMBER: \${{ github.event.pull_request.number }}
|
|
2687
|
+
# PR_BODY is what makes test-plan/closes-n EVALUATE: neither check
|
|
2688
|
+
# fetches the body itself (both read \`process.env.PR_BODY\` only) —
|
|
2689
|
+
# without it they read "no body — nothing to check" and pass
|
|
2690
|
+
# vacuously regardless of the PR's real content, on every run.
|
|
2691
|
+
PR_BODY: \${{ github.event.pull_request.body }}
|
|
2632
2692
|
BRANCH: \${{ github.head_ref }}
|
|
2633
2693
|
run: npx --yes @attalabs/vinaya check --all --diff-only
|
|
2634
2694
|
`;
|
|
@@ -2675,6 +2735,10 @@ jobs:
|
|
|
2675
2735
|
# it the adapter reads "no PR yet — local dev" and exits 0, and
|
|
2676
2736
|
# the gate is green regardless of review state.
|
|
2677
2737
|
PR_NUMBER: \${{ github.event.pull_request.number }}
|
|
2738
|
+
# Same PR_BODY gap as vinaya-checks.yml — this job also runs
|
|
2739
|
+
# \`check --all\` (test-plan/closes-n included), so it needs the
|
|
2740
|
+
# same wiring or those two checks pass vacuously here too.
|
|
2741
|
+
PR_BODY: \${{ github.event.pull_request.body }}
|
|
2678
2742
|
BRANCH: \${{ github.head_ref }}
|
|
2679
2743
|
run: npx --yes @attalabs/vinaya check --all
|
|
2680
2744
|
`;
|
|
@@ -2861,11 +2925,11 @@ function ownVersion() {
|
|
|
2861
2925
|
function preCommitBody() {
|
|
2862
2926
|
return `# Vinaya commit-time gate. Runs the deterministic checks over your staged
|
|
2863
2927
|
# diff before the commit lands.
|
|
2864
|
-
npx --yes @attalabs/vinaya@${ownVersion()} check --all --diff-only || exit 1`;
|
|
2928
|
+
npx --yes @attalabs/vinaya@${ownVersion()} check --all --diff-only --local || exit 1`;
|
|
2865
2929
|
}
|
|
2866
2930
|
function prePushBody() {
|
|
2867
2931
|
return `# Vinaya pre-push gate. Runs branch/dispatch checks before the push leaves.
|
|
2868
|
-
npx --yes @attalabs/vinaya@${ownVersion()} check --all || exit 1`;
|
|
2932
|
+
npx --yes @attalabs/vinaya@${ownVersion()} check --all --local || exit 1`;
|
|
2869
2933
|
}
|
|
2870
2934
|
function doctrinePointer() {
|
|
2871
2935
|
const doctrineRoot = join6(packageRoot(import.meta.url), "aeg-root");
|
|
@@ -3446,6 +3510,19 @@ function labelForPath(path) {
|
|
|
3446
3510
|
return "doctrine-pointer";
|
|
3447
3511
|
return "workflows";
|
|
3448
3512
|
}
|
|
3513
|
+
function resolveManagedBlockPath(repoRoot, opPath) {
|
|
3514
|
+
if (!opPath.startsWith(".git/"))
|
|
3515
|
+
return join8(repoRoot, opPath);
|
|
3516
|
+
try {
|
|
3517
|
+
const commonDir = execFileSync6("git", ["-C", repoRoot, "rev-parse", "--git-common-dir"], {
|
|
3518
|
+
encoding: "utf8"
|
|
3519
|
+
}).trim();
|
|
3520
|
+
const gitDir = isAbsolute2(commonDir) ? commonDir : join8(repoRoot, commonDir);
|
|
3521
|
+
return join8(gitDir, opPath.slice(".git/".length));
|
|
3522
|
+
} catch {
|
|
3523
|
+
return join8(repoRoot, opPath);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3449
3526
|
function diagnoseInstall(repoRoot, ctx, manifest) {
|
|
3450
3527
|
const findings = [];
|
|
3451
3528
|
let hasDrift = false;
|
|
@@ -3479,7 +3556,7 @@ function diagnoseInstall(repoRoot, ctx, manifest) {
|
|
|
3479
3556
|
}
|
|
3480
3557
|
} else if (op.kind === "managed-block") {
|
|
3481
3558
|
const check = "hooks";
|
|
3482
|
-
const abs2 =
|
|
3559
|
+
const abs2 = resolveManagedBlockPath(repoRoot, op.path);
|
|
3483
3560
|
const owned = ownedBlocks.has(blockKey(op.path, op.marker));
|
|
3484
3561
|
if (!existsSync8(abs2)) {
|
|
3485
3562
|
findings.push(owned ? error(check, `${op.path} is missing — likely a fresh clone (raw git hooks aren't tracked by git). Run \`vinaya upgrade\` to restore it.`) : info(check, `${op.path} is not installed.`));
|
|
@@ -4030,7 +4107,7 @@ async function initProductCommand(args) {
|
|
|
4030
4107
|
}
|
|
4031
4108
|
|
|
4032
4109
|
// src/commands/issue.ts
|
|
4033
|
-
import { execFileSync as
|
|
4110
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
4034
4111
|
|
|
4035
4112
|
// src/lib/forge-write.ts
|
|
4036
4113
|
import { mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
@@ -4243,7 +4320,7 @@ function locateBodyOrRefuse(ghArgs, retryCommand) {
|
|
|
4243
4320
|
function fetchForgeLabels(issueRef) {
|
|
4244
4321
|
let out;
|
|
4245
4322
|
try {
|
|
4246
|
-
out =
|
|
4323
|
+
out = execFileSync7("gh", ["issue", "view", issueRef, "--json", "labels"], {
|
|
4247
4324
|
encoding: "utf8",
|
|
4248
4325
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4249
4326
|
});
|
|
@@ -4271,7 +4348,7 @@ function reportPass(json, command) {
|
|
|
4271
4348
|
function runGhWrite(ghCmd, ghArgs, bodyResult, json) {
|
|
4272
4349
|
const { finalArgs, cleanup: cleanup2 } = resolveShippableArgs(ghArgs, bodyResult);
|
|
4273
4350
|
try {
|
|
4274
|
-
const out =
|
|
4351
|
+
const out = execFileSync7("gh", [...ghCmd, ...finalArgs], { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] });
|
|
4275
4352
|
const url = out.trim();
|
|
4276
4353
|
if (json)
|
|
4277
4354
|
printJson({ validated: true, written: true, url });
|
|
@@ -4375,12 +4452,12 @@ ${registration}
|
|
|
4375
4452
|
}
|
|
4376
4453
|
|
|
4377
4454
|
// src/commands/pr.ts
|
|
4378
|
-
import { execFileSync as
|
|
4455
|
+
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
4379
4456
|
var RETRY_CREATE2 = "vinaya pr create --validate-only …";
|
|
4380
4457
|
var RETRY_EDIT2 = "vinaya pr edit <n> --validate-only …";
|
|
4381
4458
|
function git2(args) {
|
|
4382
4459
|
try {
|
|
4383
|
-
return
|
|
4460
|
+
return execFileSync8("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
4384
4461
|
} catch {
|
|
4385
4462
|
return "";
|
|
4386
4463
|
}
|
|
@@ -4414,7 +4491,7 @@ function reportPass2(json, command) {
|
|
|
4414
4491
|
function runGhWrite2(ghCmd, ghArgs, bodyResult, json) {
|
|
4415
4492
|
const { finalArgs, cleanup: cleanup2 } = resolveShippableArgs(ghArgs, bodyResult);
|
|
4416
4493
|
try {
|
|
4417
|
-
const out =
|
|
4494
|
+
const out = execFileSync8("gh", [...ghCmd, ...finalArgs], { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] });
|
|
4418
4495
|
const url = out.trim();
|
|
4419
4496
|
if (json)
|
|
4420
4497
|
printJson({ validated: true, written: true, url });
|
|
@@ -4428,7 +4505,7 @@ function runGhWrite2(ghCmd, ghArgs, bodyResult, json) {
|
|
|
4428
4505
|
function fetchPrForgeContext(prRef) {
|
|
4429
4506
|
let viewOut;
|
|
4430
4507
|
try {
|
|
4431
|
-
viewOut =
|
|
4508
|
+
viewOut = execFileSync8("gh", ["pr", "view", prRef, "--json", "headRefName,files"], {
|
|
4432
4509
|
encoding: "utf8",
|
|
4433
4510
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4434
4511
|
});
|
|
@@ -4524,7 +4601,7 @@ function prEditCommand(args) {
|
|
|
4524
4601
|
}
|
|
4525
4602
|
|
|
4526
4603
|
// src/commands/quickstart.ts
|
|
4527
|
-
import { execFileSync as
|
|
4604
|
+
import { execFileSync as execFileSync9 } from "node:child_process";
|
|
4528
4605
|
import { existsSync as existsSync14, readFileSync as readFileSync13 } from "node:fs";
|
|
4529
4606
|
import { join as join15 } from "node:path";
|
|
4530
4607
|
|
|
@@ -4718,7 +4795,7 @@ function realDeps6() {
|
|
|
4718
4795
|
};
|
|
4719
4796
|
}
|
|
4720
4797
|
function execGit(repoRoot, args) {
|
|
4721
|
-
return
|
|
4798
|
+
return execFileSync9("git", args, { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
4722
4799
|
}
|
|
4723
4800
|
function errorDetail(err) {
|
|
4724
4801
|
const stderr = err.stderr;
|
|
@@ -5174,12 +5251,12 @@ async function upgradeCommand(args) {
|
|
|
5174
5251
|
}
|
|
5175
5252
|
|
|
5176
5253
|
// src/commands/waiver.ts
|
|
5177
|
-
import { execFileSync as
|
|
5254
|
+
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
5178
5255
|
function labelFor(kind) {
|
|
5179
5256
|
return kind === "docs" ? WAIVER_LABEL : WAIVER_LABEL_REVIEW;
|
|
5180
5257
|
}
|
|
5181
5258
|
function gh(args) {
|
|
5182
|
-
return
|
|
5259
|
+
return execFileSync10("gh", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], env: process.env }).trim();
|
|
5183
5260
|
}
|
|
5184
5261
|
function detectPrNumber() {
|
|
5185
5262
|
try {
|
|
@@ -5279,8 +5356,8 @@ Reason: ${reason}`];
|
|
|
5279
5356
|
}
|
|
5280
5357
|
process.stdout.write(`Applying \`${label2}\` to PR #${prNumber} under your authenticated \`gh\` identity — vinaya never fabricates an actor.
|
|
5281
5358
|
`);
|
|
5282
|
-
|
|
5283
|
-
|
|
5359
|
+
execFileSync10("gh", editArgs, { stdio: "inherit", env: process.env });
|
|
5360
|
+
execFileSync10("gh", commentArgs, { stdio: "inherit", env: process.env });
|
|
5284
5361
|
process.stdout.write(`
|
|
5285
5362
|
✓ Label applied and reason posted as a PR comment.
|
|
5286
5363
|
`);
|
|
@@ -5337,6 +5414,10 @@ var COMMANDS = [
|
|
|
5337
5414
|
{ flag: "--all", description: "Run every registered check instead of one named check" },
|
|
5338
5415
|
{ flag: "--json", description: "Enveloped JSON output (schema: 1)" },
|
|
5339
5416
|
{ flag: "--diff-only", description: "Scope diff-declared checks to changed files" },
|
|
5417
|
+
{
|
|
5418
|
+
flag: "--local",
|
|
5419
|
+
description: "Skip every requiresOpenPr check (closes-n, test-plan) — set by the generated hooks, never by CI"
|
|
5420
|
+
},
|
|
5340
5421
|
{ flag: "--parallel[=n]", description: "Concurrency cap (default: cpu-derived)" },
|
|
5341
5422
|
{
|
|
5342
5423
|
flag: "--plan",
|
|
@@ -5345,7 +5426,8 @@ var COMMANDS = [
|
|
|
5345
5426
|
],
|
|
5346
5427
|
details: [
|
|
5347
5428
|
"Each spawned check's child process sees only a fixed baseline (`PATH`, `LANG`, `HOME`, `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY`, `TMPDIR`) plus whatever its `CheckSpec['env']` declaration explicitly forwards — never the full parent environment. A required (`true`) or unsatisfied `anyOf` declaration missing from the caller's environment synthesizes a `CheckError` before the check ever spawns. Declare `env` (a core check's own registration, or `vinaya.config.json`'s `checks.<name>.env` for a custom one) for any check that reads `process.env`/`Bun.env`/`Deno.env` directly — `vinaya doctor` carries the permanent diagnostic for one that doesn't.",
|
|
5348
|
-
"`--plan` composes with `--json`. It requires zero env vars and never prints an env value — only how each one resolves (passthrough, optional, literal, or anyOf). A `FAIL_CLOSED` entry (a bare key with no namespace matching no core check) always renders inline rather than being dropped, and exits non-zero. `--plan` previews what the next minor's execution will enforce — `vinaya check` itself still runs the flat, unvalidated registry this release."
|
|
5429
|
+
"`--plan` composes with `--json`. It requires zero env vars and never prints an env value — only how each one resolves (passthrough, optional, literal, or anyOf). A `FAIL_CLOSED` entry (a bare key with no namespace matching no core check) always renders inline rather than being dropped, and exits non-zero. `--plan` previews what the next minor's execution will enforce — `vinaya check` itself still runs the flat, unvalidated registry this release.",
|
|
5430
|
+
"`--local` exists because a `requiresOpenPr` check (the core `closes-n`/`test-plan`, or a custom check declaring the same field) can only evaluate for real once a pull request exists — the generated `pre-commit`/`pre-push` hooks pass it so the first commit on a fresh task branch is never asked to satisfy a PR-body field before a PR can possibly exist. CI's `vinaya-checks.yml` omits it, so these checks always run for real once a PR is open."
|
|
5349
5431
|
],
|
|
5350
5432
|
status: "shipped"
|
|
5351
5433
|
},
|
package/package.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_title: Projects
|
|
3
|
+
---
|
|
4
|
+
# Projects in this repo
|
|
5
|
+
|
|
6
|
+
**The project registry.** Declares the projects in this repo and where each one's specs and per-project state live. The `Project` field on a task (a forge Issue) resolves against this file: `Project: vada` → the Developer reads that project's specs, the Archivist updates its per-project state.
|
|
7
|
+
|
|
8
|
+
## What a project is (and isn't)
|
|
9
|
+
|
|
10
|
+
A project is **a `(name, folder)` pair the developer declared** — nothing more. Not derived from the folder tree, not required to match a `package.json` name, not required to be a single package. AEG does not define what a project "really" is; the developer does, by choosing a name and a home folder when registering it.
|
|
11
|
+
|
|
12
|
+
The folder is simply **the home for that project's specs and status** (`<path>/specs/`, `<path>/aeg-project/`). A project may be one package, an app, or a grouping built from several packages.
|
|
13
|
+
|
|
14
|
+
- **Identity = the registry row.** A project exists because it has a row here, not because a folder with some name exists somewhere. Nothing searches the tree; names are unique by this registry, paths are whatever the human gave.
|
|
15
|
+
- **Path = declared, never derived.** `--path` is a required argument to `aeg add-project`; the tool stores it.
|
|
16
|
+
|
|
17
|
+
**Presence of this file means this is a multi-project repo** — the `Project` field is required. A single-project repo has **no** `projects.md`; every task shares one project, so the field is omitted, and state lives in the root `aeg-project/`. The registry appears only when there is more than one project to disambiguate.
|
|
18
|
+
|
|
19
|
+
## Registry
|
|
20
|
+
|
|
21
|
+
| Project | Path | Specs | Per-project state |
|
|
22
|
+
|----------|-----------------------|-----------------------------|--------------------------------------|
|
|
23
|
+
| admin | `tools/admin` | `tools/admin/specs/` | (state tracked globally for now) |
|
|
24
|
+
| vada | `apps/vada-ai` | `apps/vada-ai/specs/` | `apps/vada-ai/aeg-project/` |
|
|
25
|
+
| herald | `apps/herald-ai` | `apps/herald-ai/specs/` | `apps/herald-ai/aeg-project/` |
|
|
26
|
+
| aeg-core | `packages/aeg-core` | `packages/aeg-core/specs/` | (state tracked globally for now) |
|
|
27
|
+
| aeg-forge-state | `packages/aeg-forge-state` | `packages/aeg-forge-state/specs/` | (state tracked globally for now) |
|
|
28
|
+
| attalabs | `apps/attalabs` | `apps/attalabs/specs/` | (state tracked globally for now) |
|
|
29
|
+
| vinaya | `apps/vinaya` | `apps/vinaya/specs/` | Issue #768 (pinned) |
|
|
30
|
+
|
|
31
|
+
> **admin** — `tools/admin`: the internal Sanity-backed admin tool for managing per-product theme/library config across every AttaLabs product (not a product itself, no `.attalabs.dev` domain). Had real code and a task PR (#557, the Library-picker feature) before ever getting a registry row — added retroactively once that gap was noticed. `tools/*` carries no `-ai` suffix (internal-tooling convention, like `apps/desktop`, `apps/attalabs`).
|
|
32
|
+
|
|
33
|
+
> **vinaya** — Vinaya: the npm-distributed reference implementation of AEG, installed into any GitHub repository. One app folder, three workspaces: `apps/vinaya/cli` (the `vinaya` command — init/check/pr/issue/doctor/upgrade/eject/demo/waiver), `apps/vinaya/web` (**Vinaya Studio**, ported from the old AEG Studio app), and `apps/vinaya/sources` (the StateSource adapters — forge-backed primary, file-backed transitional). Imports `@atta/aeg-core` unchanged; the vinaya-namespace migration of shared code rides the later npm extraction, never a standalone rename. The registry row deliberately precedes the code. "Vinaya is the reference implementation of AEG": AEG stays the model's name (`aeg-root/` is untouched); Vinaya is the tool. Pāli name by elective aesthetic. `apps/vinaya` carries no `-ai` suffix (meta/infra convention).
|
|
34
|
+
|
|
35
|
+
> **attalabs** — The AttaLabs ecosystem hub app (`@atta/attalabs-web`/`-mobile`/`-mcp-server`, serving `attalabs.dev`), distinct from **Atta** (the deep-thinking AI product — Vāda+Vitakka+Sati; its dedicated app scaffold, `apps/atta-ai`, was retired — Atta remains a real, code-less concept, not a registered project). Registered here because it has real code and its own `apps/attalabs/specs/`, but had no registry row until it was added retroactively (found while sizing an unrelated task's `Project(s)` field). `apps/attalabs` carries no `-ai` suffix (meta/infra-app convention, like `apps/desktop`).
|
|
36
|
+
|
|
37
|
+
> **aeg-core** — `@atta/aeg-core` (`packages/aeg-core`): the pure, no-I/O package the AEG product runs on. Two capabilities: parse a repo's AEG artifacts (registry, tranche files) into a typed model, and `deriveTranche(tranche, forgeFacts)` → per-task derived status + the dependency/conflict graph + dispatch eligibility, mirroring `tranche-model.md` §3 exactly. Both **AEG Studio** (local, the first consumer) and the future **Portal** (hosted) read through this same substrate; they differ only in how they fetch the inputs. Registered as a project because a task declares `Project: aeg-core` — a package may be a project, per this file's framing above.
|
|
38
|
+
|
|
39
|
+
> **aeg-forge-state** — `@atta/aeg-forge-state` (`packages/aeg-forge-state`): the one sanctioned adapter that reads live GitHub forge state (Milestone + labeled Issues) and derives the typed `Tranche`/`Task` shapes `aeg-core`'s pure evaluators consume — `gh`-CLI-only, read-only, zero topology file. Listed in `.aeg/packages` as its own collision domain (distinct from `aeg-core`) since before this row, but had no registry row of its own — any task editing its `src/**` had no `Project:` whose declared path actually covered it, forcing every prior task to fall back on a `blast-radius-ack:` line instead of a real ownership match. Registered retroactively (found while planning follow-on forge-adapter test-coverage and label-vocabulary work) for the same reason `attalabs` and `admin` were: real code, its own collision domain, no row.
|
|
40
|
+
|
|
41
|
+
## How `Project` is validated
|
|
42
|
+
|
|
43
|
+
This registry is the **authority for valid project names.** A `Project:` value is valid iff every name in it is a row above. The Planner and Developer resolve `Project:` against this file; an unmatched name (a typo like `vda`, or unregistered) makes the task malformed and the agent refuses rather than guessing — *"Project 'vda' isn't registered; did you mean 'vada', or run `aeg add-project` first?"* Can also run mechanically in `verify-docs`.
|
|
44
|
+
|
|
45
|
+
## A task can span multiple projects — and that is normal
|
|
46
|
+
|
|
47
|
+
`Project` is **multi-valued.** A task carries as many projects as it genuinely touches: usually one (`Project: vada`), sometimes several (`Project: engine, herald`, or more). Not an exception — cross-project PRs are an expected shape. The Planner decides split-vs-combine by **verification coupling** (see `tranche-model.md` §6): provable independently → separate tasks with a `depends-on` edge; provable only as a unit → one task / branch / PR / multiple projects. The same `Ticket:` rides on all resulting tasks, so work stays atomic in Jira however it's shaped in AEG.
|
|
48
|
+
|
|
49
|
+
When a task lists multiple projects, every mechanism fans out: the Developer reads every listed project's specs; the PR is reviewed through each project's lens (more projects = more review lenses = proportionally more rigor, matching the wider blast radius); the Archivist updates every listed project's `state.md` (non-derivable operational facts; `now.md` is retired).
|
|
50
|
+
|
|
51
|
+
## Routing vs. conflicts — two different granularities
|
|
52
|
+
|
|
53
|
+
`Project` is the **coarse routing/ownership label** — "whose specs, whose state." It is **not** the conflict unit. Conflicts happen at the **package / collision-domain level**:
|
|
54
|
+
|
|
55
|
+
- **Collision domains are packages**, listed in a rarely-changed static file, `.aeg/packages`. Known cross-cutting paths that couple tasks across package boundaries — **lockfiles, `migrations/`, codegen outputs (protobuf/GraphQL/OpenAPI), monorepo config (tsconfig/eslint/turbo)** — are declared as their own collision domains.
|
|
56
|
+
- Two tasks conflict if they touch the same collision domain. The canonical case: a task generalizing `@atta/engine` (a package Vāda shares) conflicts with any in-flight Vāda task touching the engine — different projects, same package, real collision. So conflict detection keys on **packages, not projects**.
|
|
57
|
+
- Conflicts are **declared by the Planner** (`conflicts-with` edges) and **static**. The gate is forge-answerable with zero stored state: "is a `conflicts-with` sibling's PR open?" There is **no dynamic path-overlap scanner** — that would need a live task→changed-files map, the mutable state AEG eliminates (forbidden; see `tranche-model.md` §9). When unsure two tasks collide, declare the conflict and serialize.
|
|
58
|
+
|
|
59
|
+
Don't conflate them: `Project` = whose specs/state; `conflicts-with` (via collision domains) = whose files.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
Project backlogs (held / future items, out of the AEG flow) live alongside each project's specs as `<path>/specs/<project>-backlog.md`. Cross-cutting / ecosystem items are cut as backlog Issues on the forge (the old `specs/ecosystem-backlog.md` was deleted).
|