ruvnet-brain 4.7.20 → 4.7.21

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 (250) hide show
  1. package/README.md +2 -2
  2. package/bin/install.mjs +494 -97
  3. package/kb/download-retry.mjs +93 -21
  4. package/kb/forge-guard-injection.mjs +277 -0
  5. package/kb/forge-update.mjs +166 -38
  6. package/kb/lifecycle-evidence-retention.mjs +151 -14
  7. package/kb/model-requirements.mjs +4 -1
  8. package/kb/refresh-run.mjs +175 -27
  9. package/kb/verify-citation.mjs +15 -2
  10. package/package.json +3 -1
  11. package/plugin/.claude-plugin/plugin.json +1 -1
  12. package/plugin/.codex-plugin/plugin.json +1 -1
  13. package/plugin/mcp/managed-cli-interface.mjs +16 -8
  14. package/plugin/scripts/adr-currency-gate.mjs +2 -1
  15. package/plugin/scripts/advisory-contract.mjs +21 -0
  16. package/plugin/scripts/advocacy-route.mjs +5 -4
  17. package/plugin/scripts/agentdb-recall.mjs +15 -5
  18. package/plugin/scripts/automatic-update.mjs +9 -1
  19. package/plugin/scripts/brain-confirmation.mjs +2 -1
  20. package/plugin/scripts/brain-footprint.mjs +72 -11
  21. package/plugin/scripts/capability-registry.mjs +1 -1
  22. package/plugin/scripts/capacity-aware-parallel-work.mjs +2 -1
  23. package/plugin/scripts/codex-overnight-notice.mjs +33 -0
  24. package/plugin/scripts/completion-claim-evidence.mjs +56 -12
  25. package/plugin/scripts/continuation-gate.mjs +28 -9
  26. package/plugin/scripts/decision-gate.mjs +13 -63
  27. package/plugin/scripts/decision-outcomes.mjs +36 -0
  28. package/plugin/scripts/decision-recall-gate.mjs +40 -5
  29. package/plugin/scripts/decision-record.mjs +8 -3
  30. package/plugin/scripts/degradation-watch.mjs +2 -1
  31. package/plugin/scripts/developer-update-lock.mjs +172 -33
  32. package/plugin/scripts/developer-update-owner.mjs +8 -5
  33. package/plugin/scripts/developer-update-policy.mjs +4 -1
  34. package/plugin/scripts/developer-update.mjs +155 -53
  35. package/plugin/scripts/doc-currency.mjs +2 -16
  36. package/plugin/scripts/duplicate-gate.mjs +2 -1
  37. package/plugin/scripts/entrypoint.mjs +34 -0
  38. package/plugin/scripts/footprint-io.mjs +135 -8
  39. package/plugin/scripts/grok-hook-adapter.mjs +2 -1
  40. package/plugin/scripts/ground-ruvnet.sh +6 -3
  41. package/plugin/scripts/grounding-answer.mjs +2 -1
  42. package/plugin/scripts/grounding-code-projection.mjs +2 -1
  43. package/plugin/scripts/grounding-substance.mjs +2 -1
  44. package/plugin/scripts/grounding-turn-gate.mjs +2 -2
  45. package/plugin/scripts/grounding-turn-mark.mjs +2 -2
  46. package/plugin/scripts/hook-context-budget.mjs +2 -1
  47. package/plugin/scripts/hook-input.mjs +2 -2
  48. package/plugin/scripts/hook-shim.mjs +9 -2
  49. package/plugin/scripts/host-update.mjs +29 -5
  50. package/plugin/scripts/identifier-preflight.mjs +2 -1
  51. package/plugin/scripts/kb-copy-proof.mjs +57 -9
  52. package/plugin/scripts/learn-capture.mjs +2 -1
  53. package/plugin/scripts/learning-store.mjs +62 -16
  54. package/plugin/scripts/lesson-bridge.mjs +2 -2
  55. package/plugin/scripts/lesson-promote.mjs +83 -22
  56. package/plugin/scripts/md-stamp.mjs +2 -1
  57. package/plugin/scripts/native-turn-transcript.mjs +98 -6
  58. package/plugin/scripts/nightly-scheduler.mjs +10 -5
  59. package/plugin/scripts/package-recommender.mjs +2 -2
  60. package/plugin/scripts/project-store-resolver.mjs +19 -0
  61. package/plugin/scripts/routing-outcome-capture.mjs +2 -1
  62. package/plugin/scripts/session-snapshot-hook.mjs +24 -4
  63. package/plugin/scripts/session-start-core.mjs +5 -15
  64. package/plugin/scripts/session-start-health.mjs +97 -10
  65. package/plugin/scripts/session-start-issue-alert.mjs +63 -0
  66. package/plugin/scripts/session-start-update-plane.mjs +15 -1
  67. package/plugin/scripts/signal-watch.mjs +2 -1
  68. package/plugin/scripts/spend-guard.mjs +2 -1
  69. package/plugin/scripts/substitution-wall.mjs +2 -1
  70. package/plugin/scripts/turn-outcome-capture.mjs +7 -3
  71. package/plugin/scripts/unprompted-runtime.mjs +20 -3
  72. package/plugin/scripts/update-apply.mjs +186 -15
  73. package/plugin/skills/release-proof/scripts/release-proof.mjs +2 -1
  74. package/plugin/skills/ruvnet-brain/PLAYBOOK.md +2 -2
  75. package/plugin/skills/ruvnet-brain/SKILL.md +3 -2
  76. package/scripts/adr-072-completion.mjs +2 -1
  77. package/scripts/agentdb-context.mjs +2 -1
  78. package/scripts/agentdb-fleet-doctor.mjs +30 -8
  79. package/scripts/approved-runtime.mjs +2 -1
  80. package/scripts/architecture-review-lock.mjs +2 -1
  81. package/scripts/ascii-drift.mjs +2 -1
  82. package/scripts/brain-latency-50.mjs +2 -1
  83. package/scripts/brain-novice-50.mjs +2 -16
  84. package/scripts/brain-score.mjs +13 -2
  85. package/scripts/build-bundle.mjs +2 -1
  86. package/scripts/build-concepts.mjs +2 -1
  87. package/scripts/candidate-ci-receipt.mjs +2 -1
  88. package/scripts/candidate-host-evidence.mjs +2 -1
  89. package/scripts/card-from-source.mjs +2 -1
  90. package/scripts/ci/warm-brain-models.mjs +2 -1
  91. package/scripts/claims-verify.mjs +7 -3
  92. package/scripts/claude-controlled-terminal.mjs +2 -1
  93. package/scripts/claude-terminal-mod.mjs +2 -1
  94. package/scripts/code-release-corpus.mjs +2 -1
  95. package/scripts/codex-hook-trust-reconcile.mjs +67 -1
  96. package/scripts/codex-hook-trust.mjs +40 -1
  97. package/scripts/codex-hook-wrapper-history.mjs +2 -1
  98. package/scripts/codex-host-execution-proof.mjs +2 -1
  99. package/scripts/completion-claim-replay.mjs +2 -1
  100. package/scripts/console-engine.mjs +8 -3
  101. package/scripts/corpus-canary.mjs +2 -1
  102. package/scripts/corpus-candidate.mjs +2 -2
  103. package/scripts/corpus-coverage-sidecar.mjs +2 -1
  104. package/scripts/corpus-dispatch-decision.mjs +2 -1
  105. package/scripts/corpus-dispatch-receipt.mjs +2 -1
  106. package/scripts/corpus-next-seed.mjs +2 -1
  107. package/scripts/corpus-qa.mjs +2 -1
  108. package/scripts/corpus-reconcile.mjs +2 -2
  109. package/scripts/corpus-watchdog.mjs +2 -1
  110. package/scripts/count-chunks.mjs +2 -1
  111. package/scripts/customer-state-matrix.mjs +2 -1
  112. package/scripts/derive-passage-content-map.mjs +2 -1
  113. package/scripts/development-push-check.mjs +2 -1
  114. package/scripts/dispatch-receipt.mjs +2 -1
  115. package/scripts/doc-currency.mjs +2 -1
  116. package/scripts/dream-issue-gate.mjs +2 -1
  117. package/scripts/dual-host-deliberation.mjs +2 -16
  118. package/scripts/dual-host-suggest.mjs +2 -16
  119. package/scripts/eval-brain.mjs +7 -3
  120. package/scripts/execution-policy.mjs +2 -1
  121. package/scripts/execution-preflight.mjs +2 -1
  122. package/scripts/falsify.mjs +2 -1
  123. package/scripts/fix-metaharness-memretrieve.mjs +2 -1
  124. package/scripts/fix-workstream.mjs +2 -1
  125. package/scripts/full-hints.mjs +2 -1
  126. package/scripts/full-suite-gate.mjs +2 -1
  127. package/scripts/grok-host.mjs +68 -0
  128. package/scripts/hook-qualify-core.mjs +3 -1
  129. package/scripts/hook-qualify.mjs +2 -1
  130. package/scripts/hook-retirement-check.mjs +2 -1
  131. package/scripts/host-registry.mjs +2 -1
  132. package/scripts/independent-review-receipt.mjs +2 -1
  133. package/scripts/ingest-new-repos.mjs +2 -1
  134. package/scripts/ingest-repo.mjs +12 -2
  135. package/scripts/integration-evidence.mjs +2 -1
  136. package/scripts/issue-fix.mjs +7 -24
  137. package/scripts/issue-watch.mjs +116 -40
  138. package/scripts/job-heartbeat.sh +54 -19
  139. package/scripts/key-canary.mjs +9 -3
  140. package/scripts/latency-to-surface.mjs +2 -1
  141. package/scripts/learning-replay-cli.mjs +97 -19
  142. package/scripts/learning-replay-execution.mjs +2 -0
  143. package/scripts/learning-replay-fixture.mjs +3 -0
  144. package/scripts/learning-replay-proof.mjs +14 -13
  145. package/scripts/learning-replay.mjs +3 -3
  146. package/scripts/learnings.mjs +2 -1
  147. package/scripts/lesson-ratify.mjs +88 -40
  148. package/scripts/loop-checkpoint.mjs +2 -1
  149. package/scripts/metaharness-receipts.mjs +2 -1
  150. package/scripts/model-catalog.mjs +2 -1
  151. package/scripts/model-currency-evidence.mjs +6 -4
  152. package/scripts/model-currency.mjs +33 -3
  153. package/scripts/model-native-catalog.mjs +2 -1
  154. package/scripts/model-router-agent-hook.mjs +2 -1
  155. package/scripts/model-router-dispatch.mjs +2 -1
  156. package/scripts/model-router-engine.mjs +2 -1
  157. package/scripts/model-router-outcome.mjs +2 -1
  158. package/scripts/model-router-setup.mjs +2 -1
  159. package/scripts/model-routing-eval.mjs +2 -1
  160. package/scripts/model-routing-gateway.mjs +2 -1
  161. package/scripts/model-routing-launchers.mjs +4 -1
  162. package/scripts/model-terminal-gateway.mjs +2 -1
  163. package/scripts/model-terminal-launchers.mjs +2 -1
  164. package/scripts/model-weekly-analyst.mjs +2 -1
  165. package/scripts/model-weekly-cycle.mjs +2 -1
  166. package/scripts/model-weekly-qualification.mjs +2 -1
  167. package/scripts/nightly-gists.sh +26 -20
  168. package/scripts/nightly-two-run-proof.mjs +2 -1
  169. package/scripts/nightly-watchdog.mjs +158 -47
  170. package/scripts/no-silent-substitution.mjs +2 -1
  171. package/scripts/notify.sh +11 -6
  172. package/scripts/ntfy-inbox.mjs +41 -18
  173. package/scripts/onboarding-console.mjs +47 -8
  174. package/scripts/oracle/abstain-threshold-sweep.mjs +2 -1
  175. package/scripts/oracle/abstain-trace.mjs +2 -1
  176. package/scripts/oracle/doc2query-generate.mjs +2 -1
  177. package/scripts/oracle/doc2query-reach.mjs +2 -1
  178. package/scripts/oracle/judge-train.mjs +2 -1
  179. package/scripts/oracle/need-set-split.mjs +2 -1
  180. package/scripts/oracle/produce-questions.mjs +2 -16
  181. package/scripts/oracle/repo-recall.mjs +2 -2
  182. package/scripts/oracle/retrieval-accuracy.mjs +2 -2
  183. package/scripts/oracle/sona-query-adapter-eval.mjs +2 -1
  184. package/scripts/oracle/source-tree.mjs +2 -15
  185. package/scripts/oracle/source-units.mjs +2 -16
  186. package/scripts/oracle/spike-run.mjs +2 -16
  187. package/scripts/oracle/validate-labels.mjs +2 -16
  188. package/scripts/org-repo-count.mjs +2 -1
  189. package/scripts/package-cards.mjs +2 -1
  190. package/scripts/prepublication-evidence.mjs +2 -1
  191. package/scripts/private-overlay.mjs +2 -1
  192. package/scripts/product-integrity-contract.mjs +2 -1
  193. package/scripts/protected-release-invocation.mjs +2 -1
  194. package/scripts/public-verification-abandon.mjs +2 -1
  195. package/scripts/public-verification-aggregate.mjs +2 -1
  196. package/scripts/public-verification-finalizer.mjs +2 -1
  197. package/scripts/public-verification-inputs.mjs +2 -1
  198. package/scripts/public-verification-lane.mjs +2 -1
  199. package/scripts/publication-receipt.mjs +2 -1
  200. package/scripts/published-surface-probe.mjs +2 -1
  201. package/scripts/qe/card-lane-gate.mjs +2 -16
  202. package/scripts/qe/session-start-gate.mjs +2 -16
  203. package/scripts/qe/ux-suite.mjs +2 -1
  204. package/scripts/qualified-candidate-check.mjs +2 -1
  205. package/scripts/rebuild-gists-from-receipts.mjs +2 -1
  206. package/scripts/recommendation-eval.mjs +2 -1
  207. package/scripts/recommendation-floor.mjs +2 -1
  208. package/scripts/recommendation-judge-score.mjs +2 -1
  209. package/scripts/recommendation-real-host-score.mjs +2 -1
  210. package/scripts/recommendation-real-host.mjs +2 -1
  211. package/scripts/refresh-capability-only-store.mjs +2 -1
  212. package/scripts/refresh-model-catalog.mjs +2 -1
  213. package/scripts/rehearse-corpus-pipeline.mjs +2 -1
  214. package/scripts/release-authority.mjs +2 -1
  215. package/scripts/release-evidence-aggregate.mjs +2 -1
  216. package/scripts/release-payload.mjs +2 -1
  217. package/scripts/release-projection.mjs +2 -1
  218. package/scripts/release-proof.mjs +2 -1
  219. package/scripts/release-qualification-contract.mjs +64 -28
  220. package/scripts/release-qualification.mjs +8 -1
  221. package/scripts/release-vector.mjs +2 -1
  222. package/scripts/restore-local-ingests.mjs +2 -1
  223. package/scripts/retrieval-canary.mjs +2 -1
  224. package/scripts/route-cheap.mjs +2 -1
  225. package/scripts/route-gold-rank.mjs +2 -1
  226. package/scripts/route-index-memory.mjs +2 -1
  227. package/scripts/route-latency-warm.mjs +2 -1
  228. package/scripts/router-utilization.mjs +2 -1
  229. package/scripts/routing-flywheel.mjs +2 -1
  230. package/scripts/run-operational-benchmark.mjs +2 -1
  231. package/scripts/run-operational-benchmark.v3.mjs +2 -1
  232. package/scripts/rvf-index-audit.mjs +2 -16
  233. package/scripts/seal-gist-receipt.mjs +2 -1
  234. package/scripts/security-guidance-codex-compat.mjs +2 -1
  235. package/scripts/selfcheck.mjs +2 -1
  236. package/scripts/signal-watch.mjs +2 -1
  237. package/scripts/source-coverage.mjs +2 -1
  238. package/scripts/stabilization-receipt.mjs +2 -1
  239. package/scripts/stamp-sweep.mjs +2 -1
  240. package/scripts/status-honesty.mjs +2 -1
  241. package/scripts/sync-commands.mjs +2 -2
  242. package/scripts/top100-benchmark.mjs +2 -1
  243. package/scripts/top100-corpus.mjs +2 -1
  244. package/scripts/user-model-hook-install.mjs +2 -1
  245. package/scripts/user-model-prompt-hook.mjs +2 -1
  246. package/scripts/verify-bundle.mjs +3 -1
  247. package/scripts/verify-model-catalog.mjs +2 -1
  248. package/scripts/version.mjs +2 -1
  249. package/scripts/wired-check.mjs +11 -5
  250. package/scripts/worktree-integrity.mjs +2 -2
