@attalabs/vinaya 0.21.0 → 0.22.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 (117) hide show
  1. package/README.md +3 -2
  2. package/aeg-root/enforcement.md +2 -1
  3. package/aeg-root/roles/archivist.md +1 -1
  4. package/aeg-root/roles/planner.md +1 -1
  5. package/aeg-root/templates/pr-report-template.md +2 -0
  6. package/aeg-root/tranche-model.md +3 -3
  7. package/dist/checks/bin/check-body-bare-digits.js +115 -9
  8. package/dist/checks/bin/check-branch-topology.js +111 -5
  9. package/dist/checks/bin/check-brief-shape.js +111 -5
  10. package/dist/checks/bin/check-changeset-coverage.js +113 -7
  11. package/dist/checks/bin/check-closes-n.js +111 -5
  12. package/dist/checks/bin/check-coherence.js +115 -9
  13. package/dist/checks/bin/check-dead-branch-push.js +111 -5
  14. package/dist/checks/bin/check-dispatch-readiness.js +116 -10
  15. package/dist/checks/bin/check-doc-coverage-push.js +116 -10
  16. package/dist/checks/bin/check-doc-coverage.js +116 -10
  17. package/dist/checks/bin/check-doctrine-portability.js +115 -9
  18. package/dist/checks/bin/check-evidence-fresh.js +111 -5
  19. package/dist/checks/bin/check-first-push-dispatch.js +113 -7
  20. package/dist/checks/bin/check-issue-assignment.js +111 -5
  21. package/dist/checks/bin/check-main-branch-refusal.js +111 -5
  22. package/dist/checks/bin/check-no-disk-state.js +111 -5
  23. package/dist/checks/bin/check-quoted-command.js +121 -12
  24. package/dist/checks/bin/check-reader-resolvable-prose.js +152 -20
  25. package/dist/checks/bin/check-registry-gates.js +131 -10
  26. package/dist/checks/bin/check-retired-vocabulary.js +144 -12
  27. package/dist/checks/bin/check-review-gate.js +113 -7
  28. package/dist/checks/bin/check-single-plan-pr.js +111 -5
  29. package/dist/checks/bin/check-test-plan.js +111 -5
  30. package/dist/checks/bin/check-token-collection-wired.js +113 -7
  31. package/dist/checks/bin/check-token-report.js +4096 -0
  32. package/dist/checks/bin/check-workspace-escape.js +113 -7
  33. package/dist/index.js +177 -104
  34. package/package.json +1 -1
  35. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  36. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  37. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  38. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  39. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  40. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  41. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  42. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  43. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  44. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  45. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  46. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  47. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  48. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  49. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  50. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  51. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  52. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  53. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  54. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  55. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  56. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  58. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  72. 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
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__02c71kv._.js +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0ozbaq0._.js → [root-of-the-server]__069-_41._.js} +1 -1
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0o54suy._.js +1 -1
  85. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1-6rzip._.js +1 -1
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1mrtj0f._.js +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_06it6s-._.js +1 -1
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_animate_components_index_ts_186fje1._.js +1 -1
  91. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_brutal_components_index_ts_0n_lcc4._.js +1 -1
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_retro_components_index_ts_0wvpm_z._.js +1 -1
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_retro_components_index_ts_1_cfi48._.js +1 -1
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  97. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  98. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/00pi8vhg8w6gi.js +1 -0
  99. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0r4i_ks9z02bw.js → 03q0q9n6-xah8.js} +1 -1
  100. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0vc2u252q5q6o.js +1 -0
  101. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1k916ih3p4nsg.js → 13g16cu00g570.js} +1 -1
  102. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1hufpuody6vjv.js +1 -0
  103. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2hmannd4bjhzy.js → 1sfxfunirkcr6.js} +1 -1
  104. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1t2kft7bxzuxn.js → 206ajg8f1a-_h.js} +1 -1
  105. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1hfhxjy577l5d.js → 267o-tsrnuwnv.js} +1 -1
  106. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{25kbt5k-xb2a5.js → 279qq4twinc97.js} +1 -1
  107. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{112g08xpx3kro.js → 2ka8dg687auhj.js} +1 -1
  108. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0up5x3jg-cwov.js → 2rn89uwtf2lwc.js} +1 -1
  109. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2_k6j1o9q5nn4.js → 37hnluhzj9bei.js} +1 -1
  110. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3mqu_uhluy19i.css → 3qc67qhcvbg0o.css} +1 -1
  111. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1yqs2zgvwa4p1.js → 3zugx9esh2x51.js} +1 -1
  112. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0_jnwbarv-cqk.js +0 -1
  113. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1ybrihl5_aocy.js +0 -1
  114. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/3r5efmleneaco.js +0 -1
  115. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → Fmyc42qzLwFcWWHLLNy-G}/_buildManifest.js +0 -0
  116. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → Fmyc42qzLwFcWWHLLNy-G}/_clientMiddlewareManifest.js +0 -0
  117. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → Fmyc42qzLwFcWWHLLNy-G}/_ssgManifest.js +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/checks/bin/check-coherence.ts
