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
@@ -38,26 +38,148 @@
38
38
  *
39
39
  * ── Exports ───────────────────────────────────────────────────────────────────
40
40
  *
41
- * OWNER_YAML_PATH default file path on disk
41
+ * resolvePrivateConfigDir({env}?) THE host-private config dir resolver (#1223)
42
+ * resolveOwnerYamlPath(env?) — owner.yaml path, resolved at CALL time (#1223)
42
43
  * validateOwnerSections(obj) — pure validation, no I/O; bucketed per section (#820)
43
44
  * validateOwnerConfig(obj) — pure validation, no I/O; thin wrapper over validateOwnerSections
44
45
  * loadOwnerConfig({path?}) — reads file; per-section tolerance for OPTIONAL
45
46
  * sections (paths/dispatcher/vaults/baselines) — #820
46
47
  * writeOwnerConfig(config, {path?}) — validates, writes YAML, creates dir
47
48
  * getDefaults() — returns sensible default config object
49
+ *
50
+ * ── Zero bare-specifier imports (GH#62/#63, GitLab #1230) ────────────────────
51
+ *
52
+ * `js-yaml` is resolved LAZILY inside {@link loadOwnerConfig} / {@link
53
+ * writeOwnerConfig} (see {@link getYaml}), never at module load. Importing this
54
+ * module therefore costs `node:fs` + `node:path` + `node:module` and nothing
55
+ * else, which is what keeps it safe on the hook import graph: before this
56
+ * change, `import yaml from 'js-yaml'` at the top of this file crashed FOUR
57
+ * hooks with `ERR_MODULE_NOT_FOUND` for anyone whose `node_modules` was absent
58
+ * (on-session-start, on-session-end, post-edit-validate,
59
+ * skill-invocation-telemetry — measured 2026-09-06 over a `hooks/` + `scripts/`
60
+ * copy with no `node_modules`, 4 of 27 hooks rc=1).
61
+ *
62
+ * When the package cannot be resolved both entry points DEGRADE rather than
63
+ * throw: they return their normal shape plus `reason: 'yaml-parser-missing'`
64
+ * (`source: 'defaults'` / `written: false`) and emit ONE rate-limited stderr
65
+ * WARN naming `npm install` as the fix.
48
66
  */
49
67
 
50
68
  import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
51
69
  import { join, dirname } from 'node:path';
52
- import { homedir } from 'node:os';
53
- import yaml from 'js-yaml';
70
+ import { createRequire } from 'node:module';
71
+ import { resolvePrivateConfigDir } from './config/private-config-dir.mjs';
54
72
 
55
73
  // ---------------------------------------------------------------------------
56
74
  // Constants
57
75
  // ---------------------------------------------------------------------------
58
76
 
59
- /** Default path for the owner persona config file. */
60
- export const OWNER_YAML_PATH = join(homedir(), '.config', 'session-orchestrator', 'owner.yaml');
77
+ /** Basename of the owner persona config file. */
78
+ const OWNER_YAML_FILE = 'owner.yaml';
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Lazy js-yaml resolution (GH#62/#63, GitLab #1230)
82
+ // ---------------------------------------------------------------------------
83
+
84
+ /**
85
+ * Memoised `js-yaml` module, or `false` once resolution has failed.
86
+ * `null` = not yet attempted.
87
+ * @type {null | false | { load: Function, dump: Function }}
88
+ */
89
+ let _yaml = null;
90
+
91
+ /** Guards the one-per-process stderr WARN below. */
92
+ let _yamlWarned = false;
93
+
94
+ /**
95
+ * Resolve `js-yaml` at CALL time instead of at import time (GH#62/#63).
96
+ *
97
+ * WHY `createRequire` and not `await import('js-yaml')`: every caller of
98
+ * {@link loadOwnerConfig} consumes it SYNCHRONOUSLY. Measured 2026-09-06 with
99
+ * `rg -n --glob '!tests/**' 'loadOwnerConfig\(' scripts hooks skills` (minus
100
+ * this file and the unrelated async homonym in `owner-config-loader.mjs`):
101
+ * 9 call sites — 8 in code, 1 in `skills/session-start/SKILL.md:1113` — and
102
+ * `rg 'await\s+loadOwnerConfig'` over the same scope returns ZERO. Eight read
103
+ * `loadOwnerConfig().config` (`hooks/on-session-start.mjs:639`,
104
+ * `hooks/skill-invocation-telemetry.mjs:155`, `scripts/telemetry.mjs:81,130`,
105
+ * `scripts/vault-mirror.mjs:444`, `scripts/lib/telemetry/sync.mjs:202,269`,
106
+ * and the SKILL.md snippet); the ninth destructures the same sync return
107
+ * (`scripts/lib/soul-resolve.mjs:123`). `writeOwnerConfig` is likewise sync at
108
+ * its single call site, `scripts/lib/owner-interview.mjs:228`.
109
+ *
110
+ * Making either loader async would be a breaking change to all of them; a lazy
111
+ * `require()` keeps the sync contract and only fails at CALL time — where the
112
+ * failure is catchable — instead of at module load, where it is not.
113
+ *
114
+ * Same shape as the `getPicomatch()` pattern in `scripts/lib/rule-loader.mjs`
115
+ * and `scripts/lib/validate-vendored-rules.mjs`.
116
+ *
117
+ * @returns {{ load: Function, dump: Function } | null} the module, or `null`
118
+ * when `node_modules` is absent / the package cannot be resolved.
119
+ */
120
+ function getYaml() {
121
+ if (_yaml !== null) return _yaml === false ? null : _yaml;
122
+ try {
123
+ _yaml = createRequire(import.meta.url)('js-yaml');
124
+ } catch {
125
+ _yaml = false;
126
+ }
127
+ return _yaml === false ? null : _yaml;
128
+ }
129
+
130
+ /**
131
+ * Emit the one-per-process actionable WARN for a missing `js-yaml`. Kept to a
132
+ * SINGLE line and rate-limited to once per process, mirroring the GH#63
133
+ * degradation contract `hooks/on-stop.mjs` already satisfies: a missing package
134
+ * must never be louder than the fix it asks for.
135
+ */
136
+ function warnYamlMissing() {
137
+ if (_yamlWarned) return;
138
+ _yamlWarned = true;
139
+ console.warn(
140
+ "WARN owner-yaml: 'js-yaml' is not installed — owner.yaml cannot be parsed or written; " +
141
+ "using defaults. Run 'npm install' in the plugin directory to restore it.",
142
+ );
143
+ }
144
+
145
+ /**
146
+ * Re-export of the single host-private-config-dir resolver (#1223).
147
+ *
148
+ * The implementation lives in the ZERO-IMPORT leaf
149
+ * `scripts/lib/config/private-config-dir.mjs`, NOT here: `host-identity.mjs`
150
+ * sits on `hooks/on-stop.mjs`'s import subgraph (via `session-lock.mjs`), and
151
+ * this module statically imports `js-yaml`. While the resolver lived here,
152
+ * importing it from `host-identity.mjs` dragged `js-yaml` onto THAT subgraph and
153
+ * broke the GH#63 "degrade gracefully without node_modules" contract
154
+ * (`ERR_MODULE_NOT_FOUND` in `tests/hooks/on-stop.test.mjs`).
155
+ *
156
+ * As of GitLab #1230 (2026-09-06) THIS module is no longer a bare-specifier node
157
+ * on that graph either: the `js-yaml` import it used to carry statically is now
158
+ * lazy (see {@link getYaml}), so the four hooks that reach this file —
159
+ * on-session-start, on-session-end, post-edit-validate,
160
+ * skill-invocation-telemetry — load without `node_modules` instead of dying with
161
+ * ERR_MODULE_NOT_FOUND. Keep it that way: any NEW static bare import added here
162
+ * re-breaks all four at once, in a file whose own unit tests would never notice
163
+ * (the repo always has `node_modules`).
164
+ *
165
+ * NOTE for `tests/husky/pre-commit-owner-leakage.test.mjs`: that test copies
166
+ * the CP11 import chain FILE BY FILE into a tmp repo, so the leaf below is on
167
+ * its copied-file list. Any FURTHER repo-local import added here needs the same
168
+ * treatment.
169
+ */
170
+ export { resolvePrivateConfigDir };
171
+
172
+ /**
173
+ * Resolve the owner.yaml path at CALL time via the single private-config-dir
174
+ * resolver {@link resolvePrivateConfigDir} (#1223). Honours
175
+ * `SO_CONFIG_HOME` > `XDG_CONFIG_HOME` > homedir, each trimmed.
176
+ *
177
+ * @param {Record<string, string|undefined>} [env] — env source (default `process.env`)
178
+ * @returns {string} absolute path to owner.yaml
179
+ */
180
+ export function resolveOwnerYamlPath(env = process.env) {
181
+ return join(resolvePrivateConfigDir({ env }), OWNER_YAML_FILE);
182
+ }
61
183
 
62
184
  const VALID_LANGUAGES = /** @type {const} */ (['de', 'en']);
63
185
  const VALID_TONE_STYLES = /** @type {const} */ (['direct', 'neutral', 'friendly']);
@@ -74,8 +196,15 @@ const REQUIRED_SECTIONS = /** @type {const} */ (['owner', 'tone', 'efficiency',
74
196
  * OPTIONAL object sections (#820) — a malformed entry is replaced by its
75
197
  * `getDefaults()` value and reported via `droppedSections` + a stderr WARN,
76
198
  * but does NOT discard the rest of the file.
199
+ *
200
+ * Exported (#1262.4) as the SSOT for consumers that must iterate exactly these
201
+ * sections — currently `scripts/lib/owner-config-banner.mjs`, which derived the
202
+ * #1244 "survived a whole-file discard" set from a hand-mirrored local copy.
203
+ * Frozen so a consumer cannot mutate the shared array.
77
204
  */
78
- const OPTIONAL_OBJECT_SECTIONS = /** @type {const} */ (['paths', 'dispatcher']);
205
+ export const OPTIONAL_OBJECT_SECTIONS = /** @type {const} */ (
206
+ Object.freeze(['paths', 'dispatcher'])
207
+ );
79
208
 
80
209
  /**
81
210
  * OPTIONAL list sections (#820) — malformed entries are passed through
@@ -418,19 +547,43 @@ export function validateOwnerConfig(obj) {
418
547
  * surfaced only via `sectionWarnings` (never dropped, never counted towards
419
548
  * `'partial'`).
420
549
  *
550
+ * MERGE RULE for the whole-file discard (GitLab #1244). The discard returns
551
+ * `getDefaults()` — but a VALID optional object section is merged back on top
552
+ * of its default (`{...defaults[name], ...parsed[name]}`), key by key. `source`
553
+ * stays `'defaults'` and `errors` still carries every required-section error,
554
+ * so no existing caller's branch changes; what changes is that a host-local
555
+ * path the operator DID declare correctly is no longer thrown away because an
556
+ * unrelated section (e.g. `tone:`) is malformed. That silent loss was a
557
+ * fail-OPEN path for the owner-leakage scanner's CP11 rule: a partial
558
+ * owner.yaml carrying only `owner:` + `paths.confidential-names-file:` made the
559
+ * scanner report PASS while matching nothing. An INVALID optional section is
560
+ * still replaced by its default and is now reported via `droppedSections` on
561
+ * this branch too (previously only on the required-valid branch), so a consumer
562
+ * can tell "not configured" from "configured but unusable".
563
+ *
421
564
  * Defensive — never throws.
422
565
  *
566
+ * When `js-yaml` cannot be resolved (no `node_modules`), returns defaults with
567
+ * `source: 'defaults'`, `reason: 'yaml-parser-missing'` and one explanatory
568
+ * entry in `errors` — never throws, never crashes the importing hook (GH#62/#63).
569
+ * When the file exists but cannot be turned into an object at all (unreadable,
570
+ * YAML syntax error, non-mapping top level) the same shape is returned with
571
+ * `reason: 'unparseable'`: in that state NOTHING about the file's contents is
572
+ * knowable, which is the distinction CP11 needs in order to fail CLOSED rather
573
+ * than assume "nothing configured".
574
+ *
423
575
  * @param {{ path?: string }} [opts]
424
576
  * @returns {{
425
577
  * config: object,
426
578
  * source: 'file'|'defaults'|'partial',
427
579
  * errors: string[],
580
+ * reason?: 'yaml-parser-missing'|'unparseable',
428
581
  * droppedSections?: Array<{ section: string, errors: string[] }>,
429
582
  * sectionWarnings?: Array<{ section: string, errors: string[] }>,
430
583
  * }}
431
584
  */
432
585
  export function loadOwnerConfig(opts = {}) {
433
- const filePath = opts.path ?? OWNER_YAML_PATH;
586
+ const filePath = opts.path ?? resolveOwnerYamlPath();
434
587
 
435
588
  if (!existsSync(filePath)) {
436
589
  return { config: getDefaults(), source: 'defaults', errors: [] };
@@ -443,10 +596,24 @@ export function loadOwnerConfig(opts = {}) {
443
596
  return {
444
597
  config: getDefaults(),
445
598
  source: 'defaults',
599
+ reason: 'unparseable',
446
600
  errors: [`failed to read owner.yaml: ${err.message}`],
447
601
  };
448
602
  }
449
603
 
604
+ const yaml = getYaml();
605
+ if (!yaml) {
606
+ warnYamlMissing();
607
+ return {
608
+ config: getDefaults(),
609
+ source: 'defaults',
610
+ reason: 'yaml-parser-missing',
611
+ errors: [
612
+ "yaml-parser-missing: 'js-yaml' is not installed, so owner.yaml could not be parsed (run 'npm install' in the plugin directory)",
613
+ ],
614
+ };
615
+ }
616
+
450
617
  let parsed;
451
618
  try {
452
619
  parsed = yaml.load(raw);
@@ -454,6 +621,7 @@ export function loadOwnerConfig(opts = {}) {
454
621
  return {
455
622
  config: getDefaults(),
456
623
  source: 'defaults',
624
+ reason: 'unparseable',
457
625
  errors: [`YAML parse error: ${err.message}`],
458
626
  };
459
627
  }
@@ -462,20 +630,36 @@ export function loadOwnerConfig(opts = {}) {
462
630
  return {
463
631
  config: getDefaults(),
464
632
  source: 'defaults',
633
+ reason: 'unparseable',
465
634
  errors: ['owner.yaml must contain a YAML mapping at the top level'],
466
635
  };
467
636
  }
468
637
 
469
638
  const { sections, errors: allErrors } = validateOwnerSections(parsed);
470
639
 
471
- // Any REQUIRED section invalid → legacy whole-file-discard, unchanged (#820).
640
+ // Any REQUIRED section invalid → whole-file discard (#820), EXCEPT that a
641
+ // VALID optional object section is merged back onto its default (#1244 — see
642
+ // the MERGE RULE in the JSDoc above). `source` stays 'defaults' and `errors`
643
+ // is unchanged, so every existing caller branch is untouched; only the
644
+ // discarded-but-valid `paths:`/`dispatcher:` keys survive, which is what stops
645
+ // CP11 from going silently inert on a partial owner.yaml.
472
646
  const requiredInvalid = REQUIRED_SECTIONS.some((name) => !sections[name]?.valid);
473
647
  if (requiredInvalid) {
474
- return {
475
- config: getDefaults(),
476
- source: 'defaults',
477
- errors: allErrors,
478
- };
648
+ const discardConfig = getDefaults();
649
+ const discardDropped = [];
650
+ for (const name of OPTIONAL_OBJECT_SECTIONS) {
651
+ const sec = sections[name];
652
+ if (sec?.valid && isPlainObject(parsed[name])) {
653
+ discardConfig[name] = { ...discardConfig[name], ...parsed[name] };
654
+ } else if (sec && !sec.valid) {
655
+ // Present but malformed — already replaced by its default above. Report
656
+ // it so a consumer can distinguish "not configured" from "unusable".
657
+ discardDropped.push({ section: name, errors: sec.errors });
658
+ }
659
+ }
660
+ const discardResult = { config: discardConfig, source: 'defaults', errors: allErrors };
661
+ if (discardDropped.length > 0) discardResult.droppedSections = discardDropped;
662
+ return discardResult;
479
663
  }
480
664
 
481
665
  // All REQUIRED sections valid — tolerate malformed OPTIONAL sections instead
@@ -532,12 +716,16 @@ export function loadOwnerConfig(opts = {}) {
532
716
  *
533
717
  * Synchronous. Defensive — never throws.
534
718
  *
719
+ * When `js-yaml` cannot be resolved (no `node_modules`), returns
720
+ * `{ written: false, reason: 'yaml-parser-missing', errors: [...] }` — the file
721
+ * is left untouched rather than half-written (GH#62/#63).
722
+ *
535
723
  * @param {object} config
536
724
  * @param {{ path?: string }} [opts]
537
- * @returns {{ written: boolean, errors: string[] }}
725
+ * @returns {{ written: boolean, errors: string[], reason?: 'yaml-parser-missing' }}
538
726
  */
539
727
  export function writeOwnerConfig(config, opts = {}) {
540
- const filePath = opts.path ?? OWNER_YAML_PATH;
728
+ const filePath = opts.path ?? resolveOwnerYamlPath();
541
729
 
542
730
  const validation = validateOwnerConfig(config);
543
731
  if (!validation.valid) {
@@ -554,6 +742,18 @@ export function writeOwnerConfig(config, opts = {}) {
554
742
  };
555
743
  }
556
744
 
745
+ const yaml = getYaml();
746
+ if (!yaml) {
747
+ warnYamlMissing();
748
+ return {
749
+ written: false,
750
+ reason: 'yaml-parser-missing',
751
+ errors: [
752
+ "yaml-parser-missing: 'js-yaml' is not installed, so owner.yaml could not be written (run 'npm install' in the plugin directory)",
753
+ ],
754
+ };
755
+ }
756
+
557
757
  let yamlStr;
558
758
  try {
559
759
  yamlStr = yaml.dump(config, { lineWidth: 120, noRefs: true });
@@ -2,10 +2,15 @@
2
2
  * platform.mjs — platform detection for session-orchestrator (Node.js port of platform.sh)
3
3
  * ESM-importable. Uses only Node built-ins. No external dependencies.
4
4
  *
5
- * Exports 10 constants + 5 named helper functions:
6
- * SO_PLATFORM, SO_PLUGIN_ROOT, SO_PROJECT_DIR, SO_STATE_DIR, SO_CONFIG_FILE,
7
- * SO_SHARED_DIR, SO_OS, SO_IS_WINDOWS, SO_IS_WSL, SO_PATH_SEP
8
- * detectPlatform, resolvePluginRoot, resolveProjectDir, resolveStateDir, resolveConfigFile
5
+ * Exports:
6
+ * - lazy memoized accessors (#1153 P5): getPlatform, getPluginRoot, getProjectDir,
7
+ * getStateDir, getConfigFile (+ test-only _resetPlatformCache)
8
+ * - plain constants (no filesystem work): SO_SHARED_DIR, SO_OS, SO_IS_WINDOWS,
9
+ * SO_IS_WSL, SO_PATH_SEP
10
+ * - pure resolvers: detectPlatform, resolvePluginRoot, resolveProjectDir,
11
+ * resolveStateDir, resolveConfigFile
12
+ *
13
+ * NOTHING in this module touches the filesystem at import time.
9
14
  */
10
15
 
11
16
  import { existsSync, statSync } from 'node:fs';
@@ -293,23 +298,111 @@ export function resolveConfigFile(platform) {
293
298
  }
294
299
 
295
300
  // ---------------------------------------------------------------------------
296
- // Auto-initialise compute all exported constants at module load
301
+ // Lazy, memoized accessors (#1153 P5)
297
302
  // ---------------------------------------------------------------------------
303
+ //
304
+ // These five values used to be `export const … = detect…()` evaluated at MODULE
305
+ // LOAD, so every one of the ~31 static importers — including the hottest
306
+ // deny-capable hooks, which run on every single tool call — paid a filesystem
307
+ // walk-up (statSync/existsSync per ancestor directory, twice over for
308
+ // resolvePluginRoot) merely for importing this module, whether or not it ever
309
+ // read the value.
310
+ //
311
+ // They are now computed on FIRST USE and memoized. Call the getter at the point
312
+ // of use, never at a module's top level — a top-level `const X = getProjectDir()`
313
+ // re-creates the exact cost this change removes.
298
314
 
299
- /** @type {"claude"|"codex"|"cursor"|"pi"} */
300
- export const SO_PLATFORM = detectPlatform();
315
+ /**
316
+ * Memo slots. `undefined` is the miss sentinel — `''` is a legitimate
317
+ * resolvePluginRoot() result and must not re-trigger resolution.
318
+ * @type {{platform: ("claude"|"codex"|"cursor"|"pi")|undefined, pluginRoot: string|undefined, projectDir: string|undefined, stateDir: string|undefined, configFile: string|undefined}}
319
+ */
320
+ const _cache = {
321
+ platform: undefined,
322
+ pluginRoot: undefined,
323
+ projectDir: undefined,
324
+ stateDir: undefined,
325
+ configFile: undefined,
326
+ };
301
327
 
302
- /** Absolute path to the session-orchestrator plugin directory (empty string if unresolvable) */
303
- export const SO_PLUGIN_ROOT = resolvePluginRoot(SO_PLATFORM);
328
+ /**
329
+ * Host platform, detected once per process.
330
+ * @returns {"claude"|"codex"|"cursor"|"pi"}
331
+ */
332
+ export function getPlatform() {
333
+ if (_cache.platform === undefined) {
334
+ _cache.platform = detectPlatform();
335
+ }
336
+ return _cache.platform;
337
+ }
304
338
 
305
- /** Absolute path to the current project root */
306
- export const SO_PROJECT_DIR = resolveProjectDir(SO_PLATFORM);
339
+ /**
340
+ * Absolute path to the session-orchestrator plugin directory, resolved once.
341
+ * @returns {string} Absolute path, or empty string if unresolvable.
342
+ */
343
+ export function getPluginRoot() {
344
+ if (_cache.pluginRoot === undefined) {
345
+ _cache.pluginRoot = resolvePluginRoot(getPlatform());
346
+ }
347
+ return _cache.pluginRoot;
348
+ }
307
349
 
308
- /** Platform-native state directory name */
309
- export const SO_STATE_DIR = resolveStateDir(SO_PLATFORM);
350
+ /**
351
+ * Absolute path to the current project root, resolved once.
352
+ * @returns {string}
353
+ */
354
+ export function getProjectDir() {
355
+ if (_cache.projectDir === undefined) {
356
+ _cache.projectDir = resolveProjectDir(getPlatform());
357
+ }
358
+ return _cache.projectDir;
359
+ }
310
360
 
311
- /** Platform config file name */
312
- export const SO_CONFIG_FILE = resolveConfigFile(SO_PLATFORM);
361
+ /**
362
+ * Platform-native state directory name (".claude" | ".codex" | ".cursor" | ".pi").
363
+ * @returns {string}
364
+ */
365
+ export function getStateDir() {
366
+ if (_cache.stateDir === undefined) {
367
+ _cache.stateDir = resolveStateDir(getPlatform());
368
+ }
369
+ return _cache.stateDir;
370
+ }
371
+
372
+ /**
373
+ * Platform config file name ("CLAUDE.md" | "AGENTS.md").
374
+ * @returns {string}
375
+ */
376
+ export function getConfigFile() {
377
+ if (_cache.configFile === undefined) {
378
+ _cache.configFile = resolveConfigFile(getPlatform());
379
+ }
380
+ return _cache.configFile;
381
+ }
382
+
383
+ /**
384
+ * Test-only: drop every memoized value so the next getter re-detects.
385
+ * Production code must never call this — the values are process-stable.
386
+ * @returns {void}
387
+ */
388
+ export function _resetPlatformCache() {
389
+ _cache.platform = undefined;
390
+ _cache.pluginRoot = undefined;
391
+ _cache.projectDir = undefined;
392
+ _cache.stateDir = undefined;
393
+ _cache.configFile = undefined;
394
+ }
395
+
396
+ // The deprecated `export let SO_PLATFORM / SO_PLUGIN_ROOT / SO_PROJECT_DIR /
397
+ // SO_STATE_DIR / SO_CONFIG_FILE` live bindings (#1153 P5) are GONE. They were
398
+ // `undefined` until the matching getter had run in the process, which made
399
+ // every bare read a silent wrong answer. Every consumer now calls the getter
400
+ // (getPlatform(), getProjectDir(), …). A re-introduction is caught by the
401
+ // named-export assertion in tests/lib/platform.test.mjs — do not add them back.
402
+
403
+ // ---------------------------------------------------------------------------
404
+ // Plain constants — no filesystem work, safe to evaluate at load
405
+ // ---------------------------------------------------------------------------
313
406
 
314
407
  /** Shared orchestrator directory name — always ".orchestrator" */
315
408
  export const SO_SHARED_DIR = '.orchestrator';