@@ -29,6 +29,7 @@ import fs from 'node:fs';
29
29
  import path from 'node:path';
30
30
  import { fileURLToPath, pathToFileURL } from 'node:url';
31
31
  import { wilson, repoMatchesExpected } from './eval-brain.mjs';
32
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
32
33
 
33
34
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
34
35
 
@@ -151,6 +152,6 @@ async function main() {
151
152
  console.log(JSON.stringify(brief, null, 1));
152
153
  }
153
154
 
154
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
155
+ if (isDirectInvocation(import.meta.url)) {
155
156
  await main();
156
157
  }
@@ -13,6 +13,7 @@
13
13
  import fs from 'node:fs';
14
14
  import path from 'node:path';
15
15
  import { fileURLToPath, pathToFileURL } from 'node:url';
16
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
16
17
 
17
18
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
18
19
  const arg = (name) => { const i = process.argv.indexOf(name); return i >= 0 ? process.argv[i + 1] : undefined; };
@@ -48,4 +49,4 @@ async function main() {
48
49
  console.log(JSON.stringify({ impl: rel.startsWith('..') ? '<impl>' : rel, kbBuild, stores: repos.length, coldMs, warmMs, retained: retained(before, after) }));
49
50
  }
50
51
 
51
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
52
+ if (isDirectInvocation(import.meta.url)) await main();
@@ -22,6 +22,7 @@ import fs from 'node:fs';
22
22
  import os from 'node:os';
