@attalabs/vinaya 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -4
- package/aeg-root/contracts/archivist-tranche-archivist.md +2 -2
- package/aeg-root/contracts/brief-developer.md +1 -0
- package/aeg-root/contracts/developer-reviewer.md +3 -3
- package/aeg-root/contracts/reviewer-archivist.md +3 -3
- package/aeg-root/enforcement.md +28 -21
- package/aeg-root/process.md +8 -4
- package/aeg-root/roles/archivist.md +2 -2
- package/aeg-root/roles/brief-author.md +9 -3
- package/aeg-root/roles/developer.md +63 -31
- package/aeg-root/roles/planner.md +2 -2
- package/aeg-root/roles/principal.md +14 -0
- package/aeg-root/roles/reviewer.md +32 -15
- package/aeg-root/roles/security.md +15 -5
- package/aeg-root/skills/aeg/SKILL.md +9 -5
- package/aeg-root/skills/aeg-roles/SKILL.md +2 -2
- package/aeg-root/skills/brief-authoring/SKILL.md +39 -27
- package/aeg-root/state-machine.md +9 -11
- package/aeg-root/templates/brief-template.md +6 -6
- package/aeg-root/templates/pr-report-template.md +12 -7
- package/aeg-root/tranche-model.md +9 -5
- package/dist/checks/bin/check-body-bare-digits.js +667 -148
- package/dist/checks/bin/check-branch-topology.js +714 -149
- package/dist/checks/bin/check-brief-shape.js +704 -147
- package/dist/checks/bin/check-changeset-coverage.js +1046 -166
- package/dist/checks/bin/check-closes-n.js +714 -149
- package/dist/checks/bin/check-coherence.js +729 -156
- package/dist/checks/bin/check-dead-branch-push.js +663 -144
- package/dist/checks/bin/check-dispatch-readiness.js +728 -155
- package/dist/checks/bin/check-doc-coverage-push.js +838 -261
- package/dist/checks/bin/check-doc-coverage.js +838 -261
- package/dist/checks/bin/check-doctrine-no-procedures.js +4794 -0
- package/dist/checks/bin/check-doctrine-portability.js +799 -155
- package/dist/checks/bin/check-evidence-fresh.js +1132 -206
- package/dist/checks/bin/check-exec-bits.js +4931 -0
- package/dist/checks/bin/check-first-push-dispatch.js +716 -151
- package/dist/checks/bin/check-issue-assignment.js +714 -149
- package/dist/checks/bin/check-main-branch-refusal.js +663 -144
- package/dist/checks/bin/check-no-disk-state.js +663 -144
- package/dist/checks/bin/check-pr-report-density.js +4461 -0
- package/dist/checks/bin/check-quoted-command.js +741 -166
- package/dist/checks/bin/check-reader-resolvable-prose.js +768 -173
- package/dist/checks/bin/check-registry-gates.js +726 -154
- package/dist/checks/bin/check-retired-vocabulary.js +760 -165
- package/dist/checks/bin/check-review-gate.js +783 -148
- package/dist/checks/bin/check-single-plan-pr.js +663 -144
- package/dist/checks/bin/check-test-plan.js +664 -145
- package/dist/checks/bin/check-token-collection-wired.js +665 -146
- package/dist/checks/bin/check-token-report.js +4509 -0
- package/dist/checks/bin/check-workspace-escape.js +1129 -183
- package/dist/index.js +8458 -5403
- package/package.json +1 -1
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/actions.ts +173 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/anchored-region.ts +113 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/archive-task.ts +206 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/baseline-capture.ts +65 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/blast-radius-domains.ts +192 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/branch-topology-gate.ts +85 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-validation.ts +511 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/claude-code-transcript.ts +460 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/coherence-checks.ts +787 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-audit.ts +55 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-guard.ts +77 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-section7.ts +66 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-tranche.ts +94 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/diagram-model.ts +372 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/direct-main-push.ts +39 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dispatch-gate.ts +224 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doc-owners.ts +314 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/build-doc-nav.ts +38 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/docs-coherence.ts +136 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/index.ts +29 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/legacy-anchors.ts +48 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/nav-helpers.ts +17 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/node-route.ts +134 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/parse-doc.ts +43 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/published-prose.ts +306 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/surfaced-manifest.ts +89 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/types.ts +33 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-portability.ts +170 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-source.ts +23 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/ensure-label.ts +28 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/file-classify.ts +51 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/first-push-dispatch-gate.ts +80 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/gate-audience.ts +168 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/index.ts +301 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-assignment.ts +102 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-validation.ts +746 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/leftover-detection.ts +68 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/local-anchor-coverage.ts +245 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/main-branch-refusal.ts +64 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/manifest-validity.ts +81 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/markdown-table.ts +76 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/metering-io-guard.ts +119 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/milestone-validation.ts +240 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/no-disk-state.ts +50 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-ledger.ts +77 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-registry.ts +105 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-token-report.ts +165 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-tranche.ts +183 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/pr-tier.ts +81 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/premise-check.ts +125 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/quoted-command.ts +275 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/reader-resolvable-prose.ts +320 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-checks.ts +255 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-parse.ts +164 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-scaffold.ts +216 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/report-tokens.ts +261 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/retired-vocabulary.ts +163 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-gate.ts +269 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/single-plan-pr.ts +73 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-machine-model.ts +269 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-source.ts +14 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/status-block.ts +8 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/sum-ledger.ts +26 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/symbol-collisions.ts +78 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-gate.ts +104 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-section.ts +65 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/types.ts +174 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/verdict-extraction.ts +140 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/vocabulary-citation.ts +114 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/waiver-label.ts +52 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/workspace-escape.ts +172 -0
- 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/_head.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.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]__02a-3g8._.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]__0053k9k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__02c71kv._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0ozbaq0._.js → [root-of-the-server]__1mcitst._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0o54suy._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1-6rzip._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1mrtj0f._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_06it6s-._.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/chunks/ssr/packages_ui_libraries_animate_components_index_ts_186fje1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_brutal_components_index_ts_0n_lcc4._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_retro_components_index_ts_0wvpm_z._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_retro_components_index_ts_1_cfi48._.js +1 -1
- 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/00pi8vhg8w6gi.js +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0r4i_ks9z02bw.js → 03q0q9n6-xah8.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2_k6j1o9q5nn4.js → 0jer_drkl1e4r.js} +4 -4
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0vc2u252q5q6o.js +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1k916ih3p4nsg.js → 13g16cu00g570.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2hmannd4bjhzy.js → 1sfxfunirkcr6.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1t2kft7bxzuxn.js → 206ajg8f1a-_h.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1hfhxjy577l5d.js → 20x-t0a0v129z.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{25kbt5k-xb2a5.js → 279qq4twinc97.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{112g08xpx3kro.js → 2ka8dg687auhj.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/2ou_81ahqw31e.js +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0up5x3jg-cwov.js → 2rn89uwtf2lwc.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3mqu_uhluy19i.css → 3qc67qhcvbg0o.css} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1yqs2zgvwa4p1.js → 3zugx9esh2x51.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0_jnwbarv-cqk.js +0 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1ybrihl5_aocy.js +0 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/3r5efmleneaco.js +0 -1
- /package/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/{aeg-core → vinaya/studio-standalone/_node_modules/@attalabs/aeg-core}/bin/verify-coherence.ts +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → 5xy_GA7G5KRuE3HDumIiw}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → 5xy_GA7G5KRuE3HDumIiw}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → 5xy_GA7G5KRuE3HDumIiw}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live derivation of `checkBlastRadiusScope`'s collision-domain list.
|
|
3
|
+
*
|
|
4
|
+
* The list used to be 100% hand-authored in `.aeg/packages` (see that file's
|
|
5
|
+
* own header for the doctrine this module now mechanizes). Two of its three
|
|
6
|
+
* sections are derivable or defaultable, and this module produces both,
|
|
7
|
+
* pure — every filesystem read is injected by the caller (`open-issue.ts`),
|
|
8
|
+
* so this stays testable against a literal fixture with no disk I/O.
|
|
9
|
+
*
|
|
10
|
+
* 1. **`packages/*` workspace domains** (`deriveWorkspacePackageDomains`) —
|
|
11
|
+
* every workspace member (from `package.json`'s `workspaces` array, or
|
|
12
|
+
* `pnpm-workspace.yaml`'s `packages:` list — pnpm does not honor a
|
|
13
|
+
* `workspaces` key in `package.json` at all, so both sources are read and
|
|
14
|
+
* combined by the caller before this function ever sees them) that
|
|
15
|
+
* resolves under `packages/` is a shared collision domain BY CONSTRUCTION
|
|
16
|
+
* (this repo's own doctrine, `.aeg/packages`'s header). A workspace member
|
|
17
|
+
* three directories deep (`packages/agents/vada-fusion`) still collapses
|
|
18
|
+
* to its top-level directory (`packages/agents`) — the domain is the
|
|
19
|
+
* directory, not the individual package, because that is the granularity
|
|
20
|
+
* every existing static list (this repo's own, attalabs') actually uses: a
|
|
21
|
+
* monorepo's `packages/agents/*` sub-packages share one collision domain,
|
|
22
|
+
* not four. A leading `!` negates an entry (npm/yarn/pnpm's own workspace
|
|
23
|
+
* negation syntax) — resolved the same way, then subtracted from the
|
|
24
|
+
* positive matches before collapsing, so an adopter's own excluded
|
|
25
|
+
* directory is never derived as a domain.
|
|
26
|
+
* 2. **Built-in cross-cutting defaults** (`deriveBuiltinCrossCuttingDefaults`)
|
|
27
|
+
* — lockfile, monorepo config, CI, git hooks. Not derivable from workspace
|
|
28
|
+
* structure, but detectable by convention: presence-check a fixed
|
|
29
|
+
* candidate list rather than assuming any one of them exists.
|
|
30
|
+
*
|
|
31
|
+
* Neither function reads `.aeg/packages` or `vinaya.config.json`'s
|
|
32
|
+
* `blastRadius.extraDomains` — those stay additive, read by the caller and
|
|
33
|
+
* unioned on top (see `open-issue.ts`'s `readSharedPackages`).
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolves one workspace-glob entry (from either `package.json`'s
|
|
38
|
+
* `workspaces` array or `pnpm-workspace.yaml`'s `packages:` list — same
|
|
39
|
+
* grammar, different file) to the workspace member path(s) it names. Supports
|
|
40
|
+
* the one glob shape every package manager's workspaces field actually uses
|
|
41
|
+
* in practice — a trailing `/*` naming an immediate-children directory
|
|
42
|
+
* (`"packages/*"`, `"apps/*"`) — via the injected `listDirs`, which the
|
|
43
|
+
* caller resolves against the real filesystem. A literal entry with no
|
|
44
|
+
* trailing `/*` (attalabs' own `package.json` lists every member explicitly,
|
|
45
|
+
* no globs at all) passes through unchanged. Any other `*` position is not a
|
|
46
|
+
* real-world workspaces shape and is dropped rather than guessed at — this
|
|
47
|
+
* applies identically whether the entry came in positive or negated (the
|
|
48
|
+
* caller strips the leading `!` before calling this).
|
|
49
|
+
*/
|
|
50
|
+
function resolveWorkspaceEntry(entry: string, listDirs: (dir: string) => string[]): string[] {
|
|
51
|
+
if (entry.endsWith('/*')) {
|
|
52
|
+
const baseDir = entry.slice(0, -2)
|
|
53
|
+
return listDirs(baseDir).map((name) => `${baseDir}/${name}`)
|
|
54
|
+
}
|
|
55
|
+
if (entry.includes('*')) return []
|
|
56
|
+
return [entry]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Every `packages/*` workspace member, collapsed to its top-level directory
|
|
61
|
+
* under `packages/` and deduplicated. A member outside `packages/` (an
|
|
62
|
+
* `apps/*` entry, a root-level `tools/admin`) is not a `packages/*` domain
|
|
63
|
+
* and is dropped — those are within a single project's own path or covered
|
|
64
|
+
* by the cross-cutting defaults, never a shared-package collision domain.
|
|
65
|
+
*
|
|
66
|
+
* A `!`-prefixed entry (npm/yarn/pnpm workspace negation) is resolved the
|
|
67
|
+
* same way as a positive entry, and every member it resolves to is excluded
|
|
68
|
+
* from the positive result BEFORE collapsing — so `["packages/*",
|
|
69
|
+
* "!packages/legacy"]` never derives `packages/legacy`, but a negation that
|
|
70
|
+
* excludes only one member of a many-member directory (e.g. one nested
|
|
71
|
+
* package under `packages/agents`) still leaves that directory's domain
|
|
72
|
+
* derived from its remaining members, which is correct: the shared directory
|
|
73
|
+
* is still a real collision domain for whoever touches it.
|
|
74
|
+
*
|
|
75
|
+
* `listDirs(dir)` returns the immediate child directory NAMES of `dir`
|
|
76
|
+
* (repo-relative, forward-slashed, no leading `packages/`) — the caller's
|
|
77
|
+
* job is filesystem access; this function only reads its return value.
|
|
78
|
+
*/
|
|
79
|
+
export function deriveWorkspacePackageDomains(workspaces: string[], listDirs: (dir: string) => string[]): string[] {
|
|
80
|
+
const positive = workspaces.filter((entry) => !entry.startsWith('!'))
|
|
81
|
+
const negative = workspaces.filter((entry) => entry.startsWith('!')).map((entry) => entry.slice(1))
|
|
82
|
+
|
|
83
|
+
const excluded = new Set<string>()
|
|
84
|
+
for (const entry of negative) {
|
|
85
|
+
for (const member of resolveWorkspaceEntry(entry, listDirs)) excluded.add(member)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const domains = new Set<string>()
|
|
89
|
+
for (const entry of positive) {
|
|
90
|
+
for (const member of resolveWorkspaceEntry(entry, listDirs)) {
|
|
91
|
+
if (excluded.has(member)) continue
|
|
92
|
+
const segments = member.split('/')
|
|
93
|
+
if (segments[0] !== 'packages' || segments.length < 2) continue
|
|
94
|
+
domains.add(`packages/${segments[1]}`)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return [...domains].sort()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Hand-rolled parser for `pnpm-workspace.yaml`'s `packages:` list — NOT a
|
|
102
|
+
* general YAML parser, deliberately: the field is always a flat list of
|
|
103
|
+
* glob/literal strings, never nested structure, so pulling in a full YAML
|
|
104
|
+
* dependency for one narrow shape would be the wrong tool (same reasoning as
|
|
105
|
+
* this repo's other hand-rolled parsers, e.g. `parse-registry.ts` for
|
|
106
|
+
* markdown tables). Handles both forms pnpm's own docs show:
|
|
107
|
+
*
|
|
108
|
+
* ```yaml
|
|
109
|
+
* packages:
|
|
110
|
+
* - 'packages/*'
|
|
111
|
+
* - 'apps/*'
|
|
112
|
+
* - '!packages/legacy'
|
|
113
|
+
* ```
|
|
114
|
+
* ```yaml
|
|
115
|
+
* packages: ['packages/*', 'apps/*', '!packages/legacy']
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* Entries may be single- or double-quoted or bare; a trailing `# comment` on
|
|
119
|
+
* a line is stripped. A file this cannot parse (nested anchors, multi-line
|
|
120
|
+
* scalars, no `packages:` key at all) returns `[]` — the same
|
|
121
|
+
* dormant-if-unreadable seam every other input to this module uses, never a
|
|
122
|
+
* throw.
|
|
123
|
+
*/
|
|
124
|
+
export function parsePnpmWorkspaceYaml(content: string): string[] {
|
|
125
|
+
const unquote = (s: string): string => {
|
|
126
|
+
const t = s.trim()
|
|
127
|
+
if (t.length >= 2 && ((t[0] === "'" && t.at(-1) === "'") || (t[0] === '"' && t.at(-1) === '"'))) {
|
|
128
|
+
return t.slice(1, -1)
|
|
129
|
+
}
|
|
130
|
+
return t
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const inlineMatch = content.match(/^packages:\s*\[(.*)\]\s*$/m)
|
|
134
|
+
if (inlineMatch) {
|
|
135
|
+
return (inlineMatch[1] ?? '')
|
|
136
|
+
.split(',')
|
|
137
|
+
.map(unquote)
|
|
138
|
+
.filter((s) => s.length > 0)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const entries: string[] = []
|
|
142
|
+
let inBlock = false
|
|
143
|
+
for (const rawLine of content.split('\n')) {
|
|
144
|
+
const line = rawLine.replace(/#.*$/, '')
|
|
145
|
+
if (/^packages:\s*$/.test(line)) {
|
|
146
|
+
inBlock = true
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
if (!inBlock) continue
|
|
150
|
+
const itemMatch = line.match(/^\s+-\s*(.+?)\s*$/)
|
|
151
|
+
if (itemMatch?.[1]) {
|
|
152
|
+
entries.push(unquote(itemMatch[1]))
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
if (line.trim().length === 0) continue
|
|
156
|
+
break // next top-level key ends the packages: block
|
|
157
|
+
}
|
|
158
|
+
return entries
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The built-in cross-cutting candidates, in the fixed order every derived
|
|
163
|
+
* list reports them — the same order the doctrine names them
|
|
164
|
+
* (`aeg-root/tranche-model.md` §5) and the order attalabs' own static
|
|
165
|
+
* `.aeg/packages` already lists them in, so a diff against that file reads
|
|
166
|
+
* as a true empty diff rather than a reordering.
|
|
167
|
+
*
|
|
168
|
+
* Exactly one of the four lockfile names is expected to exist per repo — all
|
|
169
|
+
* four are checked, deliberately, rather than assuming one: a repo mid-
|
|
170
|
+
* migration between package managers, or one this module has never seen,
|
|
171
|
+
* should still get whichever lockfile is actually on disk rather than none.
|
|
172
|
+
*/
|
|
173
|
+
export const CROSS_CUTTING_CANDIDATES = [
|
|
174
|
+
'bun.lock',
|
|
175
|
+
'package-lock.json',
|
|
176
|
+
'pnpm-lock.yaml',
|
|
177
|
+
'yarn.lock',
|
|
178
|
+
'turbo.json',
|
|
179
|
+
'biome.json',
|
|
180
|
+
'tsconfig.json',
|
|
181
|
+
'.github/workflows',
|
|
182
|
+
'.husky'
|
|
183
|
+
] as const
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Presence-checks `CROSS_CUTTING_CANDIDATES` and returns whichever exist.
|
|
187
|
+
* `exists(path)` is injected — the caller resolves it against the real
|
|
188
|
+
* repo root (`existsSync(join(REPO_ROOT, path))`).
|
|
189
|
+
*/
|
|
190
|
+
export function deriveBuiltinCrossCuttingDefaults(exists: (path: string) => boolean): string[] {
|
|
191
|
+
return CROSS_CUTTING_CANDIDATES.filter((path) => exists(path))
|
|
192
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Tranche } from './types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Branch↔topology gate (aeg-governance-hardening task 32, #399). Pure — no
|
|
5
|
+
* `fs`, no shell-outs. The CLI shim (`bin/check-branch-topology.ts`) derives
|
|
6
|
+
* the tranche from the forge (`@attalabs/aeg-forge-state`, task
|
|
7
|
+
* aeg-forge-state-v1 3a) and passes the result (or `null` when no tranche
|
|
8
|
+
* data could be derived) in here.
|
|
9
|
+
*
|
|
10
|
+
* Closes the logic fork: `.husky/pre-push` used to answer "does this
|
|
11
|
+
* branch's task-id suffix have a topology row?" with a hand-rolled
|
|
12
|
+
* `grep -qE "^\|[[:space:]]*${id}[[:space:]]*\|"` against the tranche
|
|
13
|
+
* file — a bash reimplementation of the table-parsing that `parseTranche`
|
|
14
|
+
* used to do here, and that forge-derivation now does instead. Row
|
|
15
|
+
* membership is `topology.tasks`, and the refusal messages are byte-identical
|
|
16
|
+
* to the inline ones the hook printed before.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export type BranchTopologyInput = {
|
|
20
|
+
/** The full branch name being pushed — used verbatim in refusal messages. */
|
|
21
|
+
branch: string
|
|
22
|
+
/** Tranche slug extracted from the branch (segment 2). */
|
|
23
|
+
tranche: string
|
|
24
|
+
/** Task id extracted from the branch (segment 3). */
|
|
25
|
+
taskId: string
|
|
26
|
+
/** Repo-relative topology path — used verbatim in refusal messages. */
|
|
27
|
+
topoPath: string
|
|
28
|
+
/** Forge-derived tranche data, or `null` when none could be derived. */
|
|
29
|
+
topology: Tranche | null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type BranchTopologyVerdict = 'allow' | 'refuse'
|
|
33
|
+
|
|
34
|
+
export type BranchTopologyResult = { verdict: BranchTopologyVerdict; reason: string }
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Mirror the hook's original field extraction exactly: its shell `case`
|
|
38
|
+
* pattern — `task/` followed by two wildcard segments, where the shell `*`
|
|
39
|
+
* also matches `/` and the empty string — decided whether the check
|
|
40
|
+
* applied, and `cut -d/ -f2` / `-f3` picked the tranche and task id;
|
|
41
|
+
* segments beyond the third were ignored, exactly as `cut` ignored them.
|
|
42
|
+
* Returns `null` when the branch would not have matched that `case`
|
|
43
|
+
* pattern, i.e. when the hook would have skipped the check entirely.
|
|
44
|
+
*/
|
|
45
|
+
export function taskBranchTopologyFields(branch: string): { tranche: string; taskId: string } | null {
|
|
46
|
+
if (!/^task\/.*\/.*$/.test(branch)) return null
|
|
47
|
+
const parts = branch.split('/')
|
|
48
|
+
return { tranche: parts[1] ?? '', taskId: parts[2] ?? '' }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* `allow` — the topology file exists and `parseTranche` finds a Tasks-table
|
|
53
|
+
* row whose `#` column literal-equals the branch's task-id suffix.
|
|
54
|
+
* `refuse` — the tranche file is missing, or no row matches
|
|
55
|
+
*. Reasons are byte-identical to the hook's pre-task-32
|
|
56
|
+
* inline messages, so a refused push reads exactly as before.
|
|
57
|
+
*/
|
|
58
|
+
export function checkBranchTopology(input: BranchTopologyInput): BranchTopologyResult {
|
|
59
|
+
const { branch, tranche, taskId, topoPath, topology } = input
|
|
60
|
+
|
|
61
|
+
if (topology === null) {
|
|
62
|
+
return {
|
|
63
|
+
verdict: 'refuse',
|
|
64
|
+
reason:
|
|
65
|
+
`✖ pre-push: branch \`${branch}\` names tranche \`${tranche}\`, but ${topoPath} does not exist.\n` +
|
|
66
|
+
' A task branch must belong to a real tranche.'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const hasRow = topology?.tasks.some((t) => t.id === taskId) ?? false
|
|
71
|
+
if (!hasRow) {
|
|
72
|
+
return {
|
|
73
|
+
verdict: 'refuse',
|
|
74
|
+
reason:
|
|
75
|
+
`✖ pre-push: branch \`${branch}\` — no row with \`#\` = \`${taskId}\` in ${topoPath}.\n` +
|
|
76
|
+
" The branch suffix must literal-match the topology's # column.\n" +
|
|
77
|
+
" If the plan PR adding this row hasn't merged yet, merge it first."
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
verdict: 'allow',
|
|
83
|
+
reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
|
|
84
|
+
}
|
|
85
|
+
}
|