@attalabs/vinaya 0.27.0 → 0.29.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.
Files changed (143) hide show
  1. package/README.md +5 -4
  2. package/aeg-root/contracts/planner-developer.md +4 -1
  3. package/aeg-root/contracts/planner-operator.md +86 -0
  4. package/aeg-root/contracts/principal-operator.md +88 -0
  5. package/aeg-root/enforcement.md +4 -4
  6. package/aeg-root/roles/developer.md +25 -18
  7. package/aeg-root/roles/operator.md +133 -0
  8. package/aeg-root/roles/planner.md +6 -0
  9. package/aeg-root/roles/principal.md +4 -0
  10. package/aeg-root/roles/reviewer.md +3 -3
  11. package/aeg-root/roles/security.md +3 -3
  12. package/aeg-root/skills/aeg-context-packets/SKILL.md +123 -0
  13. package/aeg-root/skills/aeg-context-packets/examples/operator-start.md +30 -0
  14. package/aeg-root/templates/brief-template.md +6 -2
  15. package/dist/checks/bin/check-body-bare-digits.js +1275 -240
  16. package/dist/checks/bin/check-branch-topology.js +1207 -180
  17. package/dist/checks/bin/check-brief-shape.js +1279 -243
  18. package/dist/checks/bin/check-changeset-coverage.js +2176 -264
  19. package/dist/checks/bin/check-closes-n.js +1211 -184
  20. package/dist/checks/bin/check-coherence.js +1378 -265
  21. package/dist/checks/bin/check-dead-branch-push.js +1158 -176
  22. package/dist/checks/bin/check-dispatch-readiness.js +1440 -276
  23. package/dist/checks/bin/check-doc-coverage-push.js +2171 -259
  24. package/dist/checks/bin/check-doc-coverage.js +2173 -261
  25. package/dist/checks/bin/check-doctrine-no-procedures.js +1275 -240
  26. package/dist/checks/bin/check-doctrine-portability.js +2171 -259
  27. package/dist/checks/bin/check-evidence-fresh.js +2613 -347
  28. package/dist/checks/bin/check-exec-bits.js +2169 -257
  29. package/dist/checks/bin/check-first-push-dispatch.js +1326 -246
  30. package/dist/checks/bin/check-issue-assignment.js +1209 -182
  31. package/dist/checks/bin/check-issue-milestone-attach.js +6087 -0
  32. package/dist/checks/bin/check-issue-objectives-numbering.js +6089 -0
  33. package/dist/checks/bin/check-issue-parts-coverage.js +6089 -0
  34. package/dist/checks/bin/check-issue-surface-globs.js +7304 -0
  35. package/dist/checks/bin/check-issue-title-grammar.js +6089 -0
  36. package/dist/checks/bin/check-issue-tranche-label.js +6089 -0
  37. package/dist/checks/bin/check-main-branch-refusal.js +1158 -176
  38. package/dist/checks/bin/check-no-disk-state.js +1158 -176
  39. package/dist/checks/bin/check-pr-premise-reassert.js +1275 -240
  40. package/dist/checks/bin/check-pr-report-density.js +1158 -176
  41. package/dist/checks/bin/check-quoted-command.js +2150 -257
  42. package/dist/checks/bin/check-reader-resolvable-prose.js +2153 -260
  43. package/dist/checks/bin/check-registry-gates.js +1245 -176
  44. package/dist/checks/bin/check-retired-vocabulary.js +2148 -255
  45. package/dist/checks/bin/check-review-gate.js +1375 -245
  46. package/dist/checks/bin/check-single-plan-pr.js +1158 -176
  47. package/dist/checks/bin/check-surface-scope.js +1217 -182
  48. package/dist/checks/bin/check-test-plan.js +1187 -189
  49. package/dist/checks/bin/check-token-collection-wired.js +1158 -176
  50. package/dist/checks/bin/check-token-report.js +1171 -179
  51. package/dist/checks/bin/check-workspace-escape.js +2167 -255
  52. package/dist/index.js +17322 -8709
  53. package/dist/lib/pre-push-changed-files.js +57 -0
  54. package/dist/lib/pre-push-select-tests.js +1616 -0
  55. package/package.json +4 -2
  56. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  58. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js +2 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js +8 -7
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js +8 -7
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js +9 -8
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js +9 -8
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  85. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js +8 -7
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +16 -4
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js +10 -8
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  91. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js +8 -7
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  97. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js +8 -7
  98. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  99. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  100. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  101. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js +9 -8
  102. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  103. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  104. 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
  105. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__08f5pba._.js +3 -0
  106. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1o_0tjy._.js → [root-of-the-server]__0h9yhwx._.js} +2 -2
  107. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0053k9k._.js → [root-of-the-server]__0ls23oh._.js} +3 -2
  108. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0puovz5._.js → [root-of-the-server]__0nye8tb._.js} +3 -2
  109. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__18kqy4q._.js → [root-of-the-server]__0tfykr-._.js} +2 -2
  110. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0o771t1._.js → [root-of-the-server]__0th3gyp._.js} +3 -2
  111. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1-zcufa._.js +51 -0
  112. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0p8q38b._.js → [root-of-the-server]__11svemm._.js} +1 -1
  113. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__02c71kv._.js → [root-of-the-server]__140m1i_._.js} +2 -2
  114. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1bh2awk._.js +3 -0
  115. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0112h-k._.js → [root-of-the-server]__1gjqmhq._.js} +3 -2
  116. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1qmxez3._.js +4 -0
  117. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1r47dr7._.js +28 -0
  118. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  119. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_01fv4fj._.js +1 -1
  120. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0gvm3og._.js → _096f46i._.js} +3 -2
  121. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0lwxg63._.js → _0af2one._.js} +3 -2
  122. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_1n0cnq-._.js → _0zf4d27._.js} +45 -2
  123. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_03x_w6q._.js → _1-wo68i._.js} +3 -2
  124. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_projects_[name]_tranches_[slug]_05ufo8i._.js +1 -12
  125. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1wdusod._.js +3 -0
  126. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{node_modules_1vo08dj._.js → node_modules_@clerk_nextjs_dist_esm_app-router_server-actions_1x7vfhn.js} +3 -4
  127. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_1khj-jh._.js +3 -0
  128. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  129. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  130. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  131. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +17 -5
  132. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3_9xytdmiv1xi.js → 25f3-jtiv8p5n.js} +4 -4
  133. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0bn8c8v5q429o.js → 27-6ym7lp2v8o.js} +1 -1
  134. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3-6a3tinbdb-7.js → 3daxns3o--9me.js} +1 -1
  135. package/studio-standalone/apps/vinaya-studio/web/tsconfig.json +12 -0
  136. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0z6dav-._.js +0 -51
  137. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__13rrmhr._.js +0 -3
  138. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__17h4sy8._.js +0 -45
  139. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +0 -3
  140. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_17sz44y._.js +0 -3
  141. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_buildManifest.js +0 -0
  142. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_clientMiddlewareManifest.js +0 -0
  143. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_ssgManifest.js +0 -0
@@ -3,8 +3,8 @@ import { createRequire } from "node:module";
3
3
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/checks/bin/check-exec-bits.ts
6
- import { execFileSync as execFileSync5 } from "node:child_process";
7
- import { readFileSync as readFileSync3 } from "node:fs";
6
+ import { execFileSync as execFileSync7 } from "node:child_process";
7
+ import { readFileSync as readFileSync4 } from "node:fs";
8
8
 
9
9
  // src/checks/contract.ts
10
10
  var CHECK_SCHEMA_VERSION = 1;
@@ -14,8 +14,8 @@ function emitCheckError(error) {
14
14
  }
15
15
 
16
16
  // src/lib/diff-evidence.ts
17
- import { execFileSync as execFileSync4 } from "node:child_process";
18
- import { join as join2, relative, resolve as resolve2 } from "node:path";
17
+ import { execFileSync as execFileSync6 } from "node:child_process";
18
+ import { join as join5, relative, resolve as resolve2 } from "node:path";
19
19
  // ../../packages/aeg-core/src/gate-audience.ts
20
20
  var GATE_AUDIENCE = {
21
21
  "check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
@@ -1656,6 +1656,52 @@ var systemEnv3 = {
1656
1656
  ...process.env,
1657
1657
  PATH: [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin"].filter(Boolean).join(":")
1658
1658
  };
1659
+ var defaultExec = () => execFileAsync3("git", ["remote", "get-url", "origin"], { env: systemEnv3, timeout: 5000 });
1660
+ var cached;
1661
+ var inflight;
1662
+ async function resolveRepo(exec = defaultExec) {
1663
+ if (cached !== undefined)
1664
+ return cached;
1665
+ const fromEnv = process.env.AEG_REPO;
1666
+ if (fromEnv) {
1667
+ const parsed = parseOwnerRepo(fromEnv);
1668
+ if (parsed) {
1669
+ cached = parsed;
1670
+ return cached;
1671
+ }
1672
+ }
1673
+ if (inflight)
1674
+ return inflight;
1675
+ inflight = (async () => {
1676
+ try {
1677
+ const { stdout } = await exec();
1678
+ cached = parseGitRemoteUrl(stdout.trim());
1679
+ return cached;
1680
+ } catch (err) {
1681
+ const message = err instanceof Error ? err.message : String(err);
1682
+ console.warn(`[aeg-forge-state] resolveRepo: git remote lookup failed (will retry): ${message}`);
1683
+ return null;
1684
+ } finally {
1685
+ inflight = undefined;
1686
+ }
1687
+ })();
1688
+ return inflight;
1689
+ }
1690
+ function parseGitRemoteUrl(url) {
1691
+ const ssh = url.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
1692
+ if (ssh?.[1] && ssh[2])
1693
+ return { owner: ssh[1], repo: ssh[2] };
1694
+ const https = url.match(/^https?:\/\/(?:[^@]+@)?github\.com\/([^/]+)\/(.+?)(?:\.git)?\/?$/);
1695
+ if (https?.[1] && https[2])
1696
+ return { owner: https[1], repo: https[2] };
1697
+ return null;
1698
+ }
1699
+ function parseOwnerRepo(value) {
1700
+ const match = value.match(/^([^/]+)\/(.+)$/);
1701
+ if (!match?.[1] || !match[2])
1702
+ return null;
1703
+ return { owner: match[1], repo: match[2] };
1704
+ }
1659
1705
  // ../../packages/aeg-core/src/anchored-region.ts
1660
1706
  function anchoredRegionBounds(body, field) {
1661
1707
  const masked = maskCode(body);
@@ -1966,6 +2012,9 @@ function parseInlineFieldList(section) {
1966
2012
  var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1967
2013
  var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1968
2014
  var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
2015
+ var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
2016
+ var POLICY_DIGEST_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Policy digest:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
2017
+ var BASE_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged base:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1969
2018
  function firstFiveLines(comment) {
1970
2019
  return comment.split(`
1971
2020
  `).slice(0, 5).join(`
@@ -1988,6 +2037,35 @@ function extractRulingOrdinal(comment) {
1988
2037
  const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
1989
2038
  return m ? Number.parseInt(m[1], 10) : null;
1990
2039
  }
2040
+ function firstElevenLines(comment) {
2041
+ return comment.split(`
2042
+ `).slice(0, 11).join(`
2043
+ `);
2044
+ }
2045
+ function extractBriefHash(comment) {
2046
+ const m = firstElevenLines(comment).match(BRIEF_HASH_PATTERN);
2047
+ return m ? m[1].toLowerCase() : null;
2048
+ }
2049
+ function extractPolicyDigest(comment) {
2050
+ const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
2051
+ return m ? m[1].toLowerCase() : null;
2052
+ }
2053
+ function firstThirteenLines(comment) {
2054
+ return comment.split(`
2055
+ `).slice(0, 13).join(`
2056
+ `);
2057
+ }
2058
+ function extractBaseSha(comment) {
2059
+ const m = firstThirteenLines(comment).match(BASE_SHA_PATTERN);
2060
+ return m ? m[1].toLowerCase() : null;
2061
+ }
2062
+ var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
2063
+ function extractFindingSeverities(comment) {
2064
+ return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
2065
+ severity: m[1],
2066
+ location: m[2]
2067
+ }));
2068
+ }
1991
2069
  function extractVerdict(comments, valuePattern, missingLabel) {
1992
2070
  const candidates = comments.filter((c) => valuePattern.test(c));
1993
2071
  if (candidates.length === 0) {
@@ -1996,6 +2074,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1996
2074
  headSha: null,
1997
2075
  objectivesVersion: null,
1998
2076
  rulingOrdinal: null,
2077
+ briefHash: null,
2078
+ policyDigest: null,
2079
+ baseSha: null,
2080
+ findingSeverities: [],
1999
2081
  danglingNote: `no ${missingLabel} verdict comment found on this PR`
2000
2082
  };
2001
2083
  }
@@ -2007,6 +2089,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2007
2089
  headSha: null,
2008
2090
  objectivesVersion: null,
2009
2091
  rulingOrdinal: null,
2092
+ briefHash: null,
2093
+ policyDigest: null,
2094
+ baseSha: null,
2095
+ findingSeverities: [],
2010
2096
  danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
2011
2097
  };
2012
2098
  }
@@ -2015,6 +2101,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2015
2101
  headSha: extractHeadSha(latest),
2016
2102
  objectivesVersion: extractObjectivesVersion(latest),
2017
2103
  rulingOrdinal: extractRulingOrdinal(latest),
2104
+ briefHash: extractBriefHash(latest),
2105
+ policyDigest: extractPolicyDigest(latest),
2106
+ baseSha: extractBaseSha(latest),
2107
+ findingSeverities: extractFindingSeverities(latest),
2018
2108
  danglingNote: null
2019
2109
  };
2020
2110
  }
@@ -2350,6 +2440,53 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
2350
2440
  }
2351
2441
  return out;
2352
2442
  }
2443
+ // ../../packages/aeg-core/src/review-policy.ts
2444
+ var CODE_REVIEW_SEVERITY_ORDER = ["BLOCKER", "MAJOR", "MINOR"];
2445
+ var SECURITY_SEVERITY_ORDER = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
2446
+ var DEFAULT_MAX_ROUNDS = 3;
2447
+ var DEFAULT_REVIEW_POLICY = {
2448
+ codeReviewThreshold: "BLOCKER",
2449
+ securityThreshold: "HIGH",
2450
+ maxRounds: DEFAULT_MAX_ROUNDS
2451
+ };
2452
+ var FILE_SHAPED_LOCATION = /\.[a-zA-Z0-9]{1,10}(:\d+)?\s*$/;
2453
+ var PROSE_LOCATION_PATTERNS = [/\bpr\s*body\b/i, /\bcomment\b/i];
2454
+ var ROLE_FILE_LOCATION = /(^|\/)aeg-root\/roles\//i;
2455
+ function isProseLocation(location) {
2456
+ if (ROLE_FILE_LOCATION.test(location))
2457
+ return true;
2458
+ if (FILE_SHAPED_LOCATION.test(location))
2459
+ return false;
2460
+ return PROSE_LOCATION_PATTERNS.some((pattern) => pattern.test(location));
2461
+ }
2462
+ var PROSE_CAP_SEVERITY = "MINOR";
2463
+ function blockingSeverities(scale, threshold) {
2464
+ const idx = scale.indexOf(threshold);
2465
+ if (idx === -1) {
2466
+ throw new Error(`blockingSeverities: threshold "${threshold}" is not one of ${scale.join(" > ")}`);
2467
+ }
2468
+ return scale.slice(0, idx + 1);
2469
+ }
2470
+ function evaluateReviewFindings(findings, scale, threshold) {
2471
+ const blocking = new Set(blockingSeverities(scale, threshold));
2472
+ const blockingFindings = findings.filter((f) => {
2473
+ if (!scale.includes(f.severity)) {
2474
+ throw new Error(`evaluateReviewFindings: severity "${f.severity}" is not one of ${scale.join(" > ")}`);
2475
+ }
2476
+ const effectiveSeverity = f.location !== undefined && isProseLocation(f.location) ? PROSE_CAP_SEVERITY : f.severity;
2477
+ return blocking.has(effectiveSeverity);
2478
+ });
2479
+ return { outcome: blockingFindings.length > 0 ? "blocked" : "clean", blockingFindings };
2480
+ }
2481
+ function evaluateCodeReview(findings, policy) {
2482
+ return evaluateReviewFindings(findings, CODE_REVIEW_SEVERITY_ORDER, policy.codeReviewThreshold);
2483
+ }
2484
+ function evaluateSecurityReview(findings, policy) {
2485
+ return evaluateReviewFindings(findings, SECURITY_SEVERITY_ORDER, policy.securityThreshold);
2486
+ }
2487
+ function isKnownSeverity(scale, value) {
2488
+ return scale.includes(value);
2489
+ }
2353
2490
  // ../../packages/aeg-core/src/pr-tier.ts
2354
2491
  var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
2355
2492
  function readTierFromPrBody(prBody) {
@@ -2720,7 +2857,7 @@ function checkForField(prBody) {
2720
2857
  ]
2721
2858
  };
2722
2859
  }
2723
- function checkClosesN(prBody) {
2860
+ function checkClosesNPresence(prBody) {
2724
2861
  const closesPattern = /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s{0,8}:?\s{0,8}#\d+/i;
2725
2862
  if (closesPattern.test(stripCode(prBody))) {
2726
2863
  return { status: "pass", errors: [] };
@@ -2752,10 +2889,22 @@ var COMMIT_TYPES = [
2752
2889
  "Test"
2753
2890
  ];
2754
2891
  var COMMIT_TYPE_STYLE = new RegExp(`^(${COMMIT_TYPES.join("|")})(\\([a-z0-9-]+\\))?: \\S`);
2892
+ function checkForgeTitle(title) {
2893
+ const taskStyle = /^\[[a-z0-9._-]+\] \S+ — \S/;
2894
+ if (COMMIT_TYPE_STYLE.test(title) || taskStyle.test(title))
2895
+ return { status: "pass", errors: [] };
2896
+ return {
2897
+ status: "fail",
2898
+ errors: [
2899
+ `brief-validation title: "${title}" matches neither title grammar — expected \`Type: description\` / \`Type(scope): description\` (commitlint types + Plan) or \`[tranche] id — description\` (task form).`
2900
+ ]
2901
+ };
2902
+ }
2755
2903
  var BRIEF_SHAPE_MARKERS = [checkSurfaceMap, checkDocUpdateList, checkStopConditions, checkAutonomyClause];
2756
2904
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2905
+ var TASK_ISSUE_BRANCH_PATTERN = /^task\/issue-\d+$/;
2757
2906
  function isTaskBranch(branch) {
2758
- return TASK_BRANCH_PATTERN.test(branch);
2907
+ return TASK_BRANCH_PATTERN.test(branch) || TASK_ISSUE_BRANCH_PATTERN.test(branch);
2759
2908
  }
2760
2909
  function isBriefShaped(prBody) {
2761
2910
  const stripped = stripCode(prBody);
@@ -2877,8 +3026,9 @@ function packagesNamedIn(text) {
2877
3026
  }
2878
3027
  function hasTestPathForConsumer(text, consumerDir) {
2879
3028
  const escaped = consumerDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2880
- const re = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
2881
- return re.test(text);
3029
+ const filePathRe = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
3030
+ const testDirRe = new RegExp(`${escaped}\\/(?:[\\w-]+\\/)*(?:tests|specs)(?:\\/|\\b)`);
3031
+ return filePathRe.test(text) || testDirRe.test(text);
2882
3032
  }
2883
3033
  function checkConsumerTests(prBody, consumersOf) {
2884
3034
  const section4 = extractNumberedSection(prBody, 4);
@@ -2982,7 +3132,7 @@ function checkBriefSections(prBody, readTier, options = {}) {
2982
3132
  checkConsumerTests(prBody, consumersOf),
2983
3133
  checkDefeatCases(prBody),
2984
3134
  ...issueObjectives !== undefined ? [checkObjectivesCopy(prBody, issueObjectives), checkObjectivesCoverage(prBody)] : [],
2985
- ...requireClosesN ? [checkClosesN(prBody)] : []
3135
+ ...requireClosesN ? [checkClosesNPresence(prBody)] : []
2986
3136
  ];
2987
3137
  return { errors: results.flatMap((r) => r.errors) };
2988
3138
  }
@@ -3272,6 +3422,28 @@ function topLevelSectionText(body, headingName) {
3272
3422
  const next = /^##[ \t]/m.exec(afterHeading);
3273
3423
  return next ? afterHeading.slice(0, next.index) : afterHeading;
3274
3424
  }
3425
+ function partHasBacktickedPath(text) {
3426
+ let i = 0;
3427
+ while (i < text.length) {
3428
+ const start = text.indexOf("`", i);
3429
+ if (start === -1)
3430
+ return false;
3431
+ const end = text.indexOf("`", start + 1);
3432
+ if (end === -1)
3433
+ return false;
3434
+ if (text.slice(start + 1, end).includes("/"))
3435
+ return true;
3436
+ i = end + 1;
3437
+ }
3438
+ return false;
3439
+ }
3440
+ var PART_MIN_WORDS_OUTSIDE_BACKTICKS = 3;
3441
+ function stripPartBackticks(text) {
3442
+ return text.replace(/`[^`\n]*`/g, " ");
3443
+ }
3444
+ function partWordCount(text) {
3445
+ return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
3446
+ }
3275
3447
  function looksLikeFilePath(entry2) {
3276
3448
  const stripped = entry2.replace(/\/\*\*?$/, "");
3277
3449
  const lastSegment = stripped.split("/").pop() ?? stripped;
@@ -3312,6 +3484,18 @@ function globCoversPath(glob, path) {
3312
3484
  const p = path.replace(/\/+$/, "");
3313
3485
  return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
3314
3486
  }
3487
+ function checkSurfaceGlobsResolve(body, resolvesToFile) {
3488
+ const surface = parseIssueSurface(body);
3489
+ if (!surface.ok)
3490
+ return { status: "pass", errors: [] };
3491
+ const errors = [];
3492
+ for (const glob of surface.value.in) {
3493
+ if (!resolvesToFile(glob)) {
3494
+ errors.push(`issue-validation Surface: \`${glob}\` in \`## Surface\`'s \`in:\` list matches no tracked file — a Surface that cannot resolve cannot render a brief's file list.`);
3495
+ }
3496
+ }
3497
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3498
+ }
3315
3499
  function checkSurfaceScope(changedFiles, outGlobs) {
3316
3500
  if (outGlobs.length === 0)
3317
3501
  return { ok: true };
@@ -3323,9 +3507,77 @@ function checkSurfaceScope(changedFiles, outGlobs) {
3323
3507
  }
3324
3508
  return violations.length > 0 ? { ok: false, violations } : { ok: true };
3325
3509
  }
3510
+ var ISSUE_PART_LINE_RE = /^Part\s+(\d+)\s*\(([^)]*)\)\s*[-—–]\s*(.*)$/i;
3511
+ function parseIssueParts(body) {
3512
+ const section = topLevelSectionText(body, "Parts");
3513
+ if (section === null)
3514
+ return { ok: false, errors: ["no `## Parts` heading found in the body."] };
3515
+ const lines = section.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
3516
+ const parts = [];
3517
+ const errors = [];
3518
+ for (const line of lines) {
3519
+ const m = ISSUE_PART_LINE_RE.exec(line);
3520
+ if (!m) {
3521
+ errors.push(`"${line}" is not a well-formed Parts line — expected \`Part <n> (<refs>) — <outcome>\`.`);
3522
+ continue;
3523
+ }
3524
+ const n = Number.parseInt(m[1], 10);
3525
+ const refs = m[2];
3526
+ const text = m[3].trim();
3527
+ if (text.length === 0) {
3528
+ errors.push(`Part ${n} has no outcome text after the dash — every Part states one observable outcome.`);
3529
+ continue;
3530
+ }
3531
+ if (partHasBacktickedPath(text) && partWordCount(stripPartBackticks(text)) < PART_MIN_WORDS_OUTSIDE_BACKTICKS) {
3532
+ errors.push(`Part ${n} is little more than a file path — a Part names an outcome and symbols, never a bare path.`);
3533
+ continue;
3534
+ }
3535
+ const objectiveIds = [...refs.matchAll(/O(\d+)/g)].map((r) => Number.parseInt(r[1], 10));
3536
+ parts.push({ n, objectiveIds, text });
3537
+ }
3538
+ if (parts.length === 0) {
3539
+ errors.push("the `## Parts` section has no well-formed `Part <n> (<refs>) — <outcome>` lines.");
3540
+ }
3541
+ if (errors.length > 0)
3542
+ return { ok: false, errors };
3543
+ return { ok: true, value: parts };
3544
+ }
3545
+ function checkPartsCiteDefinedObjectives(body) {
3546
+ const parts = parseIssueParts(body);
3547
+ const objectives = objectivesOf(body);
3548
+ if (!parts.ok || !objectives.ok)
3549
+ return { status: "pass", errors: [] };
3550
+ const definedIds = new Set(objectives.objectives.map((o) => Number.parseInt(o.id.slice(1), 10)));
3551
+ const errors = [];
3552
+ for (const part of parts.value) {
3553
+ for (const objectiveId of part.objectiveIds) {
3554
+ if (!definedIds.has(objectiveId)) {
3555
+ errors.push(`issue-validation Parts: Part ${part.n} cites O${objectiveId}, which the Issue's own \`## Objectives\` section does not define.`);
3556
+ }
3557
+ }
3558
+ }
3559
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3560
+ }
3326
3561
  function isTaskIssueLabelSet(labels) {
3327
3562
  return hasLabel("tranche", labels);
3328
3563
  }
