@attalabs/vinaya 0.23.0 → 0.24.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 +1 -0
  2. package/dist/checks/bin/check-body-bare-digits.js +7 -1
  3. package/dist/checks/bin/check-branch-topology.js +27 -1
  4. package/dist/checks/bin/check-brief-shape.js +7 -1
  5. package/dist/checks/bin/check-changeset-coverage.js +7 -1
  6. package/dist/checks/bin/check-closes-n.js +27 -1
  7. package/dist/checks/bin/check-coherence.js +27 -1
  8. package/dist/checks/bin/check-dead-branch-push.js +7 -1
  9. package/dist/checks/bin/check-dispatch-readiness.js +27 -1
  10. package/dist/checks/bin/check-doc-coverage-push.js +7 -1
  11. package/dist/checks/bin/check-doc-coverage.js +7 -1
  12. package/dist/checks/bin/check-doctrine-no-procedures.js +7 -1
  13. package/dist/checks/bin/check-doctrine-portability.js +7 -1
  14. package/dist/checks/bin/check-evidence-fresh.js +7 -1
  15. package/dist/checks/bin/check-exec-bits.js +7 -1
  16. package/dist/checks/bin/check-first-push-dispatch.js +27 -1
  17. package/dist/checks/bin/check-issue-assignment.js +27 -1
  18. package/dist/checks/bin/check-main-branch-refusal.js +13 -2
  19. package/dist/checks/bin/check-no-disk-state.js +7 -1
  20. package/dist/checks/bin/check-pr-report-density.js +7 -1
  21. package/dist/checks/bin/check-quoted-command.js +38 -12
  22. package/dist/checks/bin/check-reader-resolvable-prose.js +38 -12
  23. package/dist/checks/bin/check-registry-gates.js +7 -1
  24. package/dist/checks/bin/check-retired-vocabulary.js +38 -12
  25. package/dist/checks/bin/check-review-gate.js +7 -1
  26. package/dist/checks/bin/check-single-plan-pr.js +7 -1
  27. package/dist/checks/bin/check-test-plan.js +7 -1
  28. package/dist/checks/bin/check-token-collection-wired.js +7 -1
  29. package/dist/checks/bin/check-token-report.js +7 -1
  30. package/dist/checks/bin/check-workspace-escape.js +7 -1
  31. package/dist/index.js +362 -87
  32. package/package.json +1 -1
  33. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/anchored-region.ts +9 -4
  34. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/blast-radius-domains.ts +7 -1
  35. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-render.ts +462 -0
  36. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-validation.ts +405 -4
  37. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/coherence-checks.ts +19 -0
  38. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/consumer-enumeration.ts +75 -0
  39. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dispatch-gate.ts +44 -0
  40. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-no-procedures.ts +94 -0
  41. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-portability.ts +128 -5
  42. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/gate-audience.ts +3 -0
  43. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/index.ts +25 -3
  44. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-token-report.ts +17 -5
  45. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/pr-report-density.ts +116 -0
  46. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/premise-check.ts +35 -0
  47. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/quoted-command.ts +3 -3
  48. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-gate.ts +116 -7
  49. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-status.ts +200 -0
  50. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-gate.ts +25 -12
  51. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/verdict-extraction.ts +70 -11
  52. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  53. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  54. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  55. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  56. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  58. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  85. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__02a-3g8._.js +1 -1
  91. 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
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
  97. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1mcitst._.js → [root-of-the-server]__1pndh3_._.js} +1 -1
  98. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  99. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
  100. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
  101. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
  102. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +2 -2
  103. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
  104. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_projects_[name]_tranches_[slug]_05ufo8i._.js +3 -3
  105. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  106. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  107. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  108. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  109. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  110. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0jer_drkl1e4r.js → 0zebsmmk1bvnb.js} +4 -4
  111. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{20x-t0a0v129z.js → 1uogpj5w2n5ju.js} +1 -1
  112. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2ou_81ahqw31e.js → 3m1kgax7j2vgs.js} +1 -1
  113. package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
  114. /package/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/{aeg-core → vinaya/studio-standalone/_node_modules/@attalabs/aeg-core}/bin/verify-coherence.ts +0 -0
  115. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5xy_GA7G5KRuE3HDumIiw → QY2GhiI47-765D9DHGy1I}/_buildManifest.js +0 -0
  116. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5xy_GA7G5KRuE3HDumIiw → QY2GhiI47-765D9DHGy1I}/_clientMiddlewareManifest.js +0 -0
  117. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5xy_GA7G5KRuE3HDumIiw → QY2GhiI47-765D9DHGy1I}/_ssgManifest.js +0 -0
