session-orchestrator 3.24.0 → 4.0.1

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 (435) hide show
  1. package/.agents/skills/architecture/SKILL.md +18 -0
  2. package/.agents/skills/autopilot/SKILL.md +17 -0
  3. package/.agents/skills/bootstrap/SKILL.md +20 -0
  4. package/.agents/skills/brainstorm/SKILL.md +22 -0
  5. package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
  6. package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
  7. package/.agents/skills/debug/SKILL.md +22 -0
  8. package/.agents/skills/discovery/SKILL.md +20 -0
  9. package/.agents/skills/dispatcher/SKILL.md +15 -0
  10. package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
  11. package/.agents/skills/ecosystem-health/SKILL.md +20 -0
  12. package/.agents/skills/eli5/SKILL.md +20 -0
  13. package/.agents/skills/eval/SKILL.md +21 -0
  14. package/.agents/skills/evolve/SKILL.md +21 -0
  15. package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
  16. package/.agents/skills/gitlab-ops/SKILL.md +20 -0
  17. package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
  18. package/.agents/skills/grill/SKILL.md +22 -0
  19. package/.agents/skills/hook-development/SKILL.md +15 -0
  20. package/.agents/skills/mcp-builder/SKILL.md +15 -0
  21. package/.agents/skills/memory-cleanup/SKILL.md +21 -0
  22. package/.agents/skills/mode-selector/SKILL.md +17 -0
  23. package/.agents/skills/npm-publish/SKILL.md +16 -0
  24. package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
  25. package/.agents/skills/persona-panel/SKILL.md +17 -0
  26. package/.agents/skills/plan/SKILL.md +20 -0
  27. package/.agents/skills/playwright-driver/SKILL.md +20 -0
  28. package/.agents/skills/quality-gates/SKILL.md +20 -0
  29. package/.agents/skills/reconcile/SKILL.md +21 -0
  30. package/.agents/skills/remote-offload/SKILL.md +20 -0
  31. package/.agents/skills/repo-audit/SKILL.md +16 -0
  32. package/.agents/skills/session-end/SKILL.md +20 -0
  33. package/.agents/skills/session-plan/SKILL.md +20 -0
  34. package/.agents/skills/session-start/SKILL.md +20 -0
  35. package/.agents/skills/spinout/SKILL.md +16 -0
  36. package/.agents/skills/sunset-review/SKILL.md +16 -0
  37. package/.agents/skills/test-runner/SKILL.md +20 -0
  38. package/.agents/skills/tmux-layout/SKILL.md +21 -0
  39. package/.agents/skills/using-orchestrator/SKILL.md +17 -0
  40. package/.agents/skills/vault-mirror/SKILL.md +15 -0
  41. package/.agents/skills/vault-sync/SKILL.md +15 -0
  42. package/.agents/skills/wave-executor/SKILL.md +20 -0
  43. package/.agents/skills/write-executable-plan/SKILL.md +22 -0
  44. package/.claude-plugin/marketplace.json +1 -1
  45. package/.claude-plugin/plugin.json +1 -1
  46. package/.codex-plugin/plugin.json +3 -2
  47. package/.codex-plugin/skills/architecture/SKILL.md +20 -0
  48. package/.codex-plugin/skills/autopilot/SKILL.md +21 -0
  49. package/.codex-plugin/skills/autopilot/agents/openai.yaml +5 -0
  50. package/.codex-plugin/skills/bootstrap/SKILL.md +22 -0
  51. package/.codex-plugin/skills/bootstrap/agents/openai.yaml +5 -0
  52. package/.codex-plugin/skills/brainstorm/SKILL.md +22 -0
  53. package/.codex-plugin/skills/brainstorm/agents/openai.yaml +5 -0
  54. package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +17 -0
  55. package/.codex-plugin/skills/close/SKILL.md +21 -0
  56. package/.codex-plugin/skills/close/agents/openai.yaml +5 -0
  57. package/.codex-plugin/skills/convergence-monitoring/SKILL.md +24 -0
  58. package/.codex-plugin/skills/debug/SKILL.md +21 -0
  59. package/.codex-plugin/skills/debug/agents/openai.yaml +5 -0
  60. package/.codex-plugin/skills/discovery/SKILL.md +21 -0
  61. package/.codex-plugin/skills/discovery/agents/openai.yaml +5 -0
  62. package/.codex-plugin/skills/dispatcher/SKILL.md +21 -0
  63. package/.codex-plugin/skills/dispatcher/agents/openai.yaml +5 -0
  64. package/.codex-plugin/skills/docs-orchestrator/SKILL.md +20 -0
  65. package/.codex-plugin/skills/ecosystem-health/SKILL.md +22 -0
  66. package/.codex-plugin/skills/eli5/SKILL.md +21 -0
  67. package/.codex-plugin/skills/eli5/agents/openai.yaml +5 -0
  68. package/.codex-plugin/skills/eval/SKILL.md +21 -0
  69. package/.codex-plugin/skills/eval/agents/openai.yaml +5 -0
  70. package/.codex-plugin/skills/evolve/SKILL.md +21 -0
  71. package/.codex-plugin/skills/evolve/agents/openai.yaml +5 -0
  72. package/.codex-plugin/skills/frontmatter-guard/SKILL.md +17 -0
  73. package/.codex-plugin/skills/gitlab-ops/SKILL.md +22 -0
  74. package/.codex-plugin/skills/gitlab-portfolio/SKILL.md +17 -0
  75. package/.codex-plugin/skills/go/SKILL.md +22 -0
  76. package/.codex-plugin/skills/go/agents/openai.yaml +5 -0
  77. package/.codex-plugin/skills/grill/SKILL.md +21 -0
  78. package/.codex-plugin/skills/grill/agents/openai.yaml +5 -0
  79. package/.codex-plugin/skills/harness-audit/SKILL.md +19 -0
  80. package/.codex-plugin/skills/harness-audit/agents/openai.yaml +5 -0
  81. package/.codex-plugin/skills/hook-development/SKILL.md +17 -0
  82. package/.codex-plugin/skills/mcp-builder/SKILL.md +17 -0
  83. package/.codex-plugin/skills/memory-cleanup/SKILL.md +21 -0
  84. package/.codex-plugin/skills/memory-cleanup/agents/openai.yaml +5 -0
  85. package/.codex-plugin/skills/mode-selector/SKILL.md +19 -0
  86. package/.codex-plugin/skills/npm-publish/SKILL.md +18 -0
  87. package/.codex-plugin/skills/peekaboo-driver/SKILL.md +20 -0
  88. package/.codex-plugin/skills/persona-panel/SKILL.md +22 -0
  89. package/.codex-plugin/skills/persona-panel/agents/openai.yaml +5 -0
  90. package/.codex-plugin/skills/plan/SKILL.md +22 -0
  91. package/.codex-plugin/skills/plan/agents/openai.yaml +5 -0
  92. package/.codex-plugin/skills/playwright-driver/SKILL.md +22 -0
  93. package/.codex-plugin/skills/portfolio/SKILL.md +21 -0
  94. package/.codex-plugin/skills/portfolio/agents/openai.yaml +5 -0
  95. package/.codex-plugin/skills/quality-gates/SKILL.md +22 -0
  96. package/.codex-plugin/skills/reconcile/SKILL.md +21 -0
  97. package/.codex-plugin/skills/reconcile/agents/openai.yaml +5 -0
  98. package/.codex-plugin/skills/release/SKILL.md +22 -0
  99. package/.codex-plugin/skills/release/agents/openai.yaml +5 -0
  100. package/.codex-plugin/skills/remote-offload/SKILL.md +22 -0
  101. package/.codex-plugin/skills/repo-audit/SKILL.md +19 -0
  102. package/.codex-plugin/skills/repo-audit/agents/openai.yaml +5 -0
  103. package/.codex-plugin/skills/session/SKILL.md +21 -0
  104. package/.codex-plugin/skills/session/agents/openai.yaml +5 -0
  105. package/.codex-plugin/skills/session-end/SKILL.md +22 -0
  106. package/.codex-plugin/skills/session-plan/SKILL.md +22 -0
  107. package/.codex-plugin/skills/session-start/SKILL.md +22 -0
  108. package/.codex-plugin/skills/spinout/SKILL.md +21 -0
  109. package/.codex-plugin/skills/spinout/agents/openai.yaml +5 -0
  110. package/.codex-plugin/skills/sunset-review/SKILL.md +21 -0
  111. package/.codex-plugin/skills/sunset-review/agents/openai.yaml +5 -0
  112. package/.codex-plugin/skills/templates-ack/SKILL.md +21 -0
  113. package/.codex-plugin/skills/templates-ack/agents/openai.yaml +5 -0
  114. package/.codex-plugin/skills/test/SKILL.md +21 -0
  115. package/.codex-plugin/skills/test/agents/openai.yaml +5 -0
  116. package/.codex-plugin/skills/test-runner/SKILL.md +22 -0
  117. package/.codex-plugin/skills/tmux-layout/SKILL.md +23 -0
  118. package/.codex-plugin/skills/using-orchestrator/SKILL.md +19 -0
  119. package/.codex-plugin/skills/vault-mirror/SKILL.md +17 -0
  120. package/.codex-plugin/skills/vault-sync/SKILL.md +17 -0
  121. package/.codex-plugin/skills/wave-executor/SKILL.md +22 -0
  122. package/.codex-plugin/skills/write-executable-plan/SKILL.md +24 -0
  123. package/.cursor/commands/autopilot.md +2 -2
  124. package/.cursor/commands/bootstrap.md +1 -1
  125. package/.cursor/commands/brainstorm.md +1 -1
  126. package/.cursor/commands/debug.md +1 -1
  127. package/.cursor/commands/discovery.md +1 -1
  128. package/.cursor/commands/dispatcher.md +2 -2
  129. package/.cursor/commands/eli5.md +2 -2
  130. package/.cursor/commands/eval.md +2 -2
  131. package/.cursor/commands/evolve.md +1 -1
  132. package/.cursor/commands/go.md +1 -1
  133. package/.cursor/commands/grill.md +2 -2
  134. package/.cursor/commands/memory-cleanup.md +2 -2
  135. package/.cursor/commands/persona-panel.md +1 -1
  136. package/.cursor/commands/plan.md +1 -1
  137. package/.cursor/commands/portfolio.md +1 -1
  138. package/.cursor/commands/reconcile.md +2 -2
  139. package/.cursor/commands/release.md +2 -2
  140. package/.cursor/commands/session.md +2 -2
  141. package/.cursor/commands/spinout.md +2 -2
  142. package/.cursor/commands/sunset-review.md +2 -2
  143. package/.cursor/commands/templates-ack.md +2 -2
  144. package/.cursor/commands/test.md +2 -2
  145. package/.cursor/skills/brainstorm/SKILL.md +1 -1
  146. package/.cursor/skills/eval/SKILL.md +1 -1
  147. package/.cursor/skills/quality-gates/SKILL.md +1 -1
  148. package/.cursor/skills/remote-offload/SKILL.md +1 -1
  149. package/.cursor-plugin/plugin.json +30 -0
  150. package/.orchestrator/policy/blocked-commands.json +121 -0
  151. package/.orchestrator/policy/ecosystem.schema.json +66 -0
  152. package/.orchestrator/policy/quality-gates.example.json +16 -0
  153. package/.orchestrator/policy/quality-gates.schema.json +38 -0
  154. package/.orchestrator/policy/templates-policy.json +27 -0
  155. package/.orchestrator/policy/test-profiles.json +47 -0
  156. package/AGENTS.md +225 -0
  157. package/CHANGELOG.md +1314 -2
  158. package/NOTICE +11 -6
  159. package/README.md +135 -94
  160. package/agents/eval-judge.md +1 -1
  161. package/agents/skill-applied-judge.md +1 -1
  162. package/assets/wave-lifecycle.svg +98 -0
  163. package/commands/release.md +6 -3
  164. package/commands/session.md +18 -3
  165. package/docs/README.md +4 -0
  166. package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
  167. package/docs/baseline.md +67 -0
  168. package/docs/ci-setup.md +108 -62
  169. package/docs/codex-setup.md +107 -29
  170. package/docs/components.md +38 -16
  171. package/docs/cursor-setup.md +6 -2
  172. package/docs/events-schema.md +9 -6
  173. package/docs/instruction-delivery.md +69 -0
  174. package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
  175. package/docs/migration-v4.md +365 -0
  176. package/docs/pi-setup.md +6 -1
  177. package/docs/plugin-architecture-v3.md +1 -1
  178. package/docs/rule-authoring.md +85 -19
  179. package/docs/scope-collision-guard.md +5 -5
  180. package/docs/session-config-reference.md +57 -56
  181. package/docs/session-config-template.md +6 -29
  182. package/docs/telemetry.md +157 -3
  183. package/docs/vault-docs-architecture.md +50 -11
  184. package/hooks/_lib/hook-import-set.json +1488 -0
  185. package/hooks/_lib/subagent-transcript.mjs +562 -0
  186. package/hooks/config-protection.mjs +2 -2
  187. package/hooks/cwd-change-restore.mjs +2 -2
  188. package/hooks/enforce-commands.mjs +69 -0
  189. package/hooks/hooks-codex.json +1 -1
  190. package/hooks/hooks-cursor.json +10 -0
  191. package/hooks/hooks-pi.json +5 -0
  192. package/hooks/hooks.json +6 -1
  193. package/hooks/loop-guard.mjs +3 -3
  194. package/hooks/on-session-end.mjs +2 -2
  195. package/hooks/on-session-start.mjs +103 -2
  196. package/hooks/on-stop.mjs +60 -14
  197. package/hooks/operator-steer.mjs +2 -2
  198. package/hooks/post-bash-write-verify.mjs +85 -0
  199. package/hooks/post-edit-import-probe.mjs +344 -0
  200. package/hooks/post-subagent-discovery-validator.mjs +187 -431
  201. package/hooks/post-tool-batch-wave-signal.mjs +118 -4
  202. package/hooks/post-tool-failure-corrective-context.mjs +2 -2
  203. package/hooks/post-tooluse-frontend-slop.mjs +3 -3
  204. package/hooks/pre-bash-destructive-guard.mjs +39 -13
  205. package/hooks/skill-invocation-telemetry.mjs +17 -5
  206. package/hooks/subagent-telemetry.mjs +13 -4
  207. package/monitors/monitors.json +3 -3
  208. package/package.json +9 -1
  209. package/pi/prompts/session.md +2 -2
  210. package/scripts/backfill-abandoned-sessions.mjs +50 -4
  211. package/scripts/backfill-learnings-from-vault.mjs +9 -3
  212. package/scripts/dialectic-deriver.mjs +73 -8
  213. package/scripts/export-hw-learnings.mjs +113 -1
  214. package/scripts/generate-agents-skills.mjs +378 -0
  215. package/scripts/generate-codex-skills.mjs +246 -0
  216. package/scripts/generate-cursor-adapter.mjs +45 -8
  217. package/scripts/generate-hook-import-set.mjs +292 -0
  218. package/scripts/lib/agent-status.mjs +13 -2
  219. package/scripts/lib/auto-dream.mjs +38 -36
  220. package/scripts/lib/autonomy/suitability.mjs +6 -0
  221. package/scripts/lib/autopilot/loop.mjs +2 -2
  222. package/scripts/lib/ci-status-banner.mjs +220 -75
  223. package/scripts/lib/codex/plugin-contract.mjs +88 -6
  224. package/scripts/lib/config/auto-dream.mjs +2 -1
  225. package/scripts/lib/config/block-header.mjs +8 -0
  226. package/scripts/lib/config/block-preprocess.mjs +177 -0
  227. package/scripts/lib/config/broken-window.mjs +2 -1
  228. package/scripts/lib/config/cold-start.mjs +2 -1
  229. package/scripts/lib/config/config-protection.mjs +22 -2
  230. package/scripts/lib/config/context-coverage.mjs +2 -1
  231. package/scripts/lib/config/cross-repo.mjs +2 -1
  232. package/scripts/lib/config/custom-phases.mjs +2 -1
  233. package/scripts/lib/config/dialectic.mjs +2 -1
  234. package/scripts/lib/config/discovery-validator.mjs +2 -1
  235. package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
  236. package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
  237. package/scripts/lib/config/docs-orchestrator.mjs +2 -1
  238. package/scripts/lib/config/docs-staleness.mjs +2 -1
  239. package/scripts/lib/config/drift-check.mjs +2 -1
  240. package/scripts/lib/config/eval.mjs +2 -1
  241. package/scripts/lib/config/events-rotation.mjs +2 -1
  242. package/scripts/lib/config/evolve.mjs +8 -2
  243. package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
  244. package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
  245. package/scripts/lib/config/handover-gate.mjs +2 -1
  246. package/scripts/lib/config/health-endpoints.mjs +7 -2
  247. package/scripts/lib/config/host-paths.mjs +20 -4
  248. package/scripts/lib/config/issue-budget.mjs +2 -1
  249. package/scripts/lib/config/loop-guard.mjs +2 -1
  250. package/scripts/lib/config/memory.mjs +2 -1
  251. package/scripts/lib/config/moc-staleness.mjs +2 -1
  252. package/scripts/lib/config/persona-gate-wave.mjs +2 -1
  253. package/scripts/lib/config/private-config-dir.mjs +67 -0
  254. package/scripts/lib/config/reconcile.mjs +2 -1
  255. package/scripts/lib/config/remote-hosts.mjs +2 -1
  256. package/scripts/lib/config/section-extractor.mjs +7 -1
  257. package/scripts/lib/config/skill-evolution.mjs +2 -1
  258. package/scripts/lib/config/slopcheck.mjs +2 -1
  259. package/scripts/lib/config/state-md-lock.mjs +2 -1
  260. package/scripts/lib/config/templates-first.mjs +2 -1
  261. package/scripts/lib/config/test.mjs +2 -1
  262. package/scripts/lib/config/vault-integration.mjs +7 -1
  263. package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
  264. package/scripts/lib/config/vault-staleness.mjs +2 -1
  265. package/scripts/lib/config/vault-sync.mjs +2 -1
  266. package/scripts/lib/config/verification-auto-fix.mjs +2 -1
  267. package/scripts/lib/config/wave-reviewers.mjs +2 -1
  268. package/scripts/lib/config/worktree-orphans.mjs +2 -1
  269. package/scripts/lib/convergence-monitor.mjs +82 -16
  270. package/scripts/lib/dispatcher/rank.mjs +124 -48
  271. package/scripts/lib/ecosystem-health.mjs +16 -2
  272. package/scripts/lib/eval/engine.mjs +9 -1
  273. package/scripts/lib/eval/session-resolve.mjs +23 -4
  274. package/scripts/lib/events.mjs +22 -6
  275. package/scripts/lib/frontmatter-guard.mjs +131 -13
  276. package/scripts/lib/gates/gate-full.mjs +30 -0
  277. package/scripts/lib/gates/gate-helpers.mjs +76 -0
  278. package/scripts/lib/hardware-pattern-detector.mjs +18 -1
  279. package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
  280. package/scripts/lib/host-identity.mjs +50 -11
  281. package/scripts/lib/instruction-budget-guard.mjs +171 -5
  282. package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
  283. package/scripts/lib/learnings/io.mjs +60 -6
  284. package/scripts/lib/memory-proposals/store.mjs +30 -22
  285. package/scripts/lib/owner-config-banner.mjs +41 -6
  286. package/scripts/lib/owner-config-loader.mjs +21 -10
  287. package/scripts/lib/owner-interview.mjs +3 -3
  288. package/scripts/lib/owner-yaml.mjs +215 -15
  289. package/scripts/lib/platform.mjs +108 -15
  290. package/scripts/lib/plugin-update-banner.mjs +414 -0
  291. package/scripts/lib/project-hygiene.mjs +38 -2
  292. package/scripts/lib/qg-command-drift-banner.mjs +50 -12
  293. package/scripts/lib/quality-gate.mjs +133 -44
  294. package/scripts/lib/reconcile/emitter.mjs +68 -6
  295. package/scripts/lib/reconcile/engine.mjs +51 -11
  296. package/scripts/lib/reconcile/idempotency.mjs +37 -4
  297. package/scripts/lib/reconcile/writer.mjs +40 -18
  298. package/scripts/lib/session-close-backfill.mjs +67 -9
  299. package/scripts/lib/session-id.mjs +12 -23
  300. package/scripts/lib/session-identity/own-session.mjs +125 -10
  301. package/scripts/lib/session-lock-shape.mjs +43 -0
  302. package/scripts/lib/session-lock.mjs +5 -10
  303. package/scripts/lib/session-registry.mjs +25 -9
  304. package/scripts/lib/session-schema/constants.mjs +64 -3
  305. package/scripts/lib/session-schema/validator.mjs +38 -4
  306. package/scripts/lib/session-start-probes.mjs +30 -1
  307. package/scripts/lib/sessions-staleness-banner.mjs +18 -11
  308. package/scripts/lib/skill-health/join.mjs +17 -4
  309. package/scripts/lib/state-md.mjs +78 -0
  310. package/scripts/lib/sunset/walker.mjs +6 -0
  311. package/scripts/lib/telemetry/schema.mjs +202 -9
  312. package/scripts/lib/telemetry/sync.mjs +368 -12
  313. package/scripts/lib/telemetry-flush-health-banner.mjs +211 -0
  314. package/scripts/lib/validate/check-agents-skills.mjs +327 -0
  315. package/scripts/lib/validate/check-agents.mjs +3 -3
  316. package/scripts/lib/validate/check-codex-skills.mjs +191 -0
  317. package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
  318. package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
  319. package/scripts/lib/validate/check-owner-leakage.mjs +319 -22
  320. package/scripts/lib/validate/check-skill-links.mjs +193 -0
  321. package/scripts/lib/validate/check-skill-script-paths.mjs +47 -28
  322. package/scripts/lib/validate/check-test-git-config-target.mjs +192 -12
  323. package/scripts/lib/validate/check-unwired-features.mjs +163 -15
  324. package/scripts/lib/validate/check-validator-registration.mjs +10 -4
  325. package/scripts/lib/validate/confidential-names.mjs +95 -30
  326. package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
  327. package/scripts/lib/validate/repo-files.mjs +48 -14
  328. package/scripts/lib/vault-backfill/template.mjs +63 -6
  329. package/scripts/lib/vault-mirror/process.mjs +165 -42
  330. package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
  331. package/scripts/lib/vault-status/narrative-mirror.mjs +127 -18
  332. package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
  333. package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
  334. package/scripts/lib/wave-executor/remote-dispatch.mjs +5 -7
  335. package/scripts/lib/wave-resource-gate.mjs +8 -2
  336. package/scripts/lib/wave-sizing.mjs +4 -1
  337. package/scripts/lib/wave-transcript-tail.mjs +118 -4
  338. package/scripts/materialize-wave-scope.mjs +12 -5
  339. package/scripts/memory-propose.mjs +19 -5
  340. package/scripts/migrate-cold-start-seed.mjs +4 -1
  341. package/scripts/parse-config.mjs +60 -3
  342. package/scripts/release.mjs +430 -31
  343. package/scripts/repair-invalid-sessions.mjs +3 -3
  344. package/scripts/run-quality-gate.mjs +128 -11
  345. package/scripts/site-numbers.mjs +344 -8
  346. package/scripts/sweep-expired-learnings.mjs +90 -0
  347. package/scripts/sync-vault-schema.mjs +3 -1
  348. package/scripts/telemetry.mjs +2 -2
  349. package/scripts/validate-plugin.mjs +164 -0
  350. package/scripts/validate-wave-scope.mjs +28 -8
  351. package/scripts/wave-scope-binding.mjs +215 -0
  352. package/skills/_shared/instruction-file-resolution.md +10 -0
  353. package/skills/_shared/parallel-aware-preamble.md +1 -0
  354. package/skills/_shared/platform-tools.md +1 -1
  355. package/skills/_shared/state-ownership.md +1 -1
  356. package/skills/architecture/SKILL.md +7 -5
  357. package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
  358. package/skills/autopilot/SKILL.md +4 -18
  359. package/skills/claude-md-drift-check/SKILL.md +5 -1
  360. package/skills/claude-md-drift-check/checker.mjs +62 -2
  361. package/skills/convergence-monitoring/SIGNALS.md +55 -0
  362. package/skills/discovery/probes/vault-staleness.mjs +37 -13
  363. package/skills/discovery/probes-arch.md +20 -18
  364. package/skills/dispatcher/SKILL.md +3 -2
  365. package/skills/evolve/SKILL.md +65 -26
  366. package/skills/frontmatter-guard/SKILL.md +11 -5
  367. package/skills/npm-publish/SKILL.md +1 -1
  368. package/skills/reconcile/SKILL.md +33 -0
  369. package/skills/remote-offload/SKILL.md +1 -1
  370. package/skills/session-end/SKILL.md +18 -905
  371. package/skills/session-end/phase-3-6-tail.md +10 -3
  372. package/skills/session-end/plan-verification.md +221 -155
  373. package/skills/session-end/references/phase-2-quality-gate.md +93 -0
  374. package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
  375. package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
  376. package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
  377. package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
  378. package/skills/session-end/references/session-summary-template.md +62 -0
  379. package/skills/session-plan/SKILL.md +49 -0
  380. package/skills/session-start/SKILL.md +22 -904
  381. package/skills/session-start/phase-8-5-express-path.md +1 -1
  382. package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
  383. package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
  384. package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
  385. package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
  386. package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
  387. package/skills/session-start/references/phase-4-ssot-environment-check.md +160 -0
  388. package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
  389. package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
  390. package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
  391. package/skills/vault-sync/SKILL.md +10 -0
  392. package/skills/vault-sync/validator.mjs +21 -27
  393. package/skills/wave-executor/SKILL.md +15 -1
  394. package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
  395. package/skills/wave-executor/references/wave-loop-review.md +570 -0
  396. package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
  397. package/skills/wave-executor/wave-loop.md +14 -1309
  398. package/templates/_shared/journey-manifest.md +10 -6
  399. package/.cursor/commands/autopilot-multi.md +0 -14
  400. package/.cursor/commands/contract-version-bump.md +0 -14
  401. package/.cursor/commands/journey-audit.md +0 -14
  402. package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
  403. package/.cursor/skills/daily/SKILL.md +0 -12
  404. package/.cursor/skills/domain-model/SKILL.md +0 -13
  405. package/.cursor/skills/journey-audit/SKILL.md +0 -13
  406. package/.cursor/skills/skill-creator/SKILL.md +0 -13
  407. package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
  408. package/commands/autopilot-multi.md +0 -74
  409. package/commands/contract-version-bump.md +0 -28
  410. package/commands/journey-audit.md +0 -43
  411. package/pi/prompts/autopilot-multi.md +0 -12
  412. package/pi/prompts/contract-version-bump.md +0 -12
  413. package/pi/prompts/journey-audit.md +0 -12
  414. package/scripts/autopilot-multi.mjs +0 -885
  415. package/scripts/backfill-learnings-expires.mjs +0 -196
  416. package/scripts/backfill-learnings.mjs +0 -203
  417. package/scripts/fleet-instruction-scan.mjs +0 -141
  418. package/scripts/lib/autopilot/dep-graph.mjs +0 -417
  419. package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
  420. package/scripts/lib/webhook-url.mjs +0 -105
  421. package/scripts/lifecycle-sim-v6.mjs +0 -347
  422. package/scripts/migrate-learnings-jsonl.mjs +0 -189
  423. package/scripts/migrate-subagents-jsonl.mjs +0 -196
  424. package/scripts/upload-social-preview.mjs +0 -316
  425. package/skills/_shared/model-selection.md +0 -64
  426. package/skills/contract-version-bump/SKILL.md +0 -219
  427. package/skills/daily/SKILL.md +0 -222
  428. package/skills/daily/generate.sh +0 -92
  429. package/skills/daily/templates/daily.md.tpl +0 -36
  430. package/skills/journey-audit/SKILL.md +0 -270
  431. package/skills/skill-creator/SKILL.md +0 -168
  432. package/skills/ubiquitous-language/SKILL.md +0 -97
  433. package/skills/vault-sync/package-lock.json +0 -40
  434. /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
  435. /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
