@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
package/dist/index.js CHANGED
@@ -801,11 +801,16 @@ var DASH_LOOKALIKES = {
801
801
  "—": "―"
802
802
  };
803
803
  var DASH_CHARS = new Set(Object.keys(DASH_LOOKALIKES));
804
+ var PIPE_LOOKALIKE = "|";
804
805
  function sanitizeForTokensLine(value) {
805
806
  const stripped = stripNewlines(value);
806
807
  let result = "";
807
808
  for (let i = 0;i < stripped.length; i++) {
808
809
  const ch = stripped[i];
810
+ if (ch === "|") {
811
+ result += PIPE_LOOKALIKE;
812
+ continue;
813
+ }
809
814
  if (DASH_CHARS.has(ch)) {
810
815
  const leftReachable = i === 0 || /\s/.test(stripped[i - 1]);
811
816
  const rightReachable = i === stripped.length - 1 || /\s/.test(stripped[i + 1]);
@@ -857,6 +862,7 @@ function formatBreakdown(summary) {
857
862
  `);
858
863
  }
859
864
  // ../../packages/aeg-core/src/claude-code-transcript.ts
865
+ import { createHash } from "node:crypto";
860
866
  function summarizeTranscript(jsonl) {
861
867
  const seen = new Set;
862
868
  const components = {
@@ -905,7 +911,14 @@ function numberOr(value, fallback) {
905
911
  function sanitizeKey(value) {
906
912
  return value.replace(/[^A-Za-z0-9]+/g, "-");
907
913
  }
914
+ function collisionResistantKey(value) {
915
+ const digest = createHash("sha256").update(value).digest("hex");
916
+ return `${sanitizeKey(value)}-${digest}`;
917
+ }
908
918
  function transcriptPointerPath(projectDir, tmpDir) {
919
+ return `${tmpDir}/claude-transcript-${collisionResistantKey(projectDir)}.txt`;
920
+ }
921
+ function legacyTranscriptPointerPath(projectDir, tmpDir) {
909
922
  return `${tmpDir}/claude-transcript-${sanitizeKey(projectDir)}.txt`;
910
923
  }
911
924
  function resolvePointer(explicitTranscriptPath, deps) {
@@ -913,13 +926,15 @@ function resolvePointer(explicitTranscriptPath, deps) {
913
926
  return { path: explicitTranscriptPath, corroborated: true };
914
927
  const projectDir = deps.env.CLAUDE_PROJECT_DIR ?? deps.cwd;
915
928
  const tmpDir = deps.env.TMPDIR ?? "/tmp";
916
- const pointerPath = transcriptPointerPath(projectDir, tmpDir);
929
+ const primaryPointerPath = transcriptPointerPath(projectDir, tmpDir);
930
+ const legacyPointerPath = legacyTranscriptPointerPath(projectDir, tmpDir);
917
931
  const currentSessionId = deps.env.CLAUDE_CODE_SESSION_ID;
918
- if (!deps.exists(pointerPath)) {
932
+ const pointerPath = deps.exists(primaryPointerPath) ? primaryPointerPath : deps.exists(legacyPointerPath) ? legacyPointerPath : undefined;
933
+ if (!pointerPath) {
919
934
  return {
920
935
  pointerExisted: false,
921
936
  corroborated: false,
922
- 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."
937
+ 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."
923
938
  };
924
939
  }
925
940
  let contents;
@@ -989,6 +1004,58 @@ function resolveMeteringCapability(deps, explicitTranscriptPath) {
989
1004
  }
990
1005
  return { capable: true, transcriptPath: resolved.path, summary };
991
1006
  }
1007
+ // ../../packages/aeg-core/src/metering-io-guard.ts
1008
+ import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
1009
+ var GUARD_OPEN_FLAGS = fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | fsConstants.O_NOFOLLOW;
1010
+ function isTrustedMeteringStat(stat, ownUid) {
1011
+ if (!stat.isFile())
1012
+ return false;
1013
+ if (typeof ownUid === "number" && stat.uid !== ownUid)
1014
+ return false;
1015
+ return true;
1016
+ }
1017
+ function ownUid() {
1018
+ return typeof process.getuid === "function" ? process.getuid() : undefined;
1019
+ }
1020
+ function guardedOpen(path) {
1021
+ try {
1022
+ return openSync(path, GUARD_OPEN_FLAGS);
1023
+ } catch {
1024
+ return;
1025
+ }
1026
+ }
1027
+ function hardenedExists(path) {
1028
+ const fd = guardedOpen(path);
1029
+ if (fd === undefined)
1030
+ return false;
1031
+ try {
1032
+ return isTrustedMeteringStat(fstatSync(fd), ownUid());
1033
+ } finally {
1034
+ closeSync(fd);
1035
+ }
1036
+ }
1037
+ function hardenedReadFile(path) {
1038
+ const fd = guardedOpen(path);
1039
+ if (fd === undefined) {
1040
+ throw new Error(`refusing to read ${path}: not openable as a plain, non-symlinked file`);
1041
+ }
1042
+ try {
1043
+ if (!isTrustedMeteringStat(fstatSync(fd), ownUid())) {
1044
+ throw new Error(`refusing to read ${path}: not a regular file owned by this user`);
1045
+ }
1046
+ return readFileSync(fd, "utf8");
1047
+ } finally {
1048
+ closeSync(fd);
1049
+ }
1050
+ }
1051
+ function hardenedMeteringDeps() {
1052
+ return {
1053
+ env: process.env,
1054
+ cwd: process.cwd(),
1055
+ exists: hardenedExists,
1056
+ readFile: hardenedReadFile
1057
+ };
1058
+ }
992
1059
  // ../../packages/aeg-core/src/file-classify.ts
993
1060
  function isCodeFile(p) {
994
1061
  if (p.endsWith(".md"))
@@ -1753,16 +1820,16 @@ function checkAdoptable(facts) {
1753
1820
  }
1754
1821
  // src/lib/detect.ts
1755
1822
  import { execFile as execFile4 } from "node:child_process";
1756
- import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync6, statSync } from "node:fs";
1823
+ import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync7, statSync } from "node:fs";
1757
1824
  import { join as join7 } from "node:path";
1758
1825
  import { promisify as promisify4 } from "node:util";
1759
1826
 
1760
1827
  // src/lib/artifacts.ts
1761
- import { readFileSync as readFileSync3 } from "node:fs";
1828
+ import { readFileSync as readFileSync4 } from "node:fs";
1762
1829
  import { join as join4 } from "node:path";
1763
1830
 
1764
1831
  // src/commands/doctrine.ts
1765
- import { existsSync as existsSync2, readdirSync, readFileSync } from "node:fs";
1832
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
1766
1833
  import { dirname as dirname2, join as join2, sep } from "node:path";
1767
1834
  import matter2 from "gray-matter";
1768
1835
 
@@ -1800,17 +1867,20 @@ function resolveDoctrineRoot(pkg = packageRoot(import.meta.url)) {
1800
1867
  if (!pkg.split(sep).includes("node_modules"))
1801
1868
  candidates.push(join2(dirname2(dirname2(pkg)), "aeg-root"));
1802
1869
  for (const root of candidates) {
1803
- if (existsSync2(join2(root, ...ENTRY_SEGMENTS)))
1870
+ if (hasDoctrineEntry(root))
1804
1871
  return root;
1805
1872
  }
1806
1873
  return null;
1807
1874
  }
1875
+ function hasDoctrineEntry(root) {
1876
+ return existsSync2(join2(root, ...ENTRY_SEGMENTS));
1877
+ }
1808
1878
  function listRoleNames(root) {
1809
1879
  const rolesDir = join2(root, "roles");
1810
1880
  if (!existsSync2(rolesDir))
1811
1881
  return [];
1812
1882
  return readdirSync(rolesDir).filter((name) => name.endsWith(".md")).map((name) => name.slice(0, -".md".length)).filter((roleName) => {
1813
- const { data } = matter2(readFileSync(join2(rolesDir, `${roleName}.md`), "utf8"));
1883
+ const { data } = matter2(readFileSync2(join2(rolesDir, `${roleName}.md`), "utf8"));
1814
1884
  return data.actor !== "human";
1815
1885
  }).sort();
1816
1886
  }
@@ -1849,7 +1919,7 @@ function doctrineCommand(args) {
1849
1919
  }
1850
1920
 
1851
1921
  // src/lib/agents-skills-emitter.ts
1852
- import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
1922
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "node:fs";
1853
1923
  import { join as join3 } from "node:path";
1854
1924
  import matter3 from "gray-matter";
1855
1925
  var AGENTS_SKILLS_GROUP = "Agent skills (.agents/skills/)";
@@ -1861,7 +1931,7 @@ function discoverRoleNames(doctrineRoot) {
1861
1931
  if (!existsSync3(rolesDir))
1862
1932
  return [];
1863
1933
  return readdirSync2(rolesDir).filter((name) => name.endsWith(".md")).map((name) => name.slice(0, -".md".length)).filter((roleName) => {
1864
- const { data } = matter3(readFileSync2(join3(rolesDir, `${roleName}.md`), "utf8"));
1934
+ const { data } = matter3(readFileSync3(join3(rolesDir, `${roleName}.md`), "utf8"));
1865
1935
  return data.actor !== "human";
1866
1936
  }).sort();
1867
1937
  }
@@ -1933,9 +2003,11 @@ process.stdin.on("end", () => {
1933
2003
  return
1934
2004
  }
1935
2005
  if (!hook.transcript_path) return
2006
+ const crypto = require("crypto")
1936
2007
  const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd()
1937
2008
  const tmpDir = process.env.TMPDIR || "/tmp"
1938
- const key = projectDir.replace(/[^A-Za-z0-9]+/g, "-")
2009
+ const digest = crypto.createHash("sha256").update(projectDir).digest("hex")
2010
+ const key = projectDir.replace(/[^A-Za-z0-9]+/g, "-") + "-" + digest
1939
2011
  const pointerPath = tmpDir + "/claude-transcript-" + key + ".txt"
1940
2012
  const content = (hook.session_id || "") + "\\t" + hook.transcript_path + "\\n"
1941
2013
  const scratchPath = pointerPath + "." + process.pid + "." + Math.random().toString(36).slice(2) + ".tmp"
@@ -2052,7 +2124,7 @@ function starterConfig() {
2052
2124
  };
2053
2125
  }
2054
2126
  function ownVersion() {
2055
- const pkg = JSON.parse(readFileSync3(join4(packageRoot(import.meta.url), "package.json"), "utf-8"));
2127
+ const pkg = JSON.parse(readFileSync4(join4(packageRoot(import.meta.url), "package.json"), "utf-8"));
2056
2128
  return pkg.version;
2057
2129
  }
2058
2130
  var SETUP_BUN_SHA = "0c5077e51419868618aeaa5fe8019c62421857d6";
@@ -2962,13 +3034,13 @@ function buildInitOps(ctx) {
2962
3034
 
2963
3035
  // src/lib/ops.ts
2964
3036
  import { execFileSync as execFileSync3 } from "node:child_process";
2965
- import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
3037
+ import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync6, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
2966
3038
  import { dirname as dirname4, isAbsolute, join as join6, resolve as resolve2, sep as sep2 } from "node:path";
2967
3039
 
2968
3040
  // src/lib/config.ts
2969
3041
  import { execFileSync as execFileSync2 } from "node:child_process";
2970
- import { createHash } from "node:crypto";
2971
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, realpathSync, writeFileSync } from "node:fs";
3042
+ import { createHash as createHash2 } from "node:crypto";
3043
+ import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync5, realpathSync, writeFileSync } from "node:fs";
2972
3044
  import { homedir } from "node:os";
2973
3045
  import { dirname as dirname3, join as join5, resolve } from "node:path";
2974
3046
  import { z } from "zod";
@@ -3301,7 +3373,7 @@ function loadConfig() {
3301
3373
  if (!path)
3302
3374
  return null;
3303
3375
  try {
3304
- const raw = JSON.parse(readFileSync4(path, "utf-8"));
3376
+ const raw = JSON.parse(readFileSync5(path, "utf-8"));
3305
3377
  return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
3306
3378
  } catch {
3307
3379
  return null;
@@ -3312,7 +3384,7 @@ function readRepoCiSetup(repoRoot) {
3312
3384
  if (!existsSync4(p))
3313
3385
  return null;
3314
3386
  try {
3315
- return VinayaConfigSchema.parse(JSON.parse(readFileSync4(p, "utf-8"))).ci?.setup ?? null;
3387
+ return VinayaConfigSchema.parse(JSON.parse(readFileSync5(p, "utf-8"))).ci?.setup ?? null;
3316
3388
  } catch {
3317
3389
  return null;
3318
3390
  }
@@ -3323,7 +3395,7 @@ function loadConfigChecked() {
3323
3395
  return { ok: true, config: null };
3324
3396
  let raw;
3325
3397
  try {
3326
- raw = JSON.parse(readFileSync4(path, "utf-8"));
3398
+ raw = JSON.parse(readFileSync5(path, "utf-8"));
3327
3399
  } catch (err) {
3328
3400
  return { ok: false, path, error: `invalid JSON: ${err.message}` };
3329
3401
  }
@@ -3339,7 +3411,7 @@ function readTokensCollectTrustStore(storePath) {
3339
3411
  try {
3340
3412
  if (!existsSync4(storePath))
3341
3413
  return {};
3342
- const raw = JSON.parse(readFileSync4(storePath, "utf-8"));
3414
+ const raw = JSON.parse(readFileSync5(storePath, "utf-8"));
3343
3415
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
3344
3416
  } catch {
3345
3417
  return {};
@@ -3385,7 +3457,7 @@ function gitBlobHash(absolutePath, cwd) {
3385
3457
  }
3386
3458
  }
3387
3459
  function tokensCollectTrustKey(repoGitCommonDir, interpreter, script) {
3388
- return createHash("sha256").update(JSON.stringify([repoGitCommonDir, interpreter, script])).digest("hex");
3460
+ return createHash2("sha256").update(JSON.stringify([repoGitCommonDir, interpreter, script])).digest("hex");
3389
3461
  }
3390
3462
  function getTokensCollectTrust(repoGitCommonDir, interpreter, script, storePath = TOKENS_COLLECT_TRUST_PATH) {
3391
3463
  const key = tokensCollectTrustKey(repoGitCommonDir, interpreter, script);
@@ -3455,7 +3527,7 @@ function fileContains(repoRoot, relPath, needle) {
3455
3527
  const p = resolveManagedBlockPath(repoRoot, relPath);
3456
3528
  if (!existsSync5(p))
3457
3529
  return false;
3458
- return readFileSync5(p, "utf-8").includes(needle);
3530
+ return readFileSync6(p, "utf-8").includes(needle);
3459
3531
  }
3460
3532
  function planInstall(ops, repoRoot, ownedFiles = new Set) {
3461
3533
  const entries = [];
@@ -3565,7 +3637,7 @@ function writeFileWithDirs(target, content, mode) {
3565
3637
  }
3566
3638
  function appendBlock(repoRoot, op) {
3567
3639
  const target = resolveManagedBlockPath(repoRoot, op.path);
3568
- const existing = readFileSync5(target, "utf-8");
3640
+ const existing = readFileSync6(target, "utf-8");
3569
3641
  const sep3 = existing.endsWith(`
3570
3642
  `) ? `
3571
3643
  ` : `
@@ -3687,7 +3759,7 @@ function planEject(manifest, repoRoot) {
3687
3759
  });
3688
3760
  continue;
3689
3761
  }
3690
- const content = readFileSync5(p, "utf-8");
3762
+ const content = readFileSync6(p, "utf-8");
3691
3763
  const stripped = stripBlockFromContent(content, b.marker, b.comment);
3692
3764
  const removesHost = stripped !== null && blockStripLeavesEmpty(stripped);
3693
3765
  actions.push({
@@ -3739,7 +3811,7 @@ function applyEject(plan, repoRoot) {
3739
3811
  const p = containedManagedBlockAbs(repoRoot, a.path);
3740
3812
  if (p === null)
3741
3813
  continue;
3742
- const content = readFileSync5(p, "utf-8");
3814
+ const content = readFileSync6(p, "utf-8");
3743
3815
  const stripped = stripBlockFromContent(content, a.marker, a.comment);
3744
3816
  if (stripped === null)
3745
3817
  continue;
@@ -3870,7 +3942,7 @@ function foreignRawHooks(repoRoot) {
3870
3942
  return activeRawHooks(repoRoot).filter((f) => {
3871
3943
  const abs2 = resolveManagedBlockPath(repoRoot, `.git/hooks/${f}`);
3872
3944
  try {
3873
- const stripped = stripBlockFromContent(readFileSync6(abs2, "utf-8"), f, "hash");
3945
+ const stripped = stripBlockFromContent(readFileSync7(abs2, "utf-8"), f, "hash");
3874
3946
  return stripped === null || !blockStripLeavesEmpty(stripped);
3875
3947
  } catch {
3876
3948
  return true;
@@ -4004,7 +4076,6 @@ function closeStdin() {
4004
4076
 
4005
4077
  // src/commands/tokens.ts
4006
4078
  import { execFileSync as execFileSync4 } from "node:child_process";
4007
- import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
4008
4079
  import { resolve as resolvePath } from "node:path";
4009
4080
  var USAGE = [
4010
4081
  'Usage: vinaya tokens --phase "<task-id>: develop" --role Developer',
@@ -4156,10 +4227,7 @@ function runDeclaredCollect(command, deps) {
4156
4227
  var COLLECT_COMMAND_TIMEOUT_MS = 30000;
4157
4228
  function realDeps() {
4158
4229
  return {
4159
- env: process.env,
4160
- cwd: process.cwd(),
4161
- exists: existsSync7,
4162
- readFile: (path) => readFileSync7(path, "utf8"),
4230
+ ...hardenedMeteringDeps(),
4163
4231
  loadConfig,
4164
4232
  repoConfigDir: repoLocalConfigDir,
4165
4233
  runScript: (interpreter, scriptAbsolutePath, cwd) => execFileSync4(interpreter, [scriptAbsolutePath], { cwd, encoding: "utf-8", timeout: COLLECT_COMMAND_TIMEOUT_MS }),
@@ -4813,11 +4881,11 @@ function emitCheckError(error) {
4813
4881
  }
4814
4882
 
4815
4883
  // src/checks/registry.ts
4816
- import { existsSync as existsSync8 } from "node:fs";
4884
+ import { existsSync as existsSync7 } from "node:fs";
4817
4885
  import { join as join8 } from "node:path";
4818
4886
  var DIST_BIN_DIR = join8(packageRoot(import.meta.url), "dist", "checks", "bin");
4819
4887
  var SRC_BIN_DIR = join8(packageRoot(import.meta.url), "src", "checks", "bin");
4820
- var BIN_DIR = existsSync8(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
4888
+ var BIN_DIR = existsSync7(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
4821
4889
  var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
4822
4890
  function bin(name) {
4823
4891
  return join8(BIN_DIR, `${name}${BIN_EXT}`);
@@ -4952,6 +5020,21 @@ var REGISTRY = [
4952
5020
  },
4953
5021
  1
4954
5022
  ],
5023
+ [
5024
+ {
5025
+ name: "token-report",
5026
+ run: bin("check-token-report"),
5027
+ scope: "diff",
5028
+ timeoutMs: 15000,
5029
+ requiresOpenPr: true,
5030
+ env: {
5031
+ PR_BODY: { optional: true },
5032
+ CLAUDE_PROJECT_DIR: { optional: true },
5033
+ CLAUDE_CODE_SESSION_ID: { optional: true }
5034
+ }
5035
+ },
5036
+ 1
5037
+ ],
4955
5038
  [
4956
5039
  {
4957
5040
  name: "no-disk-state",
@@ -5489,7 +5572,7 @@ async function runChecks(specs, opts) {
5489
5572
  }
5490
5573
 
5491
5574
  // src/roles/plan.ts
5492
- import { existsSync as existsSync9, readFileSync as readFileSync9 } from "node:fs";
5575
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "node:fs";
5493
5576
  import { join as join10 } from "node:path";
5494
5577
 
5495
5578
  // ../../packages/sources/src/commands.ts
@@ -6125,7 +6208,7 @@ function resolveRoles(core, configRoles) {
6125
6208
  var NO_DOCTRINE_REASON = "no bundled doctrine found next to this CLI install — the doctrine ships inside the @attalabs/vinaya npm package. Reinstall it, or, in a repo that vendors the CLI, run the package's bundle-doctrine script first.";
6126
6209
  function readContract(configDir, contractPath) {
6127
6210
  const absolute = join10(configDir, contractPath);
6128
- if (!existsSync9(absolute)) {
6211
+ if (!existsSync8(absolute)) {
6129
6212
  return { ok: false, errors: [`contract file "${contractPath}" does not exist (resolved to "${absolute}")`] };
6130
6213
  }
6131
6214
  try {
@@ -6424,7 +6507,7 @@ function commitMsgCommand(args) {
6424
6507
 
6425
6508
  // src/commands/demo.ts
6426
6509
  import { execFileSync as execFileSync8, spawnSync } from "node:child_process";
6427
- import { existsSync as existsSync10, readFileSync as readFileSync11, rmSync as rmSync2, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
6510
+ import { existsSync as existsSync9, readFileSync as readFileSync11, rmSync as rmSync2, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
6428
6511
  import { isAbsolute as isAbsolute2, join as join11 } from "node:path";
6429
6512
  var DEMO_BRANCH_PREFIX = "vinaya/demo-break-";
6430
6513
  var FIXTURE_PATH = ".vinaya-demo-brief.md";
@@ -6467,7 +6550,7 @@ function gitDirAbs(repoRoot) {
6467
6550
  function recoverFromCrash(repoRoot, statePath) {
6468
6551
  const currentBranch = currentBranchName(repoRoot);
6469
6552
  let state = null;
6470
- if (existsSync10(statePath)) {
6553
+ if (existsSync9(statePath)) {
6471
6554
  try {
6472
6555
  state = JSON.parse(readFileSync11(statePath, "utf-8"));
6473
6556
  } catch {
@@ -6539,14 +6622,14 @@ function cleanup(repoRoot, originalBranch, demoBranch, statePath) {
6539
6622
  gitCapture(repoRoot, ["clean", "-fd"]);
6540
6623
  gitCapture(repoRoot, ["checkout", originalBranch]);
6541
6624
  gitCapture(repoRoot, ["branch", "-D", demoBranch]);
6542
- if (existsSync10(statePath))
6625
+ if (existsSync9(statePath))
6543
6626
  rmSync2(statePath, { force: true });
6544
6627
  }
6545
6628
  async function runDemoBreak(repoRoot, args) {
6546
6629
  const keep = args.includes("--keep");
6547
6630
  const hookDir = resolveHookDir(repoRoot);
6548
6631
  const hookPath = resolveManagedBlockPath(repoRoot, `${hookDir}/pre-commit`);
6549
- if (!existsSync10(hookPath)) {
6632
+ if (!existsSync9(hookPath)) {
6550
6633
  console.error("Vinaya hooks are not installed in this repo. Run `vinaya init` first.");
6551
6634
  return 1;
6552
6635
  }
@@ -6616,7 +6699,7 @@ Attempting to commit…
6616
6699
  process.stdout.write(`✓ Commit passed — the fix worked.
6617
6700
  `);
6618
6701
  if (keep) {
6619
- if (existsSync10(statePath))
6702
+ if (existsSync9(statePath))
6620
6703
  unlinkSync(statePath);
6621
6704
  process.stdout.write(`
6622
6705
  --keep: leaving \`${demoBranch}\` checked out for you to inspect. Clean up with:
@@ -6644,7 +6727,7 @@ async function demoBreakCommand(args) {
6644
6727
 
6645
6728
  // src/commands/doctor.ts
6646
6729
  import { execFileSync as execFileSync9 } from "node:child_process";
6647
- import { existsSync as existsSync13, readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync2 } from "node:fs";
6730
+ import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync2 } from "node:fs";
6648
6731
  import { delimiter, join as join14 } from "node:path";
6649
6732
 
6650
6733
  // src/lib/self-host.ts
@@ -6762,14 +6845,14 @@ function detectVendoredVinaya(repoRoot) {
6762
6845
  }
6763
6846
 
6764
6847
  // src/lib/env-lint.ts
6765
- import { existsSync as existsSync11, readFileSync as readFileSync13 } from "node:fs";
6848
+ import { existsSync as existsSync10, readFileSync as readFileSync13 } from "node:fs";
6766
6849
  var ENV_READ_PATTERN = /\b(?:process\.env|Bun\.env|Deno\.env)\b/;
6767
6850
  function checksMissingEnvDeclaration(specs) {
6768
6851
  const names = [];
6769
6852
  for (const spec of specs) {
6770
6853
  if (spec.env)
6771
6854
  continue;
6772
- if (!existsSync11(spec.run))
6855
+ if (!existsSync10(spec.run))
6773
6856
  continue;
6774
6857
  let source;
6775
6858
  try {
@@ -6787,7 +6870,7 @@ function envDeclarationWarning(name) {
6787
6870
  }
6788
6871
 
6789
6872
  // src/lib/registry-write.ts
6790
- import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync4 } from "node:fs";
6873
+ import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync4 } from "node:fs";
6791
6874
  import { dirname as dirname6, join as join13 } from "node:path";
6792
6875
  var PROJECTS_REGISTRY_PATH = ".vinaya/projects.md";
6793
6876
  var CONFIG_FILE_PATH = "vinaya.config.json";
@@ -6856,7 +6939,7 @@ ${newRow}
6856
6939
  function planRegistryRow(repoRoot, name, path, specsPath) {
6857
6940
  const abs2 = join13(repoRoot, PROJECTS_REGISTRY_PATH);
6858
6941
  const line = rowLine(name, path, specsPath);
6859
- if (!existsSync12(abs2)) {
6942
+ if (!existsSync11(abs2)) {
6860
6943
  return { action: "create-host", rowLine: line, path: PROJECTS_REGISTRY_PATH };
6861
6944
  }
6862
6945
  const existing = readFileSync14(abs2, "utf-8");
@@ -6884,7 +6967,7 @@ function renderRegistryRowDiffLine(plan) {
6884
6967
  }
6885
6968
  function readProjectEntries(repoRoot) {
6886
6969
  const abs2 = join13(repoRoot, CONFIG_FILE_PATH);
6887
- if (!existsSync12(abs2))
6970
+ if (!existsSync11(abs2))
6888
6971
  return [];
6889
6972
  try {
6890
6973
  return VinayaConfigSchema.parse(JSON.parse(readFileSync14(abs2, "utf-8"))).projects ?? [];
@@ -6932,12 +7015,7 @@ function realDeps4() {
6932
7015
  nodeVersion: () => process.version,
6933
7016
  bunVersion: () => typeof Bun === "undefined" ? null : Bun.version,
6934
7017
  packageVersion: readVersion,
6935
- meteringCapability: () => resolveMeteringCapability({
6936
- env: process.env,
6937
- cwd: process.cwd(),
6938
- exists: existsSync13,
6939
- readFile: (path) => readFileSync15(path, "utf8")
6940
- })
7018
+ meteringCapability: () => resolveMeteringCapability(hardenedMeteringDeps())
6941
7019
  };
6942
7020
  }
6943
7021
  var ok = (check, message) => ({ check, severity: "ok", message });
@@ -6946,7 +7024,7 @@ var warn = (check, message) => ({ check, severity: "warn", message });
6946
7024
  var error = (check, message) => ({ check, severity: "error", message });
6947
7025
  function readConfig(repoRoot) {
6948
7026
  const p = join14(repoRoot, CONFIG_PATH);
6949
- if (!existsSync13(p))
7027
+ if (!existsSync12(p))
6950
7028
  return { kind: "missing" };
6951
7029
  let raw;
6952
7030
  try {
@@ -6990,7 +7068,7 @@ function diagnoseInstall(repoRoot, ctx, manifest) {
6990
7068
  if (op.kind === "create-file") {
6991
7069
  const check = labelForPath(op.path);
6992
7070
  const abs2 = join14(repoRoot, op.path);
6993
- const exists = existsSync13(abs2);
7071
+ const exists = existsSync12(abs2);
6994
7072
  const owned = ownedFiles.has(op.path) || isDefaultedAgentVendorPath(op.path, manifest);
6995
7073
  if (!exists) {
6996
7074
  findings.push(owned ? error(check, `${op.path} is recorded as vinaya-managed but missing on disk — run \`vinaya upgrade\`.`) : error(check, `${op.path} is not installed — run \`vinaya init\`.`));
@@ -7015,7 +7093,7 @@ function diagnoseInstall(repoRoot, ctx, manifest) {
7015
7093
  const check = "hooks";
7016
7094
  const abs2 = resolveManagedBlockPath(repoRoot, op.path);
7017
7095
  const owned = ownedBlocks.has(blockKey(op.path, op.marker));
7018
- if (!existsSync13(abs2)) {
7096
+ if (!existsSync12(abs2)) {
7019
7097
  findings.push(owned ? error(check, `${op.path} is missing — likely a fresh clone (raw git hooks aren't tracked by git). Run \`vinaya upgrade\` to restore it.`) : info(check, `${op.path} is not installed.`));
7020
7098
  continue;
7021
7099
  }
@@ -7068,7 +7146,7 @@ function diagnoseCustomChecks(repoRoot, config) {
7068
7146
  const findings = [];
7069
7147
  for (const [name, entry2] of Object.entries(config.checks ?? {})) {
7070
7148
  const scriptAbs = join14(repoRoot, entry2.run);
7071
- findings.push(existsSync13(scriptAbs) ? ok("checks", `custom check '${name}' → ${entry2.run}`) : error("checks", `custom check '${name}' points at a missing script: ${entry2.run}`));
7149
+ findings.push(existsSync12(scriptAbs) ? ok("checks", `custom check '${name}' → ${entry2.run}`) : error("checks", `custom check '${name}' points at a missing script: ${entry2.run}`));
7072
7150
  }
7073
7151
  return findings;
7074
7152
  }
@@ -7082,7 +7160,7 @@ function listTrackedFiles(repoRoot) {
7082
7160
  }
7083
7161
  function diagnoseDocOwnersHealth(repoRoot) {
7084
7162
  const path = join14(repoRoot, DOC_OWNERS_PATH);
7085
- const content = existsSync13(path) ? readFileSync15(path, "utf-8") : null;
7163
+ const content = existsSync12(path) ? readFileSync15(path, "utf-8") : null;
7086
7164
  const state = classifyDocOwnersManifest(content);
7087
7165
  if (state === "absent" || state === "empty")
7088
7166
  return [];
@@ -7100,7 +7178,7 @@ function diagnoseDocOwnersHealth(repoRoot) {
7100
7178
  }
7101
7179
  if (!isUrlPointer(b.pointer)) {
7102
7180
  const pointerPath = join14(repoRoot, pointerToPath(b.pointer));
7103
- if (!existsSync13(pointerPath)) {
7181
+ if (!existsSync12(pointerPath)) {
7104
7182
  flagged = true;
7105
7183
  findings.push(warn("doc-owners", `${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Repoint the ` + "binding, or add the missing doc."));
7106
7184
  }
@@ -7139,11 +7217,11 @@ function listChildDirsForDoctor(dir, repoRoot) {
7139
7217
  }
7140
7218
  function diagnoseBlastRadiusDeprecation(repoRoot, config) {
7141
7219
  const derived = deriveWorkspacePackageDomains(readWorkspacesForDoctor(repoRoot), (dir) => listChildDirsForDoctor(dir, repoRoot));
7142
- const defaults = deriveBuiltinCrossCuttingDefaults((p) => existsSync13(join14(repoRoot, p)));
7220
+ const defaults = deriveBuiltinCrossCuttingDefaults((p) => existsSync12(join14(repoRoot, p)));
7143
7221
  const covered = new Set([...derived, ...defaults]);
7144
7222
  const configExtra = new Set(config?.blastRadius?.extraDomains ?? []);
7145
7223
  const legacyPath = join14(repoRoot, LEGACY_AEG_PACKAGES_PATH);
7146
- if (!existsSync13(legacyPath)) {
7224
+ if (!existsSync12(legacyPath)) {
7147
7225
  return [
7148
7226
  info("blast-radius", `checkBlastRadiusScope is active via live derivation (${derived.length} packages/* domain(s)) + built-in defaults (${defaults.length} present) — no ${LEGACY_AEG_PACKAGES_PATH}, and the check is not dormant.`)
7149
7227
  ];
@@ -7204,7 +7282,7 @@ function diagnoseCheckClassification(config) {
7204
7282
  return findings;
7205
7283
  }
7206
7284
  function diagnoseGlobalConfigChecks() {
7207
- if (!existsSync13(GLOBAL_CONFIG_PATH))
7285
+ if (!existsSync12(GLOBAL_CONFIG_PATH))
7208
7286
  return [];
7209
7287
  let raw;
7210
7288
  try {
@@ -7258,7 +7336,7 @@ function coversWorkflowsDir(pattern) {
7258
7336
  }
7259
7337
  function diagnoseCodeowners(repoRoot) {
7260
7338
  const path = join14(repoRoot, ".github", "CODEOWNERS");
7261
- if (!existsSync13(path)) {
7339
+ if (!existsSync12(path)) {
7262
7340
  return info("codeowners", "no .github/CODEOWNERS — vinaya's workflow files have no required-review protection; see `vinaya init`'s printed recommendation.");
7263
7341
  }
7264
7342
  let body;
@@ -7276,7 +7354,7 @@ function diagnoseVinayaOnPath(agents) {
7276
7354
  return [];
7277
7355
  const names = process.platform === "win32" ? ["vinaya.cmd", "vinaya.exe", "vinaya.bat"] : ["vinaya"];
7278
7356
  const dirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
7279
- const onPath = dirs.some((dir) => names.some((name) => existsSync13(join14(dir, name))));
7357
+ const onPath = dirs.some((dir) => names.some((name) => existsSync12(join14(dir, name))));
7280
7358
  return [
7281
7359
  onPath ? ok("vinaya-on-path", "`vinaya` resolves on PATH — agent-native commands will work.") : info("vinaya-on-path", "`vinaya` is not resolvable on PATH — `/vinaya <role>` and the .agents/skills/vinaya-*/SKILL.md files " + 'installed here will fail "command not found" on first use. Run `npm install -g @attalabs/vinaya`.')
7282
7360
  ];
@@ -7289,7 +7367,7 @@ function diagnosePrincipals(config) {
7289
7367
  }
7290
7368
  function diagnoseProjectsCoherence(repoRoot, config) {
7291
7369
  const registryAbs = join14(repoRoot, PROJECTS_REGISTRY_PATH);
7292
- const registryNames = existsSync13(registryAbs) ? new Set(parseRegistry(readFileSync15(registryAbs, "utf-8")).map((p) => p.name)) : new Set;
7370
+ const registryNames = existsSync12(registryAbs) ? new Set(parseRegistry(readFileSync15(registryAbs, "utf-8")).map((p) => p.name)) : new Set;
7293
7371
  const configNames = new Set((config?.projects ?? []).map((p) => p.name));
7294
7372
  if (registryNames.size === 0 && configNames.size === 0)
7295
7373
  return [];
@@ -7316,7 +7394,7 @@ function diagnoseTestCi(repoRoot) {
7316
7394
  if (typeof testScript !== "string" || testScript.trim() === "")
7317
7395
  return [];
7318
7396
  const workflowsDir = join14(repoRoot, ".github/workflows");
7319
- const files = existsSync13(workflowsDir) ? readdirSync6(workflowsDir).filter((name) => statSync2(join14(workflowsDir, name)).isFile()) : [];
7397
+ const files = existsSync12(workflowsDir) ? readdirSync6(workflowsDir).filter((name) => statSync2(join14(workflowsDir, name)).isFile()) : [];
7320
7398
  const invoked = files.some((name) => {
7321
7399
  const content = readFileSync15(join14(workflowsDir, name), "utf-8");
7322
7400
  return TEST_INVOCATION_SUBSTRINGS.some((s) => content.includes(s));
@@ -7409,7 +7487,7 @@ async function doctorCommand(args) {
7409
7487
  }
7410
7488
 
7411
7489
  // src/commands/eject.ts
7412
- import { existsSync as existsSync14, readFileSync as readFileSync16 } from "node:fs";
7490
+ import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
7413
7491
  import { join as join15 } from "node:path";
7414
7492
  function realDeps5() {
7415
7493
  return {
@@ -7428,7 +7506,7 @@ function parse(args) {
7428
7506
  }
7429
7507
  function readManifest(repoRoot) {
7430
7508
  const p = join15(repoRoot, CONFIG_PATH);
7431
- if (!existsSync14(p))
7509
+ if (!existsSync13(p))
7432
7510
  return { kind: "none" };
7433
7511
  let raw;
7434
7512
  try {
@@ -7522,7 +7600,7 @@ async function ejectCommand(args) {
7522
7600
  }
7523
7601
 
7524
7602
  // src/commands/init.ts
7525
- import { existsSync as existsSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync5 } from "node:fs";
7603
+ import { existsSync as existsSync14, readFileSync as readFileSync17, writeFileSync as writeFileSync5 } from "node:fs";
7526
7604
  import { join as join16 } from "node:path";
7527
7605
  function realDeps6() {
7528
7606
  return {
@@ -7564,7 +7642,7 @@ function parseAgentsFlag(args) {
7564
7642
  var PRODUCT_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
7565
7643
  function readManifest2(repoRoot) {
7566
7644
  const p = join16(repoRoot, CONFIG_PATH);
7567
- if (!existsSync15(p))
7645
+ if (!existsSync14(p))
7568
7646
  return null;
7569
7647
  try {
7570
7648
  return VinayaConfigSchema.parse(JSON.parse(readFileSync17(p, "utf-8"))).managed ?? null;
@@ -7728,7 +7806,7 @@ import { execFileSync as execFileSync11 } from "node:child_process";
7728
7806
 
7729
7807
  // src/lib/forge-write.ts
7730
7808
  import { execFileSync as execFileSync10 } from "node:child_process";
7731
- import { existsSync as existsSync16, mkdtempSync, readdirSync as readdirSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
7809
+ import { existsSync as existsSync15, mkdtempSync, readdirSync as readdirSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
7732
7810
  import { readFileSync as readFileSync18 } from "node:fs";
7733
7811
  import { tmpdir } from "node:os";
7734
7812
  import { join as join17 } from "node:path";
@@ -8031,7 +8109,7 @@ function readSharedPackages(root = repoRoot()) {
8031
8109
  if (!root)
8032
8110
  return [];
8033
8111
  const derived = deriveWorkspacePackageDomains(readWorkspaceGlobs(root), (dir) => listWorkspaceChildDirs(dir, root));
8034
- const defaults = deriveBuiltinCrossCuttingDefaults((p) => existsSync16(join17(root, p)));
8112
+ const defaults = deriveBuiltinCrossCuttingDefaults((p) => existsSync15(join17(root, p)));
8035
8113
  const configExtra = readConfigExtraDomains(root);
8036
8114
  return [...new Set([...derived, ...defaults, ...configExtra])];
8037
8115
  }
@@ -8573,7 +8651,7 @@ async function milestoneCloseCommand(args) {
8573
8651
  }
8574
8652
 
8575
8653
  // src/commands/new-check.ts
8576
- import { chmodSync as chmodSync2, existsSync as existsSync17, mkdirSync as mkdirSync4, readFileSync as readFileSync19, writeFileSync as writeFileSync7 } from "node:fs";
8654
+ import { chmodSync as chmodSync2, existsSync as existsSync16, mkdirSync as mkdirSync4, readFileSync as readFileSync19, writeFileSync as writeFileSync7 } from "node:fs";
8577
8655
  import { join as join18 } from "node:path";
8578
8656
  var TEMPLATE_PATH = join18(packageRoot(import.meta.url), "templates", "custom-check.template.ts");
8579
8657
  var CHECKS_DIR = join18("scripts", "vinaya-checks");
@@ -8594,11 +8672,11 @@ function newCheckCommand(args) {
8594
8672
  process.exit(2);
8595
8673
  }
8596
8674
  const scriptsDir = join18(process.cwd(), CHECKS_DIR);
8597
- if (!existsSync17(scriptsDir))
8675
+ if (!existsSync16(scriptsDir))
8598
8676
  mkdirSync4(scriptsDir, { recursive: true });
8599
8677
  const fileStem = name.slice(name.indexOf("/") + 1);
8600
8678
  const targetPath = join18(scriptsDir, `${fileStem}.ts`);
8601
- if (existsSync17(targetPath)) {
8679
+ if (existsSync16(targetPath)) {
8602
8680
  console.error(`Error: ${targetPath} already exists.`);
8603
8681
  process.exit(1);
8604
8682
  }
@@ -8616,7 +8694,7 @@ ${registration}
8616
8694
  }
8617
8695
 
8618
8696
  // src/commands/new-noop-check.ts
8619
- import { chmodSync as chmodSync3, existsSync as existsSync18, mkdirSync as mkdirSync5, readFileSync as readFileSync20, writeFileSync as writeFileSync8 } from "node:fs";
8697
+ import { chmodSync as chmodSync3, existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync20, writeFileSync as writeFileSync8 } from "node:fs";
8620
8698
  import { join as join19 } from "node:path";
8621
8699
  var TEMPLATE_PATH2 = join19(packageRoot(import.meta.url), "templates", "noop-check.template.ts");
8622
8700
  var CHECKS_DIR2 = join19("vinaya", "checks");
@@ -8634,10 +8712,10 @@ function newNoopCheckCommand(args) {
8634
8712
  process.exit(2);
8635
8713
  }
8636
8714
  const checksDir = join19(process.cwd(), CHECKS_DIR2);
8637
- if (!existsSync18(checksDir))
8715
+ if (!existsSync17(checksDir))
8638
8716
  mkdirSync5(checksDir, { recursive: true });
8639
8717
  const targetPath = join19(checksDir, `${name}.ts`);
8640
- if (existsSync18(targetPath)) {
8718
+ if (existsSync17(targetPath)) {
8641
8719
  console.error(`Error: ${targetPath} already exists.`);
8642
8720
  process.exit(1);
8643
8721
  }
@@ -8663,7 +8741,7 @@ ${registration}
8663
8741
  }
8664
8742
 
8665
8743
  // src/commands/new-role.ts
8666
- import { existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync21, writeFileSync as writeFileSync9 } from "node:fs";
8744
+ import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync21, writeFileSync as writeFileSync9 } from "node:fs";
8667
8745
  import { join as join20 } from "node:path";
8668
8746
  var TEMPLATE_PATH3 = join20(packageRoot(import.meta.url), "templates", "role.template.md");
8669
8747
  var ROLES_DIR = join20("vinaya", "roles");
@@ -8680,11 +8758,11 @@ A bare, un-namespaced key resolves as an OVERRIDE of a core role — a complete
8680
8758
  process.exit(2);
8681
8759
  }
8682
8760
  const rolesDir = join20(process.cwd(), ROLES_DIR);
8683
- if (!existsSync19(rolesDir))
8761
+ if (!existsSync18(rolesDir))
8684
8762
  mkdirSync6(rolesDir, { recursive: true });
8685
8763
  const roleId = name.slice(name.indexOf("/") + 1);
8686
8764
  const targetPath = join20(rolesDir, `${roleId}.md`);
8687
- if (existsSync19(targetPath)) {
8765
+ if (existsSync18(targetPath)) {
8688
8766
  console.error(`Error: ${targetPath} already exists.`);
8689
8767
  process.exit(1);
8690
8768
  }
@@ -9153,7 +9231,7 @@ function prEditCommand(args) {
9153
9231
 
9154
9232
  // src/commands/pr-report.ts
9155
9233
  import { execFileSync as execFileSync14, spawnSync as spawnSync2 } from "node:child_process";
9156
- import { existsSync as existsSync20, readFileSync as readFileSync22, writeFileSync as writeFileSync10 } from "node:fs";
9234
+ import { existsSync as existsSync19, readFileSync as readFileSync22, writeFileSync as writeFileSync10 } from "node:fs";
9157
9235
  import { join as join21 } from "node:path";
9158
9236
  var EVIDENCE_START = "<!-- AEG:EVIDENCE:START -->";
9159
9237
  var EVIDENCE_END = "<!-- AEG:EVIDENCE:END -->";
@@ -9213,7 +9291,7 @@ function computeGroupA() {
9213
9291
  function resolveSelfEntry() {
9214
9292
  const root = packageRoot(import.meta.url);
9215
9293
  const dist = join21(root, "dist", "index.js");
9216
- return existsSync20(dist) ? dist : join21(root, "src", "index.ts");
9294
+ return existsSync19(dist) ? dist : join21(root, "src", "index.ts");
9217
9295
  }
9218
9296
  var FAILING_STATUSES = new Set(["fail", "error", "timeout"]);
9219
9297
  function anyGateFailed(outcomes) {
@@ -9420,7 +9498,7 @@ async function prReportCommand(args) {
9420
9498
  throw err;
9421
9499
  }
9422
9500
  if (writePath) {
9423
- const existing = existsSync20(writePath) ? readFileSync22(writePath, "utf8") : "";
9501
+ const existing = existsSync19(writePath) ? readFileSync22(writePath, "utf8") : "";
9424
9502
  const withEvidence = replaceEvidenceBlock(existing, result.blockInner);
9425
9503
  const tokensAddition = collectTokensAddition({
9426
9504
  phase: phaseOverride ?? derivePhase(),
@@ -9616,11 +9694,11 @@ async function prVerifyEvidenceCommand(args) {
9616
9694
 
9617
9695
  // src/commands/quickstart.ts
9618
9696
  import { execFileSync as execFileSync16 } from "node:child_process";
9619
- import { existsSync as existsSync22, readFileSync as readFileSync24 } from "node:fs";
9697
+ import { existsSync as existsSync21, readFileSync as readFileSync24 } from "node:fs";
9620
9698
  import { join as join23 } from "node:path";
9621
9699
 
9622
9700
  // src/lib/doc-owners-write.ts
9623
- import { existsSync as existsSync21, mkdirSync as mkdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync11 } from "node:fs";
9701
+ import { existsSync as existsSync20, mkdirSync as mkdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync11 } from "node:fs";
9624
9702
  import { dirname as dirname7, join as join22 } from "node:path";
9625
9703
  function bindingLine(glob, pointer) {
9626
9704
  return `${glob} ${pointer}`;
@@ -9639,7 +9717,7 @@ function appendDocOwnersBinding(content, glob, pointer) {
9639
9717
  function planDocOwnersBinding(repoRoot3, glob, pointer) {
9640
9718
  const abs2 = join22(repoRoot3, DOC_OWNERS_PATH);
9641
9719
  const line = bindingLine(glob, pointer);
9642
- if (!existsSync21(abs2)) {
9720
+ if (!existsSync20(abs2)) {
9643
9721
  return { action: "create-host", line, path: DOC_OWNERS_PATH };
9644
9722
  }
9645
9723
  const existing = readFileSync23(abs2, "utf-8");
@@ -9716,7 +9794,7 @@ function pointerIsMissingLocalFile(repoRoot3, pointer) {
9716
9794
  if (/^https?:\/\//i.test(pointer))
9717
9795
  return false;
9718
9796
  const path = pointer.split("#")[0] ?? pointer;
9719
- return !existsSync22(join23(repoRoot3, path));
9797
+ return !existsSync21(join23(repoRoot3, path));
9720
9798
  }
9721
9799
  async function bindDocOwnerLoop(deps, repoRoot3) {
9722
9800
  let any = false;
@@ -9807,12 +9885,7 @@ function realDeps7() {
9807
9885
  nodeVersion: () => process.version,
9808
9886
  bunVersion: () => typeof Bun === "undefined" ? null : Bun.version,
9809
9887
  packageVersion: readPackageVersion,
9810
- meteringCapability: () => resolveMeteringCapability({
9811
- env: process.env,
9812
- cwd: process.cwd(),
9813
- exists: existsSync22,
9814
- readFile: (path) => readFileSync24(path, "utf8")
9815
- })
9888
+ meteringCapability: () => resolveMeteringCapability(hardenedMeteringDeps())
9816
9889
  },
9817
9890
  confirm: async (q, defaultYes) => promptYesNo(q, defaultYes),
9818
9891
  ask: async (q) => prompt(q),
@@ -10347,7 +10420,7 @@ Self-verification: clean — re-parsed VERDICT is bound to head ${headSha}.
10347
10420
 
10348
10421
  // src/commands/studio.ts
10349
10422
  import { execFile as execFile5, spawn as spawn2 } from "node:child_process";
10350
- import { existsSync as existsSync23, readFileSync as readFileSync26, renameSync } from "node:fs";
10423
+ import { existsSync as existsSync22, readFileSync as readFileSync26, renameSync } from "node:fs";
10351
10424
  import net from "node:net";
10352
10425
  import { dirname as dirname8, join as join25 } from "node:path";
10353
10426
  import { promisify as promisify5 } from "node:util";
@@ -10404,7 +10477,7 @@ function resolveStudioTarget(cwd, moduleUrl = import.meta.url) {
10404
10477
  for (;; ) {
10405
10478
  const webDir = join25(dir, "apps", "vinaya-studio", "web");
10406
10479
  const pkgPath = join25(webDir, "package.json");
10407
- if (existsSync23(pkgPath)) {
10480
+ if (existsSync22(pkgPath)) {
10408
10481
  try {
10409
10482
  const pkg = JSON.parse(readFileSync26(pkgPath, "utf-8"));
10410
10483
  if (pkg.name === "@atta/vinaya-studio-web") {
@@ -10412,7 +10485,7 @@ function resolveStudioTarget(cwd, moduleUrl = import.meta.url) {
10412
10485
  }
10413
10486
  } catch {}
10414
10487
  }
10415
- if (existsSync23(join25(dir, ".git")))
10488
+ if (existsSync22(join25(dir, ".git")))
10416
10489
  break;
10417
10490
  const parent = dirname8(dir);
10418
10491
  if (parent === dir)
@@ -10420,7 +10493,7 @@ function resolveStudioTarget(cwd, moduleUrl = import.meta.url) {
10420
10493
  dir = parent;
10421
10494
  }
10422
10495
  const standaloneWebDir = join25(packageRoot(moduleUrl), "studio-standalone", "apps", "vinaya-studio", "web");
10423
- if (existsSync23(join25(standaloneWebDir, "server.js"))) {
10496
+ if (existsSync22(join25(standaloneWebDir, "server.js"))) {
10424
10497
  return { kind: "package", packageDir: standaloneWebDir };
10425
10498
  }
10426
10499
  return { kind: "missing" };
@@ -10442,7 +10515,7 @@ function isPortFree(port) {
10442
10515
  function ensureStudioNodeModules(bundleRoot) {
10443
10516
  const real = join25(bundleRoot, "node_modules");
10444
10517
  const packed = join25(bundleRoot, STUDIO_NODE_MODULES_PACKED_DIRNAME);
10445
- if (!existsSync23(real) && existsSync23(packed)) {
10518
+ if (!existsSync22(real) && existsSync22(packed)) {
10446
10519
  renameSync(packed, real);
10447
10520
  }
10448
10521
  }
@@ -10501,7 +10574,7 @@ async function runStudio(cwd, args, moduleUrl = import.meta.url) {
10501
10574
  }
10502
10575
 
10503
10576
  // src/commands/upgrade.ts
10504
- import { existsSync as existsSync24, readFileSync as readFileSync27, rmSync as rmSync5, writeFileSync as writeFileSync13 } from "node:fs";
10577
+ import { existsSync as existsSync23, readFileSync as readFileSync27, rmSync as rmSync5, writeFileSync as writeFileSync13 } from "node:fs";
10505
10578
  import { join as join26 } from "node:path";
10506
10579
  function realDeps8() {
10507
10580
  return {
@@ -10521,7 +10594,7 @@ function flags2(args) {
10521
10594
  }
10522
10595
  function readManifest3(repoRoot3) {
10523
10596
  const p = join26(repoRoot3, CONFIG_PATH);
10524
- if (!existsSync24(p))
10597
+ if (!existsSync23(p))
10525
10598
  return { kind: "missing" };
10526
10599
  let raw;
10527
10600
  try {
@@ -10549,7 +10622,7 @@ function writeManifestVersion(repoRoot3, manifest) {
10549
10622
  }
10550
10623
  function stripFor(repoRoot3, path, marker, comment) {
10551
10624
  const abs2 = resolveManagedBlockPath(repoRoot3, path);
10552
- if (!existsSync24(abs2))
10625
+ if (!existsSync23(abs2))
10553
10626
  return { path, marker, comment, present: false, removesHost: false };
10554
10627
  const stripped = stripBlockFromContent(readFileSync27(abs2, "utf-8"), marker, comment);
10555
10628
  if (stripped === null)
@@ -10578,7 +10651,7 @@ function planHookRouting(repoRoot3, manifest, recorded, hooksPathValue) {
10578
10651
  const blocked = [];
10579
10652
  for (const b of legacy) {
10580
10653
  const abs2 = resolveManagedBlockPath(repoRoot3, b.path);
10581
- if (!existsSync24(abs2))
10654
+ if (!existsSync23(abs2))
10582
10655
  continue;
10583
10656
  const stripped = stripBlockFromContent(readFileSync27(abs2, "utf-8"), b.marker, b.comment);
10584
10657
  if (stripped === null)
@@ -10620,7 +10693,7 @@ function planUpgrade(ops, repoRoot3, manifest, routing) {
10620
10693
  for (const op of ops) {
10621
10694
  if (op.kind === "create-file") {
10622
10695
  const abs2 = join26(repoRoot3, op.path);
10623
- const exists = existsSync24(abs2);
10696
+ const exists = existsSync23(abs2);
10624
10697
  const owned = ownedFiles.has(op.path) || isDefaultedAgentVendorPath(op.path, manifest);
10625
10698
  let action;
10626
10699
  let triggerChange;
@@ -10653,7 +10726,7 @@ function planUpgrade(ops, repoRoot3, manifest, routing) {
10653
10726
  let action;
10654
10727
  if (!owned) {
10655
10728
  action = "not-installed";
10656
- } else if (!existsSync24(abs2)) {
10729
+ } else if (!existsSync23(abs2)) {
10657
10730
  action = "recreate-host";
10658
10731
  hasChanges = true;
10659
10732
  } else {
@@ -10791,7 +10864,7 @@ function applyUpgrade(plan, repoRoot3) {
10791
10864
  if (!s.present)
10792
10865
  continue;
10793
10866
  const abs2 = resolveManagedBlockPath(repoRoot3, s.path);
10794
- if (!existsSync24(abs2))
10867
+ if (!existsSync23(abs2))
10795
10868
  continue;
10796
10869
  const stripped = stripBlockFromContent(readFileSync27(abs2, "utf-8"), s.marker, s.comment);
10797
10870
  if (stripped === null)