@@ -4158,8 +4158,12 @@ function isNewDiskStateFile(path, status) {
4158
4158
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4159
4159
  }
4160
4160
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4161
+ function pushesAnyBranchRef(pushRefs) {
4162
+ return pushRefs.split(`
4163
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4164
+ }
4161
4165
  function checkMainBranchRefusal(facts) {
4162
- const { currentSymbolicBranch, defaultBranch } = facts;
4166
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4163
4167
  if (currentSymbolicBranch === null)
4164
4168
  return null;
4165
4169
  if (defaultBranch === null) {
@@ -4171,6 +4175,8 @@ function checkMainBranchRefusal(facts) {
4171
4175
  };
4172
4176
  }
4173
4177
  if (currentSymbolicBranch === defaultBranch) {
4178
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4179
+ return null;
4174
4180
  return {
4175
4181
  reason: "on-default-branch",
4176
4182
  severity: "error",
@@ -4434,6 +4440,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4434
4440
  return findings;
4435
4441
  }
4436
4442
  // src/commands/doctrine.ts
4443
+ import { execFileSync as execFileSync2 } from "node:child_process";
4437
4444
  import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
4438
4445
  import { dirname as dirname2, join as join2, sep } from "node:path";
4439
4446
  import matter2 from "gray-matter";
@@ -4457,17 +4464,36 @@ function packageRoot(moduleUrl) {
4457
4464
 
4458
4465
  // src/commands/doctrine.ts
4459
4466
  var ENTRY_SEGMENTS = ["skills", "aeg", "SKILL.md"];
4460
- function resolveDoctrineRoot(pkg = packageRoot(import.meta.url)) {
4467
+ function resolveDoctrineRoot(pkg = packageRoot(import.meta.url), cwd = process.cwd()) {
4468
+ return resolveDoctrineRootInfo(pkg, cwd)?.root ?? null;
4469
+ }
4470
+ function gitToplevel(cwd) {
4471
+ try {
4472
+ return execFileSync2("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
4473
+ encoding: "utf8",
4474
+ stdio: ["ignore", "pipe", "pipe"]
4475
+ }).trim();
4476
+ } catch {
4477
+ return null;
4478
+ }
4479
+ }
4480
+ function resolveDoctrineRootInfo(pkg = packageRoot(import.meta.url), cwd = process.cwd()) {
4481
+ const toplevel = gitToplevel(cwd);
4482
+ if (toplevel !== null) {
4483
+ const treeRoot = join2(toplevel, "aeg-root");
4484
+ if (existsSync2(join2(treeRoot, "roles")))
4485
+ return { root: treeRoot, source: "tree" };
4486
+ }
4461
4487
  const fromSource = !pkg.split(sep).includes("node_modules");
4462
- const root = fromSource ? join2(dirname2(dirname2(pkg)), "aeg-root") : join2(pkg, "aeg-root");
4463
- return hasDoctrineEntry(root) ? root : null;
4488
+ const bundleRoot = fromSource ? join2(dirname2(dirname2(pkg)), "aeg-root") : join2(pkg, "aeg-root");
4489
+ return hasDoctrineEntry(bundleRoot) ? { root: bundleRoot, source: "bundle" } : null;
4464
4490
  }
4465
4491
  function hasDoctrineEntry(root) {
4466
4492
  return existsSync2(join2(root, ...ENTRY_SEGMENTS));
4467
4493
  }
4468
4494
 
4469
4495
  // src/lib/config.ts
4470
- import { execFileSync as execFileSync2 } from "node:child_process";
4496
+ import { execFileSync as execFileSync3 } from "node:child_process";
4471
4497
  import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, realpathSync, writeFileSync } from "node:fs";
4472
4498
  import { homedir } from "node:os";
4473
4499
  import { dirname as dirname3, join as join3, resolve } from "node:path";
@@ -4699,7 +4725,7 @@ function trustAnchorRepo() {
4699
4725
  return validated;
4700
4726
  }
4701
4727
  try {
4702
- const url = execFileSync2("git", ["remote", "get-url", "origin"], {
4728
+ const url = execFileSync3("git", ["remote", "get-url", "origin"], {
4703
4729
  encoding: "utf-8",
4704
4730
  stdio: ["ignore", "pipe", "pipe"]
4705
4731
  }).trim();
@@ -4713,7 +4739,7 @@ function ghFetchTrustAnchorConfig() {
4713
4739
  const repo = trustAnchorRepo();
4714
4740
  if (!repo)
4715
4741
  throw new Error("could not resolve repo identity for the trust-anchor read");
4716
- return execFileSync2("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
4742
+ return execFileSync3("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
4717
4743
  encoding: "utf-8",
4718
4744
  stdio: ["ignore", "pipe", "pipe"]
4719
4745
  });
@@ -4777,7 +4803,7 @@ function emitCheckError(error) {
4777
4803
  }
4778
4804
 
4779
4805
  // src/lib/diff-evidence.ts
4780
- import { execFileSync as execFileSync3 } from "node:child_process";
4806
+ import { execFileSync as execFileSync4 } from "node:child_process";
4781
4807
  import { join as join4, relative, resolve as resolve2 } from "node:path";
4782
4808
 
4783
4809
  // src/commands/review-post.ts
@@ -4811,7 +4837,7 @@ function parseChangedLineRanges(diffOutput) {
4811
4837
  function fileDiffAgainst(ref, path) {
4812
4838
  let out;
4813
4839
  try {
4814
- out = execFileSync3("git", ["diff", `${ref}...HEAD`, "--", path], {
4840
+ out = execFileSync4("git", ["diff", `${ref}...HEAD`, "--", path], {
4815
4841
  encoding: "utf8",
4816
4842
  stdio: ["ignore", "pipe", "pipe"]
4817
4843
  }).trim();
@@ -4822,7 +4848,7 @@ function fileDiffAgainst(ref, path) {
4822
4848
  }
4823
4849
  function revParse(ref) {
4824
4850
  try {
4825
- return execFileSync3("git", ["rev-parse", "--verify", ref], {
4851
+ return execFileSync4("git", ["rev-parse", "--verify", ref], {
4826
4852
  encoding: "utf8",
4827
4853
  stdio: ["ignore", "pipe", "pipe"]
4828
4854
  }).trim();
@@ -4832,7 +4858,7 @@ function revParse(ref) {
4832
4858
  }
4833
4859
  function repoRoot() {
4834
4860
  try {
4835
- return execFileSync3("git", ["rev-parse", "--show-toplevel"], {
4861
+ return execFileSync4("git", ["rev-parse", "--show-toplevel"], {
4836
4862
  encoding: "utf8",
4837
4863
  stdio: ["ignore", "pipe", "pipe"]
4838
4864
  }).trim();
@@ -4843,7 +4869,7 @@ function repoRoot() {
4843
4869
  function changedFiles(base) {
4844
4870
  let out;
4845
4871
  try {
4846
- out = execFileSync3("git", ["diff", "--name-only", `${base}...HEAD`], {
4872
+ out = execFileSync4("git", ["diff", "--name-only", `${base}...HEAD`], {
4847
4873
  encoding: "utf8",
4848
4874
  stdio: ["ignore", "pipe", "pipe"]
4849
4875
  }).trim();
@@ -4158,8 +4158,12 @@ function isNewDiskStateFile(path, status) {
4158
4158
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4159
4159
  }
4160
4160
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4161
+ function pushesAnyBranchRef(pushRefs) {
4162
+ return pushRefs.split(`
4163
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4164
+ }
4161
4165
  function checkMainBranchRefusal(facts) {
4162
- const { currentSymbolicBranch, defaultBranch } = facts;
4166
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4163
4167
  if (currentSymbolicBranch === null)
4164
4168
  return null;
4165
4169
  if (defaultBranch === null) {
@@ -4171,6 +4175,8 @@ function checkMainBranchRefusal(facts) {
4171
4175
  };
4172
4176
  }
4173
4177
  if (currentSymbolicBranch === defaultBranch) {
4178
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4179
+ return null;
4174
4180
  return {
4175
4181
  reason: "on-default-branch",
4176
4182
  severity: "error",
@@ -4434,6 +4440,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4434
4440
  return findings;
4435
4441
  }
4436
4442
  // src/commands/doctrine.ts
4443
+ import { execFileSync as execFileSync2 } from "node:child_process";
4437
4444
  import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
4438
4445
  import { dirname as dirname2, join as join2, sep } from "node:path";
4439
4446
  import matter2 from "gray-matter";
@@ -4457,17 +4464,36 @@ function packageRoot(moduleUrl) {
4457
4464
 
4458
4465
  // src/commands/doctrine.ts
4459
4466
  var ENTRY_SEGMENTS = ["skills", "aeg", "SKILL.md"];
4460
- function resolveDoctrineRoot(pkg = packageRoot(import.meta.url)) {
4467
+ function resolveDoctrineRoot(pkg = packageRoot(import.meta.url), cwd = process.cwd()) {
4468
+ return resolveDoctrineRootInfo(pkg, cwd)?.root ?? null;
4469
+ }
4470
+ function gitToplevel(cwd) {
4471
+ try {
4472
+ return execFileSync2("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
4473
+ encoding: "utf8",
4474
+ stdio: ["ignore", "pipe", "pipe"]
4475
+ }).trim();
4476
+ } catch {
4477
+ return null;
4478
+ }
4479
+ }
4480
+ function resolveDoctrineRootInfo(pkg = packageRoot(import.meta.url), cwd = process.cwd()) {
4481
+ const toplevel = gitToplevel(cwd);
4482
+ if (toplevel !== null) {
4483
+ const treeRoot = join2(toplevel, "aeg-root");
4484
+ if (existsSync2(join2(treeRoot, "roles")))
4485
+ return { root: treeRoot, source: "tree" };
4486
+ }
4461
4487
  const fromSource = !pkg.split(sep).includes("node_modules");
4462
- const root = fromSource ? join2(dirname2(dirname2(pkg)), "aeg-root") : join2(pkg, "aeg-root");
4463
- return hasDoctrineEntry(root) ? root : null;
4488
+ const bundleRoot = fromSource ? join2(dirname2(dirname2(pkg)), "aeg-root") : join2(pkg, "aeg-root");
4489
+ return hasDoctrineEntry(bundleRoot) ? { root: bundleRoot, source: "bundle" } : null;
4464
4490
  }
4465
4491
  function hasDoctrineEntry(root) {
4466
4492
  return existsSync2(join2(root, ...ENTRY_SEGMENTS));
4467
4493
  }
4468
4494
 
4469
4495
  // src/lib/config.ts
4470
- import { execFileSync as execFileSync2 } from "node:child_process";
4496
+ import { execFileSync as execFileSync3 } from "node:child_process";
4471
4497
  import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, realpathSync, writeFileSync } from "node:fs";
4472
4498
  import { homedir } from "node:os";
4473
4499
  import { dirname as dirname3, join as join3, resolve } from "node:path";
@@ -4699,7 +4725,7 @@ function trustAnchorRepo() {
4699
4725
  return validated;
4700
4726
  }
4701
4727
  try {
4702
- const url = execFileSync2("git", ["remote", "get-url", "origin"], {
4728
+ const url = execFileSync3("git", ["remote", "get-url", "origin"], {
4703
4729
  encoding: "utf-8",
4704
4730
  stdio: ["ignore", "pipe", "pipe"]
4705
4731
  }).trim();
@@ -4713,7 +4739,7 @@ function ghFetchTrustAnchorConfig() {
4713
4739
  const repo = trustAnchorRepo();
4714
4740
  if (!repo)
4715
4741
  throw new Error("could not resolve repo identity for the trust-anchor read");
4716
- return execFileSync2("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
4742
+ return execFileSync3("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
4717
4743
  encoding: "utf-8",
4718
4744
  stdio: ["ignore", "pipe", "pipe"]
4719
4745
  });
@@ -4777,7 +4803,7 @@ function emitCheckError(error) {
4777
4803
  }
4778
4804
 
4779
4805
  // src/lib/diff-evidence.ts
4780
- import { execFileSync as execFileSync3 } from "node:child_process";
4806
+ import { execFileSync as execFileSync4 } from "node:child_process";
4781
4807
  import { join as join4, relative, resolve as resolve2 } from "node:path";
4782
4808
 
4783
4809
  // src/commands/review-post.ts
@@ -4811,7 +4837,7 @@ function parseChangedLineRanges(diffOutput) {
4811
4837
  function fileDiffAgainst(ref, path) {
4812
4838
  let out;
4813
4839
  try {
4814
- out = execFileSync3("git", ["diff", `${ref}...HEAD`, "--", path], {
4840
+ out = execFileSync4("git", ["diff", `${ref}...HEAD`, "--", path], {
4815
4841
  encoding: "utf8",
4816
4842
  stdio: ["ignore", "pipe", "pipe"]
4817
4843
  }).trim();
@@ -4822,7 +4848,7 @@ function fileDiffAgainst(ref, path) {
4822
4848
  }
4823
4849
  function revParse(ref) {
4824
4850
  try {
4825
- return execFileSync3("git", ["rev-parse", "--verify", ref], {
4851
+ return execFileSync4("git", ["rev-parse", "--verify", ref], {
4826
4852
  encoding: "utf8",
4827
4853
  stdio: ["ignore", "pipe", "pipe"]
4828
4854
  }).trim();
@@ -4832,7 +4858,7 @@ function revParse(ref) {
4832
4858
  }
4833
4859
  function repoRoot() {
4834
4860
  try {
4835
- return execFileSync3("git", ["rev-parse", "--show-toplevel"], {
4861
+ return execFileSync4("git", ["rev-parse", "--show-toplevel"], {
4836
4862
  encoding: "utf8",
4837
4863
  stdio: ["ignore", "pipe", "pipe"]
4838
4864
  }).trim();
@@ -4843,7 +4869,7 @@ function repoRoot() {
4843
4869
  function changedFiles(base) {
4844
4870
  let out;
4845
4871
  try {
4846
- out = execFileSync3("git", ["diff", "--name-only", `${base}...HEAD`], {
4872
+ out = execFileSync4("git", ["diff", "--name-only", `${base}...HEAD`], {
4847
4873
  encoding: "utf8",
4848
4874
  stdio: ["ignore", "pipe", "pipe"]
4849
4875
  }).trim();
@@ -4159,8 +4159,12 @@ function isNewDiskStateFile(path, status) {
4159
4159
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4160
4160
  }
4161
4161
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4162
+ function pushesAnyBranchRef(pushRefs) {
4163
+ return pushRefs.split(`
4164
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4165
+ }
4162
4166
  function checkMainBranchRefusal(facts) {
4163
- const { currentSymbolicBranch, defaultBranch } = facts;
4167
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4164
4168
  if (currentSymbolicBranch === null)
4165
4169
  return null;
4166
4170
  if (defaultBranch === null) {
@@ -4172,6 +4176,8 @@ function checkMainBranchRefusal(facts) {
4172
4176
  };
4173
4177
  }
4174
4178
  if (currentSymbolicBranch === defaultBranch) {
4179
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4180
+ return null;
4175
4181
  return {
4176
4182
  reason: "on-default-branch",
4177
4183
  severity: "error",
@@ -4158,8 +4158,12 @@ function isNewDiskStateFile(path, status) {
4158
4158
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4159
4159
  }
4160
4160
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4161
+ function pushesAnyBranchRef(pushRefs) {
4162
+ return pushRefs.split(`
4163
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4164
+ }
4161
4165
  function checkMainBranchRefusal(facts) {
4162
- const { currentSymbolicBranch, defaultBranch } = facts;
4166
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4163
4167
  if (currentSymbolicBranch === null)
4164
4168
  return null;
4165
4169
  if (defaultBranch === null) {
@@ -4171,6 +4175,8 @@ function checkMainBranchRefusal(facts) {
4171
4175
  };
4172
4176
  }
4173
4177
  if (currentSymbolicBranch === defaultBranch) {
4178
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4179
+ return null;
4174
4180
  return {
4175
4181
  reason: "on-default-branch",
4176
4182
  severity: "error",
@@ -4434,6 +4440,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4434
4440
  return findings;
4435
4441
  }
4436
4442
  // src/commands/doctrine.ts
4443
+ import { execFileSync as execFileSync2 } from "node:child_process";
4437
4444
  import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
4438
4445
  import { dirname as dirname2, join as join2, sep } from "node:path";
4439
4446
  import matter2 from "gray-matter";
@@ -4457,17 +4464,36 @@ function packageRoot(moduleUrl) {
4457
4464
 
4458
4465
  // src/commands/doctrine.ts
4459
4466
  var ENTRY_SEGMENTS = ["skills", "aeg", "SKILL.md"];
4460
- function resolveDoctrineRoot(pkg = packageRoot(import.meta.url)) {
4467
+ function resolveDoctrineRoot(pkg = packageRoot(import.meta.url), cwd = process.cwd()) {
4468
+ return resolveDoctrineRootInfo(pkg, cwd)?.root ?? null;
4469
+ }
4470
+ function gitToplevel(cwd) {
4471
+ try {
4472
+ return execFileSync2("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
4473
+ encoding: "utf8",
4474
+ stdio: ["ignore", "pipe", "pipe"]
4475
+ }).trim();
4476
+ } catch {
4477
+ return null;
4478
+ }
4479
+ }
4480
+ function resolveDoctrineRootInfo(pkg = packageRoot(import.meta.url), cwd = process.cwd()) {
4481
+ const toplevel = gitToplevel(cwd);
4482
+ if (toplevel !== null) {
4483
+ const treeRoot = join2(toplevel, "aeg-root");
4484
+ if (existsSync2(join2(treeRoot, "roles")))
4485
+ return { root: treeRoot, source: "tree" };
4486
+ }
4461
4487
  const fromSource = !pkg.split(sep).includes("node_modules");
4462
- const root = fromSource ? join2(dirname2(dirname2(pkg)), "aeg-root") : join2(pkg, "aeg-root");
4463
- return hasDoctrineEntry(root) ? root : null;
4488
+ const bundleRoot = fromSource ? join2(dirname2(dirname2(pkg)), "aeg-root") : join2(pkg, "aeg-root");
4489
+ return hasDoctrineEntry(bundleRoot) ? { root: bundleRoot, source: "bundle" } : null;
4464
4490
  }
4465
4491
  function hasDoctrineEntry(root) {
4466
4492
  return existsSync2(join2(root, ...ENTRY_SEGMENTS));
4467
4493
  }
4468
4494
 
4469
4495
  // src/lib/config.ts
4470
- import { execFileSync as execFileSync2 } from "node:child_process";
4496
+ import { execFileSync as execFileSync3 } from "node:child_process";
4471
4497
  import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, realpathSync, writeFileSync } from "node:fs";
4472
4498
  import { homedir } from "node:os";
4473
4499
  import { dirname as dirname3, join as join3, resolve } from "node:path";
@@ -4699,7 +4725,7 @@ function trustAnchorRepo() {
4699
4725
  return validated;
4700
4726
  }
4701
4727
  try {
4702
- const url = execFileSync2("git", ["remote", "get-url", "origin"], {
4728
+ const url = execFileSync3("git", ["remote", "get-url", "origin"], {
4703
4729
  encoding: "utf-8",
4704
4730
  stdio: ["ignore", "pipe", "pipe"]
4705
4731
  }).trim();
@@ -4713,7 +4739,7 @@ function ghFetchTrustAnchorConfig() {
4713
4739
  const repo = trustAnchorRepo();
4714
4740
  if (!repo)
4715
4741
  throw new Error("could not resolve repo identity for the trust-anchor read");
4716
- return execFileSync2("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
4742
+ return execFileSync3("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
4717
4743
  encoding: "utf-8",
4718
4744
  stdio: ["ignore", "pipe", "pipe"]
4719
4745
  });
@@ -4777,7 +4803,7 @@ function emitCheckError(error) {
4777
4803
  }
4778
4804
 
4779
4805
  // src/lib/diff-evidence.ts
4780
- import { execFileSync as execFileSync3 } from "node:child_process";
4806
+ import { execFileSync as execFileSync4 } from "node:child_process";
4781
4807
  import { join as join4, relative, resolve as resolve2 } from "node:path";
4782
4808
 
4783
4809
  // src/commands/review-post.ts
@@ -4811,7 +4837,7 @@ function parseChangedLineRanges(diffOutput) {
4811
4837
  function fileDiffAgainst(ref, path) {
4812
4838
  let out;
4813
4839
  try {
4814
- out = execFileSync3("git", ["diff", `${ref}...HEAD`, "--", path], {
4840
+ out = execFileSync4("git", ["diff", `${ref}...HEAD`, "--", path], {
4815
4841
  encoding: "utf8",
4816
4842
  stdio: ["ignore", "pipe", "pipe"]
4817
4843
  }).trim();
@@ -4822,7 +4848,7 @@ function fileDiffAgainst(ref, path) {
4822
4848
  }
4823
4849
  function revParse(ref) {
4824
4850
  try {
4825
- return execFileSync3("git", ["rev-parse", "--verify", ref], {
4851
+ return execFileSync4("git", ["rev-parse", "--verify", ref], {
4826
4852
  encoding: "utf8",
4827
4853
  stdio: ["ignore", "pipe", "pipe"]
4828
4854
  }).trim();
@@ -4832,7 +4858,7 @@ function revParse(ref) {
4832
4858
  }
4833
4859
  function repoRoot() {
4834
4860
  try {
4835
- return execFileSync3("git", ["rev-parse", "--show-toplevel"], {
4861
+ return execFileSync4("git", ["rev-parse", "--show-toplevel"], {
4836
4862
  encoding: "utf8",
4837
4863
  stdio: ["ignore", "pipe", "pipe"]
4838
4864
  }).trim();
@@ -4843,7 +4869,7 @@ function repoRoot() {
4843
4869
  function changedFiles(base) {
4844
4870
  let out;
4845
4871
  try {
4846
- out = execFileSync3("git", ["diff", "--name-only", `${base}...HEAD`], {
4872
+ out = execFileSync4("git", ["diff", "--name-only", `${base}...HEAD`], {
4847
4873
  encoding: "utf8",
4848
4874
  stdio: ["ignore", "pipe", "pipe"]
4849
4875
  }).trim();
@@ -4157,8 +4157,12 @@ function isNewDiskStateFile(path, status) {
4157
4157
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4158
4158
  }
4159
4159
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4160
+ function pushesAnyBranchRef(pushRefs) {
4161
+ return pushRefs.split(`
4162
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4163
+ }
4160
4164
  function checkMainBranchRefusal(facts) {
4161
- const { currentSymbolicBranch, defaultBranch } = facts;
4165
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4162
4166
  if (currentSymbolicBranch === null)
4163
4167
  return null;
4164
4168
  if (defaultBranch === null) {
@@ -4170,6 +4174,8 @@ function checkMainBranchRefusal(facts) {
4170
4174
  };
4171
4175
  }
4172
4176
  if (currentSymbolicBranch === defaultBranch) {
4177
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4178
+ return null;
4173
4179
  return {
4174
4180
  reason: "on-default-branch",
4175
4181
  severity: "error",
@@ -4157,8 +4157,12 @@ function isNewDiskStateFile(path, status) {
4157
4157
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4158
4158
  }
4159
4159
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4160
+ function pushesAnyBranchRef(pushRefs) {
4161
+ return pushRefs.split(`
4162
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4163
+ }
4160
4164
  function checkMainBranchRefusal(facts) {
4161
- const { currentSymbolicBranch, defaultBranch } = facts;
4165
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4162
4166
  if (currentSymbolicBranch === null)
4163
4167
  return null;
4164
4168
  if (defaultBranch === null) {
@@ -4170,6 +4174,8 @@ function checkMainBranchRefusal(facts) {
4170
4174
  };
4171
4175
  }
4172
4176
  if (currentSymbolicBranch === defaultBranch) {
4177
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4178
+ return null;
4173
4179
  return {
4174
4180
  reason: "on-default-branch",
4175
4181
  severity: "error",
@@ -4154,8 +4154,12 @@ function isNewDiskStateFile(path, status) {
4154
4154
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4155
4155
  }
4156
4156
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4157
+ function pushesAnyBranchRef(pushRefs) {
4158
+ return pushRefs.split(`
4159
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4160
+ }
4157
4161
  function checkMainBranchRefusal(facts) {
4158
- const { currentSymbolicBranch, defaultBranch } = facts;
4162
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4159
4163
  if (currentSymbolicBranch === null)
4160
4164
  return null;
4161
4165
  if (defaultBranch === null) {
@@ -4167,6 +4171,8 @@ function checkMainBranchRefusal(facts) {
4167
4171
  };
4168
4172
  }
4169
4173
  if (currentSymbolicBranch === defaultBranch) {
4174
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4175
+ return null;
4170
4176
  return {
4171
4177
  reason: "on-default-branch",
4172
4178
  severity: "error",
@@ -4158,8 +4158,12 @@ function isNewDiskStateFile(path, status) {
4158
4158
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4159
4159
  }
4160
4160
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4161
+ function pushesAnyBranchRef(pushRefs) {
4162
+ return pushRefs.split(`
4163
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4164
+ }
4161
4165
  function checkMainBranchRefusal(facts) {
4162
- const { currentSymbolicBranch, defaultBranch } = facts;
4166
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4163
4167
  if (currentSymbolicBranch === null)
4164
4168
  return null;
4165
4169
  if (defaultBranch === null) {
@@ -4171,6 +4175,8 @@ function checkMainBranchRefusal(facts) {
4171
4175
  };
4172
4176
  }
4173
4177
  if (currentSymbolicBranch === defaultBranch) {
4178
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4179
+ return null;
4174
4180
  return {
4175
4181
  reason: "on-default-branch",
4176
4182
  severity: "error",
@@ -4157,8 +4157,12 @@ function isNewDiskStateFile(path, status) {
4157
4157
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4158
4158
  }
4159
4159
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4160
+ function pushesAnyBranchRef(pushRefs) {
4161
+ return pushRefs.split(`
4162
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4163
+ }
4160
4164
  function checkMainBranchRefusal(facts) {
4161
- const { currentSymbolicBranch, defaultBranch } = facts;
4165
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4162
4166
  if (currentSymbolicBranch === null)
4163
4167
  return null;
4164
4168
  if (defaultBranch === null) {
@@ -4170,6 +4174,8 @@ function checkMainBranchRefusal(facts) {
4170
4174
  };
4171
4175
  }
4172
4176
  if (currentSymbolicBranch === defaultBranch) {
4177
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4178
+ return null;
4173
4179
  return {
4174
4180
  reason: "on-default-branch",
4175
4181
  severity: "error",
@@ -4158,8 +4158,12 @@ function isNewDiskStateFile(path, status) {
4158
4158
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
4159
4159
  }
4160
4160
  // ../../packages/aeg-core/src/main-branch-refusal.ts
4161
+ function pushesAnyBranchRef(pushRefs) {
4162
+ return pushRefs.split(`
4163
+ `).map((line) => line.trim()).filter((line) => line.length > 0).some((line) => line.split(/\s+/)[2]?.startsWith("refs/heads/") === true);
4164
+ }
4161
4165
  function checkMainBranchRefusal(facts) {
4162
- const { currentSymbolicBranch, defaultBranch } = facts;
4166
+ const { currentSymbolicBranch, defaultBranch, pushRefs = null } = facts;
4163
4167
  if (currentSymbolicBranch === null)
4164
4168
  return null;
4165
4169
  if (defaultBranch === null) {
@@ -4171,6 +4175,8 @@ function checkMainBranchRefusal(facts) {
4171
4175
  };
4172
4176
  }
4173
4177
  if (currentSymbolicBranch === defaultBranch) {
4178
+ if (pushRefs !== null && !pushesAnyBranchRef(pushRefs))
4179
+ return null;
4174
4180
  return {
4175
4181
  reason: "on-default-branch",
4176
4182
  severity: "error",