4
4
  import { execFile as execFile4, execFileSync as execFileSync3 } from "node:child_process";
5
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
5
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
6
6
  import { join as join2 } from "node:path";
7
7
  import { promisify as promisify4 } from "node:util";
8
8
  // ../../packages/aeg-core/src/gate-audience.ts
@@ -1794,6 +1794,99 @@ var DERIVED_STATUSES = [
1794
1794
  "incoherent"
1795
1795
  ];
1796
1796
  var DERIVABLE_STATUSES = DERIVED_STATUSES.filter((s) => s !== "backlog");
1797
+ // ../../packages/aeg-core/src/parse-ledger.ts
1798
+ function rowFromCells(cells) {
1799
+ if (cells.length < 7)
1800
+ return null;
1801
+ const phase = (cells[0] ?? "").trim();
1802
+ if (!phase)
1803
+ return null;
1804
+ return {
1805
+ phase,
1806
+ role: (cells[1] ?? "").trim(),
1807
+ agentModel: (cells[2] ?? "").trim(),
1808
+ tokensIn: parseIntCell(cells[3] ?? ""),
1809
+ tokensOut: parseIntCell(cells[4] ?? ""),
1810
+ cost: parseCostCell(cells[5] ?? ""),
1811
+ date: (cells[6] ?? "").trim()
1812
+ };
1813
+ }
1814
+ function parseIntCell(cell) {
1815
+ const trimmed = cell.replace(/`/g, "").trim();
1816
+ if (!trimmed || isEmDashOrDash(trimmed))
1817
+ return null;
1818
+ const normalized = trimmed.replace(/[,_\s]/g, "");
1819
+ if (!/^-?\d+$/.test(normalized))
1820
+ return null;
1821
+ return Number(normalized);
1822
+ }
1823
+ function parseCostCell(cell) {
1824
+ const trimmed = cell.replace(/`/g, "").trim();
1825
+ if (!trimmed || isEmDashOrDash(trimmed))
1826
+ return null;
1827
+ const normalized = trimmed.replace(/^\$/, "").replace(/[,_\s]/g, "");
1828
+ if (!/^-?\d+(\.\d+)?$/.test(normalized))
1829
+ return null;
1830
+ return Number(normalized);
1831
+ }
1832
+ function isEmDashOrDash(s) {
1833
+ const t = s.trim();
1834
+ return t === "—" || t === "-" || t === "–";
1835
+ }
1836
+ // ../../packages/aeg-core/src/parse-token-report.ts
1837
+ var TOKEN_REPORT_HEADING = /^\s*(?:#{1,6}\s*Token report\s*|\*\*Token report\*\*)\s*$/i;
1838
+ var INLINE_FIELD_LIST = /Phase:\s*([^|]+?)\s*\|\s*Role:\s*([^|]+?)\s*\|\s*Agent\/Model:\s*([^|]+?)\s*\|\s*Tokens in:\s*([^|]+?)\s*\|\s*Tokens out:\s*([^|]+?)\s*\|\s*Cost:\s*([^|]+?)\s*\|\s*Date:\s*(.+?)\s*$/im;
1839
+ function parseTokenReportEntries(body) {
1840
+ const lines = body.split(/\r?\n/);
1841
+ const headingIdxs = [];
1842
+ lines.forEach((line, i) => {
1843
+ if (TOKEN_REPORT_HEADING.test(line))
1844
+ headingIdxs.push(i);
1845
+ });
1846
+ const out = [];
1847
+ for (let h = 0;h < headingIdxs.length; h++) {
1848
+ const start = headingIdxs[h] + 1;
1849
+ const end = h + 1 < headingIdxs.length ? headingIdxs[h + 1] : lines.length;
1850
+ const section = lines.slice(start, end).join(`
1851
+ `);
1852
+ const tableRows = parseTableSection(section);
1853
+ if (tableRows.length > 0) {
1854
+ out.push(...tableRows);
1855
+ continue;
1856
+ }
1857
+ const inlineRow = parseInlineFieldList(section);
1858
+ if (inlineRow)
1859
+ out.push(inlineRow);
1860
+ }
1861
+ return out;
1862
+ }
1863
+ function parseTableSection(section) {
1864
+ const lines = section.split(/\r?\n/);
1865
+ let i = 0;
1866
+ for (;i < lines.length; i++) {
1867
+ if ((lines[i] ?? "").trim().startsWith("|"))
1868
+ break;
1869
+ }
1870
+ if (i + 1 >= lines.length)
1871
+ return [];
1872
+ i += 2;
1873
+ const out = [];
1874
+ for (;i < lines.length; i++) {
1875
+ const trimmed = (lines[i] ?? "").trim();
1876
+ if (!trimmed.startsWith("|"))
1877
+ break;
1878
+ const row = rowFromCells(splitTableRow(trimmed));
1879
+ if (row)
1880
+ out.push(row);
1881
+ }
1882
+ return out;
1883
+ }
1884
+ function parseInlineFieldList(section) {
1885
+ const m = section.match(INLINE_FIELD_LIST);
1886
+ if (!m)
1887
+ return null;
1888
+ return rowFromCells([m[1], m[2], m[3], m[4], m[5], m[6], m[7]]);
1889
+ }
1797
1890
  // ../../packages/aeg-core/src/report-tokens.ts
1798
1891
  var DASH_LOOKALIKES = {
1799
1892
  "-": "‑",
@@ -1802,6 +1895,7 @@ var DASH_LOOKALIKES = {
1802
1895
  };
1803
1896
  var DASH_CHARS = new Set(Object.keys(DASH_LOOKALIKES));
1804
1897
  // ../../packages/aeg-core/src/claude-code-transcript.ts
1898
+ import { createHash } from "node:crypto";
1805
1899
  function summarizeTranscript(jsonl) {
1806
1900
  const seen = new Set;
1807
1901
  const components = {
@@ -1850,7 +1944,14 @@ function numberOr(value, fallback) {
1850
1944
  function sanitizeKey(value) {
1851
1945
  return value.replace(/[^A-Za-z0-9]+/g, "-");
1852
1946
  }
1947
+ function collisionResistantKey(value) {
1948
+ const digest = createHash("sha256").update(value).digest("hex");
1949
+ return `${sanitizeKey(value)}-${digest}`;
1950
+ }
1853
1951
  function transcriptPointerPath(projectDir, tmpDir) {
1952
+ return `${tmpDir}/claude-transcript-${collisionResistantKey(projectDir)}.txt`;
1953
+ }
1954
+ function legacyTranscriptPointerPath(projectDir, tmpDir) {
1854
1955
  return `${tmpDir}/claude-transcript-${sanitizeKey(projectDir)}.txt`;
1855
1956
  }
1856
1957
  function resolvePointer(explicitTranscriptPath, deps) {
@@ -1858,13 +1959,15 @@ function resolvePointer(explicitTranscriptPath, deps) {
1858
1959
  return { path: explicitTranscriptPath, corroborated: true };
1859
1960
  const projectDir = deps.env.CLAUDE_PROJECT_DIR ?? deps.cwd;
1860
1961
  const tmpDir = deps.env.TMPDIR ?? "/tmp";
1861
- const pointerPath = transcriptPointerPath(projectDir, tmpDir);
1962
+ const primaryPointerPath = transcriptPointerPath(projectDir, tmpDir);
1963
+ const legacyPointerPath = legacyTranscriptPointerPath(projectDir, tmpDir);
1862
1964
  const currentSessionId = deps.env.CLAUDE_CODE_SESSION_ID;
1863
- if (!deps.exists(pointerPath)) {
1965
+ const pointerPath = deps.exists(primaryPointerPath) ? primaryPointerPath : deps.exists(legacyPointerPath) ? legacyPointerPath : undefined;
1966
+ if (!pointerPath) {
1864
1967
  return {
1865
1968
  pointerExisted: false,
1866
1969
  corroborated: false,
1867
- error: `No transcript pointer at ${pointerPath} and no --transcript given. ` + "Either this repo installs no track-transcript.sh Stop hook (lacking one is not a defect — " + "name the transcript directly instead), or no session has completed a turn yet."
1970
+ error: `No transcript pointer at ${primaryPointerPath} (nor its pre-migration name ${legacyPointerPath}) ` + "and no --transcript given. Either this repo installs no track-transcript.sh Stop hook (lacking one " + "is not a defect — name the transcript directly instead), or no session has completed a turn yet."
1868
1971
  };
1869
1972
  }
1870
1973
  let contents;
@@ -1939,6 +2042,9 @@ function isTokenCollectionWiringBroken(capability) {
1939
2042
  return false;
1940
2043
  return capability.reason !== "no-transcript-resolved";
1941
2044
  }
2045
+ // ../../packages/aeg-core/src/metering-io-guard.ts
2046
+ import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
2047
+ var GUARD_OPEN_FLAGS = fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | fsConstants.O_NOFOLLOW;
1942
2048
  // ../../packages/aeg-core/src/file-classify.ts
1943
2049
  function isCodeFile(p) {
1944
2050
  if (p.endsWith(".md"))
@@ -2145,7 +2251,7 @@ function overrideActive(opts) {
2145
2251
  return false;
2146
2252
  }
2147
2253
  // ../../packages/aeg-core/src/premise-check.ts
2148
- import { createHash } from "node:crypto";
2254
+ import { createHash as createHash2 } from "node:crypto";
2149
2255
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
2150
2256
  function isPremiseHeader(line) {
2151
2257
  const stripped = line.replace(/[*#]/g, "").trim();
@@ -2190,7 +2296,7 @@ function checkPremises(assertions, fileReader) {
2190
2296
  } else if (a.kind === "absent" && content.includes(a.value)) {
2191
2297
  failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
2192
2298
  } else if (a.kind === "sha256") {
2193
- const actual = createHash("sha256").update(content).digest("hex");
2299
+ const actual = createHash2("sha256").update(content).digest("hex");
2194
2300
  if (actual !== a.value.toLowerCase()) {
2195
2301
  failures.push(`premise-check: ${a.path} sha256 mismatch (brief pinned ${a.value}, file is now ${actual}) — the file changed since this brief was authored; re-dig before proceeding.`);
2196
2302
  }
@@ -4378,7 +4484,7 @@ function emitCheckError(error) {
4378
4484
 
4379
4485
  // src/lib/config.ts
4380
4486
  import { execFileSync as execFileSync2 } from "node:child_process";
4381
- import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
4487
+ import { existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "node:fs";
4382
4488
  import { homedir } from "node:os";
4383
4489
  import { dirname, join, resolve } from "node:path";
4384
4490
  import { z as z2 } from "zod";
@@ -4671,7 +4777,7 @@ function loadConfig() {
4671
4777
  if (!path)
4672
4778
  return null;
4673
4779
  try {
4674
- const raw = JSON.parse(readFileSync(path, "utf-8"));
4780
+ const raw = JSON.parse(readFileSync2(path, "utf-8"));
4675
4781
  return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
4676
4782
  } catch {
4677
4783
  return null;
@@ -4696,7 +4802,7 @@ function readRegisteredProjectNames() {
4696
4802
  const path = join2(root, ".vinaya/projects.md");
4697
4803
  if (!existsSync2(path))
4698
4804
  return [];
4699
- return parseRegistry(readFileSync2(path, "utf8")).map((p) => p.name);
4805
+ return parseRegistry(readFileSync3(path, "utf8")).map((p) => p.name);
4700
4806
  }
4701
4807
  function resolveRepo2() {
4702
4808
  const fromEnv = process.env.AEG_REPO;
@@ -1791,6 +1791,99 @@ var DERIVED_STATUSES = [
1791
1791
  "incoherent"
1792
1792
  ];
1793
1793
  var DERIVABLE_STATUSES = DERIVED_STATUSES.filter((s) => s !== "backlog");
1794
+ // ../../packages/aeg-core/src/parse-ledger.ts
1795
+ function rowFromCells(cells) {
1796
+ if (cells.length < 7)
1797
+ return null;
1798
+ const phase = (cells[0] ?? "").trim();
1799
+ if (!phase)
1800
+ return null;
1801
+ return {
1802
+ phase,
1803
+ role: (cells[1] ?? "").trim(),
1804
+ agentModel: (cells[2] ?? "").trim(),
1805
+ tokensIn: parseIntCell(cells[3] ?? ""),
1806
+ tokensOut: parseIntCell(cells[4] ?? ""),
1807
+ cost: parseCostCell(cells[5] ?? ""),
1808
+ date: (cells[6] ?? "").trim()
1809
+ };
1810
+ }
1811
+ function parseIntCell(cell) {
1812
+ const trimmed = cell.replace(/`/g, "").trim();
1813
+ if (!trimmed || isEmDashOrDash(trimmed))
1814
+ return null;
1815
+ const normalized = trimmed.replace(/[,_\s]/g, "");
1816
+ if (!/^-?\d+$/.test(normalized))
1817
+ return null;
1818
+ return Number(normalized);
1819
+ }
1820
+ function parseCostCell(cell) {
1821
+ const trimmed = cell.replace(/`/g, "").trim();
1822
+ if (!trimmed || isEmDashOrDash(trimmed))
1823
+ return null;
1824
+ const normalized = trimmed.replace(/^\$/, "").replace(/[,_\s]/g, "");
1825
+ if (!/^-?\d+(\.\d+)?$/.test(normalized))
1826
+ return null;
1827
+ return Number(normalized);
1828
+ }
1829
+ function isEmDashOrDash(s) {
1830
+ const t = s.trim();
1831
+ return t === "—" || t === "-" || t === "–";
1832
+ }
1833
+ // ../../packages/aeg-core/src/parse-token-report.ts
1834
+ var TOKEN_REPORT_HEADING = /^\s*(?:#{1,6}\s*Token report\s*|\*\*Token report\*\*)\s*$/i;
1835
+ var INLINE_FIELD_LIST = /Phase:\s*([^|]+?)\s*\|\s*Role:\s*([^|]+?)\s*\|\s*Agent\/Model:\s*([^|]+?)\s*\|\s*Tokens in:\s*([^|]+?)\s*\|\s*Tokens out:\s*([^|]+?)\s*\|\s*Cost:\s*([^|]+?)\s*\|\s*Date:\s*(.+?)\s*$/im;
1836
+ function parseTokenReportEntries(body) {
1837
+ const lines = body.split(/\r?\n/);
1838
+ const headingIdxs = [];
1839
+ lines.forEach((line, i) => {
1840
+ if (TOKEN_REPORT_HEADING.test(line))
1841
+ headingIdxs.push(i);
1842
+ });
1843
+ const out = [];
1844
+ for (let h = 0;h < headingIdxs.length; h++) {
1845
+ const start = headingIdxs[h] + 1;
1846
+ const end = h + 1 < headingIdxs.length ? headingIdxs[h + 1] : lines.length;
1847
+ const section = lines.slice(start, end).join(`
1848
+ `);
1849
+ const tableRows = parseTableSection(section);
1850
+ if (tableRows.length > 0) {
1851
+ out.push(...tableRows);
1852
+ continue;
1853
+ }
1854
+ const inlineRow = parseInlineFieldList(section);
1855
+ if (inlineRow)
1856
+ out.push(inlineRow);
1857
+ }
1858
+ return out;
1859
+ }
1860
+ function parseTableSection(section) {
1861
+ const lines = section.split(/\r?\n/);
1862
+ let i = 0;
1863
+ for (;i < lines.length; i++) {
1864
+ if ((lines[i] ?? "").trim().startsWith("|"))
1865
+ break;
1866
+ }
1867
+ if (i + 1 >= lines.length)
1868
+ return [];
1869
+ i += 2;
1870
+ const out = [];
1871
+ for (;i < lines.length; i++) {
1872
+ const trimmed = (lines[i] ?? "").trim();
1873
+ if (!trimmed.startsWith("|"))
1874
+ break;
1875
+ const row = rowFromCells(splitTableRow(trimmed));
1876
+ if (row)
1877
+ out.push(row);
1878
+ }
1879
+ return out;
1880
+ }
1881
+ function parseInlineFieldList(section) {
1882
+ const m = section.match(INLINE_FIELD_LIST);
1883
+ if (!m)
1884
+ return null;
1885
+ return rowFromCells([m[1], m[2], m[3], m[4], m[5], m[6], m[7]]);
1886
+ }
1794
1887
  // ../../packages/aeg-core/src/report-tokens.ts
1795
1888
  var DASH_LOOKALIKES = {
1796
1889
  "-": "‑",
@@ -1799,6 +1892,7 @@ var DASH_LOOKALIKES = {
1799
1892
  };
1800
1893
  var DASH_CHARS = new Set(Object.keys(DASH_LOOKALIKES));
1801
1894
  // ../../packages/aeg-core/src/claude-code-transcript.ts
1895
+ import { createHash } from "node:crypto";
1802
1896
  function summarizeTranscript(jsonl) {
1803
1897
  const seen = new Set;
1804
1898
  const components = {
@@ -1847,7 +1941,14 @@ function numberOr(value, fallback) {
1847
1941
  function sanitizeKey(value) {
1848
1942
  return value.replace(/[^A-Za-z0-9]+/g, "-");
1849
1943
  }
1944
+ function collisionResistantKey(value) {
1945
+ const digest = createHash("sha256").update(value).digest("hex");
1946
+ return `${sanitizeKey(value)}-${digest}`;
1947
+ }
1850
1948
  function transcriptPointerPath(projectDir, tmpDir) {
1949
+ return `${tmpDir}/claude-transcript-${collisionResistantKey(projectDir)}.txt`;
1950
+ }
1951
+ function legacyTranscriptPointerPath(projectDir, tmpDir) {
1851
1952
  return `${tmpDir}/claude-transcript-${sanitizeKey(projectDir)}.txt`;
1852
1953
  }
1853
1954
  function resolvePointer(explicitTranscriptPath, deps) {
@@ -1855,13 +1956,15 @@ function resolvePointer(explicitTranscriptPath, deps) {
1855
1956
  return { path: explicitTranscriptPath, corroborated: true };
1856
1957
  const projectDir = deps.env.CLAUDE_PROJECT_DIR ?? deps.cwd;
1857
1958
  const tmpDir = deps.env.TMPDIR ?? "/tmp";
1858
- const pointerPath = transcriptPointerPath(projectDir, tmpDir);
1959
+ const primaryPointerPath = transcriptPointerPath(projectDir, tmpDir);
1960
+ const legacyPointerPath = legacyTranscriptPointerPath(projectDir, tmpDir);
1859
1961
  const currentSessionId = deps.env.CLAUDE_CODE_SESSION_ID;
1860
- if (!deps.exists(pointerPath)) {
1962
+ const pointerPath = deps.exists(primaryPointerPath) ? primaryPointerPath : deps.exists(legacyPointerPath) ? legacyPointerPath : undefined;
1963
+ if (!pointerPath) {
1861
1964
  return {
1862
1965
  pointerExisted: false,
1863
1966
  corroborated: false,
1864
- error: `No transcript pointer at ${pointerPath} and no --transcript given. ` + "Either this repo installs no track-transcript.sh Stop hook (lacking one is not a defect — " + "name the transcript directly instead), or no session has completed a turn yet."
1967
+ error: `No transcript pointer at ${primaryPointerPath} (nor its pre-migration name ${legacyPointerPath}) ` + "and no --transcript given. Either this repo installs no track-transcript.sh Stop hook (lacking one " + "is not a defect — name the transcript directly instead), or no session has completed a turn yet."
1865
1968
  };
1866
1969
  }
1867
1970
  let contents;
@@ -1936,6 +2039,9 @@ function isTokenCollectionWiringBroken(capability) {
1936
2039
  return false;
1937
2040
  return capability.reason !== "no-transcript-resolved";
1938
2041
  }
2042
+ // ../../packages/aeg-core/src/metering-io-guard.ts
2043
+ import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
2044
+ var GUARD_OPEN_FLAGS = fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | fsConstants.O_NOFOLLOW;
1939
2045
  // ../../packages/aeg-core/src/file-classify.ts
1940
2046
  function isCodeFile(p) {
1941
2047
  if (p.endsWith(".md"))
@@ -2142,7 +2248,7 @@ function overrideActive(opts) {
2142
2248
  return false;
2143
2249
  }
2144
2250
  // ../../packages/aeg-core/src/premise-check.ts
2145
- import { createHash } from "node:crypto";
2251
+ import { createHash as createHash2 } from "node:crypto";
2146
2252
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
2147
2253
  function isPremiseHeader(line) {
2148
2254
  const stripped = line.replace(/[*#]/g, "").trim();
@@ -2187,7 +2293,7 @@ function checkPremises(assertions, fileReader) {
2187
2293
  } else if (a.kind === "absent" && content.includes(a.value)) {
2188
2294
  failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
2189
2295
  } else if (a.kind === "sha256") {
2190
- const actual = createHash("sha256").update(content).digest("hex");
2296
+ const actual = createHash2("sha256").update(content).digest("hex");
2191
2297
  if (actual !== a.value.toLowerCase()) {
2192
2298
  failures.push(`premise-check: ${a.path} sha256 mismatch (brief pinned ${a.value}, file is now ${actual}) — the file changed since this brief was authored; re-dig before proceeding.`);
2193
2299
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/checks/bin/check-dispatch-readiness.ts
4
4
  import { execFile as execFile4, execFileSync as execFileSync4 } from "node:child_process";
5
- import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "node:fs";
5
+ import { existsSync as existsSync2, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
6
6
  import { sep as sep2 } from "node:path";
7
7
  import { promisify as promisify4 } from "node:util";
8
8
  // ../../packages/aeg-core/src/gate-audience.ts
@@ -1794,6 +1794,99 @@ var DERIVED_STATUSES = [
1794
1794
  "incoherent"
1795
1795
  ];
1796
1796
  var DERIVABLE_STATUSES = DERIVED_STATUSES.filter((s) => s !== "backlog");
1797
+ // ../../packages/aeg-core/src/parse-ledger.ts
1798
+ function rowFromCells(cells) {
1799
+ if (cells.length < 7)
1800
+ return null;
1801
+ const phase = (cells[0] ?? "").trim();
1802
+ if (!phase)
1803
+ return null;
1804
+ return {
1805
+ phase,
1806
+ role: (cells[1] ?? "").trim(),
1807
+ agentModel: (cells[2] ?? "").trim(),
1808
+ tokensIn: parseIntCell(cells[3] ?? ""),
1809
+ tokensOut: parseIntCell(cells[4] ?? ""),
1810
+ cost: parseCostCell(cells[5] ?? ""),
1811
+ date: (cells[6] ?? "").trim()
1812
+ };
1813
+ }
1814
+ function parseIntCell(cell) {
1815
+ const trimmed = cell.replace(/`/g, "").trim();
1816
+ if (!trimmed || isEmDashOrDash(trimmed))
1817
+ return null;
1818
+ const normalized = trimmed.replace(/[,_\s]/g, "");
1819
+ if (!/^-?\d+$/.test(normalized))
1820
+ return null;
1821
+ return Number(normalized);
1822
+ }
1823
+ function parseCostCell(cell) {
1824
+ const trimmed = cell.replace(/`/g, "").trim();
1825
+ if (!trimmed || isEmDashOrDash(trimmed))
1826
+ return null;
1827
+ const normalized = trimmed.replace(/^\$/, "").replace(/[,_\s]/g, "");
1828
+ if (!/^-?\d+(\.\d+)?$/.test(normalized))
1829
+ return null;
1830
+ return Number(normalized);
1831
+ }
1832
+ function isEmDashOrDash(s) {
1833
+ const t = s.trim();
1834
+ return t === "—" || t === "-" || t === "–";
1835
+ }
1836
+ // ../../packages/aeg-core/src/parse-token-report.ts
1837
+ var TOKEN_REPORT_HEADING = /^\s*(?:#{1,6}\s*Token report\s*|\*\*Token report\*\*)\s*$/i;
1838
+ var INLINE_FIELD_LIST = /Phase:\s*([^|]+?)\s*\|\s*Role:\s*([^|]+?)\s*\|\s*Agent\/Model:\s*([^|]+?)\s*\|\s*Tokens in:\s*([^|]+?)\s*\|\s*Tokens out:\s*([^|]+?)\s*\|\s*Cost:\s*([^|]+?)\s*\|\s*Date:\s*(.+?)\s*$/im;
1839
+ function parseTokenReportEntries(body) {
1840
+ const lines = body.split(/\r?\n/);
1841
+ const headingIdxs = [];
1842
+ lines.forEach((line, i) => {
1843
+ if (TOKEN_REPORT_HEADING.test(line))
1844
+ headingIdxs.push(i);
1845
+ });
1846
+ const out = [];
1847
+ for (let h = 0;h < headingIdxs.length; h++) {
1848
+ const start = headingIdxs[h] + 1;
1849
+ const end = h + 1 < headingIdxs.length ? headingIdxs[h + 1] : lines.length;
1850
+ const section = lines.slice(start, end).join(`
1851
+ `);
1852
+ const tableRows = parseTableSection(section);
1853
+ if (tableRows.length > 0) {
1854
+ out.push(...tableRows);
1855
+ continue;
1856
+ }
1857
+ const inlineRow = parseInlineFieldList(section);
1858
+ if (inlineRow)
1859
+ out.push(inlineRow);
1860
+ }
1861
+ return out;
1862
+ }
1863
+ function parseTableSection(section) {
1864
+ const lines = section.split(/\r?\n/);
1865
+ let i = 0;
1866
+ for (;i < lines.length; i++) {
1867
+ if ((lines[i] ?? "").trim().startsWith("|"))
1868
+ break;
1869
+ }
1870
+ if (i + 1 >= lines.length)
1871
+ return [];
1872
+ i += 2;
1873
+ const out = [];
1874
+ for (;i < lines.length; i++) {
1875
+ const trimmed = (lines[i] ?? "").trim();
1876
+ if (!trimmed.startsWith("|"))
1877
+ break;
1878
+ const row = rowFromCells(splitTableRow(trimmed));
1879
+ if (row)
1880
+ out.push(row);
1881
+ }
1882
+ return out;
1883
+ }
1884
+ function parseInlineFieldList(section) {
1885
+ const m = section.match(INLINE_FIELD_LIST);
1886
+ if (!m)
1887
+ return null;
1888
+ return rowFromCells([m[1], m[2], m[3], m[4], m[5], m[6], m[7]]);
1889
+ }
1797
1890
  // ../../packages/aeg-core/src/report-tokens.ts
1798
1891
  var DASH_LOOKALIKES = {
1799
1892
  "-": "‑",
@@ -1802,6 +1895,7 @@ var DASH_LOOKALIKES = {
1802
1895
  };
1803
1896
  var DASH_CHARS = new Set(Object.keys(DASH_LOOKALIKES));
1804
1897
  // ../../packages/aeg-core/src/claude-code-transcript.ts
1898
+ import { createHash } from "node:crypto";
1805
1899
  function summarizeTranscript(jsonl) {
1806
1900
  const seen = new Set;
1807
1901
  const components = {
@@ -1850,7 +1944,14 @@ function numberOr(value, fallback) {
1850
1944
  function sanitizeKey(value) {
1851
1945
  return value.replace(/[^A-Za-z0-9]+/g, "-");
1852
1946
  }
1947
+ function collisionResistantKey(value) {
1948
+ const digest = createHash("sha256").update(value).digest("hex");
1949
+ return `${sanitizeKey(value)}-${digest}`;
1950
+ }
1853
1951
  function transcriptPointerPath(projectDir, tmpDir) {
1952
+ return `${tmpDir}/claude-transcript-${collisionResistantKey(projectDir)}.txt`;
1953
+ }
1954
+ function legacyTranscriptPointerPath(projectDir, tmpDir) {
1854
1955
  return `${tmpDir}/claude-transcript-${sanitizeKey(projectDir)}.txt`;
1855
1956
  }
1856
1957
  function resolvePointer(explicitTranscriptPath, deps) {
@@ -1858,13 +1959,15 @@ function resolvePointer(explicitTranscriptPath, deps) {
1858
1959
  return { path: explicitTranscriptPath, corroborated: true };
1859
1960
  const projectDir = deps.env.CLAUDE_PROJECT_DIR ?? deps.cwd;
1860
1961
  const tmpDir = deps.env.TMPDIR ?? "/tmp";
1861
- const pointerPath = transcriptPointerPath(projectDir, tmpDir);
1962
+ const primaryPointerPath = transcriptPointerPath(projectDir, tmpDir);
1963
+ const legacyPointerPath = legacyTranscriptPointerPath(projectDir, tmpDir);
1862
1964
  const currentSessionId = deps.env.CLAUDE_CODE_SESSION_ID;
1863
- if (!deps.exists(pointerPath)) {
1965
+ const pointerPath = deps.exists(primaryPointerPath) ? primaryPointerPath : deps.exists(legacyPointerPath) ? legacyPointerPath : undefined;
1966
+ if (!pointerPath) {
1864
1967
  return {
1865
1968
  pointerExisted: false,
1866
1969
  corroborated: false,
1867
- error: `No transcript pointer at ${pointerPath} and no --transcript given. ` + "Either this repo installs no track-transcript.sh Stop hook (lacking one is not a defect — " + "name the transcript directly instead), or no session has completed a turn yet."
1970
+ error: `No transcript pointer at ${primaryPointerPath} (nor its pre-migration name ${legacyPointerPath}) ` + "and no --transcript given. Either this repo installs no track-transcript.sh Stop hook (lacking one " + "is not a defect — name the transcript directly instead), or no session has completed a turn yet."
1868
1971
  };
1869
1972
  }
1870
1973
  let contents;
@@ -1939,6 +2042,9 @@ function isTokenCollectionWiringBroken(capability) {
1939
2042
  return false;
1940
2043
  return capability.reason !== "no-transcript-resolved";
1941
2044
  }
2045
+ // ../../packages/aeg-core/src/metering-io-guard.ts
2046
+ import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
2047
+ var GUARD_OPEN_FLAGS = fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | fsConstants.O_NOFOLLOW;
1942
2048
  // ../../packages/aeg-core/src/file-classify.ts
1943
2049
  function isCodeFile(p) {
1944
2050
  if (p.endsWith(".md"))
@@ -2145,7 +2251,7 @@ function overrideActive(opts) {
2145
2251
  return false;
2146
2252
  }
2147
2253
  // ../../packages/aeg-core/src/premise-check.ts
2148
- import { createHash } from "node:crypto";
2254
+ import { createHash as createHash2 } from "node:crypto";
2149
2255
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
2150
2256
  function isPremiseHeader(line) {
2151
2257
  const stripped = line.replace(/[*#]/g, "").trim();
@@ -2190,7 +2296,7 @@ function checkPremises(assertions, fileReader) {
2190
2296
  } else if (a.kind === "absent" && content.includes(a.value)) {
2191
2297
  failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
2192
2298
  } else if (a.kind === "sha256") {
2193
- const actual = createHash("sha256").update(content).digest("hex");
2299
+ const actual = createHash2("sha256").update(content).digest("hex");
2194
2300
  if (actual !== a.value.toLowerCase()) {
2195
2301
  failures.push(`premise-check: ${a.path} sha256 mismatch (brief pinned ${a.value}, file is now ${actual}) — the file changed since this brief was authored; re-dig before proceeding.`);
2196
2302
  }
@@ -4378,7 +4484,7 @@ function emitCheckError(error) {
4378
4484
 
4379
4485
  // src/lib/config.ts
4380
4486
  import { execFileSync as execFileSync2 } from "node:child_process";
4381
- import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
4487
+ import { existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "node:fs";
4382
4488
  import { homedir } from "node:os";
4383
4489
  import { dirname, join, resolve } from "node:path";
4384
4490
  import { z as z2 } from "zod";
@@ -4671,7 +4777,7 @@ function loadConfig() {
4671
4777
  if (!path)
4672
4778
  return null;
4673
4779
  try {
4674
- const raw = JSON.parse(readFileSync(path, "utf-8"));
4780
+ const raw = JSON.parse(readFileSync2(path, "utf-8"));
4675
4781
  return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
4676
4782
  } catch {
4677
4783
  return null;
@@ -4910,13 +5016,13 @@ function checkPremiseReassertion() {
4910
5016
  const premiseFile = process.env.PREMISE_FILE;
4911
5017
  if (!premiseFile)
4912
5018
  return true;
4913
- const body = existsSync2(premiseFile) ? readFileSync2(premiseFile, "utf8") : null;
5019
+ const body = existsSync2(premiseFile) ? readFileSync3(premiseFile, "utf8") : null;
4914
5020
  const result = reassertPremiseFile(CHECK_NAME, premiseFile, body, (p) => {
4915
5021
  const real = containedRealPath(process.cwd(), p);
4916
5022
  if (real === null)
4917
5023
  return null;
4918
5024
  try {
4919
- return readFileSync2(real, "utf8");
5025
+ return readFileSync3(real, "utf8");
4920
5026
  } catch {
4921
5027
  return null;
4922
5028
  }