@@ -1,196 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * backfill-learnings-expires.mjs — one-shot backfill helper for `expires_at`.
4
- *
5
- * Closes issue #323. Surfaced by 2026-05-07 W1 D2 surface-map: 1/129 records
6
- * in .orchestrator/metrics/learnings.jsonl was missing `expires_at` (id:
7
- * `archive-en-masse-residual-policy-2026-05-01`).
8
- *
9
- * For each record without `expires_at`, derives one from `created_at` + `type`
10
- * via `deriveExpiresAt()` from `scripts/lib/learnings.mjs`. Records that
11
- * already have `expires_at` pass through untouched.
12
- *
13
- * Forensics: every patched record gets a `_backfilled_expires_at: true` tag
14
- * so downstream readers can identify backfilled vs originally-stamped values.
15
- *
16
- * Usage:
17
- * node scripts/backfill-learnings-expires.mjs [--source <path>] [--dry-run] [--apply]
18
- *
19
- * Flags:
20
- * --source <path> Path to learnings.jsonl (default: .orchestrator/metrics/learnings.jsonl)
21
- * --dry-run Preview changes without writing (DEFAULT)
22
- * --apply Write patched records back; backup original to <path>.bak.<isoDate>
23
- *
24
- * Exit codes:
25
- * 0 Success (including no-op when nothing needs backfilling)
26
- * 1 Input/validation error
27
- * 2 I/O error
28
- *
29
- * Idempotent: a second --apply run produces 0 to_backfill (every record now
30
- * has expires_at; the `_backfilled_expires_at` tag is preserved).
31
- *
32
- * Output (stdout — single JSON summary line):
33
- * {"total":N,"already_has_expires":A,"to_backfill":B,"parse_errors":P,"applied":bool}
34
- *
35
- * Per-record narration goes to stderr so stdout stays machine-parseable.
36
- */
37
-
38
- import { existsSync, readFileSync, writeFileSync, renameSync, copyFileSync, mkdirSync } from 'node:fs';
39
- import { dirname } from 'node:path';
40
- import { deriveExpiresAt } from './lib/learnings.mjs';
41
-
42
- // ---------------------------------------------------------------------------
43
- // Arg parsing
44
- // ---------------------------------------------------------------------------
45
-
46
- const args = process.argv.slice(2);
47
- if (args.includes('--help') || args.includes('-h')) {
48
- process.stdout.write(
49
- `Usage: backfill-learnings-expires.mjs [--source <path>] [--dry-run] [--apply]
50
-
51
- Options:
52
- --source <path> Path to learnings.jsonl (default: .orchestrator/metrics/learnings.jsonl)
53
- --dry-run Preview changes without writing (DEFAULT)
54
- --apply Write patched records; backup original to <path>.bak.<isoDate>
55
-
56
- Exit codes: 0 success 1 input error 2 I/O error
57
- `
58
- );
59
- process.exit(0);
60
- }
61
-
62
- const applyFlag = args.includes('--apply');
63
- const dryRun = !applyFlag;
64
-
65
- const sourceIdx = args.indexOf('--source');
66
- const sourcePath =
67
- sourceIdx !== -1 && args[sourceIdx + 1]
68
- ? args[sourceIdx + 1]
69
- : '.orchestrator/metrics/learnings.jsonl';
70
-
71
- // ---------------------------------------------------------------------------
72
- // Load
73
- // ---------------------------------------------------------------------------
74
-
75
- if (!existsSync(sourcePath)) {
76
- process.stderr.write(`backfill-learnings-expires: source file not found: ${sourcePath}\n`);
77
- process.exit(1);
78
- }
79
-
80
- let raw;
81
- try {
82
- raw = readFileSync(sourcePath, 'utf8');
83
- } catch (err) {
84
- process.stderr.write(
85
- `backfill-learnings-expires: failed to read ${sourcePath}: ${err.message}\n`
86
- );
87
- process.exit(2);
88
- }
89
-
90
- const lines = raw.split('\n').filter((l) => l.trim().length > 0);
91
-
92
- // ---------------------------------------------------------------------------
93
- // Backfill
94
- // ---------------------------------------------------------------------------
95
-
96
- let countAlready = 0;
97
- let countToBackfill = 0;
98
- let countParseErrors = 0;
99
- const outputLines = [];
100
-
101
- for (const line of lines) {
102
- let parsed;
103
- try {
104
- parsed = JSON.parse(line);
105
- } catch {
106
- countParseErrors++;
107
- process.stderr.write(
108
- `backfill-learnings-expires: WARN skipping malformed JSON line: ${line.slice(0, 80)}\n`
109
- );
110
- // Preserve original line — never destroy data
111
- outputLines.push(line);
112
- continue;
113
- }
114
-
115
- const hasExpires =
116
- typeof parsed.expires_at === 'string' && parsed.expires_at.length > 0;
117
- if (hasExpires) {
118
- countAlready++;
119
- outputLines.push(JSON.stringify(parsed));
120
- continue;
121
- }
122
-
123
- // Derive expires_at from created_at + type. deriveExpiresAt() falls back
124
- // to Date.now() when created_at is missing/unparseable, so we always
125
- // produce a valid ISO timestamp.
126
- const newExpires = deriveExpiresAt(parsed.created_at, parsed.type);
127
- const patched = {
128
- ...parsed,
129
- expires_at: newExpires,
130
- _backfilled_expires_at: true,
131
- };
132
- countToBackfill++;
133
- outputLines.push(JSON.stringify(patched));
134
- process.stderr.write(
135
- `backfill-learnings-expires: patched id=${parsed.id ?? '<no id>'} type=${parsed.type ?? '<no type>'} expires_at=${newExpires}\n`
136
- );
137
- }
138
-
139
- // ---------------------------------------------------------------------------
140
- // Write (--apply only)
141
- // ---------------------------------------------------------------------------
142
-
143
- let applied = false;
144
- if (!dryRun && countToBackfill > 0) {
145
- // Backup first
146
- const isoDate = new Date().toISOString().replace(/[:.]/g, '-');
147
- const backupPath = `${sourcePath}.bak.${isoDate}`;
148
- try {
149
- copyFileSync(sourcePath, backupPath);
150
- } catch (err) {
151
- process.stderr.write(
152
- `backfill-learnings-expires: ERROR failed to create backup ${backupPath}: ${err.message}\n`
153
- );
154
- process.exit(2);
155
- }
156
-
157
- // Atomic write via tmp + rename
158
- const body = outputLines.join('\n') + '\n';
159
- const tmp = `${sourcePath}.backfill-tmp-${process.pid}-${Date.now()}`;
160
- try {
161
- mkdirSync(dirname(sourcePath), { recursive: true });
162
- writeFileSync(tmp, body, 'utf8');
163
- renameSync(tmp, sourcePath);
164
- applied = true;
165
- process.stderr.write(
166
- `backfill-learnings-expires: backup written to ${backupPath}\n`
167
- );
168
- } catch (err) {
169
- process.stderr.write(
170
- `backfill-learnings-expires: ERROR failed to write ${sourcePath}: ${err.message}\n`
171
- );
172
- try {
173
- if (existsSync(tmp)) renameSync(tmp, tmp + '.failed');
174
- } catch {
175
- /* ignore */
176
- }
177
- process.exit(2);
178
- }
179
- }
180
-
181
- // ---------------------------------------------------------------------------
182
- // Summary (single JSON line on stdout)
183
- // ---------------------------------------------------------------------------
184
-
185
- const summary = {
186
- total: lines.length,
187
- already_has_expires: countAlready,
188
- to_backfill: countToBackfill,
189
- parse_errors: countParseErrors,
190
- applied,
191
- dry_run: dryRun,
192
- source: sourcePath,
193
- };
194
- process.stdout.write(JSON.stringify(summary) + '\n');
195
-
196
- process.exit(0);
@@ -1,203 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * backfill-learnings.mjs — normalize producer DIALECTS in learnings.jsonl.
4
- *
5
- * Epic #723 B2. The live corpus historically carried the rule-conversion scope
6
- * under `files` (not the canonical `file_paths`), duplicated `source_session`
7
- * into `session_id`, used `last_seen` instead of `updated_at`, and left
8
- * `next_review: null` / non-canonical (no-millis) timestamps. This one-shot
9
- * backfill routes every line through the schema SSOT (`migrateLegacyLearning`,
10
- * which applies `normalizeDialects` + the insight/subject alias chain + a
11
- * `schema_version:1` stamp), gates the result with `validateLearning`, and
12
- * rewrites the file where a safe normalization exists.
13
- *
14
- * Data-loss safety (three guarantees):
15
- * - A line that fails `JSON.parse` is preserved byte-identical and counted
16
- * (`parse_errors`) — never dropped.
17
- * - A record that still fails `validateLearning` AFTER migration is passed
18
- * through byte-identical and counted (`invalid_after_migration`) — never
19
- * mutated, never flagged.
20
- * - `--apply` writes atomically (copy-to-`.bak-<ISO>` → tmp → rename), so the
21
- * canonical file always exists holding either the old or the new content.
22
- *
23
- * This script duplicates NO normalization logic — all shape work lives in
24
- * `scripts/lib/learnings/schema.mjs`.
25
- *
26
- * Usage:
27
- * node scripts/backfill-learnings.mjs [--file PATH] [--apply|--dry-run]
28
- *
29
- * Modes:
30
- * (default / --dry-run) compute + report intended rewrites per line; does
31
- * not touch the file
32
- * --apply write the normalized file atomically via tmp+rename,
33
- * after copying the original to `${file}.bak-<ISO>`
34
- *
35
- * Exit codes:
36
- * 0 — completed (dry-run or apply)
37
- * 1 — I/O error (file not found, unreadable, write failed)
38
- * 2 — usage error (unknown argument)
39
- *
40
- * Output: JSON summary on stdout (single line)
41
- * {"scanned":N,"normalized":N,"unchanged":N,"parse_errors":N,
42
- * "invalid_after_migration":N,"applied":bool,"dry_run":bool,"backup":"<path>|null","file":"<path>"}
43
- */
44
-
45
- import { readFileSync, writeFileSync, renameSync, copyFileSync, existsSync } from 'node:fs';
46
- import { join, dirname, basename } from 'node:path';
47
- import {
48
- migrateLegacyLearning,
49
- normalizeDialects,
50
- validateLearning,
51
- ValidationError,
52
- } from './lib/learnings/schema.mjs';
53
-
54
- const DEFAULT_FILE = '.orchestrator/metrics/learnings.jsonl';
55
-
56
- function parseArgs(argv) {
57
- const args = { file: DEFAULT_FILE, apply: false };
58
- for (let i = 0; i < argv.length; i++) {
59
- const a = argv[i];
60
- if (a === '--file') args.file = argv[++i];
61
- else if (a === '--apply') args.apply = true;
62
- else if (a === '--dry-run') args.apply = false;
63
- else if (a === '--help' || a === '-h') {
64
- process.stdout.write(
65
- 'Usage: node scripts/backfill-learnings.mjs [--file PATH] [--apply|--dry-run]\n' +
66
- ' --file target learnings.jsonl (default: .orchestrator/metrics/learnings.jsonl)\n' +
67
- ' --dry-run report normalizations; do not modify file (default)\n' +
68
- ' --apply rewrite file atomically with a .bak-<ISO> backup\n'
69
- );
70
- process.exit(0);
71
- } else {
72
- process.stderr.write(`backfill-learnings: unknown argument: ${a}\n`);
73
- process.exit(2);
74
- }
75
- }
76
- return args;
77
- }
78
-
79
- /**
80
- * Classify + transform a single parsed record via the schema SSOT.
81
- *
82
- * Returns { outcome, line } where outcome is one of:
83
- * - 'unchanged' : migration is a semantic no-op (serialized form matches input)
84
- * - 'normalized' : migration changed the record AND it validates
85
- * - 'invalid' : migration result still fails validateLearning → keep original
86
- *
87
- * @param {object} parsed — the JSON.parse'd record
88
- * @param {string} originalLine — the verbatim source line (returned untouched on 'invalid')
89
- * @returns {{ outcome: 'unchanged'|'normalized'|'invalid', line: string }}
90
- */
91
- function processRecord(parsed, originalLine) {
92
- // Two SSOT calls, no duplicated normalization logic:
93
- // 1. migrateLegacyLearning — aliases + schema_version:1 stamp + dialects
94
- // (files→file_paths, session_id/last_seen/next_review), byte-exact timestamps.
95
- // 2. normalizeDialects (full) — canonicalize timestamp FORMAT to millis+Z.
96
- // Idempotent for every other dialect (already handled in step 1).
97
- const migrated = normalizeDialects(migrateLegacyLearning(parsed));
98
-
99
- // Gate: a record that cannot pass the schema after migration is passed
100
- // through byte-identical (never mutated, never flagged).
101
- try {
102
- validateLearning(migrated);
103
- } catch (err) {
104
- if (err instanceof ValidationError) {
105
- return { outcome: 'invalid', line: originalLine };
106
- }
107
- throw err;
108
- }
109
-
110
- const migratedLine = JSON.stringify(migrated);
111
- // Semantic-equality against the re-serialized parsed input: a migration that
112
- // reorders nothing and changes no value is a no-op.
113
- if (migratedLine === JSON.stringify(parsed)) {
114
- return { outcome: 'unchanged', line: migratedLine };
115
- }
116
- return { outcome: 'normalized', line: migratedLine };
117
- }
118
-
119
- function main() {
120
- const args = parseArgs(process.argv.slice(2));
121
-
122
- if (!args.file || !existsSync(args.file)) {
123
- process.stderr.write(`backfill-learnings: file not found: ${args.file}\n`);
124
- process.exit(1);
125
- }
126
-
127
- let lines;
128
- try {
129
- lines = readFileSync(args.file, 'utf8').split('\n').filter((l) => l.length > 0);
130
- } catch (err) {
131
- process.stderr.write(`backfill-learnings: read failed: ${err.message}\n`);
132
- process.exit(1);
133
- }
134
-
135
- const outputLines = [];
136
- const counts = {
137
- scanned: 0,
138
- normalized: 0,
139
- unchanged: 0,
140
- parse_errors: 0,
141
- invalid_after_migration: 0,
142
- };
143
-
144
- for (const line of lines) {
145
- counts.scanned++;
146
- let parsed;
147
- try {
148
- parsed = JSON.parse(line);
149
- } catch {
150
- counts.parse_errors++;
151
- outputLines.push(line); // byte-identical preservation — never drop
152
- continue;
153
- }
154
-
155
- const { outcome, line: outLine } = processRecord(parsed, line);
156
- if (outcome === 'invalid') counts.invalid_after_migration++;
157
- else counts[outcome]++;
158
- outputLines.push(outLine);
159
- }
160
-
161
- const summary = {
162
- scanned: counts.scanned,
163
- normalized: counts.normalized,
164
- unchanged: counts.unchanged,
165
- parse_errors: counts.parse_errors,
166
- invalid_after_migration: counts.invalid_after_migration,
167
- applied: false,
168
- dry_run: !args.apply,
169
- backup: null,
170
- file: args.file,
171
- };
172
-
173
- if (!args.apply) {
174
- process.stdout.write(JSON.stringify(summary) + '\n');
175
- return;
176
- }
177
-
178
- // Apply path — POSIX atomic replace, self-contained (no io.mjs dependency).
179
- // 1. copyFileSync: canonical → .bak-<ISO> (backup; canonical still present)
180
- // 2. writeFileSync: normalized → tmp (new content; canonical still present)
181
- // 3. renameSync: tmp → canonical (atomic replace per POSIX)
182
- // The canonical file exists at every step, holding old or new content.
183
- const iso = new Date().toISOString().replace(/[:.]/g, '-');
184
- const backupPath = `${args.file}.bak-${iso}`;
185
- const tmpPath = join(dirname(args.file), `.${basename(args.file)}.tmp-${process.pid}`);
186
- try {
187
- copyFileSync(args.file, backupPath);
188
- writeFileSync(tmpPath, outputLines.join('\n') + '\n', 'utf8');
189
- renameSync(tmpPath, args.file);
190
- summary.applied = true;
191
- summary.backup = backupPath;
192
- } catch (err) {
193
- const recoveryHint = existsSync(backupPath)
194
- ? `Canonical file is intact; backup at ${backupPath}.`
195
- : 'Backup was not created.';
196
- process.stderr.write(`backfill-learnings: write failed: ${err.message}. ${recoveryHint}\n`);
197
- process.exit(1);
198
- }
199
-
200
- process.stdout.write(JSON.stringify(summary) + '\n');
201
- }
202
-
203
- main();
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * fleet-instruction-scan.mjs — always-on instruction load across every repo on the host.
4
- *
5
- * `scripts/measure-context-overhead.sh` measures one directory precisely but
6
- * costs an API call per measurement. This scans the whole fleet for free by
7
- * counting bytes and classifying them the way `scripts/lib/rule-loader.mjs`
8
- * does: a rule file is always-on unless its frontmatter carries `globs:` or
9
- * `paths:` (issue #795), and it reaches wave agents unless it is tagged
10
- * `tier: coordinator-only` (issue #692).
11
- *
12
- * Token estimates use the ratio measured 2026-07-30 on claude-opus-5[1m]:
13
- * 108589 always-on bytes in this repo produced roughly 67396 context tokens,
14
- * i.e. about 1 token per 1.6 bytes. Treat the estimate as an order of
15
- * magnitude and confirm a specific repo with measure-context-overhead.sh.
16
- *
17
- * Usage:
18
- * node scripts/fleet-instruction-scan.mjs
19
- * node scripts/fleet-instruction-scan.mjs ~/Projects/intern ~/Projects/extern
20
- * node scripts/fleet-instruction-scan.mjs --json
21
- */
22
-
23
- import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
24
- import { homedir } from 'node:os';
25
- import { basename, join } from 'node:path';
26
-
27
- const BYTES_PER_TOKEN = 1.6;
28
-
29
- const argv = process.argv.slice(2);
30
- const asJson = argv.includes('--json');
31
- const roots = argv.filter((a) => !a.startsWith('--'));
32
- const ROOTS = roots.length
33
- ? roots
34
- : [
35
- join(homedir(), 'Projects', 'extern'),
36
- join(homedir(), 'Projects', 'intern'),
37
- join(homedir(), 'Projects', 'Ventures'),
38
- join(homedir(), 'Projects', 'Bernhard'),
39
- ];
40
-
41
- /** Classify one rule file the way rule-loader.mjs does. */
42
- function classify(path) {
43
- const body = readFileSync(path, 'utf8');
44
- const fmMatch = body.match(/^---\n([\s\S]*?)\n---/);
45
- const fm = fmMatch ? fmMatch[1] : '';
46
- const tierMatch = fm.match(/^tier:\s*(\S+)/m);
47
- return {
48
- scoped: /^(globs|paths):/m.test(fm),
49
- tier: tierMatch ? tierMatch[1] : 'always',
50
- bytes: Buffer.byteLength(body),
51
- };
52
- }
53
-
54
- function scanRepo(dir) {
55
- let alwaysBytes = 0;
56
- let waveBytes = 0;
57
- let files = 0;
58
- let scopedFiles = 0;
59
- const rulesDir = join(dir, '.claude', 'rules');
60
- if (existsSync(rulesDir)) {
61
- for (const f of readdirSync(rulesDir).filter((n) => n.endsWith('.md'))) {
62
- const c = classify(join(rulesDir, f));
63
- files++;
64
- if (c.scoped) {
65
- scopedFiles++;
66
- continue;
67
- }
68
- alwaysBytes += c.bytes;
69
- if (c.tier !== 'coordinator-only') waveBytes += c.bytes;
70
- }
71
- }
72
- const instructionFile = ['CLAUDE.md', 'AGENTS.md'].map((f) => join(dir, f)).find(existsSync);
73
- const cmBytes = instructionFile ? statSync(instructionFile).size : 0;
74
- return { files, scopedFiles, alwaysBytes, waveBytes, cmBytes, total: alwaysBytes + cmBytes };
75
- }
76
-
77
- const rows = [];
78
- for (const root of ROOTS) {
79
- if (!existsSync(root)) continue;
80
- for (const name of readdirSync(root)) {
81
- const dir = join(root, name);
82
- try {
83
- if (!statSync(dir).isDirectory()) continue;
84
- } catch {
85
- continue;
86
- }
87
- if (!existsSync(join(dir, '.git'))) continue;
88
- rows.push({ repo: `${basename(root)}/${name}`, ...scanRepo(dir) });
89
- }
90
- }
91
- rows.sort((a, b) => b.total - a.total);
92
-
93
- if (asJson) {
94
- console.log(JSON.stringify({ bytesPerToken: BYTES_PER_TOKEN, repos: rows }, null, 2));
95
- process.exit(0);
96
- }
97
-
98
- const pad = (s, n) => String(s).padStart(n);
99
- console.log(
100
- 'REPO'.padEnd(36),
101
- pad('RULES', 6),
102
- pad('SCOPED', 7),
103
- pad('ALWAYS_B', 9),
104
- pad('WAVE_B', 8),
105
- pad('INSTR_B', 8),
106
- pad('EST_TOK', 8),
107
- );
108
- for (const r of rows) {
109
- console.log(
110
- r.repo.padEnd(36),
111
- pad(r.files, 6),
112
- pad(r.scopedFiles, 7),
113
- pad(r.alwaysBytes, 9),
114
- pad(r.waveBytes, 8),
115
- pad(r.cmBytes, 8),
116
- pad(Math.round(r.total / BYTES_PER_TOKEN), 8),
117
- );
118
- }
119
-
120
- const totalFiles = rows.reduce((a, r) => a + r.files, 0);
121
- const totalScoped = rows.reduce((a, r) => a + r.scopedFiles, 0);
122
- const median = (xs) => {
123
- const s = [...xs].sort((a, b) => a - b);
124
- return s.length ? s[Math.floor(s.length / 2)] : 0;
125
- };
126
- const withRules = rows.filter((r) => r.files > 0);
127
-
128
- console.log(`\nrepos scanned : ${rows.length} (${withRules.length} with rule files)`);
129
- console.log(`rule files : ${totalFiles} (${totalScoped} glob/path-scoped, ${totalFiles - totalScoped} always-on)`);
130
- console.log(`median always-on bytes : ${median(withRules.map((r) => r.alwaysBytes))}`);
131
- console.log(`median est. tokens/session: ${Math.round(median(withRules.map((r) => r.total)) / BYTES_PER_TOKEN)}`);
132
-
133
- // A value shared by many repos means a vendored rule set: trimming it at the
134
- // source propagates everywhere, which is the cheapest lever in the fleet.
135
- const byBytes = new Map();
136
- for (const r of withRules) byBytes.set(r.alwaysBytes, (byBytes.get(r.alwaysBytes) || 0) + 1);
137
- const shared = [...byBytes.entries()].filter(([, n]) => n > 1).sort((a, b) => b[1] - a[1]);
138
- if (shared.length) {
139
- console.log('\nidentical always-on totals (vendored rule sets — trim once, propagate widely):');
140
- for (const [bytes, n] of shared.slice(0, 5)) console.log(` ${bytes} B in ${n} repos`);
141
- }