3564
+ function checkTrancheLabelPresence(_body, _labels) {
3565
+ return { status: "pass", errors: [] };
3566
+ }
3567
+ function checkMilestoneAttach(labels, currentMilestoneTitle, resolvedMilestoneTitle) {
3568
+ if (!isTaskIssueLabelSet(labels))
3569
+ return { status: "pass", errors: [] };
3570
+ if (resolvedMilestoneTitle === null)
3571
+ return { status: "pass", errors: [] };
3572
+ if (currentMilestoneTitle === resolvedMilestoneTitle)
3573
+ return { status: "pass", errors: [] };
3574
+ return {
3575
+ status: "fail",
3576
+ errors: [
3577
+ `issue-validation milestone attach: this task Issue's tranche label resolves to Milestone "${resolvedMilestoneTitle}", but its live Milestone is ${currentMilestoneTitle === null ? "unset" : `"${currentMilestoneTitle}"`} — attach it to "${resolvedMilestoneTitle}".`
3578
+ ]
3579
+ };
3580
+ }
3329
3581
  var TYPE_LABEL_IDS = LABELS.filter((l) => l.category === "type").map((l) => l.id);
3330
3582
  function isControlCodePoint(codePoint) {
3331
3583
  return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
@@ -3390,6 +3642,19 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
3390
3642
  var DOC_PATH_RE = /(?:(?:aeg-root|apps|packages|specs|docs|tools|\.claude|\.github)\/[\w./@-]*\.(?:md|mdx)|\.claude\/(?:skills|rules)\/[\w./-]+|\b(?:docs-index|decisions|projects|state-machine|enforcement|process|README|CLAUDE)\.md\b|\b[\w-]+-(?:spec|decisions|backlog)\.md\b)/i;
3391
3643
  var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
3392
3644
 
3645
+ // ../../packages/aeg-core/src/task-branch-identity.ts
3646
+ var ISSUE_BRANCH_PATTERN = /^task\/issue-(\d+)$/;
3647
+ var TRANCHE_BRANCH_PATTERN = /^task\/([^/]+)\/([^/]+)$/;
3648
+ function parseTaskBranchIdentity(branch) {
3649
+ const issueMatch = ISSUE_BRANCH_PATTERN.exec(branch);
3650
+ if (issueMatch)
3651
+ return { kind: "issue", issueNumber: Number(issueMatch[1]) };
3652
+ const trancheMatch = TRANCHE_BRANCH_PATTERN.exec(branch);
3653
+ if (trancheMatch)
3654
+ return { kind: "tranche", tranche: trancheMatch[1], taskId: trancheMatch[2] };
3655
+ return null;
3656
+ }
3657
+
3393
3658
  // ../../packages/aeg-core/src/coherence-checks.ts
3394
3659
  var COHERENCE_ENFORCED_FROM = "2026-07-01";
3395
3660
  function isGrandfathered(isoDate) {
@@ -3410,6 +3675,7 @@ function checkA1(entries, principalAllowlist = PRINCIPAL_ALLOWLIST) {
3410
3675
  if (handClosed)
3411
3676
  continue;
3412
3677
  failures.push({
3678
+ code: "closed-without-merge",
3413
3679
  issue: e.task.issue,
3414
3680
  tranche: e.trancheSlug,
3415
3681
  task: e.task.id,
@@ -3434,6 +3700,7 @@ function checkA3(entries) {
3434
3700
  continue;
3435
3701
  if (e.facts.prState === "merged" && e.facts.issueState !== "closed") {
3436
3702
  failures.push({
3703
+ code: "auto-close-misfire",
3437
3704
  issue: e.task.issue,
3438
3705
  tranche: e.trancheSlug,
3439
3706
  task: e.task.id,
@@ -3458,6 +3725,7 @@ function checkT1(entries) {
3458
3725
  continue;
3459
3726
  if (e.facts === undefined) {
3460
3727
  failures.push({
3728
+ code: "phantom-issue-ref",
3461
3729
  issue: e.task.issue,
3462
3730
  tranche: e.trancheSlug,
3463
3731
  task: e.task.id,
@@ -3476,6 +3744,7 @@ function checkT2(openIssuesBySlug, topologyIssuesBySlug, ciTrancheSlug) {
3476
3744
  for (const num of openNums) {
3477
3745
  if (!topologySet.has(num)) {
3478
3746
  failures.push({
3747
+ code: "orphan-task",
3479
3748
  issue: num,
3480
3749
  tranche: slug,
3481
3750
  reason: `Issue #${num} is open and labeled ${trancheLabel(slug)} but does not appear in the topology file`
@@ -3510,6 +3779,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3510
3779
  continue;
3511
3780
  if (forgeUnavailableSlugs?.has(e.trancheSlug)) {
3512
3781
  failures.push({
3782
+ code: "tbd-in-active-tranche",
3513
3783
  issue: null,
3514
3784
  tranche: e.trancheSlug,
3515
3785
  task: e.task.id,
@@ -3519,6 +3789,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3519
3789
  continue;
3520
3790
  }
3521
3791
  failures.push({
3792
+ code: "tbd-in-active-tranche",
3522
3793
  issue: null,
3523
3794
  tranche: e.trancheSlug,
3524
3795
  task: e.task.id,
@@ -3551,6 +3822,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3551
3822
  const sameIssue = depEntry.task.issue !== null && e.task.issue !== null && depEntry.task.issue === e.task.issue;
3552
3823
  if (sameTask || sameIssue) {
3553
3824
  failures.push({
3825
+ code: "d1-self-dependency",
3554
3826
  issue: e.task.issue,
3555
3827
  tranche: e.trancheSlug,
3556
3828
  task: e.task.id,
@@ -3562,6 +3834,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3562
3834
  const depClosed = depFacts?.issueState === "closed";
3563
3835
  if (!depClosed) {
3564
3836
  failures.push({
3837
+ code: "dispatched-on-unmet-deps",
3565
3838
  issue: e.task.issue,
3566
3839
  tranche: e.trancheSlug,
3567
3840
  task: e.task.id,
@@ -3587,11 +3860,13 @@ function checkR1(issuesBySlug, grandfatheredIssues, registeredNames = []) {
3587
3860
  const errors = [
3588
3861
  ...checkIssueRationale(issue.body).errors,
3589
3862
  ...checkProjectsRegistered(issue.body, issue.labels, registeredNames).errors,
3590
- ...checkIssueObjectives(issue.body, issue.number).errors
3863
+ ...checkIssueObjectives(issue.body, issue.number).errors,
3864
+ ...checkPartsCiteDefinedObjectives(issue.body).errors
3591
3865
  ];
3592
3866
  if (errors.length === 0)
3593
3867
  continue;
3594
3868
  failures.push({
3869
+ code: "missing-rationale-field",
3595
3870
  issue: issue.number,
3596
3871
  tranche: slug,
3597
3872
  reason: `Issue #${issue.number} fails the rationale gate: ${errors.join(" | ")}`,
@@ -3620,6 +3895,7 @@ function checkL1(files, entriesBySlug) {
3620
3895
  const allClosed = withFacts.every((e) => e.facts?.issueState === "closed");
3621
3896
  if (allClosed) {
3622
3897
  failures.push({
3898
+ code: "archive-recommended",
3623
3899
  tranche: f.slug,
3624
3900
  reason: "Active tranche has no open task-Issues — consider archiving to completed/"
3625
3901
  });
@@ -3651,27 +3927,38 @@ function extractClosesReferences(prBody) {
3651
3927
  }
3652
3928
  return referenced;
3653
3929
  }
3654
- function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
3930
+ function checkClosesNTopology(branch, prBody, trancheFiles, taskIssueRefs) {
3655
3931
  const referenced = extractClosesReferences(prBody);
3656
3932
  if (taskIssueRefs) {
3657
3933
  for (const n of referenced) {
3658
- const ref = taskIssueRefs.get(n);
3659
- if (!ref)
3934
+ const ref2 = taskIssueRefs.get(n);
3935
+ if (!ref2)
3660
3936
  continue;
3661
- const expectedBranch = `task/${ref.trancheSlug}/${ref.taskId}`;
3937
+ const expectedBranch = `task/${ref2.trancheSlug}/${ref2.taskId}`;
3662
3938
  if (branch !== expectedBranch) {
3663
3939
  return {
3664
3940
  ok: false,
3665
- message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${ref.taskId} of tranche "${ref.trancheSlug}") but is not named "${expectedBranch}" — rename the branch and re-push, or if this work is intentionally outside AEG's dispatch flow, remove the Closes reference.`
3941
+ message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${ref2.taskId} of tranche "${ref2.trancheSlug}") but is not named "${expectedBranch}" — rename the branch and re-push, or if this work is intentionally outside AEG's dispatch flow, remove the Closes reference.`
3666
3942
  };
3667
3943
  }
3668
3944
  }
3669
3945
  }
3670
- const m = branch.match(/^task\/([^/]+)\/([^/]+)$/);
3671
- if (!m)
3946
+ const ref = parseTaskBranchIdentity(branch);
3947
+ if (!ref)
3672
3948
  return { ok: true };
3673
- const trancheSlug = m[1];
3674
- const taskId = m[2];
3949
+ if (ref.kind === "issue") {
3950
+ const expectedIssue2 = ref.issueNumber;
3951
+ if (!referenced.has(expectedIssue2)) {
3952
+ return {
3953
+ ok: false,
3954
+ expectedIssue: expectedIssue2,
3955
+ message: `closes-n: PR body does not contain \`Closes #${expectedIssue2}\` (required for branch "${branch}"). Add it to the PR body Summary section.`
3956
+ };
3957
+ }
3958
+ return { ok: true, expectedIssue: expectedIssue2 };
3959
+ }
3960
+ const trancheSlug = ref.tranche;
3961
+ const taskId = ref.taskId;
3675
3962
  const trancheFile = trancheFiles.find((f) => f.slug === trancheSlug);
3676
3963
  if (!trancheFile) {
3677
3964
  return {
@@ -3723,34 +4010,79 @@ function extractIssue(body) {
3723
4010
  const issue = headerNums.length > 0 ? headerNums[0] : bodyNums[0];
3724
4011
  return { issue, extraIssues: bodyNums.filter((n) => n !== issue), outsideHeader: headerNums.length === 0 };
3725
4012
  }
3726
- // ../../packages/aeg-core/src/review-gate.ts
3727
- function isBoundToHead(extraction, headSha) {
3728
- if (!extraction.headSha)
4013
+ // ../../packages/aeg-core/src/review-input-manifest.ts
4014
+ import { createHash as createHash4 } from "node:crypto";
4015
+ function briefHash(brief) {
4016
+ return createHash4("sha256").update(`${brief}
4017
+ `).digest("hex");
4018
+ }
4019
+ function policyDigest(policy) {
4020
+ return createHash4("sha256").update(JSON.stringify({
4021
+ codeReviewThreshold: policy.codeReviewThreshold,
4022
+ securityThreshold: policy.securityThreshold,
4023
+ maxRounds: policy.maxRounds
4024
+ })).digest("hex");
4025
+ }
4026
+ function isBoundToHead(echoed, headSha) {
4027
+ if (!echoed.headSha)
3729
4028
  return false;
3730
- return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
4029
+ return headSha.toLowerCase().startsWith(echoed.headSha.toLowerCase());
3731
4030
  }
3732
- function isBoundByPatchIdentity(extraction, headSha, patchIdOf) {
3733
- if (patchIdOf === undefined || !extraction.headSha)
4031
+ function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
4032
+ if (patchIdOf === undefined || !echoed.headSha)
3734
4033
  return false;
3735
- const judged = patchIdOf(extraction.headSha);
4034
+ const judged = patchIdOf(echoed.headSha);
3736
4035
  const current = patchIdOf(headSha);
3737
4036
  if (judged === null || current === null)
3738
4037
  return false;
3739
4038
  return judged === current;
3740
4039
  }
3741
- function isBoundToPatch(extraction, headSha, patchIdOf) {
3742
- return isBoundToHead(extraction, headSha) || isBoundByPatchIdentity(extraction, headSha, patchIdOf);
4040
+ function isBoundToBase(echoed, currentBase) {
4041
+ if (currentBase === null)
4042
+ return true;
4043
+ if (!echoed.baseSha)
4044
+ return false;
4045
+ return currentBase.toLowerCase().startsWith(echoed.baseSha.toLowerCase());
3743
4046
  }
3744
- function isBoundToObjectives(extraction, currentVersion) {
4047
+ function isBoundToObjectives(echoed, currentVersion) {
3745
4048
  if (currentVersion === null)
3746
4049
  return true;
3747
- return extraction.objectivesVersion === currentVersion;
4050
+ return echoed.objectivesVersion === currentVersion;
3748
4051
  }
3749
- function isBoundToRulings(extraction, currentOrdinal) {
3750
- if (extraction.rulingOrdinal === null)
4052
+ function isBoundToRulings(echoed, currentOrdinal) {
4053
+ if (echoed.rulingOrdinal === null)
3751
4054
  return currentOrdinal === 0;
3752
- return extraction.rulingOrdinal === currentOrdinal;
4055
+ return echoed.rulingOrdinal === currentOrdinal;
4056
+ }
4057
+ function isBoundToBriefHash(echoed, currentHash) {
4058
+ if (currentHash === null)
4059
+ return true;
4060
+ return echoed.briefHash === currentHash;
4061
+ }
4062
+ function isBoundToPolicy(echoed, currentDigest) {
4063
+ return echoed.policyDigest === currentDigest;
4064
+ }
4065
+ function compareManifest(echoed, current, patchIdOf) {
4066
+ const exactHead = isBoundToHead(echoed, current.headSha);
4067
+ const patchHead = exactHead ? false : isBoundByPatchIdentity(echoed, current.headSha, patchIdOf);
4068
+ const head = exactHead || patchHead;
4069
+ const base = patchHead ? true : isBoundToBase(echoed, current.baseSha);
4070
+ const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
4071
+ const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
4072
+ const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
4073
+ const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
4074
+ return {
4075
+ bound: head && base && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
4076
+ head,
4077
+ base,
4078
+ briefHash: briefHashBound,
4079
+ objectivesVersion: objectivesVersion2,
4080
+ rulingOrdinal,
4081
+ policyDigest: policyDigestBound
4082
+ };
3753
4083
  }
4084
+
4085
+ // ../../packages/aeg-core/src/review-gate.ts
3754
4086
  function checkReviewGate(input) {
3755
4087
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
3756
4088
  const waived = isWaiverLabelActorVerified({
@@ -3773,15 +4105,58 @@ function checkReviewGate(input) {
3773
4105
  const verifiedBodies = verified.map((c) => c.body);
3774
4106
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
3775
4107
  const security = extractSecurityReviewVerdict(verifiedBodies);
3776
- const codeReviewClean = codeReview.value === "APPROVE";
3777
- const securityClean = security.value === "PASS";
3778
- const codeReviewBound = isBoundToPatch(codeReview, input.headSha, input.patchIdOf);
3779
- const securityBound = isBoundToPatch(security, input.headSha, input.patchIdOf);
3780
- const codeReviewObjectivesBound = isBoundToObjectives(codeReview, input.objectivesVersion);
3781
- const securityObjectivesBound = isBoundToObjectives(security, input.objectivesVersion);
3782
- const codeReviewRulingsBound = isBoundToRulings(codeReview, input.rulingOrdinal);
3783
- const securityRulingsBound = isBoundToRulings(security, input.rulingOrdinal);
3784
- if (codeReviewClean && codeReviewBound && codeReviewObjectivesBound && codeReviewRulingsBound && securityClean && securityBound && securityObjectivesBound && securityRulingsBound && mechanicalChecksClean) {
4108
+ const policy = input.policy ?? DEFAULT_REVIEW_POLICY;
4109
+ let codeReviewPolicyEvaluation;
4110
+ let securityPolicyEvaluation;
4111
+ try {
4112
+ codeReviewPolicyEvaluation = evaluateCodeReview(codeReview.findingSeverities, policy);
4113
+ securityPolicyEvaluation = evaluateSecurityReview(security.findingSeverities, policy);
4114
+ } catch (err) {
4115
+ return {
4116
+ verdict: "fail",
4117
+ reason: `a verdict comment carries a finding severity this repository's policy does not recognize: ${err instanceof Error ? err.message : String(err)}`,
4118
+ waived: false
4119
+ };
4120
+ }
4121
+ const codeReviewTextClean = codeReview.value === "APPROVE";
4122
+ const securityTextClean = security.value === "PASS";
4123
+ const codeReviewPolicyClean = codeReviewPolicyEvaluation.outcome === "clean";
4124
+ const securityPolicyClean = securityPolicyEvaluation.outcome === "clean";
4125
+ const codeReviewClean = codeReviewTextClean && codeReviewPolicyClean;
4126
+ const securityClean = securityTextClean && securityPolicyClean;
4127
+ const currentManifest = {
4128
+ headSha: input.headSha,
4129
+ baseSha: input.baseSha ?? null,
4130
+ briefHash: input.briefHash ?? null,
4131
+ objectivesVersion: input.objectivesVersion,
4132
+ rulingOrdinal: input.rulingOrdinal,
4133
+ policyDigest: policyDigest(policy)
4134
+ };
4135
+ const codeReviewEchoed = {
4136
+ headSha: codeReview.headSha,
4137
+ baseSha: codeReview.baseSha,
4138
+ briefHash: codeReview.briefHash,
4139
+ objectivesVersion: codeReview.objectivesVersion,
4140
+ rulingOrdinal: codeReview.rulingOrdinal,
4141
+ policyDigest: codeReview.policyDigest
4142
+ };
4143
+ const securityEchoed = {
4144
+ headSha: security.headSha,
4145
+ baseSha: security.baseSha,
4146
+ briefHash: security.briefHash,
4147
+ objectivesVersion: security.objectivesVersion,
4148
+ rulingOrdinal: security.rulingOrdinal,
4149
+ policyDigest: security.policyDigest
4150
+ };
4151
+ const codeReviewBinding = compareManifest(codeReviewEchoed, currentManifest, input.patchIdOf);
4152
+ const securityBinding = compareManifest(securityEchoed, currentManifest, input.patchIdOf);
4153
+ const codeReviewBound = codeReviewBinding.head;
4154
+ const securityBound = securityBinding.head;
4155
+ const codeReviewObjectivesBound = codeReviewBinding.objectivesVersion;
4156
+ const securityObjectivesBound = securityBinding.objectivesVersion;
4157
+ const codeReviewRulingsBound = codeReviewBinding.rulingOrdinal;
4158
+ const securityRulingsBound = securityBinding.rulingOrdinal;
4159
+ if (codeReviewClean && codeReviewBinding.bound && securityClean && securityBinding.bound && mechanicalChecksClean) {
3785
4160
  return {
3786
4161
  verdict: "pass",
3787
4162
  reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}, and every reported mechanical check is green.`,
@@ -3789,23 +4164,39 @@ function checkReviewGate(input) {
3789
4164
  };
3790
4165
  }
3791
4166
  const problems = [];
3792
- if (!codeReviewClean) {
4167
+ if (!codeReviewTextClean) {
3793
4168
  problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
4169
+ } else if (!codeReviewPolicyClean) {
4170
+ problems.push(`code-reviewer verdict says APPROVE but carries a finding (${codeReviewPolicyEvaluation.blockingFindings.map((f) => f.severity).join(", ")}) at or above this repository's code-review policy threshold (${policy.codeReviewThreshold}) — a reviewer's own APPROVE never overrides policy`);
3794
4171
  } else if (!codeReviewBound) {
3795
4172
  problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
4173
+ } else if (!codeReviewBinding.base) {
4174
+ problems.push(`the newest code-review verdict was cast against base ${codeReview.baseSha ?? "no recorded base"}, the PR's base is now ${currentManifest.baseSha ?? "unresolved"} (a base-only change under an unchanged candidate — same patch text on a new base is not automatically equivalent)`);
3796
4175
  } else if (!codeReviewObjectivesBound) {
3797
4176
  problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3798
4177
  } else if (!codeReviewRulingsBound) {
3799
4178
  problems.push(`the newest code-review verdict was cast against ruling ordinal ${codeReview.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
4179
+ } else if (!codeReviewBinding.briefHash) {
4180
+ problems.push(`the newest code-review verdict was cast against brief hash ${codeReview.briefHash ?? "none"}, the frozen brief's current hash is ${currentManifest.briefHash ?? "none"}`);
4181
+ } else if (!codeReviewBinding.policyDigest) {
4182
+ problems.push(`the newest code-review verdict was cast against review policy digest ${codeReview.policyDigest ?? "none"}, this repository's current policy digest is ${currentManifest.policyDigest}`);
3800
4183
  }
3801
- if (!securityClean) {
4184
+ if (!securityTextClean) {
3802
4185
  problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
4186
+ } else if (!securityPolicyClean) {
4187
+ problems.push(`security-review verdict says PASS but carries a finding (${securityPolicyEvaluation.blockingFindings.map((f) => f.severity).join(", ")}) at or above this repository's security policy threshold (${policy.securityThreshold}) — a reviewer's own PASS never overrides policy`);
3803
4188
  } else if (!securityBound) {
3804
4189
  problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
4190
+ } else if (!securityBinding.base) {
4191
+ problems.push(`the newest security-review verdict was cast against base ${security.baseSha ?? "no recorded base"}, the PR's base is now ${currentManifest.baseSha ?? "unresolved"} (a base-only change under an unchanged candidate — same patch text on a new base is not automatically equivalent)`);
3805
4192
  } else if (!securityObjectivesBound) {
3806
4193
  problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3807
4194
  } else if (!securityRulingsBound) {
3808
4195
  problems.push(`the newest security-review verdict was cast against ruling ordinal ${security.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
4196
+ } else if (!securityBinding.briefHash) {
4197
+ problems.push(`the newest security-review verdict was cast against brief hash ${security.briefHash ?? "none"}, the frozen brief's current hash is ${currentManifest.briefHash ?? "none"}`);
4198
+ } else if (!securityBinding.policyDigest) {
4199
+ problems.push(`the newest security-review verdict was cast against review policy digest ${security.policyDigest ?? "none"}, this repository's current policy digest is ${currentManifest.policyDigest}`);
3809
4200
  }
3810
4201
  if (!mechanicalChecksClean) {
3811
4202
  problems.push(reportedMechanicalChecks.length === 0 ? "no mechanical checks have reported for this head yet" : `mechanical check(s) not green: ${reportedMechanicalChecks.filter((c) => c.bucket !== "pass").map((c) => `${c.name} (${c.bucket})`).join(", ")}`);
@@ -4497,42 +4888,45 @@ function checkDispatchReadiness(input) {
4497
4888
  const { trancheSlug, task } = input;
4498
4889
  const taskLabel = `task ${task.id} (tranche ${trancheSlug})`;
4499
4890
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
4500
- const blockers = [];
4891
+ const blockerDetails = [];
4892
+ const push = (blockerClass, message) => {
4893
+ blockerDetails.push({ class: blockerClass, message });
4894
+ };
4501
4895
  if (task.issue === null) {
4502
- blockers.push(`dispatch-gate issue-existence: ${taskLabel} has no Issue (#TBD or blank) in the topology — not dispatchable until the Planner cuts the Issue.`);
4896
+ push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} has no Issue (#TBD or blank) in the topology — not dispatchable until the Planner cuts the Issue.`);
4503
4897
  } else if (input.issue === null) {
4504
- blockers.push(`dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
4898
+ push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
4505
4899
  }
4506
4900
  if (input.issue !== null && !input.issueRationalePass) {
4507
- blockers.push(`dispatch-gate rationale: Issue #${input.issue.number} for ${taskLabel} fails the rationale gate (checkIssueRationale) — the Planner must complete the eight-field rationale before this task is dispatchable.`);
4901
+ push("rationale", `dispatch-gate rationale: Issue #${input.issue.number} for ${taskLabel} fails the rationale gate (checkIssueRationale) — the Planner must complete the eight-field rationale before this task is dispatchable.`);
4508
4902
  }
4509
4903
  for (const dep of input.dependsOn) {
4510
4904
  if (isSelfDependency(dep, task, input.issue)) {
4511
4905
  const issueStr = input.issue !== null ? `#${input.issue.number}` : "?";
4512
- blockers.push(`dispatch-gate INTERNAL: parsed a self-dependency for task ${task.id} (${issueStr}) — this is a parser bug in parseRationaleDeps, not a real dependency. Please report it upstream. Re-run once the rationale is corrected or the fix ships.`);
4906
+ push("internal-self-dependency", `dispatch-gate INTERNAL: parsed a self-dependency for task ${task.id} (${issueStr}) — this is a parser bug in parseRationaleDeps, not a real dependency. Please report it upstream. Re-run once the rationale is corrected or the fix ships.`);
4513
4907
  continue;
4514
4908
  }
4515
4909
  if (dep.resolved === false) {
4516
- blockers.push(`dispatch-gate depends-on: ${taskLabel} depends on "${dep.id}", which is UNRESOLVABLE — the resolver could not find a matching tranche/task/Issue for this edge (not a claim about merge status). Not dispatchable until the edge is corrected.`);
4910
+ push("depends-on-unresolvable", `dispatch-gate depends-on: ${taskLabel} depends on "${dep.id}", which is UNRESOLVABLE — the resolver could not find a matching tranche/task/Issue for this edge (not a claim about merge status). Not dispatchable until the edge is corrected.`);
4517
4911
  continue;
4518
4912
  }
4519
4913
  if (!dep.merged && !isHandClosedByRecognizedPrincipal(dep, principalAllowlist)) {
4520
4914
  const issueStr = dep.issue !== null ? ` (#${dep.issue})` : "";
4521
- blockers.push(`dispatch-gate depends-on: ${taskLabel} depends on ${dep.id}${issueStr}, whose PR is not merged yet — not dispatchable, it serializes behind it.`);
4915
+ push("depends-on-not-merged", `dispatch-gate depends-on: ${taskLabel} depends on ${dep.id}${issueStr}, whose PR is not merged yet — not dispatchable, it serializes behind it.`);
4522
4916
  }
4523
4917
  }
4524
4918
  for (const c of input.conflictsWith) {
4525
4919
  if (c.openOrInFlight) {
4526
4920
  const issueStr = c.issue !== null ? ` (#${c.issue})` : "";
4527
- blockers.push(`dispatch-gate conflicts-with: ${taskLabel} conflicts with ${c.id}${issueStr}, whose PR is open or in-flight — not dispatchable until it merges.`);
4921
+ push("conflicts-with", `dispatch-gate conflicts-with: ${taskLabel} conflicts with ${c.id}${issueStr}, whose PR is open or in-flight — not dispatchable until it merges.`);
4528
4922
  }
4529
4923
  }
4530
4924
  for (const proj of input.priorTrancheArchival) {
4531
4925
  if (proj.priorTrancheSlug !== null && !proj.archived) {
4532
- blockers.push(`dispatch-gate prior-tranche-archival: project \`${proj.project}\`'s previous tranche \`${proj.priorTrancheSlug}\` is not archived — the Tranche Archivist must run before new work on this product.`);
4926
+ push("prior-tranche-archival", `dispatch-gate prior-tranche-archival: project \`${proj.project}\`'s previous tranche \`${proj.priorTrancheSlug}\` is not archived — the Tranche Archivist must run before new work on this product.`);
4533
4927
  }
4534
4928
  }
4535
- return { ready: blockers.length === 0, blockers };
4929
+ return { ready: blockerDetails.length === 0, blockers: blockerDetails.map((b) => b.message), blockerDetails };
4536
4930
  }
4537
4931
  // ../../packages/aeg-core/src/single-plan-pr.ts
4538
4932
  function trancheSlugFromTopologyPath(path) {
@@ -4634,6 +5028,137 @@ function checkBranchTopology(input) {
4634
5028
  reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
4635
5029
  };
4636
5030
  }
5031
+ // ../../packages/aeg-core/src/task-tools.ts
5032
+ import { z } from "zod";
5033
+ var TASK_TOOL_ERROR_KINDS = [
5034
+ "validation",
5035
+ "authority",
5036
+ "precondition",
5037
+ "capability",
5038
+ "infrastructure",
5039
+ "cancellation",
5040
+ "timeout",
5041
+ "uncertain_effect"
5042
+ ];
5043
+ var TaskToolErrorSchema = z.object({
5044
+ kind: z.enum(TASK_TOOL_ERROR_KINDS),
5045
+ message: z.string().min(1),
5046
+ detail: z.string().optional()
5047
+ });
5048
+ var TaskToolRefSchema = z.union([
5049
+ z.object({ tranche: z.string().min(1), id: z.string().min(1) }).strict(),
5050
+ z.object({ issue: z.number().int().positive() }).strict()
5051
+ ]);
5052
+ var MAX_PAGE_LIMIT = 100;
5053
+ var PageRequestSchema = z.object({
5054
+ cursor: z.string().optional(),
5055
+ limit: z.number().int().positive().max(MAX_PAGE_LIMIT).optional()
5056
+ });
5057
+ var FreshnessSchema = z.enum(["fresh", "stale", "unknown"]);
5058
+ var ObservedSchema = z.object({
5059
+ observedAt: z.string(),
5060
+ freshness: FreshnessSchema
5061
+ });
5062
+ var TaskStatusInputSchema = z.object({
5063
+ task: TaskToolRefSchema.optional()
5064
+ }).merge(PageRequestSchema).strict();
5065
+ var TaskStatusItemSchema = z.object({
5066
+ task: TaskToolRefSchema,
5067
+ issue: z.number().int().positive(),
5068
+ pr: z.number().int().positive().nullable(),
5069
+ state: z.string()
5070
+ }).merge(ObservedSchema);
5071
+ var TaskStatusResultSchema = z.object({
5072
+ items: z.array(TaskStatusItemSchema),
5073
+ nextCursor: z.string().nullable()
5074
+ });
5075
+ var RequestedAuthoritySchema = z.enum(["planner", "principal", "operator", "self"]);
5076
+ var EscalationInputsSchema = z.object({
5077
+ task: z.number().int().positive(),
5078
+ round: z.number().int().nonnegative(),
5079
+ head: z.string(),
5080
+ branch: z.string(),
5081
+ prNumber: z.number().int().positive()
5082
+ });
5083
+ var EscalationEvidenceSchema = z.object({
5084
+ round: z.number().int().nonnegative(),
5085
+ reviewer: z.string().nullable(),
5086
+ security: z.string().nullable()
5087
+ });
5088
+ var EscalationRunIdentitySchema = z.object({
5089
+ runId: z.string(),
5090
+ pid: z.number().int().positive(),
5091
+ host: z.string()
5092
+ });
5093
+ var EscalationInputVersionsSchema = z.object({
5094
+ briefHash: z.string().nullable(),
5095
+ objectivesVersion: z.string().nullable(),
5096
+ rulingOrdinal: z.number().int().nonnegative(),
5097
+ policyDigest: z.string()
5098
+ });
5099
+ var TaskEscalationReadInputSchema = z.object({
5100
+ task: TaskToolRefSchema
5101
+ }).merge(PageRequestSchema).strict();
5102
+ var TaskEscalationPacketSchema = z.object({
5103
+ reason: z.string(),
5104
+ detail: z.string().nullable(),
5105
+ inputs: EscalationInputsSchema.nullable(),
5106
+ evidence: EscalationEvidenceSchema.nullable(),
5107
+ attemptedRecovery: z.string(),
5108
+ requestedAuthority: RequestedAuthoritySchema,
5109
+ permittedNextActions: z.array(z.string()),
5110
+ runIdentity: EscalationRunIdentitySchema.nullable(),
5111
+ inputVersions: EscalationInputVersionsSchema.nullable()
5112
+ }).merge(ObservedSchema);
5113
+ var TaskEscalationReadResultSchema = z.object({
5114
+ items: z.array(TaskEscalationPacketSchema),
5115
+ nextCursor: z.string().nullable()
5116
+ }).merge(ObservedSchema);
5117
+ var TaskStartInputSchema = z.object({
5118
+ tranche: z.string().min(1),
5119
+ id: z.string().min(1)
5120
+ }).strict();
5121
+ var TaskStartResultSchema = z.object({
5122
+ requestId: z.string().min(1),
5123
+ run: z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
5124
+ started: z.boolean(),
5125
+ startedAt: z.string(),
5126
+ mode: z.literal("attended")
5127
+ });
5128
+ var TaskResumeInputSchema = z.object({
5129
+ task: TaskToolRefSchema
5130
+ }).strict();
5131
+ var TaskCancelInputSchema = z.object({
5132
+ task: TaskToolRefSchema,
5133
+ reason: z.string().min(1)
5134
+ }).strict();
5135
+ var TaskResumeResultSchema = z.object({
5136
+ task: z.number().int().positive(),
5137
+ pr: z.number().int().positive(),
5138
+ escalationId: z.string().min(1),
5139
+ outcome: z.enum(["started", "already_resumed"]),
5140
+ authenticatedBy: z.string().min(1),
5141
+ authenticatedFrom: z.string().min(1)
5142
+ });
5143
+ var TaskCancelOutcomeSchema = z.enum(["confirmed", "pending", "uncertain"]);
5144
+ var TaskCancelResultSchema = z.object({
5145
+ task: z.number().int().positive(),
5146
+ pr: z.number().int().positive(),
5147
+ escalationId: z.string().min(1),
5148
+ outcome: TaskCancelOutcomeSchema,
5149
+ authenticatedBy: z.string().min(1),
5150
+ authenticatedFrom: z.string().min(1),
5151
+ fencedEffectKeys: z.array(z.string())
5152
+ });
5153
+ var TASK_TOOL_NAMES = [
5154
+ "task_start",
5155
+ "task_status",
5156
+ "task_escalation_read",
5157
+ "task_resume",
5158
+ "task_cancel"
5159
+ ];
5160
+ var OPERATOR_STATUS_FOLLOW = "task_status_follow";
5161
+ var OPERATOR_TOOL_GRANT = [...TASK_TOOL_NAMES, OPERATOR_STATUS_FOLLOW];
4637
5162
  // ../../packages/aeg-core/src/first-push-dispatch-gate.ts
4638
5163
  function parseTaskBranch(branch) {
4639
5164
  const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
@@ -4717,7 +5242,6 @@ function decideIssueAssignment(input) {
4717
5242
  };
4718
5243
  }
4719
5244
  // ../../packages/aeg-core/src/test-plan-gate.ts
4720
- var TASK_BRANCH_PATTERN2 = /^task\/[^/]+\/[^/]+$/;
4721
5245
  function evaluateTestPlanGate(body, branch) {
4722
5246
  if (!body) {
4723
5247
  return {
@@ -4730,7 +5254,7 @@ function evaluateTestPlanGate(body, branch) {
4730
5254
  }
4731
5255
  const located = locateTestPlanSection(body);
4732
5256
  if (!located.found) {
4733
- if (TASK_BRANCH_PATTERN2.test(branch)) {
5257
+ if (parseTaskBranchIdentity(branch) !== null) {
4734
5258
  return {
4735
5259
  verdict: "fail",
4736
5260
  messages: [
@@ -4857,8 +5381,11 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4857
5381
  }
4858
5382
  return findings;
4859
5383
  }
5384
+ // ../../packages/aeg-core/src/log/envelope.ts
5385
+ import { createHash as createHash5 } from "node:crypto";
5386
+
4860
5387
  // ../../packages/aeg-core/src/log/schema.ts
4861
- import { z } from "zod";
5388
+ import { z as z2 } from "zod";
4862
5389
  var ROLE_VALUES = [
4863
5390
  "planner",
4864
5391
  "developer",
@@ -4868,136 +5395,174 @@ var ROLE_VALUES = [
4868
5395
  "archivist",
4869
5396
  "architect"
4870
5397
  ];
4871
- var RoleSchema = z.enum(ROLE_VALUES);
5398
+ var RoleSchema = z2.enum(ROLE_VALUES);
4872
5399
  var HOST_VALUES = ["hook", "ci", "cli", "loop"];
4873
- var HostSchema = z.enum(HOST_VALUES);
5400
+ var HostSchema = z2.enum(HOST_VALUES);
4874
5401
  var RUN_ID_PATTERN = /^[A-Za-z0-9_.-]{1,128}$/;
4875
- var HeaderMetaSchema = z.object({
4876
- schema: z.literal(1),
4877
- ts: z.string(),
4878
- run_id: z.string().regex(RUN_ID_PATTERN),
4879
- seq: z.number().int().nonnegative(),
4880
- repo: z.string().nullable(),
4881
- vinaya: z.string(),
4882
- doctrine: z.string(),
5402
+ var headerMetaCore = {
5403
+ ts: z2.string(),
5404
+ run_id: z2.string().regex(RUN_ID_PATTERN),
5405
+ seq: z2.number().int().nonnegative(),
5406
+ repo: z2.string().nullable(),
5407
+ vinaya: z2.string(),
5408
+ doctrine: z2.string(),
4883
5409
  host: HostSchema,
4884
- machine: z.string()
5410
+ machine: z2.string()
5411
+ };
5412
+ var HeaderMetaV1Schema = z2.object({
5413
+ schema: z2.literal(1),
5414
+ ...headerMetaCore
5415
+ }).strict();
5416
+ var LineageSchema = z2.object({
5417
+ run: z2.string().nullable(),
5418
+ attempt: z2.number().int().nullable(),
5419
+ parent: z2.string().nullable()
5420
+ }).strict();
5421
+ var InputVersionsSchema = z2.object({
5422
+ objectives_version: z2.string().nullable(),
5423
+ brief_hash: z2.string().nullable(),
5424
+ ruling_ordinal: z2.number().int().nullable(),
5425
+ policy_digest: z2.string().nullable()
5426
+ }).strict();
5427
+ var ProvenanceSchema = z2.enum(["parent_attributed", "env_correlated", "self_reported", "unavailable"]);
5428
+ var HeaderMetaV2Schema = z2.object({
5429
+ schema: z2.literal(2),
5430
+ ...headerMetaCore,
5431
+ event_id: z2.string().min(1),
5432
+ process_id: z2.string().min(1),
5433
+ actor_id: z2.string().nullable(),
5434
+ lineage: LineageSchema,
5435
+ input_versions: InputVersionsSchema,
5436
+ provenance: ProvenanceSchema
4885
5437
  }).strict();
4886
- var SubjectSchema = z.object({
4887
- issue: z.number().int().nullable(),
4888
- pr: z.number().int().optional(),
4889
- sha: z.string().optional(),
4890
- role: z.union([RoleSchema, z.literal("unattributed")]),
4891
- round: z.number().int().optional(),
4892
- objectives_version: z.string().optional()
5438
+ var HeaderMetaSchema = z2.discriminatedUnion("schema", [HeaderMetaV1Schema, HeaderMetaV2Schema]);
5439
+ var SubjectSchema = z2.object({
5440
+ issue: z2.number().int().nullable(),
5441
+ pr: z2.number().int().optional(),
5442
+ sha: z2.string().optional(),
5443
+ role: z2.union([RoleSchema, z2.literal("unattributed")]),
5444
+ round: z2.number().int().optional(),
5445
+ objectives_version: z2.string().optional()
4893
5446
  }).strict();
4894
- var HeaderSchema = z.object({
5447
+ var HeaderSchema = z2.object({
4895
5448
  meta: HeaderMetaSchema,
4896
5449
  subject: SubjectSchema
4897
5450
  }).strict();
4898
5451
  var envelopeTail = {
4899
- duration_ms: z.number().nonnegative().optional(),
4900
- payload: z.object({}).strict()
5452
+ duration_ms: z2.number().nonnegative().optional(),
5453
+ payload: z2.object({}).strict()
4901
5454
  };
4902
- var DispatchOutcomeSchema = z.discriminatedUnion("type", [
4903
- z.object({ type: z.literal("pr_opened"), pr: z.number().int(), head: z.string() }).strict(),
4904
- z.object({
4905
- type: z.literal("round_pushed"),
4906
- pr: z.number().int(),
4907
- head: z.string(),
4908
- comment_id: z.number().int()
5455
+ var ReviewFindingSchema = z2.object({
5456
+ id: z2.string(),
5457
+ severity: z2.string(),
5458
+ state: z2.string().optional(),
5459
+ severity_scale: z2.string().optional(),
5460
+ policy_treatment: z2.enum(["blocking", "non_blocking", "unavailable"]).optional(),
5461
+ confidence: z2.number().min(0).max(1).optional(),
5462
+ confidence_scale: z2.string().optional(),
5463
+ confidence_source: z2.string().optional()
5464
+ }).strict();
5465
+ var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
5466
+ z2.object({ type: z2.literal("pr_opened"), pr: z2.number().int(), head: z2.string() }).strict(),
5467
+ z2.object({
5468
+ type: z2.literal("round_pushed"),
5469
+ pr: z2.number().int(),
5470
+ head: z2.string(),
5471
+ comment_id: z2.number().int()
4909
5472
  }).strict(),
4910
- z.object({
4911
- type: z.literal("verdict"),
4912
- verdict: z.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
4913
- head: z.string(),
4914
- comment_id: z.number().int(),
4915
- objectives: z.array(z.object({ id: z.string(), met: z.boolean() }).strict()),
4916
- findings: z.array(z.object({ id: z.string(), severity: z.string(), state: z.string().optional() }).strict())
5473
+ z2.object({
5474
+ type: z2.literal("verdict"),
5475
+ verdict: z2.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
5476
+ head: z2.string(),
5477
+ comment_id: z2.number().int(),
5478
+ objectives: z2.array(z2.object({ id: z2.string(), met: z2.boolean() }).strict()),
5479
+ findings: z2.array(ReviewFindingSchema)
4917
5480
  }).strict(),
4918
- z.object({
4919
- type: z.literal("escalation"),
4920
- class: z.enum(["authority", "strategy", "product"]),
4921
- comment_id: z.number().int()
5481
+ z2.object({
5482
+ type: z2.literal("escalation"),
5483
+ class: z2.enum(["authority", "strategy", "product"]),
5484
+ comment_id: z2.number().int()
4922
5485
  }).strict(),
4923
- z.object({ type: z.literal("brief"), comment_id: z.number().int(), hash: z.string() }).strict(),
4924
- z.object({ type: z.literal("plan"), issues: z.array(z.number().int()) }).strict(),
4925
- z.object({ type: z.literal("archive"), provenance_comment_id: z.number().int() }).strict()
5486
+ z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
5487
+ z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
5488
+ z2.object({ type: z2.literal("archive"), provenance_comment_id: z2.number().int() }).strict(),
5489
+ z2.object({ type: z2.literal("completed") }).strict()
4926
5490
  ]);
4927
5491
  var dispatchShared = {
4928
5492
  meta: HeaderMetaSchema,
4929
5493
  subject: SubjectSchema,
4930
- kind: z.literal("dispatch"),
5494
+ kind: z2.literal("dispatch"),
4931
5495
  ...envelopeTail,
4932
5496
  target_role: RoleSchema,
4933
- model: z.string(),
4934
- round: z.number().int().optional(),
4935
- effect_id: z.string()
5497
+ model: z2.string(),
5498
+ round: z2.number().int().optional(),
5499
+ effect_id: z2.string()
4936
5500
  };
4937
- var dispatchUsageField = z.object({ input: z.number().nonnegative(), output: z.number().nonnegative() }).strict().nullable();
4938
- var DispatchEventSchema = z.discriminatedUnion("event", [
4939
- z.object({ ...dispatchShared, event: z.literal("dispatched"), prompt_hash: z.string() }).strict(),
4940
- z.object({
5501
+ var dispatchUsageField = z2.object({ input: z2.number().nonnegative(), output: z2.number().nonnegative() }).strict().nullable();
5502
+ var DispatchEventSchema = z2.discriminatedUnion("event", [
5503
+ z2.object({ ...dispatchShared, event: z2.literal("dispatched"), prompt_hash: z2.string() }).strict(),
5504
+ z2.object({
4941
5505
  ...dispatchShared,
4942
- event: z.literal("outcome_received"),
5506
+ event: z2.literal("outcome_received"),
4943
5507
  outcome: DispatchOutcomeSchema,
4944
5508
  usage: dispatchUsageField
4945
5509
  }).strict(),
4946
- z.object({
5510
+ z2.object({
4947
5511
  ...dispatchShared,
4948
- event: z.literal("dispatch_failed"),
4949
- reason: z.enum(["timeout", "crash", "refused", "unattributed_write"]),
5512
+ event: z2.literal("dispatch_failed"),
5513
+ reason: z2.enum(["timeout", "crash", "refused", "unattributed_write"]),
4950
5514
  usage: dispatchUsageField
4951
5515
  }).strict()
4952
5516
  ]);
4953
5517
  var loopShared = {
4954
5518
  meta: HeaderMetaSchema,
4955
5519
  subject: SubjectSchema,
4956
- kind: z.literal("dev_review_loop"),
5520
+ kind: z2.literal("dev_review_loop"),
4957
5521
  ...envelopeTail,
4958
- loop_id: z.string()
5522
+ loop_id: z2.string()
4959
5523
  };
4960
- var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4961
- z.object({
5524
+ var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
5525
+ z2.object({
4962
5526
  ...loopShared,
4963
- event: z.literal("loop_started"),
4964
- task: z.number().int(),
4965
- policy: z.object({
4966
- max_rounds: z.number().int().nonnegative(),
4967
- reviewers: z.array(RoleSchema),
4968
- models: z.record(RoleSchema, z.string())
5527
+ event: z2.literal("loop_started"),
5528
+ task: z2.number().int(),
5529
+ policy: z2.object({
5530
+ max_rounds: z2.number().int().nonnegative(),
5531
+ reviewers: z2.array(RoleSchema),
5532
+ models: z2.record(RoleSchema, z2.string())
4969
5533
  }).strict()
4970
5534
  }).strict(),
4971
- z.object({ ...loopShared, event: z.literal("round_started"), round: z.number().int(), base_head: z.string() }).strict(),
4972
- z.object({
5535
+ z2.object({ ...loopShared, event: z2.literal("round_started"), round: z2.number().int(), base_head: z2.string() }).strict(),
5536
+ z2.object({
4973
5537
  ...loopShared,
4974
- event: z.literal("gate_result_read"),
4975
- round: z.number().int(),
4976
- head: z.string(),
4977
- green: z.boolean()
5538
+ event: z2.literal("gate_result_read"),
5539
+ round: z2.number().int(),
5540
+ head: z2.string(),
5541
+ green: z2.boolean()
4978
5542
  }).strict(),
4979
- z.object({
5543
+ z2.object({
4980
5544
  ...loopShared,
4981
- event: z.literal("verdicts_read"),
4982
- round: z.number().int(),
4983
- head: z.string(),
4984
- all_approve: z.boolean(),
4985
- blockers: z.number().int().nonnegative()
5545
+ event: z2.literal("verdicts_read"),
5546
+ round: z2.number().int(),
5547
+ head: z2.string(),
5548
+ all_approve: z2.boolean(),
5549
+ blockers: z2.number().int().nonnegative(),
5550
+ findings: z2.array(ReviewFindingSchema).optional()
4986
5551
  }).strict(),
4987
- z.object({
5552
+ z2.object({
4988
5553
  ...loopShared,
4989
- event: z.literal("findings_compared"),
4990
- round: z.number().int(),
4991
- open: z.array(z.string()),
4992
- resolved: z.array(z.string()),
4993
- new: z.array(z.string()),
4994
- recurring: z.array(z.string())
5554
+ event: z2.literal("findings_compared"),
5555
+ round: z2.number().int(),
5556
+ open: z2.array(z2.string()),
5557
+ resolved: z2.array(z2.string()),
5558
+ new: z2.array(z2.string()),
5559
+ recurring: z2.array(z2.string())
4995
5560
  }).strict(),
4996
- z.object({
5561
+ z2.object({
4997
5562
  ...loopShared,
4998
- event: z.literal("stop_condition_met"),
4999
- round: z.number().int(),
5000
- condition: z.enum([
5563
+ event: z2.literal("stop_condition_met"),
5564
+ round: z2.number().int(),
5565
+ condition: z2.enum([
5001
5566
  "green",
5002
5567
  "max_rounds",
5003
5568
  "no_progress",
@@ -5007,42 +5572,49 @@ var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
5007
5572
  "reappearance"
5008
5573
  ])
5009
5574
  }).strict(),
5010
- z.object({
5575
+ z2.object({
5576
+ ...loopShared,
5577
+ event: z2.literal("paused"),
5578
+ round: z2.number().int(),
5579
+ reason: z2.enum(["escalation", "principal_item", "refreeze_needed"])
5580
+ }).strict(),
5581
+ z2.object({
5011
5582
  ...loopShared,
5012
- event: z.literal("paused"),
5013
- round: z.number().int(),
5014
- reason: z.enum(["escalation", "principal_item", "refreeze_needed"])
5583
+ event: z2.literal("resumed"),
5584
+ round: z2.number().int(),
5585
+ by: z2.literal("principal")
5015
5586
  }).strict(),
5016
- z.object({
5587
+ z2.object({
5017
5588
  ...loopShared,
5018
- event: z.literal("resumed"),
5019
- round: z.number().int(),
5020
- by: z.literal("principal")
5589
+ event: z2.literal("unpushed_work_resume"),
5590
+ round: z2.number().int(),
5591
+ branch: z2.string(),
5592
+ detail: z2.string()
5021
5593
  }).strict(),
5022
- z.object({
5594
+ z2.object({
5023
5595
  ...loopShared,
5024
- event: z.literal("round_ended"),
5025
- round: z.number().int(),
5026
- base_head: z.string(),
5027
- head: z.string(),
5028
- files_changed: z.number().int().nonnegative(),
5029
- insertions: z.number().int().nonnegative(),
5030
- deletions: z.number().int().nonnegative(),
5031
- wall_ms: z.number().nonnegative(),
5032
- outcome: z.enum(["green", "changes_requested", "escalated"])
5596
+ event: z2.literal("round_ended"),
5597
+ round: z2.number().int(),
5598
+ base_head: z2.string(),
5599
+ head: z2.string(),
5600
+ files_changed: z2.number().int().nonnegative(),
5601
+ insertions: z2.number().int().nonnegative(),
5602
+ deletions: z2.number().int().nonnegative(),
5603
+ wall_ms: z2.number().nonnegative(),
5604
+ outcome: z2.enum(["green", "changes_requested", "escalated"])
5033
5605
  }).strict(),
5034
- z.object({
5606
+ z2.object({
5035
5607
  ...loopShared,
5036
- event: z.literal("journal_finalized"),
5037
- rounds: z.number().int().nonnegative(),
5038
- total_wall_ms: z.number().nonnegative(),
5039
- time_to_green_ms: z.number().nonnegative().nullable(),
5040
- files_changed_total: z.number().int().nonnegative(),
5041
- final_head: z.string(),
5042
- result: z.enum(["merged_ready", "stopped"])
5608
+ event: z2.literal("journal_finalized"),
5609
+ rounds: z2.number().int().nonnegative(),
5610
+ total_wall_ms: z2.number().nonnegative(),
5611
+ time_to_green_ms: z2.number().nonnegative().nullable(),
5612
+ files_changed_total: z2.number().int().nonnegative(),
5613
+ final_head: z2.string(),
5614
+ result: z2.enum(["merged_ready", "stopped"])
5043
5615
  }).strict()
5044
5616
  ]);
5045
- var ForgeOpSchema = z.enum([
5617
+ var ForgeOpSchema = z2.enum([
5046
5618
  "pr.create",
5047
5619
  "pr.comment",
5048
5620
  "pr.body.replace",
@@ -5056,50 +5628,462 @@ var ForgeOpSchema = z.enum([
5056
5628
  "label.add",
5057
5629
  "label.remove"
5058
5630
  ]);
5059
- var ForgeWriteTargetSchema = z.object({
5060
- issue: z.number().int().optional(),
5061
- pr: z.number().int().optional()
5631
+ var ForgeWriteTargetSchema = z2.object({
5632
+ issue: z2.number().int().optional(),
5633
+ pr: z2.number().int().optional()
5062
5634
  }).strict();
5063
5635
  var forgeWriteShared = {
5064
5636
  meta: HeaderMetaSchema,
5065
5637
  subject: SubjectSchema,
5066
- kind: z.literal("forge_write"),
5638
+ kind: z2.literal("forge_write"),
5067
5639
  ...envelopeTail,
5068
5640
  op: ForgeOpSchema,
5069
5641
  target: ForgeWriteTargetSchema
5070
5642
  };
5071
- var ForgeWriteEventSchema = z.discriminatedUnion("event", [
5072
- z.object({ ...forgeWriteShared, event: z.literal("validated") }).strict(),
5073
- z.object({ ...forgeWriteShared, event: z.literal("refused"), reason: z.string() }).strict(),
5074
- z.object({ ...forgeWriteShared, event: z.literal("written"), comment_ids: z.array(z.string()) }).strict()
5643
+ var ForgeWriteEventSchema = z2.discriminatedUnion("event", [
5644
+ z2.object({ ...forgeWriteShared, event: z2.literal("validated") }).strict(),
5645
+ z2.object({ ...forgeWriteShared, event: z2.literal("refused"), reason: z2.string() }).strict(),
5646
+ z2.object({ ...forgeWriteShared, event: z2.literal("written"), comment_ids: z2.array(z2.string()) }).strict()
5075
5647
  ]);
5076
- var LogEventSchema = z.union([DispatchEventSchema, DevReviewLoopEventSchema, ForgeWriteEventSchema]);
5648
+ var GateOutcomeSchema = z2.enum([
5649
+ "pass",
5650
+ "fail",
5651
+ "wait",
5652
+ "skip",
5653
+ "invalid_input",
5654
+ "unavailable_dependency",
5655
+ "timeout",
5656
+ "cancelled"
5657
+ ]);
5658
+ var gateShared = {
5659
+ meta: HeaderMetaSchema,
5660
+ subject: SubjectSchema,
5661
+ kind: z2.literal("gate"),
5662
+ ...envelopeTail,
5663
+ check: z2.string(),
5664
+ check_version: z2.string().nullable(),
5665
+ policy_version: z2.string().nullable(),
5666
+ input_fingerprint: z2.string().nullable()
5667
+ };
5668
+ var GateEventSchema = z2.discriminatedUnion("event", [
5669
+ z2.object({
5670
+ ...gateShared,
5671
+ event: z2.literal("checked"),
5672
+ outcome: GateOutcomeSchema,
5673
+ reason: z2.string().optional()
5674
+ }).strict()
5675
+ ]);
5676
+ var OperationResultSchema = z2.enum(["ok", "error", "refused", "timeout", "cancelled", "unavailable"]);
5677
+ var operationShared = {
5678
+ meta: HeaderMetaSchema,
5679
+ subject: SubjectSchema,
5680
+ kind: z2.literal("operation"),
5681
+ ...envelopeTail,
5682
+ operation: z2.string(),
5683
+ target: z2.string().nullable()
5684
+ };
5685
+ var OperationEventSchema = z2.discriminatedUnion("event", [
5686
+ z2.object({
5687
+ ...operationShared,
5688
+ event: z2.literal("completed"),
5689
+ result: OperationResultSchema,
5690
+ error_class: z2.string().nullable()
5691
+ }).strict()
5692
+ ]);
5693
+ var UsageUnitsSchema = z2.object({
5694
+ input: z2.number().nonnegative().nullable(),
5695
+ output: z2.number().nonnegative().nullable(),
5696
+ cache: z2.number().nonnegative().nullable()
5697
+ }).strict();
5698
+ var usageShared = {
5699
+ meta: HeaderMetaSchema,
5700
+ subject: SubjectSchema,
5701
+ kind: z2.literal("usage"),
5702
+ ...envelopeTail,
5703
+ model: z2.string().nullable(),
5704
+ source: z2.string(),
5705
+ semantics: z2.enum(["cumulative", "delta"])
5706
+ };
5707
+ var UsageEventSchema = z2.discriminatedUnion("event", [
5708
+ z2.object({
5709
+ ...usageShared,
5710
+ event: z2.literal("observed"),
5711
+ units: UsageUnitsSchema,
5712
+ unknown_reason: z2.string().nullable()
5713
+ }).strict()
5714
+ ]);
5715
+ var RoleAttemptOutcomeSchema = z2.enum([
5716
+ "completed",
5717
+ "incomplete",
5718
+ "infrastructure_failed",
5719
+ "cancelled",
5720
+ "timed_out",
5721
+ "capability_refused"
5722
+ ]);
5723
+ var roleAttemptShared = {
5724
+ meta: HeaderMetaSchema,
5725
+ subject: SubjectSchema,
5726
+ kind: z2.literal("role_attempt"),
5727
+ ...envelopeTail,
5728
+ actor: z2.string().nullable(),
5729
+ attempt: z2.number().int().nullable(),
5730
+ effect_id: z2.string(),
5731
+ model: z2.string().nullable()
5732
+ };
5733
+ var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
5734
+ z2.object({
5735
+ ...roleAttemptShared,
5736
+ event: z2.literal("attempted"),
5737
+ outcome: RoleAttemptOutcomeSchema,
5738
+ usage: dispatchUsageField
5739
+ }).strict()
5740
+ ]);
5741
+ var handoffShared = {
5742
+ meta: HeaderMetaSchema,
5743
+ subject: SubjectSchema,
5744
+ kind: z2.literal("handoff"),
5745
+ ...envelopeTail,
5746
+ class: z2.enum(["authority", "strategy", "product"]),
5747
+ reason: z2.string()
5748
+ };
5749
+ var HandoffEventSchema = z2.discriminatedUnion("event", [
5750
+ z2.object({
5751
+ ...handoffShared,
5752
+ event: z2.literal("raised"),
5753
+ requested_decision: z2.string().nullable()
5754
+ }).strict(),
5755
+ z2.object({
5756
+ ...handoffShared,
5757
+ event: z2.literal("resolved"),
5758
+ resolution: z2.string().nullable(),
5759
+ resolved_by: z2.string().nullable()
5760
+ }).strict()
5761
+ ]);
5762
+ var EffectTargetSchema = z2.object({
5763
+ kind: z2.string(),
5764
+ ref: z2.string()
5765
+ }).strict();
5766
+ var effectShared = {
5767
+ meta: HeaderMetaSchema,
5768
+ subject: SubjectSchema,
5769
+ kind: z2.literal("effect"),
5770
+ ...envelopeTail,
5771
+ effect_id: z2.string(),
5772
+ target: EffectTargetSchema
5773
+ };
5774
+ var EffectEventSchema = z2.discriminatedUnion("event", [
5775
+ z2.object({ ...effectShared, event: z2.literal("attempted") }).strict(),
5776
+ z2.object({ ...effectShared, event: z2.literal("observed"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict(),
5777
+ z2.object({ ...effectShared, event: z2.literal("verified"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict()
5778
+ ]);
5779
+ var LogEventSchema = z2.union([
5780
+ DispatchEventSchema,
5781
+ DevReviewLoopEventSchema,
5782
+ ForgeWriteEventSchema,
5783
+ GateEventSchema,
5784
+ OperationEventSchema,
5785
+ UsageEventSchema,
5786
+ RoleAttemptEventSchema,
5787
+ HandoffEventSchema,
5788
+ EffectEventSchema
5789
+ ]);
5790
+
5791
+ // ../../packages/aeg-core/src/log/envelope.ts
5792
+ function isRole(value) {
5793
+ return value !== undefined && ROLE_VALUES.includes(value);
5794
+ }
5795
+ function actorIdFromEnv(role) {
5796
+ return role === undefined || role === "" ? null : role;
5797
+ }
5798
+ function lineageFieldFromEnv(value) {
5799
+ return value === undefined || value === "" ? null : value;
5800
+ }
5801
+ function attemptFromEnv(value) {
5802
+ if (value === undefined || value === "")
5803
+ return null;
5804
+ const n = Number(value);
5805
+ return Number.isInteger(n) ? n : null;
5806
+ }
5807
+ function provenanceFor(input) {
5808
+ if (input.provenance)
5809
+ return input.provenance;
5810
+ if (input.env.role || input.env.task)
5811
+ return "env_correlated";
5812
+ return "unavailable";
5813
+ }
5814
+ function issueFromTask(task) {
5815
+ if (task === undefined || task === "")
5816
+ return null;
5817
+ const n = Number(task);
5818
+ return Number.isInteger(n) ? n : null;
5819
+ }
5820
+ function roundFromEnv(round) {
5821
+ if (round === undefined || round === "")
5822
+ return;
5823
+ const n = Number(round);
5824
+ return Number.isInteger(n) ? n : undefined;
5825
+ }
5826
+ function buildHeader(input) {
5827
+ const role = isRole(input.env.role) ? input.env.role : "unattributed";
5828
+ const round = roundFromEnv(input.env.round);
5829
+ const subject = {
5830
+ issue: issueFromTask(input.env.task),
5831
+ role,
5832
+ ...round !== undefined ? { round } : {},
5833
+ ...input.subject ?? {}
5834
+ };
5835
+ return {
5836
+ meta: {
5837
+ schema: 2,
5838
+ ts: input.now.toISOString(),
5839
+ run_id: input.runId,
5840
+ seq: input.seq,
5841
+ repo: input.repo,
5842
+ vinaya: input.vinaya,
5843
+ doctrine: input.doctrine,
5844
+ host: input.host,
5845
+ machine: createHash5("sha256").update(input.hostname).digest("hex"),
5846
+ event_id: input.eventId,
5847
+ process_id: input.processId,
5848
+ actor_id: actorIdFromEnv(input.env.role),
5849
+ lineage: {
5850
+ run: lineageFieldFromEnv(input.env.run),
5851
+ attempt: attemptFromEnv(input.env.attempt),
5852
+ parent: lineageFieldFromEnv(input.env.parent)
5853
+ },
5854
+ input_versions: {
5855
+ objectives_version: input.inputVersions?.objectivesVersion ?? null,
5856
+ brief_hash: input.inputVersions?.briefHash ?? null,
5857
+ ruling_ordinal: input.inputVersions?.rulingOrdinal ?? null,
5858
+ policy_digest: input.inputVersions?.policyDigest ?? null
5859
+ },
5860
+ provenance: provenanceFor(input)
5861
+ },
5862
+ subject
5863
+ };
5864
+ }
5865
+ // ../../packages/aeg-core/src/log/redact.ts
5866
+ var GITHUB_TOKEN_PATTERN = /\b(?:gho_|ghp_|ghs_|ghu_|ghr_|github_pat_)[A-Za-z0-9_]+\b/g;
5867
+ var CLASSIC_GITHUB_PAT_PATTERN = /\b((?:token|GITHUB_TOKEN|PAT|api[_-]?key|api[_-]?token)\s*[:=]\s*)[a-f0-9]{40}\b/gi;
5868
+ var BEARER_TOKEN_PATTERN = /\bBearer\s+\S+/g;
5869
+ var AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/g;
5870
+ var SLACK_TOKEN_PATTERN = /\bxox[baprs]-[0-9A-Za-z-]+\b/g;
5871
+ var STRIPE_KEY_PATTERN = /\b(?:sk|pk|rk)_(?:live|test)_[0-9A-Za-z]{10,}\b/g;
5872
+ var ANTHROPIC_KEY_PATTERN = /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g;
5873
+ var OPENAI_KEY_PATTERN = /\bsk-(?!ant-)[A-Za-z0-9]{20,}\b/g;
5874
+ var NPM_TOKEN_PATTERN = /\bnpm_[A-Za-z0-9]{36}\b/g;
5875
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g;
5876
+ var PEM_BLOCK_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
5877
+ var BASIC_AUTH_URL_PATTERN = /(https?:\/\/)[^/\s:@]+:[^/\s@]+@/g;
5878
+ var GENERIC_SECRET_ASSIGNMENT_PATTERN = /\b((?:secret|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[:=]\s*)[A-Za-z0-9+/_=-]{16,}\b/gi;
5879
+ function redactString(value, home) {
5880
+ let out = value.replace(GITHUB_TOKEN_PATTERN, "<redacted>").replace(CLASSIC_GITHUB_PAT_PATTERN, "$1<redacted>").replace(BEARER_TOKEN_PATTERN, "<redacted>").replace(AWS_ACCESS_KEY_PATTERN, "<redacted>").replace(SLACK_TOKEN_PATTERN, "<redacted>").replace(STRIPE_KEY_PATTERN, "<redacted>").replace(ANTHROPIC_KEY_PATTERN, "<redacted>").replace(OPENAI_KEY_PATTERN, "<redacted>").replace(NPM_TOKEN_PATTERN, "<redacted>").replace(JWT_PATTERN, "<redacted>").replace(PEM_BLOCK_PATTERN, "<redacted>").replace(BASIC_AUTH_URL_PATTERN, "$1<redacted>@").replace(GENERIC_SECRET_ASSIGNMENT_PATTERN, "$1<redacted>");
5881
+ if (home.length > 0 && out.startsWith(home)) {
5882
+ const rest = out.slice(home.length);
5883
+ if (rest === "" || rest.startsWith("/"))
5884
+ out = `~${rest}`;
5885
+ }
5886
+ return out;
5887
+ }
5888
+ function redact(value, home) {
5889
+ if (typeof value === "string")
5890
+ return redactString(value, home);
5891
+ if (Array.isArray(value))
5892
+ return value.map((v) => redact(v, home));
5893
+ if (value !== null && typeof value === "object") {
5894
+ const out = {};
5895
+ for (const [k, v] of Object.entries(value)) {
5896
+ out[k] = redact(v, home);
5897
+ }
5898
+ return out;
5899
+ }
5900
+ return value;
5901
+ }
5902
+ // ../../packages/aeg-core/src/log/store.ts
5903
+ function metaOf(obj) {
5904
+ if (obj === null || typeof obj !== "object")
5905
+ return null;
5906
+ const meta = obj.meta;
5907
+ if (meta === null || typeof meta !== "object")
5908
+ return null;
5909
+ return meta;
5910
+ }
5911
+ function recordIdentity(obj) {
5912
+ const meta = metaOf(obj);
5913
+ if (meta === null)
5914
+ return null;
5915
+ const eventId = meta.event_id;
5916
+ if (typeof eventId === "string" && eventId.length > 0)
5917
+ return eventId;
5918
+ const runId = meta.run_id;
5919
+ const seq = meta.seq;
5920
+ if (typeof runId === "string" && runId.length > 0 && typeof seq === "number" && Number.isInteger(seq)) {
5921
+ return `${runId}:${seq}`;
5922
+ }
5923
+ return null;
5924
+ }
5925
+
5926
+ // ../../packages/aeg-core/src/log/artifact.ts
5927
+ var TASK_LOG_ARTIFACT_MAX_BYTES = 8 * 1024 * 1024;
5928
+ // ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
5929
+ var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
5930
+ // ../../packages/aeg-core/src/control-store/records.ts
5931
+ import { z as z3 } from "zod";
5932
+ var isoTimestamp = z3.string().min(1);
5933
+ var taskId = z3.number().int().positive();
5934
+ var epochNumber = z3.number().int().nonnegative();
5935
+ var RunRecordSchema = z3.object({
5936
+ version: z3.literal(1),
5937
+ kind: z3.literal("run"),
5938
+ task: taskId,
5939
+ runId: z3.string().min(1),
5940
+ pid: z3.number().int().positive(),
5941
+ host: z3.string().min(1),
5942
+ startedAt: isoTimestamp,
5943
+ childStartedAt: z3.string().min(1).nullable().optional(),
5944
+ childCommand: z3.string().min(1).nullable().optional()
5945
+ }).strict();
5946
+ var InputRecordSchema = z3.object({
5947
+ version: z3.literal(1),
5948
+ kind: z3.literal("input"),
5949
+ task: taskId,
5950
+ runId: z3.string().min(1),
5951
+ source: z3.union([z3.literal("fresh"), z3.literal("resume")]),
5952
+ pr: z3.number().int().positive().nullable(),
5953
+ round: z3.number().int().nonnegative(),
5954
+ recordedAt: isoTimestamp
5955
+ }).strict();
5956
+ var OwnershipRecordSchema = z3.object({
5957
+ version: z3.literal(1),
5958
+ kind: z3.literal("ownership"),
5959
+ task: taskId,
5960
+ epoch: epochNumber,
5961
+ ownerId: z3.string().min(1),
5962
+ pid: z3.number().int().positive(),
5963
+ host: z3.string().min(1),
5964
+ acquiredAt: isoTimestamp
5965
+ }).strict();
5966
+ var TransitionRecordSchema = z3.object({
5967
+ version: z3.literal(1),
5968
+ kind: z3.literal("transition"),
5969
+ task: taskId,
5970
+ epoch: epochNumber,
5971
+ seq: z3.number().int().nonnegative(),
5972
+ from: z3.string().min(1),
5973
+ to: z3.string().min(1),
5974
+ detail: z3.string().optional(),
5975
+ at: isoTimestamp
5976
+ }).strict();
5977
+ var ManifestRecordSchema = z3.object({
5978
+ version: z3.literal(1),
5979
+ kind: z3.literal("manifest"),
5980
+ task: taskId,
5981
+ round: epochNumber,
5982
+ repository: z3.string().min(1),
5983
+ pr: z3.number().int().positive(),
5984
+ branch: z3.string().min(1),
5985
+ baseSha: z3.string().min(1).nullable(),
5986
+ headSha: z3.string().min(1),
5987
+ briefHash: z3.string().min(1).nullable(),
5988
+ objectivesVersion: z3.string().min(1).nullable(),
5989
+ rulingOrdinal: epochNumber,
5990
+ policyDigest: z3.string().min(1),
5991
+ recordedAt: isoTimestamp
5992
+ }).strict();
5993
+ var roundHeadIdentity = z3.object({ round: z3.number().int().positive(), head: z3.string().min(1) }).strict();
5994
+ var LoopBudgetsSchema = z3.object({
5995
+ mechanicalRetries: z3.number().int().nonnegative(),
5996
+ reviewRounds: z3.number().int().nonnegative(),
5997
+ infrastructureRetries: z3.number().int().nonnegative()
5998
+ }).strict();
5999
+ var LoopStateRecordSchema = z3.object({
6000
+ version: z3.literal(1),
6001
+ kind: z3.literal("loop_state"),
6002
+ task: taskId,
6003
+ round: z3.number().int().positive(),
6004
+ phase: z3.string().min(1),
6005
+ pauseReason: z3.string().min(1).nullable(),
6006
+ budgets: LoopBudgetsSchema,
6007
+ heldResult: roundHeadIdentity.nullable(),
6008
+ deliveredFindings: roundHeadIdentity.nullable(),
6009
+ recordedAt: isoTimestamp
6010
+ }).strict();
6011
+ var EffectRecordSchema = z3.object({
6012
+ version: z3.literal(1),
6013
+ kind: z3.literal("effect"),
6014
+ task: taskId,
6015
+ key: z3.string().min(1),
6016
+ operation: z3.string().min(1),
6017
+ target: z3.string().min(1),
6018
+ inputVersion: z3.number().int().nonnegative(),
6019
+ payloadDigest: z3.string().min(1),
6020
+ status: z3.union([z3.literal("started"), z3.literal("verified"), z3.literal("uncertain")]),
6021
+ url: z3.string().optional(),
6022
+ recordedAt: isoTimestamp
6023
+ }).strict();
6024
+ var EscalationRecordSchema = z3.object({
6025
+ version: z3.literal(1),
6026
+ kind: z3.literal("escalation"),
6027
+ task: taskId,
6028
+ escalationId: z3.string().min(1),
6029
+ round: epochNumber,
6030
+ head: z3.string().min(1),
6031
+ branch: z3.string().min(1),
6032
+ pr: z3.number().int().positive().nullable(),
6033
+ runId: z3.string().min(1),
6034
+ pid: z3.number().int().positive(),
6035
+ host: z3.string().min(1),
6036
+ agent: z3.string().min(1).optional(),
6037
+ reason: z3.string().min(1),
6038
+ detail: z3.string().optional(),
6039
+ evidence: z3.string().optional(),
6040
+ attemptedRecovery: z3.string().min(1),
6041
+ requestedDecision: z3.string().min(1),
6042
+ recipient: z3.string().min(1),
6043
+ briefHash: z3.string().min(1).nullable(),
6044
+ objectivesVersion: z3.string().min(1).nullable(),
6045
+ rulingOrdinal: epochNumber,
6046
+ policyDigest: z3.string().min(1),
6047
+ recordedAt: isoTimestamp
6048
+ }).strict();
6049
+ var ResolutionRecordSchema = z3.object({
6050
+ version: z3.literal(1),
6051
+ kind: z3.literal("resolution"),
6052
+ task: taskId,
6053
+ escalationId: z3.string().min(1),
6054
+ decision: z3.union([z3.literal("resume"), z3.literal("cancel")]),
6055
+ authenticatedBy: z3.string().min(1),
6056
+ authenticatedFrom: z3.string().min(1),
6057
+ consumedAt: isoTimestamp
6058
+ }).strict();
5077
6059
  // src/lib/config.ts
5078
6060
  import { execFileSync as execFileSync2 } from "node:child_process";
5079
6061
  import { existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "node:fs";
5080
6062
  import { homedir } from "node:os";
5081
6063
  import { dirname, join, resolve } from "node:path";
5082
- import { z as z2 } from "zod";
6064
+ import { z as z4 } from "zod";
5083
6065
 
5084
6066
  // src/lib/agent-vendors.ts
5085
6067
  var AGENT_VENDORS = ["skills", "claude", "gemini"];
5086
6068
 
5087
6069
  // src/lib/config.ts
5088
- var EnvEntrySchema = z2.union([
5089
- z2.literal(true),
5090
- z2.object({ optional: z2.literal(true) }),
5091
- z2.object({ anyOf: z2.array(z2.string()).min(2) }),
5092
- z2.string()
6070
+ var EnvEntrySchema = z4.union([
6071
+ z4.literal(true),
6072
+ z4.object({ optional: z4.literal(true) }),
6073
+ z4.object({ anyOf: z4.array(z4.string()).min(2) }),
6074
+ z4.string()
5093
6075
  ]);
5094
- var CheckEntrySchema = z2.object({
5095
- run: z2.string(),
5096
- scope: z2.enum(["diff", "full"]),
5097
- include: z2.array(z2.string()).optional(),
5098
- args: z2.array(z2.string()).optional(),
5099
- timeoutMs: z2.number().optional(),
5100
- env: z2.record(z2.string(), EnvEntrySchema).optional(),
5101
- requiresOpenPr: z2.boolean().optional(),
5102
- ownWorkflow: z2.boolean().optional()
6076
+ var CheckEntrySchema = z4.object({
6077
+ run: z4.string(),
6078
+ scope: z4.enum(["diff", "full"]),
6079
+ include: z4.array(z4.string()).optional(),
6080
+ args: z4.array(z4.string()).optional(),
6081
+ timeoutMs: z4.number().optional(),
6082
+ env: z4.record(z4.string(), EnvEntrySchema).optional(),
6083
+ requiresOpenPr: z4.boolean().optional(),
6084
+ ownWorkflow: z4.boolean().optional(),
6085
+ principalOwed: z4.literal(true).optional(),
6086
+ validates: z4.enum(["body", "issue"]).optional()
5103
6087
  }).superRefine((entry2, ctx) => {
5104
6088
  if (!entry2.env)
5105
6089
  return;
@@ -5109,25 +6093,26 @@ var CheckEntrySchema = z2.object({
5109
6093
  const members = value.anyOf;
5110
6094
  if (new Set(members).size !== members.length) {
5111
6095
  ctx.addIssue({
5112
- code: z2.ZodIssueCode.custom,
6096
+ code: z4.ZodIssueCode.custom,
5113
6097
  message: `env.${key}.anyOf has duplicate members`,
5114
6098
  path: ["env", key, "anyOf"]
5115
6099
  });
5116
6100
  }
5117
6101
  if (!members.includes(key)) {
5118
6102
  ctx.addIssue({
5119
- code: z2.ZodIssueCode.custom,
6103
+ code: z4.ZodIssueCode.custom,
5120
6104
  message: `env.${key}.anyOf must include "${key}" itself as a member`,
5121
6105
  path: ["env", key, "anyOf"]
5122
6106
  });
5123
6107
  }
5124
6108
  }
5125
6109
  });
5126
- var RoleEntrySchema = z2.object({
5127
- contract: z2.string().refine((p) => p.includes("/"), {
6110
+ var RoleEntrySchema = z4.object({
6111
+ contract: z4.string().refine((p) => p.includes("/"), {
5128
6112
  message: 'must be a path (contain at least one "/"), not a bare filename'
5129
6113
  })
5130
6114
  });
6115
+ var MAX_REPORT_COMMAND_TIMEOUT_MS = 3600000;
5131
6116
  var BRIEF_BUILTINS = [
5132
6117
  "tier",
5133
6118
  "testPlan",
@@ -5147,17 +6132,17 @@ var BRIEF_BUILTINS = [
5147
6132
  "briefSections",
5148
6133
  "milestoneShape"
5149
6134
  ];
5150
- var BriefSectionSchema = z2.union([
5151
- z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
5152
- z2.object({ heading: z2.string().min(1), name: z2.string().optional() }),
5153
- z2.object({ field: z2.string().min(1), name: z2.string().optional() }),
5154
- z2.object({ phrase: z2.string().min(1), name: z2.string().optional() })
6135
+ var BriefSectionSchema = z4.union([
6136
+ z4.object({ builtin: z4.enum(BRIEF_BUILTINS) }),
6137
+ z4.object({ heading: z4.string().min(1), name: z4.string().optional() }),
6138
+ z4.object({ field: z4.string().min(1), name: z4.string().optional() }),
6139
+ z4.object({ phrase: z4.string().min(1), name: z4.string().optional() })
5155
6140
  ]);
5156
- var BriefSchemaSchema = z2.object({
5157
- pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
5158
- issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
5159
- milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
5160
- ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
6141
+ var BriefSchemaSchema = z4.object({
6142
+ pr: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
6143
+ issue: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
6144
+ milestone: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
6145
+ ack: z4.array(z4.enum(BRIEF_BUILTINS)).optional()
5161
6146
  });
5162
6147
  function isSafeRepoRelPath(p) {
5163
6148
  if (p.length === 0)
@@ -5166,7 +6151,7 @@ function isSafeRepoRelPath(p) {
5166
6151
  return false;
5167
6152
  return p.split(/[\\/]/).every((seg) => seg !== ".." && seg !== "");
5168
6153
  }
5169
- var SafeRepoRelPath = z2.string().refine(isSafeRepoRelPath, {
6154
+ var SafeRepoRelPath = z4.string().refine(isSafeRepoRelPath, {
5170
6155
  message: "must be a repo-root-relative path with no `..` segment or absolute root"
5171
6156
  });
5172
6157
  var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
@@ -5176,22 +6161,22 @@ function isCanonicalHookBlockPath(p) {
5176
6161
  var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
5177
6162
  message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
5178
6163
  });
5179
- var ManagedBlockRecordSchema = z2.object({
6164
+ var ManagedBlockRecordSchema = z4.object({
5180
6165
  path: ManagedHookBlockPath,
5181
- marker: z2.string(),
5182
- comment: z2.enum(["hash", "html"])
6166
+ marker: z4.string(),
6167
+ comment: z4.enum(["hash", "html"])
5183
6168
  });
5184
- var ManagedManifestSchema = z2.object({
5185
- version: z2.number().int().positive(),
5186
- files: z2.array(SafeRepoRelPath),
5187
- blocks: z2.array(ManagedBlockRecordSchema),
5188
- labels: z2.array(z2.string()),
5189
- agents: z2.array(z2.enum(AGENT_VENDORS)).optional()
6169
+ var ManagedManifestSchema = z4.object({
6170
+ version: z4.number().int().positive(),
6171
+ files: z4.array(SafeRepoRelPath),
6172
+ blocks: z4.array(ManagedBlockRecordSchema),
6173
+ labels: z4.array(z4.string()),
6174
+ agents: z4.array(z4.enum(AGENT_VENDORS)).optional()
5190
6175
  });
5191
- var ProjectEntrySchema = z2.object({
5192
- name: z2.string().min(1),
5193
- description: z2.string().min(1).optional(),
5194
- path: z2.string().min(1).optional()
6176
+ var ProjectEntrySchema = z4.object({
6177
+ name: z4.string().min(1),
6178
+ description: z4.string().min(1).optional(),
6179
+ path: z4.string().min(1).optional()
5195
6180
  });
5196
6181
  function parseTokensCollectDeclaration(value) {
5197
6182
  const m = value.trim().match(/^(\S+)\s+(\S+)$/);
@@ -5202,34 +6187,62 @@ function parseTokensCollectDeclaration(value) {
5202
6187
  return null;
5203
6188
  return { interpreter, script };
5204
6189
  }
5205
- var VinayaConfigSchema = z2.object({
5206
- rings: z2.object({
5207
- ring1_forgeWriteInterception: z2.boolean(),
5208
- ring2_asyncAudits: z2.boolean()
6190
+ var VinayaConfigSchema = z4.object({
6191
+ rings: z4.object({
6192
+ ring1_forgeWriteInterception: z4.boolean(),
6193
+ ring2_asyncAudits: z4.boolean()
5209
6194
  }).optional(),
5210
- checks: z2.record(z2.string(), CheckEntrySchema).optional(),
5211
- roles: z2.record(z2.string(), RoleEntrySchema).optional(),
6195
+ checks: z4.record(z4.string(), CheckEntrySchema).optional(),
6196
+ roles: z4.record(z4.string(), RoleEntrySchema).optional(),
5212
6197
  briefSchema: BriefSchemaSchema.optional(),
5213
6198
  managed: ManagedManifestSchema.optional(),
5214
- principals: z2.array(z2.string()).min(1).optional(),
5215
- releaseActor: z2.string().min(1).optional(),
5216
- ci: z2.object({ setup: z2.string().min(1) }).optional(),
5217
- tokens: z2.object({
5218
- collect: z2.string().min(1).refine((v) => parseTokensCollectDeclaration(v) !== null, {
6199
+ principals: z4.array(z4.string()).min(1).optional(),
6200
+ releaseActor: z4.string().min(1).optional(),
6201
+ ci: z4.object({ setup: z4.string().min(1) }).optional(),
6202
+ tokens: z4.object({
6203
+ collect: z4.string().min(1).refine((v) => parseTokensCollectDeclaration(v) !== null, {
5219
6204
  message: 'tokens.collect must be exactly "<interpreter> <repo-relative-script-path>" — two whitespace-separated tokens, no flags, no shell syntax, no quoting'
5220
6205
  })
5221
6206
  }).optional(),
5222
- blastRadius: z2.object({ extraDomains: z2.array(z2.string()).optional() }).optional(),
5223
- proseGates: z2.object({
5224
- doctrineRoot: z2.string().min(1).optional(),
5225
- readerFacingPrefix: z2.string().min(1).optional(),
5226
- readerFacingSuffix: z2.string().min(1).optional(),
5227
- legacySlugDir: z2.string().min(1).optional()
6207
+ blastRadius: z4.object({ extraDomains: z4.array(z4.string()).optional() }).optional(),
6208
+ proseGates: z4.object({
6209
+ doctrineRoot: z4.string().min(1).optional(),
6210
+ readerFacingPrefix: z4.string().min(1).optional(),
6211
+ readerFacingSuffix: z4.string().min(1).optional(),
6212
+ legacySlugDir: z4.string().min(1).optional()
6213
+ }).optional(),
6214
+ projects: z4.array(ProjectEntrySchema).optional(),
6215
+ dispatch: z4.object({
6216
+ timeoutMs: z4.number().int().positive().optional(),
6217
+ killGraceMs: z4.number().int().positive().optional(),
6218
+ agent: z4.enum(["claude", "codex", "gemini"]).optional()
6219
+ }).optional(),
6220
+ reviewPolicy: z4.object({
6221
+ codeReviewThreshold: z4.string().min(1).optional(),
6222
+ securityThreshold: z4.string().min(1).optional(),
6223
+ maxRounds: z4.number().optional()
5228
6224
  }).optional(),
5229
- projects: z2.array(ProjectEntrySchema).optional(),
5230
- dispatch: z2.object({
5231
- timeoutMs: z2.number().int().positive().optional(),
5232
- agent: z2.enum(["claude", "codex", "gemini"]).optional()
6225
+ prePush: z4.object({
6226
+ alwaysRun: z4.array(z4.string()).optional()
6227
+ }).optional(),
6228
+ report: z4.object({
6229
+ commandTimeoutMs: z4.number().int().positive().optional()
6230
+ }).superRefine((report, ctx) => {
6231
+ const commandTimeoutMs = report.commandTimeoutMs;
6232
+ if (commandTimeoutMs !== undefined && commandTimeoutMs > MAX_REPORT_COMMAND_TIMEOUT_MS) {
6233
+ ctx.addIssue({
6234
+ code: z4.ZodIssueCode.custom,
6235
+ path: ["commandTimeoutMs"],
6236
+ message: "must be at most 3600000 (1 hour)"
6237
+ });
6238
+ }
6239
+ }).optional(),
6240
+ logPublish: z4.object({
6241
+ issue: z4.number().int().positive().optional(),
6242
+ pr: z4.number().int().positive().optional(),
6243
+ maxChunksPerFlush: z4.number().int().positive().optional()
6244
+ }).refine((v) => !(v.issue !== undefined && v.pr !== undefined), {
6245
+ message: "logPublish: set at most one of issue/pr, not both"
5233
6246
  }).optional()
5234
6247
  });
5235
6248
  var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
@@ -5304,6 +6317,28 @@ function resolvePrincipalAllowlist(config) {
5304
6317
  function resolveReleaseActor(config) {
5305
6318
  return config?.releaseActor ?? DEFAULT_RELEASE_ACTOR;
5306
6319
  }
6320
+ function resolveReviewPolicy(config) {
6321
+ const raw = config?.reviewPolicy;
6322
+ if (!raw)
6323
+ return DEFAULT_REVIEW_POLICY;
6324
+ const codeReviewThreshold = raw.codeReviewThreshold ?? DEFAULT_REVIEW_POLICY.codeReviewThreshold;
6325
+ if (!isKnownSeverity(CODE_REVIEW_SEVERITY_ORDER, codeReviewThreshold)) {
6326
+ throw new Error(`vinaya.config.json: reviewPolicy.codeReviewThreshold "${codeReviewThreshold}" is not one of ${CODE_REVIEW_SEVERITY_ORDER.join(" > ")} — fix the config, this never falls back to a default.`);
6327
+ }
6328
+ const securityThreshold = raw.securityThreshold ?? DEFAULT_REVIEW_POLICY.securityThreshold;
6329
+ if (!isKnownSeverity(SECURITY_SEVERITY_ORDER, securityThreshold)) {
6330
+ throw new Error(`vinaya.config.json: reviewPolicy.securityThreshold "${securityThreshold}" is not one of ${SECURITY_SEVERITY_ORDER.join(" > ")} — fix the config, this never falls back to a default.`);
6331
+ }
6332
+ const maxRounds = raw.maxRounds ?? DEFAULT_REVIEW_POLICY.maxRounds;
6333
+ if (!Number.isInteger(maxRounds) || maxRounds < 1) {
6334
+ throw new Error(`vinaya.config.json: reviewPolicy.maxRounds "${maxRounds}" is not a positive integer — fix the config, this never falls back to a default.`);
6335
+ }
6336
+ return {
6337
+ codeReviewThreshold,
6338
+ securityThreshold,
6339
+ maxRounds
6340
+ };
6341
+ }
5307
6342
  function trustAnchorRepo() {
5308
6343
  const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
5309
6344
  const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
@@ -5383,6 +6418,9 @@ function loadConfig() {
5383
6418
  }
5384
6419
  var TOKENS_COLLECT_TRUST_PATH = join(GLOBAL_VINAYA_HOME, "tokens-collect-trust.json");
5385
6420
 
6421
+ // src/lib/brief-assembly.ts
6422
+ import { execFileSync as execFileSync4 } from "node:child_process";
6423
+
5386
6424
  // ../../packages/sources/src/commands.ts
5387
6425
  var COMMANDS = [
5388
6426
  {
@@ -5541,6 +6579,27 @@ var COMMANDS = [
5541
6579
  ],
5542
6580
  status: "shipped"
5543
6581
  },
6582
+ {
6583
+ name: "task status",
6584
+ description: "Every open task with a frozen brief, its pull request, and whether its loop is running, paused, or published",
6585
+ flags: [{ flag: "--json", description: "Enveloped JSON output (schema: 1)" }],
6586
+ details: [
6587
+ "Read-only: one `gh issue list` for every open task Issue across every tranche (title/label resolved through the same `resolveTaskIssueRef` `list-tasks.ts` already uses), the open pull request per branch, and the driver pid record / pause record / publish effect markers under `<outboxRoot>/dev-review-loop/<task>/` — never a `ps` scan, never a re-parse of posted verdict comments to decide `published`.",
6588
+ "`running` names the driver's pid (`review-validity-v1` task 7's pid record); `paused` names the reason from the pause record; `published` means the newest round's reviewer and security verdict effect markers both read `posted`; `no driver` is the fallback when none of the above holds.",
6589
+ "`vinaya task status <tranche> <n>` narrows to one task and adds the last round's held or published verdict lines (`round-<n>-reviewer.md`/`round-<n>-security.md`, whichever their outbox carries) plus the exact `vinaya dev-review-loop --resume <pr>` command when paused."
6590
+ ],
6591
+ status: "shipped"
6592
+ },
6593
+ {
6594
+ name: "task-tools serve",
6595
+ description: "Run the task-operator MCP tool server over stdio — the command both runtime adapters register",
6596
+ details: [
6597
+ "Exposes the task-operator tool catalog (`packages/aeg-core/src/task-tools.ts`) to an agent runtime as one MCP server speaking newline-delimited JSON-RPC 2.0 (`initialize`/`tools/list`/`tools/call`). Claude registers it through the generated `.mcp.json`; Codex through its documented `~/.codex/config.toml` `[mcp_servers]` table — both point at this same command.",
6598
+ "stdout carries JSON-RPC and nothing else: any stray write from the CLI (a forge-read warning) is redirected to stderr, so the protocol stream is never corrupted.",
6599
+ "`task_status`/`task_escalation_read` read; `task_start` starts a run in attended mode only, requiring an authenticated caller from the invocation context (`VINAYA_MCP_CALLER`) and refusing without one — MCP is a transport, not authorization. `task_resume`/`task_cancel` require the same authenticated caller, plus a current Principal ruling read fresh from the run's own PR — never a caller-supplied approval; `task_resume` triggers the existing `dev-review-loop --resume` continuation exactly once per escalation, and `task_cancel` reports a truthful `confirmed`/`pending`/`uncertain` outcome, idempotently, across repeated calls. No unattended start until the worker-isolation boundary and a capability flag land."
6600
+ ],
6601
+ status: "shipped"
6602
+ },
5544
6603
  {
5545
6604
  name: "pr create",
5546
6605
  description: "Open a pull request after full brief-schema validation",
@@ -5685,6 +6744,30 @@ var COMMANDS = [
5685
6744
  ],
5686
6745
  status: "shipped"
5687
6746
  },
6747
+ {
6748
+ name: "log export-artifact",
6749
+ description: "Copy this run's own local outbox into a file, for the generated task-path workflow's own upload step",
6750
+ flags: [],
6751
+ details: [
6752
+ "Concatenates every `*.ndjson` file under `~/.vinaya/outbox/` into `<dest>`, verbatim — no filtering, no second redaction pass (lines are already redacted at `log()`'s own write boundary). Writes nothing when the outbox is empty, and exits 0 either way: no gate events this run is a legitimate outcome, never a failure.",
6753
+ "Runs inside the generated `vinaya-checks.yml` job, which holds no forge-write credential — this command never calls the forge. Both this step and the `actions/upload-artifact` step after it run `if: always()`, so a cancelled or failed job still exports whatever partial outbox it has."
6754
+ ],
6755
+ status: "shipped"
6756
+ },
6757
+ {
6758
+ name: "log collect-artifact",
6759
+ description: "Validate a downloaded task-log artifact and publish the valid records through the existing flush path",
6760
+ flags: [
6761
+ { flag: "--pr", description: "The pull request this artifact belongs to" },
6762
+ { flag: "--repo", description: "Expected `owner/repo` — a provenance cross-check against each record" }
6763
+ ],
6764
+ details: [
6765
+ "Runs inside the generated `vinaya-task-log-collector.yml` workflow — a `workflow_run`-triggered job on the default branch, holding the write credential the task-path job that produced the artifact never gets. `<path>` is already downloaded by that workflow, scoped to a specific, API-verified run id — a provenance guarantee this command never re-derives from the artifact bytes.",
6766
+ "Never executes, imports, or evaluates the artifact's content: every line is read as text and validated (schema, an 8 MiB whole-artifact size cap, redaction, and a repo cross-check) before anything is trusted. A rejected line becomes a named gap — printed, never a silent drop — and the artifact is never partially trusted past that check into executing anything.",
6767
+ "The valid, re-redacted survivors are appended into the same local outbox `vinaya log flush` would read for that PR's Issue, then published through the existing `flushOutbox` unmodified — reusing its chunking, its `<!-- aeg:log:… -->` marker, and its idempotent-retry read, rather than a second publisher. A retried collector run (a fresh runner, the same forge state) therefore dedupes for free: the marker already on the forge is acknowledged, never re-posted."
6768
+ ],
6769
+ status: "shipped"
6770
+ },
5688
6771
  {
5689
6772
  name: "milestone create",
5690
6773
  description: "Create a GitHub Milestone from a validated body",
@@ -6050,10 +7133,10 @@ function createForgeSource(config) {
6050
7133
  };
6051
7134
  }
6052
7135
  // ../../packages/sources/src/select-source.ts
6053
- import { z as z3 } from "zod";
6054
- var StateSourceConfigSchema = z3.discriminatedUnion("kind", [
6055
- z3.object({ kind: z3.literal("forge"), owner: z3.string(), repo: z3.string() }),
6056
- z3.object({ kind: z3.literal("file"), root: z3.string().optional() })
7136
+ import { z as z5 } from "zod";
7137
+ var StateSourceConfigSchema = z5.discriminatedUnion("kind", [
7138
+ z5.object({ kind: z5.literal("forge"), owner: z5.string(), repo: z5.string() }),
7139
+ z5.object({ kind: z5.literal("file"), root: z5.string().optional() })
6057
7140
  ]);
6058
7141
  // src/checks/edge-resolve.ts
6059
7142
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -6173,6 +7256,835 @@ async function resolveEdge(id, taskById, factsByTaskId, repo, resolveSibling = d
6173
7256
  };
6174
7257
  }
6175
7258
 
7259
+ // src/lib/brief-assembly.ts
7260
+ function git(args) {
7261
+ try {
7262
+ return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
7263
+ } catch {
7264
+ return "";
7265
+ }
7266
+ }
7267
+ function expandGlob(glob) {
7268
+ const out = git(["ls-files", "--", glob]);
7269
+ return out.split(`
7270
+ `).map((s) => s.trim()).filter(Boolean);
7271
+ }
7272
+ var DRAFT_ISSUE_SENTINEL = Number.MAX_SAFE_INTEGER;
7273
+
7274
+ // src/checks/registry.ts
7275
+ import { existsSync as existsSync3 } from "node:fs";
7276
+ import { join as join3 } from "node:path";
7277
+
7278
+ // src/lib/package-root.ts
7279
+ import { existsSync as existsSync2 } from "node:fs";
7280
+ import { dirname as dirname2, join as join2 } from "node:path";
7281
+ import { fileURLToPath } from "node:url";
7282
+ function packageRoot(moduleUrl) {
7283
+ let dir = dirname2(fileURLToPath(moduleUrl));
7284
+ while (!existsSync2(join2(dir, "package.json"))) {
7285
+ if (existsSync2(join2(dir, ".git")))
7286
+ break;
7287
+ const parent = dirname2(dir);
7288
+ if (parent === dir)
7289
+ break;
7290
+ dir = parent;
7291
+ }
7292
+ return dir;
7293
+ }
7294
+
7295
+ // src/checks/registry.ts
7296
+ var DIST_BIN_DIR = join3(packageRoot(import.meta.url), "dist", "checks", "bin");
7297
+ var SRC_BIN_DIR = join3(packageRoot(import.meta.url), "src", "checks", "bin");
7298
+ var BIN_DIR = existsSync3(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
7299
+ var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
7300
+ function bin(name) {
7301
+ return join3(BIN_DIR, `${name}${BIN_EXT}`);
7302
+ }
7303
+ var REGISTRY = [
7304
+ [
7305
+ {
7306
+ name: "brief-shape",
7307
+ validates: "body",
7308
+ run: bin("check-brief-shape"),
7309
+ scope: "diff",
7310
+ timeoutMs: 15000,
7311
+ env: {
7312
+ PR_BODY: { optional: true },
7313
+ BRANCH: { optional: true },
7314
+ PR_NUMBER: { optional: true },
7315
+ GITHUB_TOKEN: { optional: true },
7316
+ GH_TOKEN: { optional: true }
7317
+ }
7318
+ },
7319
+ 0
7320
+ ],
7321
+ [
7322
+ {
7323
+ name: "pr-report-density",
7324
+ validates: "body",
7325
+ run: bin("check-pr-report-density"),
7326
+ scope: "diff",
7327
+ timeoutMs: 15000,
7328
+ env: {
7329
+ PR_BODY: { optional: true }
7330
+ }
7331
+ },
7332
+ 0
7333
+ ],
7334
+ [
7335
+ {
7336
+ name: "doc-coverage",
7337
+ validates: "body",
7338
+ run: bin("check-doc-coverage"),
7339
+ scope: "diff",
7340
+ timeoutMs: 15000,
7341
+ env: {
7342
+ BASE_SHA: { optional: true },
7343
+ PR_BODY: { optional: true },
7344
+ PR_BODY_FILE: { optional: true },
7345
+ PR_NUMBER: { optional: true },
7346
+ GITHUB_REPOSITORY: { optional: true },
7347
+ GITHUB_TOKEN: { optional: true },
7348
+ GH_TOKEN: { optional: true }
7349
+ }
7350
+ },
7351
+ 0
7352
+ ],
7353
+ [
7354
+ {
7355
+ name: "coherence",
7356
+ run: bin("check-coherence"),
7357
+ scope: "full",
7358
+ timeoutMs: 30000,
7359
+ env: {
7360
+ AEG_REPO: { optional: true },
7361
+ BRANCH: { optional: true },
7362
+ GITHUB_TOKEN: { optional: true },
7363
+ GH_TOKEN: { optional: true }
7364
+ }
7365
+ },
7366
+ 0
7367
+ ],
7368
+ [
7369
+ {
7370
+ name: "pr-premise-reassert",
7371
+ validates: "body",
7372
+ run: bin("check-pr-premise-reassert"),
7373
+ scope: "diff",
7374
+ timeoutMs: 15000,
7375
+ env: {
7376
+ PR_BODY: { optional: true }
7377
+ }
7378
+ },
7379
+ 0
7380
+ ],
7381
+ [
7382
+ {
7383
+ name: "dispatch-readiness",
7384
+ run: bin("check-dispatch-readiness"),
7385
+ scope: "full",
7386
+ timeoutMs: 30000,
7387
+ env: {
7388
+ AEG_REPO: { optional: true },
7389
+ BRANCH: { optional: true },
7390
+ GITHUB_TOKEN: { optional: true },
7391
+ GH_TOKEN: { optional: true },
7392
+ PREMISE_FILE: { optional: true }
7393
+ }
7394
+ },
7395
+ 0
7396
+ ],
7397
+ [
7398
+ {
7399
+ name: "closes-n",
7400
+ validates: "body",
7401
+ run: bin("check-closes-n"),
7402
+ scope: "diff",
7403
+ timeoutMs: 15000,
7404
+ requiresOpenPr: true,
7405
+ env: {
7406
+ BRANCH: { optional: true },
7407
+ PR_BODY: { optional: true },
7408
+ AEG_REPO: { optional: true },
7409
+ GITHUB_TOKEN: { optional: true },
7410
+ GH_TOKEN: { optional: true }
7411
+ }
7412
+ },
7413
+ 1
7414
+ ],
7415
+ [
7416
+ {
7417
+ name: "single-plan-pr",
7418
+ run: bin("check-single-plan-pr"),
7419
+ scope: "diff",
7420
+ timeoutMs: 15000,
7421
+ env: {
7422
+ BASE_SHA: { optional: true },
7423
+ PR_NUMBER: { optional: true },
7424
+ GITHUB_TOKEN: { optional: true },
7425
+ GH_TOKEN: { optional: true }
7426
+ }
7427
+ },
7428
+ 0
7429
+ ],
7430
+ [
7431
+ {
7432
+ name: "surface-scope",
7433
+ run: bin("check-surface-scope"),
7434
+ scope: "diff",
7435
+ timeoutMs: 15000,
7436
+ env: {
7437
+ AEG_REPO: { optional: true },
7438
+ BASE_SHA: { optional: true },
7439
+ BRANCH: { optional: true },
7440
+ GITHUB_TOKEN: { optional: true },
7441
+ GH_TOKEN: { optional: true }
7442
+ }
7443
+ },
7444
+ 0
7445
+ ],
7446
+ [
7447
+ {
7448
+ name: "test-plan",
7449
+ validates: "body",
7450
+ run: bin("check-test-plan"),
7451
+ scope: "diff",
7452
+ timeoutMs: 15000,
7453
+ requiresOpenPr: true,
7454
+ principalOwed: true,
7455
+ env: {
7456
+ PR_BODY: { optional: true },
7457
+ BRANCH: { optional: true }
7458
+ }
7459
+ },
7460
+ 1
7461
+ ],
7462
+ [
7463
+ {
7464
+ name: "body-bare-digits",
7465
+ validates: "body",
7466
+ run: bin("check-body-bare-digits"),
7467
+ scope: "diff",
7468
+ timeoutMs: 15000,
7469
+ requiresOpenPr: true,
7470
+ ownWorkflow: true,
7471
+ env: {
7472
+ PR_BODY: { optional: true },
7473
+ PR_NUMBER: { optional: true },
7474
+ GITHUB_REPOSITORY: { optional: true },
7475
+ GITHUB_TOKEN: { optional: true },
7476
+ GH_TOKEN: { optional: true }
7477
+ }
7478
+ },
7479
+ 1
7480
+ ],
7481
+ [
7482
+ {
7483
+ name: "token-report",
7484
+ validates: "body",
7485
+ run: bin("check-token-report"),
7486
+ scope: "diff",
7487
+ timeoutMs: 15000,
7488
+ requiresOpenPr: true,
7489
+ env: {
7490
+ PR_BODY: { optional: true },
7491
+ BRANCH: { optional: true },
7492
+ CLAUDE_PROJECT_DIR: { optional: true },
7493
+ CLAUDE_CODE_SESSION_ID: { optional: true }
7494
+ }
7495
+ },
7496
+ 1
7497
+ ],
7498
+ [
7499
+ {
7500
+ name: "no-disk-state",
7501
+ run: bin("check-no-disk-state"),
7502
+ scope: "diff",
7503
+ timeoutMs: 15000,
7504
+ env: { BASE_SHA: { optional: true } }
7505
+ },
7506
+ 0
7507
+ ],
7508
+ [
7509
+ {
7510
+ name: "registry-gates",
7511
+ run: bin("check-registry-gates"),
7512
+ scope: "full",
7513
+ timeoutMs: 30000,
7514
+ env: {
7515
+ AEG_REPO: { optional: true },
7516
+ GITHUB_TOKEN: { optional: true },
7517
+ GH_TOKEN: { optional: true }
7518
+ }
7519
+ },
7520
+ 0
7521
+ ],
7522
+ [
7523
+ {
7524
+ name: "review-gate",
7525
+ run: bin("check-review-gate"),
7526
+ scope: "full",
7527
+ timeoutMs: 30000,
7528
+ ownWorkflow: true,
7529
+ env: {
7530
+ PR_NUMBER: { optional: true },
7531
+ GITHUB_REPOSITORY: { optional: true },
7532
+ GITHUB_TOKEN: { optional: true },
7533
+ GH_TOKEN: { optional: true }
7534
+ }
7535
+ },
7536
+ 1
7537
+ ],
7538
+ [
7539
+ {
7540
+ name: "branch-topology",
7541
+ run: bin("check-branch-topology"),
7542
+ scope: "full",
7543
+ timeoutMs: 30000,
7544
+ env: {
7545
+ BRANCH: { optional: true },
7546
+ AEG_REPO: { optional: true },
7547
+ GITHUB_TOKEN: { optional: true },
7548
+ GH_TOKEN: { optional: true }
7549
+ }
7550
+ },
7551
+ 0
7552
+ ],
7553
+ [
7554
+ {
7555
+ name: "dead-branch-push",
7556
+ run: bin("check-dead-branch-push"),
7557
+ scope: "full",
7558
+ timeoutMs: 30000,
7559
+ env: {
7560
+ BRANCH: { optional: true },
7561
+ GITHUB_TOKEN: { optional: true },
7562
+ GH_TOKEN: { optional: true }
7563
+ }
7564
+ },
7565
+ 0
7566
+ ],
7567
+ [
7568
+ {
7569
+ name: "first-push-dispatch",
7570
+ run: bin("check-first-push-dispatch"),
7571
+ scope: "full",
7572
+ timeoutMs: 30000,
7573
+ env: {
7574
+ BRANCH: { optional: true },
7575
+ AEG_REPO: { optional: true },
7576
+ GITHUB_TOKEN: { optional: true },
7577
+ GH_TOKEN: { optional: true }
7578
+ }
7579
+ },
7580
+ 0
7581
+ ],
7582
+ [
7583
+ {
7584
+ name: "doc-coverage-push",
7585
+ validates: "body",
7586
+ run: bin("check-doc-coverage-push"),
7587
+ scope: "diff",
7588
+ timeoutMs: 15000,
7589
+ env: {
7590
+ OVERRIDE_DOCS: { optional: true },
7591
+ BASE_SHA: { optional: true },
7592
+ PR_BODY: { optional: true },
7593
+ PR_BODY_FILE: { optional: true },
7594
+ PR_LABELS: { optional: true },
7595
+ WAIVER_LABEL_ACTOR: { optional: true },
7596
+ GITHUB_REPOSITORY: { optional: true },
7597
+ GITHUB_TOKEN: { optional: true },
7598
+ GH_TOKEN: { optional: true }
7599
+ }
7600
+ },
7601
+ 0
7602
+ ],
7603
+ [
7604
+ {
7605
+ name: "issue-assignment",
7606
+ run: bin("check-issue-assignment"),
7607
+ scope: "full",
7608
+ timeoutMs: 30000,
7609
+ env: {
7610
+ AEG_REPO: { optional: true },
7611
+ BRANCH: { optional: true },
7612
+ GITHUB_TOKEN: { optional: true },
7613
+ GH_TOKEN: { optional: true }
7614
+ }
7615
+ },
7616
+ 0
7617
+ ],
7618
+ [
7619
+ {
7620
+ name: "evidence-fresh",
7621
+ validates: "body",
7622
+ run: bin("check-evidence-fresh"),
7623
+ scope: "diff",
7624
+ timeoutMs: 15000,
7625
+ requiresOpenPr: true,
7626
+ env: {
7627
+ PR_NUMBER: { optional: true },
7628
+ PR_BODY: { optional: true },
7629
+ BASE_SHA: { optional: true },
7630
+ GITHUB_TOKEN: { optional: true },
7631
+ GH_TOKEN: { optional: true }
7632
+ }
7633
+ },
7634
+ 1
7635
+ ],
7636
+ [
7637
+ {
7638
+ name: "reader-resolvable-prose",
7639
+ run: bin("check-reader-resolvable-prose"),
7640
+ scope: "full",
7641
+ timeoutMs: 30000,
7642
+ env: {},
7643
+ include: [
7644
+ "aeg-root/**/*.md",
7645
+ "apps/cli/src/**",
7646
+ ".github/workflows/**",
7647
+ ".vinaya/**",
7648
+ "apps/cli/README.md",
7649
+ "packages/sources/README.md"
7650
+ ]
7651
+ },
7652
+ 0
7653
+ ],
7654
+ [
7655
+ {
7656
+ name: "retired-vocabulary",
7657
+ run: bin("check-retired-vocabulary"),
7658
+ scope: "full",
7659
+ timeoutMs: 30000,
7660
+ env: {},
7661
+ include: ["aeg-root/**/*.md"]
7662
+ },
7663
+ 0
7664
+ ],
7665
+ [
7666
+ {
7667
+ name: "doctrine-portability",
7668
+ run: bin("check-doctrine-portability"),
7669
+ scope: "full",
7670
+ timeoutMs: 30000,
7671
+ env: { BASE_SHA: { optional: true } },
7672
+ include: ["aeg-root/**/*.md"]
7673
+ },
7674
+ 0
7675
+ ],
7676
+ [
7677
+ {
7678
+ name: "doctrine-no-procedures",
7679
+ run: bin("check-doctrine-no-procedures"),
7680
+ scope: "full",
7681
+ timeoutMs: 30000,
7682
+ env: {},
7683
+ include: ["aeg-root/**/*.md"]
7684
+ },
7685
+ 0
7686
+ ],
7687
+ [
7688
+ {
7689
+ name: "exec-bits",
7690
+ run: bin("check-exec-bits"),
7691
+ scope: "diff",
7692
+ timeoutMs: 30000,
7693
+ env: {}
7694
+ },
7695
+ 0
7696
+ ],
7697
+ [
7698
+ {
7699
+ name: "workspace-escape",
7700
+ run: bin("check-workspace-escape"),
7701
+ scope: "full",
7702
+ timeoutMs: 30000,
7703
+ env: {},
7704
+ include: ["aeg-root/**/*.md"]
7705
+ },
7706
+ 0
7707
+ ],
7708
+ [
7709
+ {
7710
+ name: "changeset-coverage",
7711
+ run: bin("check-changeset-coverage"),
7712
+ scope: "diff",
7713
+ timeoutMs: 15000,
7714
+ env: {}
7715
+ },
7716
+ 0
7717
+ ],
7718
+ [
7719
+ {
7720
+ name: "quoted-command",
7721
+ run: bin("check-quoted-command"),
7722
+ scope: "diff",
7723
+ timeoutMs: 15000,
7724
+ env: {}
7725
+ },
7726
+ 0
7727
+ ],
7728
+ [
7729
+ {
7730
+ name: "main-branch-refusal",
7731
+ run: bin("check-main-branch-refusal"),
7732
+ scope: "full",
7733
+ timeoutMs: 15000,
7734
+ env: { VINAYA_PUSH_REFS: { optional: true } }
7735
+ },
7736
+ 0
7737
+ ],
7738
+ [
7739
+ {
7740
+ name: "token-collection-wired",
7741
+ run: bin("check-token-collection-wired"),
7742
+ scope: "full",
7743
+ timeoutMs: 15000,
7744
+ env: {
7745
+ CLAUDE_PROJECT_DIR: { optional: true },
7746
+ CLAUDE_CODE_SESSION_ID: { optional: true }
7747
+ }
7748
+ },
7749
+ 0
7750
+ ],
7751
+ [
7752
+ {
7753
+ name: "issue-title-grammar",
7754
+ run: bin("check-issue-title-grammar"),
7755
+ validates: "issue",
7756
+ scope: "full",
7757
+ ownWorkflow: true,
7758
+ timeoutMs: 15000,
7759
+ env: { ISSUE_TITLE: { optional: true } }
7760
+ },
7761
+ 1
7762
+ ],
7763
+ [
7764
+ {
7765
+ name: "issue-objectives-numbering",
7766
+ run: bin("check-issue-objectives-numbering"),
7767
+ validates: "issue",
7768
+ scope: "full",
7769
+ ownWorkflow: true,
7770
+ timeoutMs: 15000,
7771
+ env: { ISSUE_BODY: { optional: true }, ISSUE_NUMBER: { optional: true } }
7772
+ },
7773
+ 1
7774
+ ],
7775
+ [
7776
+ {
7777
+ name: "issue-parts-coverage",
7778
+ run: bin("check-issue-parts-coverage"),
7779
+ validates: "issue",
7780
+ scope: "full",
7781
+ ownWorkflow: true,
7782
+ timeoutMs: 15000,
7783
+ env: { ISSUE_BODY: { optional: true } }
7784
+ },
7785
+ 1
7786
+ ],
7787
+ [
7788
+ {
7789
+ name: "issue-surface-globs",
7790
+ run: bin("check-issue-surface-globs"),
7791
+ validates: "issue",
7792
+ scope: "full",
7793
+ ownWorkflow: true,
7794
+ timeoutMs: 15000,
7795
+ env: { ISSUE_BODY: { optional: true } }
7796
+ },
7797
+ 1
7798
+ ],
7799
+ [
7800
+ {
7801
+ name: "issue-tranche-label",
7802
+ run: bin("check-issue-tranche-label"),
7803
+ validates: "issue",
7804
+ scope: "full",
7805
+ ownWorkflow: true,
7806
+ timeoutMs: 15000,
7807
+ env: { ISSUE_BODY: { optional: true }, ISSUE_LABELS: { optional: true } }
7808
+ },
7809
+ 1
7810
+ ],
7811
+ [
7812
+ {
7813
+ name: "issue-milestone-attach",
7814
+ run: bin("check-issue-milestone-attach"),
7815
+ validates: "issue",
7816
+ scope: "full",
7817
+ ownWorkflow: true,
7818
+ timeoutMs: 15000,
7819
+ env: {
7820
+ ISSUE_LABELS: { optional: true },
7821
+ CURRENT_MILESTONE_TITLE: { optional: true },
7822
+ RESOLVED_MILESTONE_TITLE: { optional: true }
7823
+ }
7824
+ },
7825
+ 1
7826
+ ]
7827
+ ];
7828
+ function coreCheckRegistry() {
7829
+ return REGISTRY.map(([spec]) => spec);
7830
+ }
7831
+ var CORE_CHECK_RING = Object.fromEntries(REGISTRY.map(([spec, ring]) => [spec.name, ring]));
7832
+
7833
+ // src/lib/log-sink.ts
7834
+ import { execFileSync as execFileSync5 } from "node:child_process";
7835
+ import { randomUUID } from "node:crypto";
7836
+ import {
7837
+ closeSync as closeSync2,
7838
+ constants as fsConstants2,
7839
+ existsSync as existsSync4,
7840
+ fstatSync as fstatSync2,
7841
+ mkdirSync as mkdirSync2,
7842
+ openSync as openSync2,
7843
+ readFileSync as readFileSync3,
7844
+ renameSync,
7845
+ writeSync
7846
+ } from "node:fs";
7847
+ import { hostname as osHostname, homedir as homedir2 } from "node:os";
7848
+ import { dirname as dirname3, join as join4 } from "node:path";
7849
+ var OUTBOX_MAX_BYTES = 8 * 1024 * 1024;
7850
+ function isEnoent(err) {
7851
+ return typeof err === "object" && err !== null && err.code === "ENOENT";
7852
+ }
7853
+ function resolveDoctrine(cwd, vinayaVersion) {
7854
+ let toplevel;
7855
+ try {
7856
+ toplevel = execFileSync5("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
7857
+ encoding: "utf8",
7858
+ stdio: ["ignore", "pipe", "pipe"]
7859
+ }).trim();
7860
+ } catch (err) {
7861
+ return isEnoent(err) ? "unknown" : vinayaVersion;
7862
+ }
7863
+ if (!existsSync4(join4(toplevel, "aeg-root", "roles")))
7864
+ return vinayaVersion;
7865
+ try {
7866
+ const sha = execFileSync5("git", ["-C", toplevel, "rev-parse", "HEAD:aeg-root"], {
7867
+ encoding: "utf8",
7868
+ stdio: ["ignore", "pipe", "pipe"]
7869
+ }).trim();
7870
+ return `aeg-root@${sha}`;
7871
+ } catch {
7872
+ return vinayaVersion;
7873
+ }
7874
+ }
7875
+ function readVinayaVersion() {
7876
+ try {
7877
+ const pkg = JSON.parse(readFileSync3(join4(packageRoot(import.meta.url), "package.json"), "utf8"));
7878
+ return pkg.version ?? "unknown";
7879
+ } catch {
7880
+ return "unknown";
7881
+ }
7882
+ }
7883
+ var SAFE_PATH_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
7884
+ function isSafeRepoSegment(segment) {
7885
+ return SAFE_PATH_SEGMENT.test(segment) && !segment.includes("..");
7886
+ }
7887
+ function outboxPathFor(deps, repo, issue) {
7888
+ const dirName = repo ? `${repo.owner}-${repo.repo}` : "unresolved";
7889
+ const fileName = `${issue ?? "none"}.ndjson`;
7890
+ return join4(deps.outboxRoot(), dirName, fileName);
7891
+ }
7892
+ function hostFromEnv(env) {
7893
+ if (env.GITHUB_ACTIONS)
7894
+ return "ci";
7895
+ if (env.VINAYA_HOST === "hook")
7896
+ return "hook";
7897
+ if (env.VINAYA_HOST === "loop")
7898
+ return "loop";
7899
+ return "cli";
7900
+ }
7901
+ function defaultDeps() {
7902
+ return {
7903
+ outboxRoot: () => join4(GLOBAL_VINAYA_HOME, "outbox"),
7904
+ home: () => homedir2(),
7905
+ hostname: () => osHostname(),
7906
+ cwd: () => process.cwd(),
7907
+ now: () => new Date,
7908
+ env: () => process.env,
7909
+ resolveRepo: () => resolveRepo(),
7910
+ vinayaVersion: () => readVinayaVersion(),
7911
+ stderr: (message) => {
7912
+ process.stderr.write(message);
7913
+ },
7914
+ inputVersions: () => {
7915
+ return;
7916
+ }
7917
+ };
7918
+ }
7919
+ var APPEND_OPEN_FLAGS = fsConstants2.O_WRONLY | fsConstants2.O_APPEND | fsConstants2.O_CREAT | fsConstants2.O_NOFOLLOW | fsConstants2.O_NONBLOCK;
7920
+ function guardedAppendOpen(path) {
7921
+ try {
7922
+ return openSync2(path, APPEND_OPEN_FLAGS, 384);
7923
+ } catch {
7924
+ return;
7925
+ }
7926
+ }
7927
+ function reportRotationOverflow(backupPath, warn) {
7928
+ let raw;
7929
+ try {
7930
+ raw = readFileSync3(backupPath, "utf8");
7931
+ } catch {
7932
+ return;
7933
+ }
7934
+ const lines = raw.split(`
7935
+ `).filter((l) => l.length > 0);
7936
+ if (lines.length === 0)
7937
+ return;
7938
+ const droppedIdentities = lines.map((line, i) => {
7939
+ try {
7940
+ return recordIdentity(JSON.parse(line)) ?? `unreadable:${i}`;
7941
+ } catch {
7942
+ return `unreadable:${i}`;
7943
+ }
7944
+ });
7945
+ const diagnostic = { reason: "capacity", dropped: droppedIdentities.length, droppedIdentities };
7946
+ const shown = diagnostic.droppedIdentities.slice(0, 20);
7947
+ const more = diagnostic.dropped > shown.length ? `, +${diagnostic.dropped - shown.length} more` : "";
7948
+ warn(`vinaya: log outbox rotation is overwriting ${backupPath} — ${diagnostic.dropped} record(s) permanently lost: ${shown.join(", ")}${more}
7949
+ `);
7950
+ }
7951
+ function appendLine(path, line, warn) {
7952
+ try {
7953
+ mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
7954
+ let fd = guardedAppendOpen(path);
7955
+ if (fd === undefined) {
7956
+ warn(`vinaya: log outbox target could not be opened (symlink, FIFO, or unwritable) — refusing: ${path}
7957
+ `);
7958
+ return;
7959
+ }
7960
+ let closed = false;
7961
+ try {
7962
+ const stat = fstatSync2(fd);
7963
+ if (!stat.isFile()) {
7964
+ warn(`vinaya: log outbox target is not a regular file — refusing to write: ${path}
7965
+ `);
7966
+ return;
7967
+ }
7968
+ if (stat.size > OUTBOX_MAX_BYTES) {
7969
+ closeSync2(fd);
7970
+ closed = true;
7971
+ const backupPath = path.replace(/\.ndjson$/, ".1.ndjson");
7972
+ reportRotationOverflow(backupPath, warn);
7973
+ renameSync(path, backupPath);
7974
+ const rotated = guardedAppendOpen(path);
7975
+ if (rotated === undefined) {
7976
+ warn(`vinaya: log outbox target could not be reopened after rotation — refusing: ${path}
7977
+ `);
7978
+ return;
7979
+ }
7980
+ fd = rotated;
7981
+ closed = false;
7982
+ }
7983
+ writeSync(fd, line);
7984
+ } finally {
7985
+ if (!closed)
7986
+ closeSync2(fd);
7987
+ }
7988
+ } catch (err) {
7989
+ warn(`vinaya: log outbox write failed — ${err instanceof Error ? err.message : String(err)}
7990
+ `);
7991
+ }
7992
+ }
7993
+ function createLogSink(overrides = {}) {
7994
+ const deps = { ...defaultDeps(), ...overrides };
7995
+ const runId = deps.env().VINAYA_RUN_ID || randomUUID();
7996
+ const processId = randomUUID();
7997
+ let seq = 0;
7998
+ let warned = false;
7999
+ const warnOnce = (message) => {
8000
+ if (warned)
8001
+ return;
8002
+ warned = true;
8003
+ try {
8004
+ deps.stderr(message);
8005
+ } catch {}
8006
+ };
8007
+ let doctrineCache;
8008
+ const doctrine = () => {
8009
+ if (doctrineCache === undefined)
8010
+ doctrineCache = resolveDoctrine(deps.cwd(), deps.vinayaVersion());
8011
+ return doctrineCache;
8012
+ };
8013
+ let resolveRepoCache;
8014
+ const resolveRepoOnce = () => {
8015
+ if (resolveRepoCache === undefined)
8016
+ resolveRepoCache = deps.resolveRepo();
8017
+ return resolveRepoCache;
8018
+ };
8019
+ function log(e) {
8020
+ try {
8021
+ const env = deps.env();
8022
+ const host = hostFromEnv(env);
8023
+ const now = deps.now();
8024
+ const mySeq = seq++;
8025
+ resolveRepoOnce().then((resolved) => {
8026
+ const repo = resolved && isSafeRepoSegment(resolved.owner) && isSafeRepoSegment(resolved.repo) ? resolved : null;
8027
+ const header = buildHeader({
8028
+ now,
8029
+ runId,
8030
+ seq: mySeq,
8031
+ repo: repo ? `${repo.owner}/${repo.repo}` : null,
8032
+ vinaya: deps.vinayaVersion(),
8033
+ doctrine: doctrine(),
8034
+ host,
8035
+ hostname: deps.hostname(),
8036
+ env: {
8037
+ role: env.VINAYA_ROLE,
8038
+ task: env.VINAYA_TASK,
8039
+ round: env.VINAYA_ROUND,
8040
+ run: env.VINAYA_RUN,
8041
+ attempt: env.VINAYA_ATTEMPT,
8042
+ parent: env.VINAYA_PARENT_EVENT
8043
+ },
8044
+ eventId: randomUUID(),
8045
+ processId,
8046
+ inputVersions: deps.inputVersions()
8047
+ });
8048
+ const full = { ...e, ...header };
8049
+ const parsed = LogEventSchema.safeParse(full);
8050
+ if (!parsed.success) {
8051
+ warnOnce(`vinaya: log() refused an invalid payload — ${parsed.error.issues[0]?.message ?? "schema violation"}
8052
+ `);
8053
+ return;
8054
+ }
8055
+ const line = `${JSON.stringify(redact(parsed.data, deps.home()))}
8056
+ `;
8057
+ appendLine(outboxPathFor(deps, repo, header.subject.issue), line, warnOnce);
8058
+ }).catch((err) => {
8059
+ warnOnce(`vinaya: log() failed — ${err instanceof Error ? err.message : String(err)}
8060
+ `);
8061
+ });
8062
+ } catch (err) {
8063
+ warnOnce(`vinaya: log() failed — ${err instanceof Error ? err.message : String(err)}
8064
+ `);
8065
+ }
8066
+ }
8067
+ const warmup = () => {
8068
+ doctrine();
8069
+ const originalWarn = console.warn;
8070
+ console.warn = () => {};
8071
+ resolveRepoOnce().finally(() => {
8072
+ console.warn = originalWarn;
8073
+ });
8074
+ };
8075
+ return { log, runId, warmup };
8076
+ }
8077
+ var defaultSink = createLogSink();
8078
+
8079
+ // src/checks/runner.ts
8080
+ var activeChecks = new Map;
8081
+
8082
+ // src/lib/forge-write.ts
8083
+ var INFORMATIONAL_DISPATCH_BLOCKER_CLASSES = new Set([
8084
+ "depends-on-not-merged",
8085
+ "conflicts-with"
8086
+ ]);
8087
+
6176
8088
  // src/commands/review-post.ts
6177
8089
  function parseChangedLineRanges(diffOutput) {
6178
8090
  const result = {};
@@ -6204,7 +8116,7 @@ function parseChangedLineRanges(diffOutput) {
6204
8116
  function fileDiffAgainst(ref, path) {
6205
8117
  let out;
6206
8118
  try {
6207
- out = execFileSync4("git", ["diff", `${ref}...HEAD`, "--", path], {
8119
+ out = execFileSync6("git", ["diff", `${ref}...HEAD`, "--", path], {
6208
8120
  encoding: "utf8",
6209
8121
  stdio: ["ignore", "pipe", "pipe"]
6210
8122
  }).trim();
@@ -6215,7 +8127,7 @@ function fileDiffAgainst(ref, path) {
6215
8127
  }
6216
8128
  function revParse(ref) {
6217
8129
  try {
6218
- return execFileSync4("git", ["rev-parse", "--verify", ref], {
8130
+ return execFileSync6("git", ["rev-parse", "--verify", ref], {
6219
8131
  encoding: "utf8",
6220
8132
  stdio: ["ignore", "pipe", "pipe"]
6221
8133
  }).trim();
@@ -6225,7 +8137,7 @@ function revParse(ref) {
6225
8137
  }
6226
8138
  function repoRoot() {
6227
8139
  try {
6228
- return execFileSync4("git", ["rev-parse", "--show-toplevel"], {
8140
+ return execFileSync6("git", ["rev-parse", "--show-toplevel"], {
6229
8141
  encoding: "utf8",
6230
8142
  stdio: ["ignore", "pipe", "pipe"]
6231
8143
  }).trim();
@@ -6236,7 +8148,7 @@ function repoRoot() {
6236
8148
  function changedFiles(base) {
6237
8149
  let out;
6238
8150
  try {
6239
- out = execFileSync4("git", ["diff", "--name-only", `${base}...HEAD`], {
8151
+ out = execFileSync6("git", ["diff", "--name-only", `${base}...HEAD`], {
6240
8152
  encoding: "utf8",
6241
8153
  stdio: ["ignore", "pipe", "pipe"]
6242
8154
  }).trim();
@@ -6261,7 +8173,7 @@ function resolveDiff(base = process.env.BASE_SHA || "origin/main") {
6261
8173
  const relPaths = changedFiles(ref);
6262
8174
  if (relPaths === null)
6263
8175
  continue;
6264
- return { base: ref, root, files: relPaths.map((p) => join2(root, p)) };
8176
+ return { base: ref, root, files: relPaths.map((p) => join5(root, p)) };
6265
8177
  }
6266
8178
  return null;
6267
8179
  }
@@ -6295,15 +8207,15 @@ function findingsInThisDiff(findings) {
6295
8207
  // src/checks/bin/check-exec-bits.ts
6296
8208
  var CHECK_NAME = "exec-bits";
6297
8209
  var EXECUTABLE_MODE = "100755";
6298
- function git(args) {
8210
+ function git2(args) {
6299
8211
  try {
6300
- return execFileSync5("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
8212
+ return execFileSync7("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
6301
8213
  } catch {
6302
8214
  return null;
6303
8215
  }
6304
8216
  }
6305
8217
  function indexMode(path) {
6306
- const out = git(["ls-files", "-s", "--", path]);
8218
+ const out = git2(["ls-files", "-s", "--", path]);
6307
8219
  if (out === null || out === "")
6308
8220
  return null;
6309
8221
  const mode = out.split(/\s+/)[0] ?? "";
@@ -6311,7 +8223,7 @@ function indexMode(path) {
6311
8223
  }
6312
8224
  function hasShebang(path) {
6313
8225
  try {
6314
- return readFileSync3(path, "utf8").startsWith("#!");
8226
+ return readFileSync4(path, "utf8").startsWith("#!");
6315
8227
  } catch {
6316
8228
  return false;
6317
8229
  }