23
23
  import path from 'node:path';
24
24
  import { fileURLToPath, pathToFileURL } from 'node:url';
25
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
25
26
 
26
27
  export const percentile = (xs, p) => {
27
28
  const s = [...xs].sort((a, b) => a - b);
@@ -120,4 +121,4 @@ async function main() {
120
121
  process.exit(0);
121
122
  }
122
123
 
123
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
124
+ if (isDirectInvocation(import.meta.url)) await main();
@@ -179,4 +179,5 @@ export function mainUtil() {
179
179
 
180
180
  import { fileURLToPath } from 'node:url';
181
181
  import path from 'node:path';
182
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) mainUtil();
182
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
183
+ if (isDirectInvocation(import.meta.url)) mainUtil();
@@ -55,6 +55,7 @@ import {
55
55
  import { effectivePrices, loadLabelledRows, OUTCOMES } from './metaharness-router.mjs';
56
56
  import { assertEvolutionAllowed } from './metaharness-gate.mjs';
57
57
  import { loadCatalog, applyProfile, loadProfile } from './model-router-engine.mjs';
58
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
58
59
 
59
60
  // ─── HARD CAPS — the self-DDoS fence. Clamped, never raised by flags. ─────────────────────────────
60
61
  export const HARD_MAX_GENERATIONS = 6;
@@ -599,7 +600,7 @@ async function main() {
599
600
  }
600
601
  }
601
602
 
602
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
603
+ if (isDirectInvocation(import.meta.url)) {
603
604
  main().catch((e) => {
604
605
  process.stderr.write(`routing-flywheel: ${e.stack || e.message}\n`);
605
606
  process.exit(1);
@@ -14,6 +14,7 @@ import {
14
14
  latencyDistribution,
15
15
  verifyFixtureSourceSupport,
16
16
  } from '../evals/operational-benchmark.v2.mjs';
17
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
17
18
 
18
19
  const execFileAsync = promisify(execFile);
19
20
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
@@ -146,6 +147,6 @@ async function main() {
146
147
  if (report.passed !== report.total || report.unavailable.length) process.exitCode = 1;
147
148
  }
148
149
 
149
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
150
+ if (isDirectInvocation(import.meta.url)) {
150
151
  main().catch((error) => { console.error(error.stack || error.message); process.exitCode = 2; });
151
152
  }
@@ -16,6 +16,7 @@ import {
16
16
  preflightOperationalOracle,
17
17
  } from '../evals/operational-benchmark.v3.mjs';
18
18
  import { verifyGrounding as evaluatorVerifyGrounding } from '../kb/verify-citation.mjs';
19
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
19
20
 
20
21
  const execFileAsync = promisify(execFile);
21
22
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
@@ -189,6 +190,6 @@ async function main() {
189
190
  if (!report.qualificationPass) process.exitCode = 1;
190
191
  }
191
192
 
192
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
193
+ if (isDirectInvocation(import.meta.url)) {
193
194
  main().catch((error) => { console.error(error.stack || error.message); process.exitCode = 2; });
194
195
  }
@@ -37,6 +37,7 @@ import {
37
37
  writeRvfGeneration,
38
38
  } from './rvf-generation.mjs';
39
39
  import { metricFromId, readRvfStoredVectors } from './rvf-wire.mjs';
40
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
40
41
 
41
42
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
42
43
  export const RVF_HNSW_THRESHOLD = 1024;
@@ -675,22 +676,7 @@ async function main() {
675
676
  if (failed.length) process.exitCode = 1;
676
677
  }
677
678
 
678
- // Entry-point guard. Compares REALPATHS on both sides: path.resolve() normalizes a path but does
679
- // NOT follow symlinks, while import.meta.url IS symlink-resolved by Node. Through a symlink (npm bin
680
- // shims, wrapper scripts, and every os.tmpdir() path on macOS) the two sides disagree, so main()
681
- // never runs -- and because nothing throws, the process exits 0. A silent exit 0 is indistinguishable
682
- // from "ran, found nothing", which is how prepareCorpusCandidate once reported SUCCESS with no
683
- // archive on disk. Reproduced live 2026-07-27; pinned by tests/unit/entrypoint-symlink.test.mjs.
684
- function isDirectInvocation() {
685
- try {
686
- if (!process.argv[1]) return false;
687
- return fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url));
688
- } catch {
689
- return false;
690
- }
691
- }
692
-
693
- if (isDirectInvocation()) {
679
+ if (isDirectInvocation(import.meta.url)) {
694
680
  main().catch((error) => {
695
681
  console.error(error.stack || error.message);
696
682
  process.exitCode = 1;
@@ -13,6 +13,7 @@ import fs from 'node:fs';
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { observeSourceUniverse } from './source-coverage.mjs';
15
15
  import { buildGistAggregate } from './gist-receipts.mjs';
16
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
16
17
 
17
18
  export const REPO_KB = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'kb');
18
19
 
@@ -57,7 +58,7 @@ async function main(argv = process.argv.slice(2)) {
57
58
  return 0;
58
59
  }
59
60
 
60
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
61
+ if (isDirectInvocation(import.meta.url)) {
61
62
  main().then((code) => { process.exitCode = code; }).catch((error) => {
62
63
  console.error(`[seal-gist-receipt] ${error.message}`);
63
64
  process.exitCode = 1;
@@ -14,6 +14,7 @@ import path from 'node:path';
14
14
  import os from 'node:os';
15
15
  import crypto from 'node:crypto';
16
16
  import { fileURLToPath } from 'node:url';
17
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
17
18
 
18
19
  export const COMPATIBILITY = Object.freeze({
19
20
  version: '2.0.9', nativeContract: 'Codex 0.160.0 PostToolUse',
@@ -128,7 +129,7 @@ export function repairSecurityGuidance({ codexHome = process.env.CODEX_HOME || p
128
129
  return { ...receipt, status: 'patched', backup, patchedSha256: sha256(readRegular(target).bytes) };
129
130
  }
130
131
 
131
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
132
+ if (isDirectInvocation(import.meta.url)) {
132
133
  try {
133
134
  const args = process.argv.slice(2);
134
135
  let codexHome; let apply = false;
@@ -67,6 +67,7 @@ import { fileURLToPath } from 'node:url';
67
67
  // THE canonical continuity policy — the same module bin/install.mjs and scripts/hook-retirement-check.mjs
68
68
  // import. Never re-implement this predicate locally; see the note below the imports.
69
69
  import { isAllowedContinuityRegistration } from '../plugin/scripts/continuity-hook-policy.mjs';
70
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
70
71
 
71
72
  // ── contract constants (ADR-053 §2.5 / §2.3) ────────────────────────────────────────────────────
72
73
  export const STDOUT_CAP_BYTES = 4096; // it lands in the user's context window
@@ -739,7 +740,7 @@ export function formatVerdict(result, { color = null } = {}) {
739
740
  }
740
741
 
741
742
  // ── CLI ─────────────────────────────────────────────────────────────────────────────────────────
742
- if (process.argv[1] && (() => { try { return fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })()) {
743
+ if (isDirectInvocation(import.meta.url)) {
743
744
  const noSecurity = process.argv.includes('--no-security');
744
745
  const json = process.argv.includes('--json');
745
746
  const result = await selfCheck({ security: !noSecurity });
@@ -47,6 +47,7 @@ import os from 'node:os';
47
47
  import { spawnSync } from 'node:child_process';
48
48
  import { fileURLToPath, pathToFileURL } from 'node:url';
49
49
  import { assessCiGate } from './ci-verdict.mjs';
50
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
50
51
 
51
52
  const BRAIN_HOME = process.env.RUVNET_BRAIN_HOME || path.join(os.homedir(), '.cache', 'ruvnet-brain');
52
53
  const SIGNAL_DIR = process.env.RUVNET_SIGNAL_DIR || path.join(BRAIN_HOME, 'external-signals');
@@ -164,7 +165,7 @@ function main() {
164
165
  }
165
166
 
166
167
  function isMain() {
167
- try { return process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href; }
168
+ try { return isDirectInvocation(import.meta.url); }
168
169
  catch { return false; }
169
170
  }
170
171
 
@@ -10,6 +10,7 @@ import { canonicalJson, coverageGenerationFor, digest, validateGistAggregateRece
10
10
  import { repositoryNames } from '../kb/card-lane.mjs';
11
11
  import { rootNeverMaterialized, storeRoot } from '../kb/store-root.mjs';
12
12
  import { isTransientText, retryTransient, sleepSync } from './transient-gh.mjs';
13
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
13
14
 
14
15
  export { canonicalJson, digest } from './coverage-integrity.mjs';
15
16
 
@@ -759,6 +760,6 @@ export async function main(argv = process.argv.slice(2)) {
759
760
  return 0;
760
761
  }
761
762
 
762
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
763
+ if (isDirectInvocation(import.meta.url)) {
763
764
  process.exitCode = await main();
764
765
  }
@@ -8,6 +8,7 @@ import path from 'node:path';
8
8
  import { spawnSync } from 'node:child_process';
9
9
  import { pathToFileURL } from 'node:url';
10
10
  import { evaluateStabilizationCandidateReceipt } from './release-proof.mjs';
11
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
11
12
 
12
13
  const readJson = (file) => JSON.parse(fs.readFileSync(file, 'utf8'));
13
14
  const sha256 = (file) => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
@@ -115,4 +116,4 @@ export function main(args = process.argv.slice(2)) {
115
116
  }
116
117
  }
117
118
 
118
- if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) process.exitCode = main();
119
+ if (isDirectInvocation(import.meta.url)) process.exitCode = main();
@@ -39,6 +39,7 @@ import path from 'node:path';
39
39
  import { spawnSync } from 'node:child_process';
40
40
  import { fileURLToPath } from 'node:url';
41
41
  import { ensureStamp, hasStamp, stampInsertionPoint } from '../plugin/scripts/md-stamp.mjs';
42
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
42
43
 
43
44
  const HERE = path.dirname(fileURLToPath(import.meta.url));
44
45
  export const REPO_ROOT = path.resolve(HERE, '..');
@@ -137,7 +138,7 @@ function main() {
137
138
  }
138
139
 
139
140
  function isMain() {
140
- try { return process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url); }
141
+ try { return isDirectInvocation(import.meta.url); }
141
142
  catch { return false; }
142
143
  }
143
144
 
@@ -28,6 +28,7 @@
28
28
  import fs from 'node:fs';
29
29
  import path from 'node:path';
30
30
  import { fileURLToPath } from 'node:url';
31
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
31
32
 
32
33
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
33
34
 
@@ -115,7 +116,7 @@ export function scanRepo(root = ROOT) {
115
116
  return out;
116
117
  }
117
118
 
118
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
119
+ if (isDirectInvocation(import.meta.url)) {
119
120
  const bad = scanRepo();
120
121
  if (bad.length) {
121
122
  console.error('status-honesty: ASSERTED (underived) terminal success literals found:\n');
@@ -34,6 +34,7 @@
34
34
  import fs from 'node:fs';
35
35
  import path from 'node:path';
36
36
  import { fileURLToPath } from 'node:url';
37
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
37
38
 
38
39
  const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
39
40
  const DIR = path.join(ROOT, 'plugin', 'commands');
@@ -76,8 +77,7 @@ function rebuild(aliasText, canonicalFrontmatter, canonicalBody) {
76
77
  // able to crash the caller that merely imported this module: not-resolvable means not-main.
77
78
  function resolvedIsMain() {
78
79
  try {
79
- return Boolean(process.argv[1])
80
- && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url));
80
+ return isDirectInvocation(import.meta.url);
81
81
  } catch { return false; }
82
82
  }
83
83
  if (!resolvedIsMain()) { /* imported for its exports — do nothing else */ } else {
@@ -10,6 +10,7 @@ import { performance } from 'node:perf_hooks';
10
10
  import { createHash } from 'node:crypto';
11
11
  import { execFileSync } from 'node:child_process';
12
12
  import { pathToFileURL, fileURLToPath } from 'node:url';
13
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
13
14
 
14
15
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
15
16
  const CORPUS = path.join(ROOT, 'evals', 'top-100.json');
@@ -476,4 +477,4 @@ Use --out when a durable evidence artifact is intentional; release checks are pu
476
477
  });
477
478
  }
478
479
 
479
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
480
+ if (isDirectInvocation(import.meta.url)) await main();
@@ -5,6 +5,7 @@ import path from 'node:path';
5
5
  import { createHash } from 'node:crypto';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { semanticAssertionsFor } from './top100-semantic-assertions.mjs';
8
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
8
9
 
9
10
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
10
11
  const HELD_OUT = path.join(ROOT, 'evals', 'held-out.json');
@@ -105,7 +106,7 @@ export function corpusHash(corpus) {
105
106
  return createHash('sha256').update(JSON.stringify(corpus.questions)).digest('hex');
106
107
  }
107
108
 
108
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
109
+ if (isDirectInvocation(import.meta.url)) {
109
110
  const corpus = buildTop100();
110
111
  fs.writeFileSync(OUT, JSON.stringify({ ...corpus, sha256: corpusHash(corpus) }, null, 2) + '\n');
111
112
  console.log(`${OUT}: ${corpus.questions.length} questions, sha256=${corpusHash(corpus)}`);
@@ -5,6 +5,7 @@ import path from 'node:path';
5
5
  import os from 'node:os';
6
6
  import crypto from 'node:crypto';
7
7
  import { pathToFileURL } from 'node:url';
8
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
8
9
 
9
10
  export function shellQuote(value) { return `'${value.replaceAll("'", "'\\''")}'`; }
10
11
 
@@ -134,7 +135,7 @@ export function applyUserModelHooks(plan) {
134
135
  return { applied: true, written };
135
136
  }
136
137
 
137
- if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
138
+ if (isDirectInvocation(import.meta.url)) {
138
139
  try {
139
140
  const args = process.argv.slice(2);
140
141
  if (args.some(arg => !['--apply', '--dry-run', '--plan'].includes(arg))) throw new Error('Usage: user-model-hook-install.mjs [--apply|--dry-run|--plan]');
@@ -8,6 +8,7 @@ import os from 'node:os';
8
8
  import { spawnSync } from 'node:child_process';
9
9
  import { pathToFileURL } from 'node:url';
10
10
  import { weeklyCycleStatus } from './model-weekly-cycle.mjs';
11
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
11
12
 
12
13
  export const PRESENTATION = 'For terminal briefings: give concise executive status; use narrow padded ASCII tables with borders, plain cell text, aligned columns and short rows. Never send pipe-delimited Markdown tables to this terminal. Use short lists when a table would wrap. Do not flood the response with commands or technical logs.';
13
14
 
@@ -65,6 +66,6 @@ async function main() {
65
66
  process.stdout.write(JSON.stringify(envelope(promptContext(payload))) + '\n');
66
67
  }
67
68
 
68
- if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
69
+ if (isDirectInvocation(import.meta.url)) {
69
70
  main().catch(() => process.stdout.write(JSON.stringify(envelope(PRESENTATION)) + '\n'));
70
71
  }
@@ -42,7 +42,9 @@ export function verifyBundle(bundlePath, sigPath = `${bundlePath}.sig`, pubPath
42
42
  }
43
43
 
44
44
  // CLI
45
- if (import.meta.url === `file://${process.argv[1]}`) {
45
+ // Copied ALONE into every brain bundle (scripts/build-bundle.mjs), so it cannot import
46
+ // plugin/scripts/entrypoint.mjs; this is that helper's comparison, inline: real paths on both sides.
47
+ if ((() => { try { return Boolean(process.argv[1]) && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } })()) {
46
48
  const [bundle, sig] = process.argv.slice(2);
47
49
  if (!bundle) { console.error('Usage: node scripts/verify-bundle.mjs <bundle.zip> [<bundle.zip.sig>]'); process.exit(2); }
48
50
  const r = verifyBundle(bundle, sig);
@@ -15,6 +15,7 @@
15
15
  import fs from 'node:fs';
16
16
  import path from 'node:path';
17
17
  import { fileURLToPath } from 'node:url';
18
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
18
19
 
19
20
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
21
  const ROOT = path.resolve(__dirname, '..');
@@ -99,6 +100,6 @@ export async function main(argv = process.argv) {
99
100
  console.log(`✓ model-catalog VERIFIED: ${r.checked} model facts match the ${live ? 'LIVE OpenRouter' : 'committed snapshot'} catalog (pulled ${source.pulledAt}, ${r.ageDays.toFixed(1)}d old ≤ 14d).`);
100
101
  }
101
102
 
102
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
103
+ if (isDirectInvocation(import.meta.url)) {
103
104
  main().catch((e) => { console.error('verify-model-catalog error:', e.message); process.exit(1); });
104
105
  }
@@ -6,6 +6,7 @@
6
6
  import fs from 'node:fs';
7
7
  import path from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
9
10
 
10
11
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
11
12
  export const PLUGIN_JSON = path.join(ROOT, 'plugin', '.claude-plugin', 'plugin.json');
@@ -35,6 +36,6 @@ export function getVersionTag() {
35
36
  export const stripTag = (v) => String(v).replace(/^v/, '');
36
37
 
37
38
  // CLI: `node scripts/version.mjs` prints the version (handy for shell scripts).
38
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
39
+ if (isDirectInvocation(import.meta.url)) {
39
40
  process.stdout.write(getVersion() + '\n');
40
41
  }
@@ -172,8 +172,8 @@ const STANDALONE = [
172
172
  // plist's own ProgramArguments on 2026-07-23, not assumed from the header comment alone:
173
173
  ['clear-claude-tmp', 'launchd, every 3h (out-of-repo scheduler) — confirmed live: '
174
174
  + 'com.stuartkerr.clear-claude-tmp.plist is loaded and its ProgramArguments invoke this exact file'],
175
- ['nightly-gists', 'launchd nightly 21:47 (out-of-repo scheduler) — confirmed live: '
176
- + 'com.ruvnet.brain-gists.plist is loaded and its ProgramArguments invoke this exact file'],
175
+ ['nightly-gists', 'manual re-embed of the developer checkout gists store (the launchd job '
176
+ + 'com.ruvnet.brain-gists was retired 2026-10-26: no installed brain reads that store)'],
177
177
  ['nightly-wrapper', 'author-run maintenance harness, deliberately unscheduled; refuses primary, nested, and dirty worktrees'],
178
178
  ['routing-flywheel', 'launchd nightly 04:45 --dry-run (out-of-repo scheduler) — confirmed live: '
179
179
  + 'com.ruvnet.routing-flywheel.plist is loaded and its ProgramArguments invoke this exact file'],
@@ -409,13 +409,13 @@ export const REQUIRED_OPERATIONAL_EXPORTS = [
409
409
  const isTestFile = (f) => /\.(test|spec)\.(mjs|js)$/.test(path.basename(f))
410
410
  || f.includes(`${path.sep}tests${path.sep}`) || f.startsWith(`tests${path.sep}`);
411
411
 
412
- function walk(abs, recurse, out = []) {
412
+ function walk(abs, recurse, out = [], prune = () => false) {
413
413
  let entries = [];
414
414
  try { entries = fs.readdirSync(abs, { withFileTypes: true }); } catch { return out; }
415
415
  for (const e of entries) {
416
416
  const full = path.join(abs, e.name);
417
417
  if (e.isDirectory()) {
418
- if (recurse && e.name !== 'node_modules' && !e.name.startsWith('.')) walk(full, recurse, out);
418
+ if (recurse && e.name !== 'node_modules' && !e.name.startsWith('.') && !prune(full)) walk(full, recurse, out, prune);
419
419
  } else out.push(full);
420
420
  }
421
421
  return out;
@@ -451,7 +451,10 @@ function callerFiles(repo = REPO) {
451
451
  // wired into pre-push and `wired-check` went on reporting it `manual`. This file's own note names
452
452
  // the remedy: "an invoker outside the roots proves the ROOTS are incomplete — the fix is to add
453
453
  // the root, never to" special-case the module. Same rule, applied to the extension filter.
454
- for (const f of walk(abs, true)) {
454
+ // Pruned BEFORE descending (see the worktrees note below): 100+ agent worktrees under .claude/ are full
455
+ // repository copies, and walking them only to drop every file afterwards dominated this audit's run time.
456
+ const worktrees = path.join(repo, '.claude', 'worktrees');
457
+ for (const f of walk(abs, true, [], (dir) => dir === worktrees)) {
455
458
  // `.claude/` is a caller root because `.claude/settings.json` genuinely invokes hooks. But
456
459
  // `.claude/worktrees/<agent>/` holds FULL COPIES of this repository (Claude Code agent
457
460
  // worktrees), and a copy of the repo is not a caller of the repo. Measured 2026-09-11: with any
@@ -634,6 +637,9 @@ export function callersOf(mod, files, repo = REPO, sourceCache = createInvocatio
634
637
  const rel = path.relative(repo, f).split(path.sep).join('/');
635
638
  if (rel === mod.rel) continue; // self
636
639
  if (isTestFile(rel)) continue; // a test is not a caller
640
+ // Cheap substring pre-filter: callerPattern() only ever matches text that contains the literal file
641
+ // name, so skipping the regex when the name is absent cannot change the result, only its cost.
642
+ if (!sourceCache.read(f)?.includes(mod.file)) continue;
637
643
  const src = sourceCache.commentFree(f);
638
644
  if (src !== null && re.test(src)) hits.push(rel);
639
645
  }
@@ -12,6 +12,7 @@ import path from 'node:path';
12
12
  import crypto from 'node:crypto';
13
13
  import { spawnSync } from 'node:child_process';
14
14
  import { fileURLToPath } from 'node:url';
15
+ import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
15
16
 
16
17
  function git(cwd, args) {
17
18
  const result = spawnSync('git', ['-C', cwd, ...args], { encoding: 'utf8' });
@@ -101,8 +102,7 @@ export function assertPrimaryCheckoutUnchanged(root, before) {
101
102
  return after;
102
103
  }
103
104
 
104
- const invokedDirectly = process.argv[1]
105
- && fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
105
+ const invokedDirectly = isDirectInvocation(import.meta.url);
106
106
  if (invokedDirectly) {
107
107
  try {
108
108
  const command = process.argv[2];