session-orchestrator 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (762) hide show
  1. package/.claude-plugin/marketplace.json +29 -0
  2. package/.claude-plugin/plugin.json +18 -0
  3. package/.codex-plugin/agents/explorer.toml +14 -0
  4. package/.codex-plugin/agents/session-reviewer.toml +23 -0
  5. package/.codex-plugin/agents/wave-worker.toml +15 -0
  6. package/.codex-plugin/config.toml +20 -0
  7. package/.codex-plugin/plugin.json +37 -0
  8. package/.cursor/rules/000-session-orchestrator.mdc +73 -0
  9. package/.cursor/rules/010-session-workflow.mdc +170 -0
  10. package/.cursor/rules/020-quality-gates.mdc +128 -0
  11. package/.cursor/rules/030-wave-execution.mdc +216 -0
  12. package/.cursor/rules/040-discovery.mdc +242 -0
  13. package/.cursor/rules/050-plan.mdc +235 -0
  14. package/.cursor/rules/060-evolve.mdc +232 -0
  15. package/.cursor/rules/070-gitlab-ops.mdc +246 -0
  16. package/.cursor/rules/080-ecosystem-health.mdc +145 -0
  17. package/.mcp.json +8 -0
  18. package/CHANGELOG.md +1544 -0
  19. package/LICENSE +21 -0
  20. package/NOTICE +64 -0
  21. package/README.md +242 -0
  22. package/SECURITY.md +90 -0
  23. package/agents/AGENTS.md +136 -0
  24. package/agents/analyst.md +99 -0
  25. package/agents/architect-reviewer.md +93 -0
  26. package/agents/code-implementer.md +106 -0
  27. package/agents/db-specialist.md +104 -0
  28. package/agents/dialectic-deriver.md +139 -0
  29. package/agents/docs-writer.md +113 -0
  30. package/agents/eval-judge.md +146 -0
  31. package/agents/memory-proposal-collector.md +297 -0
  32. package/agents/qa-strategist.md +102 -0
  33. package/agents/schemas/analyst.schema.json +46 -0
  34. package/agents/schemas/architect-reviewer.schema.json +50 -0
  35. package/agents/schemas/code-implementer.schema.json +61 -0
  36. package/agents/schemas/db-specialist.schema.json +80 -0
  37. package/agents/schemas/docs-writer.schema.json +56 -0
  38. package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
  39. package/agents/schemas/qa-strategist.schema.json +46 -0
  40. package/agents/schemas/security-reviewer.schema.json +86 -0
  41. package/agents/schemas/session-reviewer.schema.json +69 -0
  42. package/agents/schemas/test-writer.schema.json +69 -0
  43. package/agents/schemas/ui-developer.schema.json +90 -0
  44. package/agents/schemas/ux-evaluator.schema.json +51 -0
  45. package/agents/security-reviewer.md +236 -0
  46. package/agents/session-reviewer.md +201 -0
  47. package/agents/skill-applied-judge.md +122 -0
  48. package/agents/test-writer.md +123 -0
  49. package/agents/ui-developer.md +109 -0
  50. package/agents/ux-evaluator.md +161 -0
  51. package/assets/icon.svg +11 -0
  52. package/assets/og-card.png +0 -0
  53. package/assets/og-card.svg +47 -0
  54. package/commands/autopilot-multi.md +74 -0
  55. package/commands/autopilot.md +80 -0
  56. package/commands/bootstrap.md +56 -0
  57. package/commands/brainstorm.md +48 -0
  58. package/commands/close.md +24 -0
  59. package/commands/debug.md +36 -0
  60. package/commands/discovery.md +32 -0
  61. package/commands/dispatcher.md +59 -0
  62. package/commands/eval.md +28 -0
  63. package/commands/evolve.md +10 -0
  64. package/commands/go.md +41 -0
  65. package/commands/grill.md +45 -0
  66. package/commands/harness-audit.md +26 -0
  67. package/commands/memory-cleanup.md +25 -0
  68. package/commands/persona-panel.md +121 -0
  69. package/commands/plan.md +15 -0
  70. package/commands/portfolio.md +97 -0
  71. package/commands/reconcile.md +23 -0
  72. package/commands/repo-audit.md +24 -0
  73. package/commands/session.md +30 -0
  74. package/commands/spinout.md +15 -0
  75. package/commands/sunset-review.md +27 -0
  76. package/commands/templates-ack.md +96 -0
  77. package/commands/test.md +97 -0
  78. package/docs/README.md +105 -0
  79. package/docs/USER-GUIDE.md +1403 -0
  80. package/docs/ci-setup.md +81 -0
  81. package/docs/codex-setup.md +142 -0
  82. package/docs/components.md +74 -0
  83. package/docs/cursor-setup.md +104 -0
  84. package/docs/events-schema.md +81 -0
  85. package/docs/migration-v3.md +148 -0
  86. package/docs/owner-config-schema.md +154 -0
  87. package/docs/persona-panel.md +433 -0
  88. package/docs/pi-setup.md +115 -0
  89. package/docs/plugin-architecture-v3.md +296 -0
  90. package/docs/pm-skills-marketplace.md +114 -0
  91. package/docs/policy-cache-validation-2026-04-28.md +118 -0
  92. package/docs/rule-authoring.md +316 -0
  93. package/docs/session-config-reference.md +1439 -0
  94. package/docs/session-config-template.md +961 -0
  95. package/docs/vault-docs-architecture.md +297 -0
  96. package/hooks/_lib/lock-bootstrap.mjs +272 -0
  97. package/hooks/_lib/lock-reconcile.mjs +93 -0
  98. package/hooks/_lib/profile-gate.mjs +95 -0
  99. package/hooks/_lib/transcript-history.mjs +211 -0
  100. package/hooks/agent-teams-h3-test.sh +362 -0
  101. package/hooks/config-protection.mjs +0 -0
  102. package/hooks/cwd-change-restore.mjs +131 -0
  103. package/hooks/enforce-commands.mjs +179 -0
  104. package/hooks/enforce-scope.mjs +273 -0
  105. package/hooks/hooks-codex.json +60 -0
  106. package/hooks/hooks-cursor.json +15 -0
  107. package/hooks/hooks-pi.json +115 -0
  108. package/hooks/hooks.json +215 -0
  109. package/hooks/loop-guard.mjs +260 -0
  110. package/hooks/on-session-end.mjs +217 -0
  111. package/hooks/on-session-start.mjs +660 -0
  112. package/hooks/on-stop.mjs +294 -0
  113. package/hooks/operator-steer.mjs +64 -0
  114. package/hooks/post-edit-validate.mjs +225 -0
  115. package/hooks/post-subagent-discovery-validator.mjs +398 -0
  116. package/hooks/post-tool-batch-wave-signal.mjs +328 -0
  117. package/hooks/post-tool-failure-corrective-context.mjs +248 -0
  118. package/hooks/post-tooluse-frontend-slop.mjs +184 -0
  119. package/hooks/pre-bash-destructive-guard.mjs +515 -0
  120. package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
  121. package/hooks/pre-bash-staging-fence.mjs +223 -0
  122. package/hooks/pre-bash-templates-first.mjs +404 -0
  123. package/hooks/run-node.sh +72 -0
  124. package/hooks/skill-invocation-telemetry.mjs +99 -0
  125. package/hooks/subagent-telemetry.mjs +249 -0
  126. package/hooks/wave-scope-commit-guard.mjs +191 -0
  127. package/monitors/monitors.json +14 -0
  128. package/output-styles/finding-report.md +48 -0
  129. package/output-styles/session-report.md +53 -0
  130. package/output-styles/wave-summary.md +38 -0
  131. package/package.json +94 -0
  132. package/pi/extensions/session-orchestrator.ts +25 -0
  133. package/pi/prompts/autopilot-multi.md +12 -0
  134. package/pi/prompts/autopilot.md +12 -0
  135. package/pi/prompts/bootstrap.md +12 -0
  136. package/pi/prompts/brainstorm.md +12 -0
  137. package/pi/prompts/close.md +11 -0
  138. package/pi/prompts/debug.md +12 -0
  139. package/pi/prompts/discovery.md +12 -0
  140. package/pi/prompts/dispatcher.md +12 -0
  141. package/pi/prompts/eval.md +12 -0
  142. package/pi/prompts/evolve.md +12 -0
  143. package/pi/prompts/go.md +12 -0
  144. package/pi/prompts/grill.md +12 -0
  145. package/pi/prompts/harness-audit.md +12 -0
  146. package/pi/prompts/memory-cleanup.md +12 -0
  147. package/pi/prompts/persona-panel.md +12 -0
  148. package/pi/prompts/plan.md +12 -0
  149. package/pi/prompts/portfolio.md +12 -0
  150. package/pi/prompts/reconcile.md +12 -0
  151. package/pi/prompts/repo-audit.md +12 -0
  152. package/pi/prompts/session.md +12 -0
  153. package/pi/prompts/spinout.md +12 -0
  154. package/pi/prompts/sunset-review.md +12 -0
  155. package/pi/prompts/templates-ack.md +12 -0
  156. package/pi/prompts/test.md +12 -0
  157. package/rules/_index.md +51 -0
  158. package/rules/always-on/commit-discipline.md +26 -0
  159. package/rules/always-on/npm-quality-gates.md +26 -0
  160. package/rules/always-on/parallel-sessions.md +43 -0
  161. package/rules/opt-in-domain/prompt-caching.md +270 -0
  162. package/rules/opt-in-stack/backend-data.md +188 -0
  163. package/rules/opt-in-stack/backend.md +390 -0
  164. package/rules/opt-in-stack/frontend.md +98 -0
  165. package/rules/opt-in-stack/security-web.md +194 -0
  166. package/rules/opt-in-stack/swift.md +65 -0
  167. package/scripts/archive-closed-prds.mjs +416 -0
  168. package/scripts/autopilot-multi.mjs +802 -0
  169. package/scripts/autopilot.mjs +383 -0
  170. package/scripts/backfill-abandoned-sessions.mjs +265 -0
  171. package/scripts/backfill-learnings-expires.mjs +196 -0
  172. package/scripts/backfill-learnings.mjs +203 -0
  173. package/scripts/backfill-sessions.mjs +282 -0
  174. package/scripts/check-doc-consistency.sh +279 -0
  175. package/scripts/check-package-manager.mjs +445 -0
  176. package/scripts/ci/assert-vitest-green.mjs +267 -0
  177. package/scripts/codex-install.mjs +435 -0
  178. package/scripts/compute-grounding-injection.sh +186 -0
  179. package/scripts/cursor-install.mjs +113 -0
  180. package/scripts/dialectic-deriver.mjs +573 -0
  181. package/scripts/emit-event.mjs +160 -0
  182. package/scripts/emit-session.mjs +212 -0
  183. package/scripts/eval-session.mjs +262 -0
  184. package/scripts/export-hw-learnings.mjs +437 -0
  185. package/scripts/gc-stale-worktrees.mjs +666 -0
  186. package/scripts/generate-pi-prompts.mjs +127 -0
  187. package/scripts/harness-audit.mjs +287 -0
  188. package/scripts/lib/agent-frontmatter.mjs +266 -0
  189. package/scripts/lib/agent-output-schema.mjs +166 -0
  190. package/scripts/lib/agent-status.mjs +303 -0
  191. package/scripts/lib/ajv-loader.mjs +34 -0
  192. package/scripts/lib/auto-dialectic.mjs +382 -0
  193. package/scripts/lib/auto-dream.mjs +471 -0
  194. package/scripts/lib/autonomy/suitability.mjs +212 -0
  195. package/scripts/lib/autopilot/dep-graph.mjs +417 -0
  196. package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
  197. package/scripts/lib/autopilot/flags.mjs +104 -0
  198. package/scripts/lib/autopilot/kill-switches.mjs +174 -0
  199. package/scripts/lib/autopilot/loop.mjs +320 -0
  200. package/scripts/lib/autopilot/mr-draft.mjs +520 -0
  201. package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
  202. package/scripts/lib/autopilot/recent-runs.mjs +106 -0
  203. package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
  204. package/scripts/lib/autopilot/telemetry.mjs +224 -0
  205. package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
  206. package/scripts/lib/autopilot-telemetry.mjs +11 -0
  207. package/scripts/lib/autopilot.mjs +39 -0
  208. package/scripts/lib/backlog-scan.mjs +179 -0
  209. package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
  210. package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
  211. package/scripts/lib/build-live-signals.mjs +150 -0
  212. package/scripts/lib/ci-status-banner.mjs +425 -0
  213. package/scripts/lib/claude-md-budget-lint.mjs +246 -0
  214. package/scripts/lib/cli-flags.mjs +158 -0
  215. package/scripts/lib/codex/plugin-contract.mjs +610 -0
  216. package/scripts/lib/cold-start-detector.mjs +240 -0
  217. package/scripts/lib/command-blocker.mjs +458 -0
  218. package/scripts/lib/common.mjs +333 -0
  219. package/scripts/lib/config/auto-dream.mjs +77 -0
  220. package/scripts/lib/config/block-header.mjs +94 -0
  221. package/scripts/lib/config/broken-window.mjs +114 -0
  222. package/scripts/lib/config/coercers.mjs +248 -0
  223. package/scripts/lib/config/cold-start.mjs +92 -0
  224. package/scripts/lib/config/config-protection.mjs +120 -0
  225. package/scripts/lib/config/cross-repo.mjs +104 -0
  226. package/scripts/lib/config/custom-phases.mjs +213 -0
  227. package/scripts/lib/config/dialectic.mjs +92 -0
  228. package/scripts/lib/config/discovery-validator.mjs +75 -0
  229. package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
  230. package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
  231. package/scripts/lib/config/docs-orchestrator.mjs +90 -0
  232. package/scripts/lib/config/docs-staleness.mjs +96 -0
  233. package/scripts/lib/config/drift-check.mjs +155 -0
  234. package/scripts/lib/config/eval.mjs +130 -0
  235. package/scripts/lib/config/events-rotation.mjs +74 -0
  236. package/scripts/lib/config/evolve.mjs +308 -0
  237. package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
  238. package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
  239. package/scripts/lib/config/handover-gate.mjs +106 -0
  240. package/scripts/lib/config/host-paths.mjs +76 -0
  241. package/scripts/lib/config/io.mjs +54 -0
  242. package/scripts/lib/config/loop-guard.mjs +117 -0
  243. package/scripts/lib/config/memory.mjs +150 -0
  244. package/scripts/lib/config/persona-gate-wave.mjs +258 -0
  245. package/scripts/lib/config/reconcile.mjs +205 -0
  246. package/scripts/lib/config/section-extractor.mjs +100 -0
  247. package/scripts/lib/config/skill-evolution.mjs +112 -0
  248. package/scripts/lib/config/slopcheck.mjs +99 -0
  249. package/scripts/lib/config/state-md-lock.mjs +83 -0
  250. package/scripts/lib/config/templates-first.mjs +94 -0
  251. package/scripts/lib/config/test.mjs +113 -0
  252. package/scripts/lib/config/vault-integration.mjs +201 -0
  253. package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
  254. package/scripts/lib/config/vault-staleness.mjs +84 -0
  255. package/scripts/lib/config/vault-sync.mjs +96 -0
  256. package/scripts/lib/config/verification-auto-fix.mjs +84 -0
  257. package/scripts/lib/config/wave-reviewers.mjs +133 -0
  258. package/scripts/lib/config-schema.mjs +345 -0
  259. package/scripts/lib/config.mjs +474 -0
  260. package/scripts/lib/convergence-monitor.mjs +389 -0
  261. package/scripts/lib/coordinator-snapshot.mjs +371 -0
  262. package/scripts/lib/crypto-digest-utils.mjs +91 -0
  263. package/scripts/lib/discovery/helpers.mjs +127 -0
  264. package/scripts/lib/discovery/triage-state.mjs +279 -0
  265. package/scripts/lib/dispatcher/cli.mjs +257 -0
  266. package/scripts/lib/dispatcher/enumerate.mjs +243 -0
  267. package/scripts/lib/dispatcher/rank.mjs +363 -0
  268. package/scripts/lib/ecosystem-health.mjs +224 -0
  269. package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
  270. package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
  271. package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
  272. package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
  273. package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
  274. package/scripts/lib/ecosystem-wizard.mjs +48 -0
  275. package/scripts/lib/env-check.mjs +89 -0
  276. package/scripts/lib/eval/engine.mjs +605 -0
  277. package/scripts/lib/eval/judge.mjs +433 -0
  278. package/scripts/lib/eval/report.mjs +367 -0
  279. package/scripts/lib/eval/schema.mjs +618 -0
  280. package/scripts/lib/eval/session-resolve.mjs +137 -0
  281. package/scripts/lib/eval/sink.mjs +77 -0
  282. package/scripts/lib/events-rotation.mjs +86 -0
  283. package/scripts/lib/events-schema.mjs +81 -0
  284. package/scripts/lib/events.mjs +80 -0
  285. package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
  286. package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
  287. package/scripts/lib/exclusivity-matrix.mjs +68 -0
  288. package/scripts/lib/fetch-baseline.mjs +311 -0
  289. package/scripts/lib/file-lock.mjs +512 -0
  290. package/scripts/lib/frontend-detect/detect.mjs +138 -0
  291. package/scripts/lib/frontend-detect/rules.mjs +295 -0
  292. package/scripts/lib/frontmatter-guard.mjs +241 -0
  293. package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
  294. package/scripts/lib/gates/gate-baseline.mjs +42 -0
  295. package/scripts/lib/gates/gate-full.mjs +85 -0
  296. package/scripts/lib/gates/gate-helpers.mjs +231 -0
  297. package/scripts/lib/gates/gate-incremental.mjs +76 -0
  298. package/scripts/lib/gates/gate-per-file.mjs +55 -0
  299. package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
  300. package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
  301. package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
  302. package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
  303. package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
  304. package/scripts/lib/handover-gate.mjs +222 -0
  305. package/scripts/lib/hardening.mjs +43 -0
  306. package/scripts/lib/hardware-pattern-detector.mjs +238 -0
  307. package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
  308. package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
  309. package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
  310. package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
  311. package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
  312. package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
  313. package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
  314. package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
  315. package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
  316. package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
  317. package/scripts/lib/harness-audit/categories.mjs +19 -0
  318. package/scripts/lib/historical-guard.mjs +15 -0
  319. package/scripts/lib/host-identity.mjs +262 -0
  320. package/scripts/lib/instruction-budget-guard.mjs +332 -0
  321. package/scripts/lib/io.mjs +304 -0
  322. package/scripts/lib/issue-close-strip-labels.mjs +161 -0
  323. package/scripts/lib/language-mappers/README.md +57 -0
  324. package/scripts/lib/language-mappers/index.mjs +165 -0
  325. package/scripts/lib/language-mappers/markdown.mjs +149 -0
  326. package/scripts/lib/language-mappers/python.mjs +249 -0
  327. package/scripts/lib/language-mappers/swift.mjs +201 -0
  328. package/scripts/lib/language-mappers/typescript.mjs +433 -0
  329. package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
  330. package/scripts/lib/learnings/filters.mjs +43 -0
  331. package/scripts/lib/learnings/io.mjs +255 -0
  332. package/scripts/lib/learnings/schema.mjs +518 -0
  333. package/scripts/lib/learnings/surface.mjs +207 -0
  334. package/scripts/lib/learnings.mjs +42 -0
  335. package/scripts/lib/lock-reaper.mjs +648 -0
  336. package/scripts/lib/locks/index.mjs +31 -0
  337. package/scripts/lib/locks/lock-body.mjs +62 -0
  338. package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
  339. package/scripts/lib/locks/state-md-lock.mjs +351 -0
  340. package/scripts/lib/loop-readiness-banner.mjs +144 -0
  341. package/scripts/lib/memory-banner.mjs +478 -0
  342. package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
  343. package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
  344. package/scripts/lib/memory-paths.mjs +31 -0
  345. package/scripts/lib/memory-proposals/collector.mjs +334 -0
  346. package/scripts/lib/memory-proposals/schema.mjs +289 -0
  347. package/scripts/lib/memory-proposals/sink.mjs +507 -0
  348. package/scripts/lib/memory-proposals/store.mjs +441 -0
  349. package/scripts/lib/mission-status-schema.mjs +114 -0
  350. package/scripts/lib/mode-selector/alternatives.mjs +64 -0
  351. package/scripts/lib/mode-selector/constants.mjs +29 -0
  352. package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
  353. package/scripts/lib/mode-selector/rationale.mjs +55 -0
  354. package/scripts/lib/mode-selector/scoring.mjs +221 -0
  355. package/scripts/lib/mode-selector-accuracy.mjs +121 -0
  356. package/scripts/lib/mode-selector.mjs +160 -0
  357. package/scripts/lib/multi-provider-build/providers.mjs +64 -0
  358. package/scripts/lib/multi-provider-build/templating.mjs +130 -0
  359. package/scripts/lib/named-baseline-resolver.mjs +233 -0
  360. package/scripts/lib/named-vault-resolver.mjs +433 -0
  361. package/scripts/lib/owner-config/coerce.mjs +29 -0
  362. package/scripts/lib/owner-config/constants.mjs +21 -0
  363. package/scripts/lib/owner-config/defaults.mjs +50 -0
  364. package/scripts/lib/owner-config/error.mjs +19 -0
  365. package/scripts/lib/owner-config/index.mjs +13 -0
  366. package/scripts/lib/owner-config/merge.mjs +52 -0
  367. package/scripts/lib/owner-config/validate.mjs +259 -0
  368. package/scripts/lib/owner-config-banner.mjs +126 -0
  369. package/scripts/lib/owner-config-loader.mjs +159 -0
  370. package/scripts/lib/owner-config.example.yaml +72 -0
  371. package/scripts/lib/owner-config.mjs +28 -0
  372. package/scripts/lib/owner-interview.mjs +243 -0
  373. package/scripts/lib/owner-yaml.mjs +571 -0
  374. package/scripts/lib/package-manager.mjs +160 -0
  375. package/scripts/lib/path-utils.mjs +217 -0
  376. package/scripts/lib/peer-cards/merger.mjs +310 -0
  377. package/scripts/lib/peer-cards/reader.mjs +125 -0
  378. package/scripts/lib/peer-cards/schema.mjs +230 -0
  379. package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
  380. package/scripts/lib/peer-cards/writer.mjs +138 -0
  381. package/scripts/lib/peer-discovery.mjs +200 -0
  382. package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
  383. package/scripts/lib/persona-panel/consolidator.mjs +370 -0
  384. package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
  385. package/scripts/lib/persona-panel/threshold.mjs +130 -0
  386. package/scripts/lib/pi-hook-bridge.mjs +328 -0
  387. package/scripts/lib/platform.mjs +266 -0
  388. package/scripts/lib/playwright-driver/runner.mjs +297 -0
  389. package/scripts/lib/plugin-root.mjs +210 -0
  390. package/scripts/lib/pre-dispatch-check.mjs +126 -0
  391. package/scripts/lib/product-repo-detect.mjs +121 -0
  392. package/scripts/lib/profiles/registry.mjs +176 -0
  393. package/scripts/lib/profiles/schema.mjs +209 -0
  394. package/scripts/lib/qg-command-drift-banner.mjs +88 -0
  395. package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
  396. package/scripts/lib/quality-gate.mjs +536 -0
  397. package/scripts/lib/quality-gates-cache.mjs +228 -0
  398. package/scripts/lib/quality-gates-policy.mjs +95 -0
  399. package/scripts/lib/recommendations-v0.mjs +156 -0
  400. package/scripts/lib/reconcile/eligibility.mjs +203 -0
  401. package/scripts/lib/reconcile/emitter.mjs +244 -0
  402. package/scripts/lib/reconcile/engine.mjs +412 -0
  403. package/scripts/lib/reconcile/idempotency.mjs +239 -0
  404. package/scripts/lib/reconcile/renderer.mjs +211 -0
  405. package/scripts/lib/reconcile/writer.mjs +293 -0
  406. package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
  407. package/scripts/lib/resource-probe/evaluate.mjs +190 -0
  408. package/scripts/lib/resource-probe/parsers.mjs +181 -0
  409. package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
  410. package/scripts/lib/resource-probe.mjs +95 -0
  411. package/scripts/lib/rule-loader.mjs +552 -0
  412. package/scripts/lib/rules-sync.mjs +439 -0
  413. package/scripts/lib/scope-gate.mjs +496 -0
  414. package/scripts/lib/session-close-backfill.mjs +539 -0
  415. package/scripts/lib/session-discovery.mjs +256 -0
  416. package/scripts/lib/session-end/phase-skip.mjs +357 -0
  417. package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
  418. package/scripts/lib/session-id.mjs +362 -0
  419. package/scripts/lib/session-lock.mjs +703 -0
  420. package/scripts/lib/session-registry.mjs +355 -0
  421. package/scripts/lib/session-schema/aliases.mjs +71 -0
  422. package/scripts/lib/session-schema/constants.mjs +115 -0
  423. package/scripts/lib/session-schema/normalizer.mjs +66 -0
  424. package/scripts/lib/session-schema/timestamps.mjs +64 -0
  425. package/scripts/lib/session-schema/validator.mjs +453 -0
  426. package/scripts/lib/session-schema.mjs +71 -0
  427. package/scripts/lib/session-token-rollup.mjs +137 -0
  428. package/scripts/lib/sessions-staleness-banner.mjs +247 -0
  429. package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
  430. package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
  431. package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
  432. package/scripts/lib/skill-evolution/engine.mjs +719 -0
  433. package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
  434. package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
  435. package/scripts/lib/skill-health/join.mjs +181 -0
  436. package/scripts/lib/skill-health/score.mjs +123 -0
  437. package/scripts/lib/skill-invocations-schema.mjs +214 -0
  438. package/scripts/lib/skill-judge.mjs +348 -0
  439. package/scripts/lib/skill-judgments-schema.mjs +264 -0
  440. package/scripts/lib/slopcheck.mjs +501 -0
  441. package/scripts/lib/soul-resolve.mjs +118 -0
  442. package/scripts/lib/spiral-carryover.mjs +495 -0
  443. package/scripts/lib/state-md/body-sections.mjs +851 -0
  444. package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
  445. package/scripts/lib/state-md/mission-status.mjs +247 -0
  446. package/scripts/lib/state-md/recommendations.mjs +57 -0
  447. package/scripts/lib/state-md/yaml-parser.mjs +234 -0
  448. package/scripts/lib/state-md-peer-guard.mjs +232 -0
  449. package/scripts/lib/state-md.mjs +53 -0
  450. package/scripts/lib/subagents-schema.mjs +309 -0
  451. package/scripts/lib/sunset/walker.mjs +1192 -0
  452. package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
  453. package/scripts/lib/test-runner/fingerprint.mjs +33 -0
  454. package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
  455. package/scripts/lib/tmux-layout/layouts.mjs +224 -0
  456. package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
  457. package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
  458. package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
  459. package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
  460. package/scripts/lib/validate/check-agents.mjs +457 -0
  461. package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
  462. package/scripts/lib/validate/check-commands.mjs +148 -0
  463. package/scripts/lib/validate/check-component-paths.mjs +112 -0
  464. package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
  465. package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
  466. package/scripts/lib/validate/check-json-files.mjs +116 -0
  467. package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
  468. package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
  469. package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
  470. package/scripts/lib/validate/check-pi-package.mjs +110 -0
  471. package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
  472. package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
  473. package/scripts/lib/validate/check-plugin-json.mjs +96 -0
  474. package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
  475. package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
  476. package/scripts/lib/validate/check-rules.mjs +143 -0
  477. package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
  478. package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
  479. package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
  480. package/scripts/lib/validate/confidential-names.mjs +169 -0
  481. package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
  482. package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
  483. package/scripts/lib/validate/tier-inference.mjs +100 -0
  484. package/scripts/lib/validate-vendored-rules.mjs +519 -0
  485. package/scripts/lib/vault-archive.mjs +404 -0
  486. package/scripts/lib/vault-backfill/glab.mjs +164 -0
  487. package/scripts/lib/vault-backfill/manifest.mjs +75 -0
  488. package/scripts/lib/vault-backfill/template.mjs +130 -0
  489. package/scripts/lib/vault-consolidate-fs.mjs +331 -0
  490. package/scripts/lib/vault-migration-rules.mjs +155 -0
  491. package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
  492. package/scripts/lib/vault-mirror/namespace.mjs +152 -0
  493. package/scripts/lib/vault-mirror/process.mjs +567 -0
  494. package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
  495. package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
  496. package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
  497. package/scripts/lib/vault-mirror/render.mjs +8 -0
  498. package/scripts/lib/vault-mirror/utils.mjs +217 -0
  499. package/scripts/lib/vault-relocation-rules.mjs +555 -0
  500. package/scripts/lib/vault-repo-backfill.mjs +235 -0
  501. package/scripts/lib/vault-staleness-banner.mjs +142 -0
  502. package/scripts/lib/vault-status/board-writer.mjs +769 -0
  503. package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
  504. package/scripts/lib/vault-sync-baseline.mjs +152 -0
  505. package/scripts/lib/wave-context.mjs +29 -0
  506. package/scripts/lib/wave-executor/pool.mjs +248 -0
  507. package/scripts/lib/wave-resource-gate.mjs +204 -0
  508. package/scripts/lib/wave-sizing.mjs +75 -0
  509. package/scripts/lib/webhook-url.mjs +105 -0
  510. package/scripts/lib/workspace.mjs +198 -0
  511. package/scripts/lib/worktree/constants.mjs +35 -0
  512. package/scripts/lib/worktree/index.mjs +17 -0
  513. package/scripts/lib/worktree/lifecycle.mjs +287 -0
  514. package/scripts/lib/worktree/listing.mjs +118 -0
  515. package/scripts/lib/worktree/meta.mjs +64 -0
  516. package/scripts/lib/worktree-freshness.mjs +313 -0
  517. package/scripts/lib/worktree.mjs +15 -0
  518. package/scripts/lifecycle-sim-v6.mjs +347 -0
  519. package/scripts/lock-reaper.mjs +185 -0
  520. package/scripts/mcp-server.sh +241 -0
  521. package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
  522. package/scripts/memory-propose.mjs +464 -0
  523. package/scripts/migrate-cold-start-seed.mjs +404 -0
  524. package/scripts/migrate-learnings-jsonl.mjs +189 -0
  525. package/scripts/migrate-legacy-learnings.sh +61 -0
  526. package/scripts/migrate-sessions-jsonl.mjs +448 -0
  527. package/scripts/migrate-subagents-jsonl.mjs +196 -0
  528. package/scripts/migrate-vault-paths.mjs +796 -0
  529. package/scripts/parse-config.mjs +149 -0
  530. package/scripts/pi-install.mjs +117 -0
  531. package/scripts/print-applicable-rules.mjs +247 -0
  532. package/scripts/promote-vault-strict.mjs +496 -0
  533. package/scripts/relocate-vault-corpus.mjs +1178 -0
  534. package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
  535. package/scripts/run-quality-gate.mjs +216 -0
  536. package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
  537. package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
  538. package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
  539. package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
  540. package/scripts/sweep-expired-learnings.mjs +135 -0
  541. package/scripts/sync-vault-schema.mjs +376 -0
  542. package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
  543. package/scripts/tmux-layout.mjs +245 -0
  544. package/scripts/token-audit.sh +191 -0
  545. package/scripts/typecheck.mjs +42 -0
  546. package/scripts/upload-social-preview.mjs +316 -0
  547. package/scripts/validate-config.mjs +46 -0
  548. package/scripts/validate-plugin-manifests.mjs +163 -0
  549. package/scripts/validate-plugin.mjs +264 -0
  550. package/scripts/validate-wave-scope.mjs +289 -0
  551. package/scripts/vault-backfill.mjs +404 -0
  552. package/scripts/vault-consolidate.mjs +596 -0
  553. package/scripts/vault-integration-watcher.mjs +394 -0
  554. package/scripts/vault-mirror.mjs +430 -0
  555. package/skills/_shared/bootstrap-gate.md +111 -0
  556. package/skills/_shared/config-reading.md +226 -0
  557. package/skills/_shared/instruction-file-resolution.md +79 -0
  558. package/skills/_shared/model-selection.md +64 -0
  559. package/skills/_shared/monitor-patterns.md +300 -0
  560. package/skills/_shared/parallel-aware-auq.md +121 -0
  561. package/skills/_shared/parallel-aware-preamble.md +185 -0
  562. package/skills/_shared/platform-tools.md +96 -0
  563. package/skills/_shared/state-ownership.md +221 -0
  564. package/skills/architecture/DEEPENING.md +37 -0
  565. package/skills/architecture/INTERFACE-DESIGN.md +44 -0
  566. package/skills/architecture/LANGUAGE.md +53 -0
  567. package/skills/architecture/SKILL.md +92 -0
  568. package/skills/autopilot/SKILL.md +419 -0
  569. package/skills/bootstrap/SKILL.md +592 -0
  570. package/skills/bootstrap/STATE.md.template +24 -0
  571. package/skills/bootstrap/_shared-template.md +243 -0
  572. package/skills/bootstrap/deep-template.md +659 -0
  573. package/skills/bootstrap/fast-template.md +251 -0
  574. package/skills/bootstrap/intensity-heuristic.md +80 -0
  575. package/skills/bootstrap/public-fallback.md +342 -0
  576. package/skills/bootstrap/standard-template.md +736 -0
  577. package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
  578. package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
  579. package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
  580. package/skills/brainstorm/SKILL.md +268 -0
  581. package/skills/brainstorm/soul.md +49 -0
  582. package/skills/claude-md-drift-check/SKILL.md +186 -0
  583. package/skills/claude-md-drift-check/checker.mjs +1380 -0
  584. package/skills/claude-md-drift-check/checker.sh +37 -0
  585. package/skills/claude-md-drift-check/package.json +16 -0
  586. package/skills/convergence-monitoring/README.md +39 -0
  587. package/skills/convergence-monitoring/SIGNALS.md +246 -0
  588. package/skills/convergence-monitoring/SKILL.md +285 -0
  589. package/skills/daily/SKILL.md +222 -0
  590. package/skills/daily/generate.sh +92 -0
  591. package/skills/daily/templates/daily.md.tpl +36 -0
  592. package/skills/debug/SKILL.md +188 -0
  593. package/skills/debug/soul.md +35 -0
  594. package/skills/discovery/SKILL.md +567 -0
  595. package/skills/discovery/issue-templates.md +237 -0
  596. package/skills/discovery/probes/docs-staleness.mjs +195 -0
  597. package/skills/discovery/probes/frontend-slop.mjs +186 -0
  598. package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
  599. package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
  600. package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
  601. package/skills/discovery/probes/vault-staleness.mjs +272 -0
  602. package/skills/discovery/probes-arch.md +252 -0
  603. package/skills/discovery/probes-audit.md +95 -0
  604. package/skills/discovery/probes-code.md +329 -0
  605. package/skills/discovery/probes-docs.md +76 -0
  606. package/skills/discovery/probes-feature.md +150 -0
  607. package/skills/discovery/probes-infra.md +138 -0
  608. package/skills/discovery/probes-intro.md +25 -0
  609. package/skills/discovery/probes-session.md +495 -0
  610. package/skills/discovery/probes-supply-chain.md +94 -0
  611. package/skills/discovery/probes-ui.md +147 -0
  612. package/skills/discovery/probes-vault.md +64 -0
  613. package/skills/discovery/slop-patterns.md +115 -0
  614. package/skills/dispatcher/SKILL.md +173 -0
  615. package/skills/docs-orchestrator/SKILL.md +362 -0
  616. package/skills/docs-orchestrator/audience-mapping.md +140 -0
  617. package/skills/domain-model/ADR-FORMAT.md +47 -0
  618. package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
  619. package/skills/domain-model/SKILL.md +85 -0
  620. package/skills/ecosystem-health/SKILL.md +119 -0
  621. package/skills/ecosystem-health/wizard.md +193 -0
  622. package/skills/eval/SKILL.md +293 -0
  623. package/skills/eval/rubric-v1.md +218 -0
  624. package/skills/evolve/SKILL.md +546 -0
  625. package/skills/frontmatter-guard/SKILL.md +126 -0
  626. package/skills/gitlab-ops/SKILL.md +368 -0
  627. package/skills/gitlab-portfolio/SKILL.md +196 -0
  628. package/skills/grill/SKILL.md +185 -0
  629. package/skills/grill/soul.md +55 -0
  630. package/skills/hook-development/SKILL.md +413 -0
  631. package/skills/mcp-builder/SKILL.md +260 -0
  632. package/skills/memory-cleanup/SKILL.md +310 -0
  633. package/skills/mode-selector/SKILL.md +226 -0
  634. package/skills/peekaboo-driver/SKILL.md +237 -0
  635. package/skills/peekaboo-driver/soul.md +32 -0
  636. package/skills/persona-panel/SKILL.md +365 -0
  637. package/skills/persona-panel/persona-format.md +205 -0
  638. package/skills/persona-panel/presets/designer-lens.md +87 -0
  639. package/skills/persona-panel/presets/engineer-lens.md +88 -0
  640. package/skills/persona-panel/presets/pm-lens.md +86 -0
  641. package/skills/plan/SKILL.md +496 -0
  642. package/skills/plan/mode-feature.md +141 -0
  643. package/skills/plan/mode-new.md +297 -0
  644. package/skills/plan/mode-retro.md +271 -0
  645. package/skills/plan/prd-feature-template.md +132 -0
  646. package/skills/plan/prd-full-template.md +151 -0
  647. package/skills/plan/prd-reviewer-prompt.md +103 -0
  648. package/skills/plan/retro-template.md +75 -0
  649. package/skills/plan/soul.md +62 -0
  650. package/skills/playwright-driver/SKILL.md +226 -0
  651. package/skills/playwright-driver/soul.md +30 -0
  652. package/skills/quality-gates/SKILL.md +212 -0
  653. package/skills/reconcile/SKILL.md +324 -0
  654. package/skills/repo-audit/SKILL.md +272 -0
  655. package/skills/session-end/SKILL.md +1044 -0
  656. package/skills/session-end/discovery-scan.md +37 -0
  657. package/skills/session-end/drift-operations.md +97 -0
  658. package/skills/session-end/learning-patterns.md +78 -0
  659. package/skills/session-end/metrics-collection.md +175 -0
  660. package/skills/session-end/phase-3-2-docs-verification.md +148 -0
  661. package/skills/session-end/phase-3-6-tail.md +344 -0
  662. package/skills/session-end/phase-3-7a-recommendations.md +86 -0
  663. package/skills/session-end/plan-verification.md +288 -0
  664. package/skills/session-end/session-metrics-write.md +223 -0
  665. package/skills/session-end/vault-operations.md +50 -0
  666. package/skills/session-end/verification-checklist.md +20 -0
  667. package/skills/session-plan/SKILL.md +554 -0
  668. package/skills/session-plan/wave-template.md +37 -0
  669. package/skills/session-start/SKILL.md +1043 -0
  670. package/skills/session-start/phase-2-5-docs-planning.md +119 -0
  671. package/skills/session-start/phase-4-5-resource-health.md +49 -0
  672. package/skills/session-start/phase-7-1-premise-check.md +47 -0
  673. package/skills/session-start/phase-7-5-mode-selector.md +237 -0
  674. package/skills/session-start/phase-8-5-express-path.md +61 -0
  675. package/skills/session-start/presentation-format.md +81 -0
  676. package/skills/session-start/soul.md +57 -0
  677. package/skills/skill-creator/SKILL.md +168 -0
  678. package/skills/spinout/SKILL.md +76 -0
  679. package/skills/sunset-review/SKILL.md +96 -0
  680. package/skills/test-runner/SKILL.md +362 -0
  681. package/skills/test-runner/rubric-v1.md +388 -0
  682. package/skills/test-runner/soul.md +46 -0
  683. package/skills/tmux-layout/SKILL.md +104 -0
  684. package/skills/ubiquitous-language/SKILL.md +97 -0
  685. package/skills/using-orchestrator/SKILL.md +144 -0
  686. package/skills/vault-mirror/SKILL.md +234 -0
  687. package/skills/vault-sync/SKILL.md +319 -0
  688. package/skills/vault-sync/package-lock.json +40 -0
  689. package/skills/vault-sync/package.json +11 -0
  690. package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
  691. package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
  692. package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +8 -0
  693. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
  694. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +8 -0
  695. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
  696. package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
  697. package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
  698. package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
  699. package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
  700. package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
  701. package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
  702. package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +9 -0
  703. package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
  704. package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
  705. package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
  706. package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +7 -0
  707. package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
  708. package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
  709. package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +11 -0
  710. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
  711. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
  712. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
  713. package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
  714. package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
  715. package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +11 -0
  716. package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
  717. package/skills/vault-sync/validator.mjs +658 -0
  718. package/skills/vault-sync/validator.sh +55 -0
  719. package/skills/wave-executor/SKILL.md +496 -0
  720. package/skills/wave-executor/circuit-breaker.md +169 -0
  721. package/skills/wave-executor/wave-loop.md +1043 -0
  722. package/skills/write-executable-plan/SKILL.md +237 -0
  723. package/skills/write-executable-plan/plan-template.md +154 -0
  724. package/templates/_minimal/CLAUDE.md.tmpl +41 -0
  725. package/templates/_minimal/README.md.tmpl +15 -0
  726. package/templates/_minimal/gitignore.tmpl +47 -0
  727. package/templates/_shared/harte-regeln.md +16 -0
  728. package/templates/_shared/loop.md +90 -0
  729. package/templates/_shared/rules/parallel-sessions.md +77 -0
  730. package/templates/nextjs-minimal/README.md +30 -0
  731. package/templates/nextjs-minimal/app/layout.tsx +18 -0
  732. package/templates/nextjs-minimal/app/page.tsx +7 -0
  733. package/templates/nextjs-minimal/eslint.config.mjs +16 -0
  734. package/templates/nextjs-minimal/next.config.mjs +4 -0
  735. package/templates/nextjs-minimal/package.json +27 -0
  736. package/templates/nextjs-minimal/tsconfig.json +23 -0
  737. package/templates/node-minimal/README.md +33 -0
  738. package/templates/node-minimal/eslint.config.mjs +10 -0
  739. package/templates/node-minimal/package.json +21 -0
  740. package/templates/node-minimal/src/index.ts +1 -0
  741. package/templates/node-minimal/tests/sanity.test.ts +5 -0
  742. package/templates/node-minimal/tsconfig.json +17 -0
  743. package/templates/personas/README.md +150 -0
  744. package/templates/personas/accounting-compliance.v1.md +120 -0
  745. package/templates/personas/accounting-tax-advisor.v1.md +116 -0
  746. package/templates/personas/buyer-p1-cto.v1.md +125 -0
  747. package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
  748. package/templates/personas/buyer-p3-build.v1.md +130 -0
  749. package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
  750. package/templates/personas/buyer-p5-solo.v1.md +132 -0
  751. package/templates/personas/buyer-p6-ld.v1.md +130 -0
  752. package/templates/personas/klima-ai-expert.v1.md +114 -0
  753. package/templates/personas/klima-physicist.v1.md +117 -0
  754. package/templates/python-uv/README.md +28 -0
  755. package/templates/python-uv/pyproject.toml +32 -0
  756. package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
  757. package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
  758. package/templates/python-uv/tests/test_sanity.py +2 -0
  759. package/templates/static-html/README.md +19 -0
  760. package/templates/static-html/index.html +15 -0
  761. package/templates/static-html/script.js +1 -0
  762. package/templates/static-html/styles.css +26 -0
@@ -0,0 +1,660 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * on-session-start.mjs — SessionStart hook: emit event + optional host/resource banner.
4
+ *
5
+ * Node.js port of hooks/on-session-start.sh. Part of v3.0.0 migration
6
+ * (Epic #124, issue #140). Extended in v3.1.0 (Epic #157):
7
+ * - #164: host-identity + resource-probe banner surfaced via systemMessage.
8
+ * - #168: multi-session registry — register this session, detect peers, sweep
9
+ * zombies. Peer summary is appended to the banner and surfaced in the event.
10
+ *
11
+ * Behaviour:
12
+ * 1. Resolves project name and current git branch.
13
+ * 2. When env-aware libs are available AND enable-host-banner config is true,
14
+ * collects host fingerprint + resource snapshot and emits a one-line
15
+ * systemMessage banner. Populates .orchestrator/host.json for skills.
16
+ * 3. Reads session_id from stdin (Claude Code hook contract). Falls back to
17
+ * a generated uuid-v4 and caches it at .orchestrator/current-session.json
18
+ * so on-stop can deregister cleanly.
19
+ * 4. Sweeps zombie heartbeats older than the configured threshold, registers
20
+ * this session, detects live peers on the same host.
21
+ * 5. Emits "orchestrator.session.started" event to .orchestrator/metrics/events.jsonl.
22
+ * 6. Optionally POSTs to Clank Event Bus if CLANK_EVENT_SECRET is set.
23
+ *
24
+ * Exit codes:
25
+ * 0 — always (informational, never blocking)
26
+ *
27
+ * hooks.json wiring (SessionStart, async: true, timeout: 5s) is managed separately.
28
+ * stdin: optional JSON payload from Claude Code containing session_id.
29
+ */
30
+
31
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
32
+ import { execFile } from 'node:child_process';
33
+ import { promisify } from 'node:util';
34
+ import { randomUUID } from 'node:crypto';
35
+ import path from 'node:path';
36
+
37
+ import { shouldRunHook } from './_lib/profile-gate.mjs';
38
+ // #211: exit 0 immediately (silent allow) when this hook is disabled via profile/env
39
+ if (!shouldRunHook('on-session-start')) process.exit(0);
40
+
41
+ import { emitEvent, eventsFilePath } from '../scripts/lib/events.mjs';
42
+ import { maybeRotate } from '../scripts/lib/events-rotation.mjs';
43
+ import { readConfigFile, parseSessionConfig } from '../scripts/lib/config.mjs';
44
+ import { SO_PLATFORM, resolveProjectDir } from '../scripts/lib/platform.mjs';
45
+ import {
46
+ registerSelf,
47
+ detectPeers,
48
+ sweepZombies,
49
+ logSweepEvent,
50
+ } from '../scripts/lib/session-registry.mjs';
51
+ import { detectColdStart, consumeMarker } from '../scripts/lib/cold-start-detector.mjs';
52
+
53
+ const execFileAsync = promisify(execFile);
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Helpers
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /**
60
+ * Run a git command in cwd; return trimmed stdout. Returns null on failure.
61
+ * @param {string[]} args
62
+ * @param {string} cwd
63
+ * @returns {Promise<string|null>}
64
+ */
65
+ async function gitOutput(args, cwd) {
66
+ try {
67
+ const { stdout } = await execFileAsync('git', args, { cwd });
68
+ return stdout.trim();
69
+ } catch {
70
+ return null;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Read `enable-host-banner` from CLAUDE.md / AGENTS.md Session Config. Returns
76
+ * true as the default — missing config or parse errors fall back to enabled,
77
+ * matching the documented behaviour for issue #166.
78
+ */
79
+ async function isHostBannerEnabled(projectRoot) {
80
+ for (const name of ['CLAUDE.md', 'AGENTS.md']) {
81
+ try {
82
+ const raw = await readFile(path.join(projectRoot, name), 'utf8');
83
+ const m = raw.match(/^\s*enable-host-banner:\s*(true|false)\b/im);
84
+ if (m) return m[1].toLowerCase() === 'true';
85
+ } catch { /* file missing is fine */ }
86
+ }
87
+ return true;
88
+ }
89
+
90
+ /**
91
+ * Read `cold-start.*` block from Session Config with PRD defaults applied.
92
+ *
93
+ * Uses `parseSessionConfig(md)['cold-start']` (wired via I6). Any parse
94
+ * failure returns defaults so the cold-start nudge is never blocked.
95
+ *
96
+ * All keys are optional. Returns:
97
+ * { enabled: boolean, 'nudge-after-hours': number, 'silence-after-sessions': number }
98
+ *
99
+ * PRD defaults (F1.3): enabled=true, nudge-after-hours=1,
100
+ * silence-after-sessions=1. Any parse failure → defaults.
101
+ */
102
+ export async function readColdStartConfig(projectRoot) {
103
+ const defaults = {
104
+ enabled: true,
105
+ 'nudge-after-hours': 1,
106
+ 'silence-after-sessions': 1,
107
+ };
108
+
109
+ try {
110
+ const md = await readConfigFile(projectRoot);
111
+ try {
112
+ const config = parseSessionConfig(md);
113
+ const block = config['cold-start'];
114
+ if (block && typeof block === 'object') {
115
+ return {
116
+ enabled: block.enabled !== false,
117
+ 'nudge-after-hours':
118
+ typeof block['nudge-after-hours'] === 'number'
119
+ ? block['nudge-after-hours']
120
+ : defaults['nudge-after-hours'],
121
+ 'silence-after-sessions':
122
+ typeof block['silence-after-sessions'] === 'number'
123
+ ? block['silence-after-sessions']
124
+ : defaults['silence-after-sessions'],
125
+ };
126
+ }
127
+ } catch { return defaults; }
128
+ } catch {
129
+ return defaults;
130
+ }
131
+ return defaults;
132
+ }
133
+
134
+ /**
135
+ * Read `resource-thresholds.concurrent-sessions-warn` from Session Config.
136
+ * Used to decide when the peer banner should show the WARN icon. Defaults to
137
+ * 5 — matches the documented default in docs/session-config-reference.md.
138
+ */
139
+ async function peerWarnThreshold(projectRoot) {
140
+ const DEFAULT = 5;
141
+ for (const name of ['CLAUDE.md', 'AGENTS.md']) {
142
+ try {
143
+ const raw = await readFile(path.join(projectRoot, name), 'utf8');
144
+ // Match `concurrent-sessions-warn: <int>` inside resource-thresholds or top-level.
145
+ const m = raw.match(/^\s*concurrent-sessions-warn:\s*(\d+)\b/im);
146
+ if (m) {
147
+ const n = parseInt(m[1], 10);
148
+ if (!Number.isNaN(n) && n > 0) return n;
149
+ }
150
+ } catch { /* file missing is fine */ }
151
+ }
152
+ return DEFAULT;
153
+ }
154
+
155
+ /**
156
+ * Non-blocking stdin read for Claude Code hook payload. Returns parsed JSON or
157
+ * null if stdin is closed, empty, unparseable, or times out.
158
+ */
159
+ async function readStdinJson(timeoutMs = 500) {
160
+ return new Promise((resolve) => {
161
+ if (process.stdin.readableEnded || process.stdin.closed) {
162
+ resolve(null);
163
+ return;
164
+ }
165
+ const chunks = [];
166
+ const timer = setTimeout(() => { resolve(null); }, timeoutMs);
167
+ process.stdin.setEncoding('utf8');
168
+ process.stdin.on('data', (c) => chunks.push(c));
169
+ process.stdin.on('end', () => {
170
+ clearTimeout(timer);
171
+ const raw = chunks.join('').trim();
172
+ if (!raw) { resolve(null); return; }
173
+ try { resolve(JSON.parse(raw)); } catch { resolve(null); }
174
+ });
175
+ process.stdin.on('error', () => { clearTimeout(timer); resolve(null); });
176
+ process.stdin.resume();
177
+ });
178
+ }
179
+
180
+ /**
181
+ * Resolve a session_id for this run. Preference order:
182
+ * 1. stdin payload (`session_id` or `sessionId`)
183
+ * 2. generated uuid-v4 via crypto.randomUUID()
184
+ *
185
+ * In both cases, persist the resolved id to
186
+ * `.orchestrator/current-session.json` so on-stop can deregister even when the
187
+ * stop-hook stdin does not carry the same id (Claude Code guarantees this, but
188
+ * Codex/Cursor may not).
189
+ *
190
+ * Best-effort: any persistence failure is swallowed (hook must remain non-blocking).
191
+ */
192
+ async function resolveSessionId(input, projectRoot) {
193
+ const fromStdin = (input && (input.session_id || input.sessionId)) ?? null;
194
+
195
+ // Mode normalization is shared by both branches (stdin-UUID + semantic-gen)
196
+ // so the semantic-id derivation works identically regardless of how
197
+ // sessionId was sourced. Epic #583 D4 #587: a semantic id is ALWAYS surfaced.
198
+ const rawMode = (input && (input.mode || input.session_type)) || 'session';
199
+ const normalizedMode =
200
+ String(rawMode).toLowerCase().replace(/[^a-z-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'session';
201
+
202
+ let sessionId;
203
+ let source;
204
+ // Epic #583 D4 #587: semanticSessionId is computed on BOTH branches so the
205
+ // session.lock + downstream consumers always see the semantic form, even
206
+ // when Claude Code's stdin payload provided a UUID-v4. Defaults to null
207
+ // and is populated below; the lock-bootstrap helper falls back to mirroring
208
+ // sessionId when this stays null.
209
+ let semanticSessionId = null;
210
+
211
+ if (typeof fromStdin === 'string' && fromStdin.length > 0) {
212
+ sessionId = fromStdin;
213
+ source = 'stdin';
214
+
215
+ // D4 #587: even on the stdin-UUID path, ALSO compute a semantic
216
+ // session-id so the lock and registry can surface it downstream.
217
+ // Best-effort: any failure leaves semanticSessionId = null which is
218
+ // handled gracefully by the lock-bootstrap helper.
219
+ try {
220
+ const semCandidate = await deriveSemanticCandidate({
221
+ projectRoot,
222
+ mode: normalizedMode,
223
+ });
224
+ if (semCandidate) semanticSessionId = semCandidate;
225
+ } catch { /* best effort — leave semanticSessionId = null */ }
226
+ } else {
227
+ // No stdin id — generate a semantic session-id via P2.2 #573 (PRD §3 P2).
228
+ // Falls back to randomUUID() on any failure to keep the hook non-blocking.
229
+ try {
230
+ const candidate = await deriveSemanticCandidate({
231
+ projectRoot,
232
+ mode: normalizedMode,
233
+ });
234
+ if (!candidate) throw new Error('semantic-derivation-empty');
235
+
236
+ // Race-free host-wide uniqueness: try to atomically claim the registry slot
237
+ // for this sessionId via O_CREAT|O_EXCL. If another process won the race
238
+ // (EEXIST), fall back to UUID-v4 to guarantee distinct sessionIds across
239
+ // parallel hook invocations. The empty file is immediately overwritten by
240
+ // registerSelf() with the real entry — _validEntry() in readers filters
241
+ // any zero-content artifact during the millisecond gap.
242
+ try {
243
+ // entryPath() is NOT exported from session-registry.mjs (it is an
244
+ // internal helper); replicate its body inline so the race-free slot
245
+ // claim actually succeeds. Without this inline build, the
246
+ // destructuring on `entryPath` returns undefined and calling it
247
+ // throws TypeError → silent UUID-fallback, defeating the semantic-id
248
+ // generation path entirely. Pre-existing bug pre-dating Epic #583 P3.
249
+ const { activeDir } = await import('../scripts/lib/session-registry.mjs');
250
+ const fsAsync = await import('node:fs/promises');
251
+ await fsAsync.mkdir(activeDir(), { recursive: true });
252
+ const claimPath = path.join(activeDir(), `${candidate}.json`);
253
+ const handle = await fsAsync.open(claimPath, 'wx'); // O_CREAT|O_EXCL — fails with EEXIST on collision
254
+ await handle.close();
255
+ sessionId = candidate;
256
+ semanticSessionId = candidate;
257
+ source = 'generated-semantic';
258
+ } catch (claimErr) {
259
+ if (claimErr.code === 'EEXIST') {
260
+ // Collision with another parallel hook — fall back to UUID-v4 silently.
261
+ // Hook is informational-only; never write to stderr per existing convention.
262
+ sessionId = randomUUID();
263
+ source = 'generated-uuid-fallback-collision';
264
+ // We still surface the semantic candidate as semanticSessionId so the
265
+ // lock reflects what this session would have been called — useful for
266
+ // forensics even when the UUID won the registry-slot race.
267
+ semanticSessionId = candidate;
268
+ } else {
269
+ throw claimErr; // surfaces to outer catch → UUID fallback
270
+ }
271
+ }
272
+ } catch {
273
+ // Semantic id generation failed for any reason — silently fall back to UUID-v4.
274
+ // Hook is informational-only; never write to stderr per existing convention.
275
+ sessionId = randomUUID();
276
+ source = 'generated-uuid-fallback';
277
+ }
278
+ }
279
+
280
+ try {
281
+ const dir = path.join(projectRoot, '.orchestrator');
282
+ await mkdir(dir, { recursive: true });
283
+ const sessionFilePath = path.join(dir, 'current-session.json');
284
+
285
+ // High-water-mark preservation (#612 root-cause fix).
286
+ // SessionStart fires on startup|clear|compact|resume of the SAME logical
287
+ // session. On clear/compact/resume the UUID `session_id` changes but the
288
+ // `semantic_session_id` (branch+date+mode+n) stays stable. A naive full
289
+ // overwrite of current-session.json drops the `last_wave` / `last_batch`
290
+ // markers written mid-session by post-tool-batch-wave-signal.mjs, which
291
+ // makes the next PostToolBatch re-read last_wave as absent→0 and re-emit a
292
+ // duplicate orchestrator.wave.started{N} with no intervening
293
+ // wave.completed. To prevent that, PRESERVE last_wave/last_batch across a
294
+ // SessionStart of the SAME logical session (matching semantic id), while
295
+ // still RESETTING them for a genuinely new session (different/absent
296
+ // semantic id, or an unparseable prior file). Best-effort: a read failure
297
+ // must never throw — we simply fall through to the reset path.
298
+ const preserved = {};
299
+ if (typeof semanticSessionId === 'string' && semanticSessionId.length > 0) {
300
+ try {
301
+ const prevRaw = await readFile(sessionFilePath, 'utf8');
302
+ const prev = JSON.parse(prevRaw);
303
+ if (prev && prev.semantic_session_id === semanticSessionId) {
304
+ if (Object.prototype.hasOwnProperty.call(prev, 'last_wave')) {
305
+ preserved.last_wave = prev.last_wave;
306
+ }
307
+ if (Object.prototype.hasOwnProperty.call(prev, 'last_batch')) {
308
+ preserved.last_batch = prev.last_batch;
309
+ }
310
+ }
311
+ } catch { /* absent / unparseable → no preservation (reset) */ }
312
+ }
313
+
314
+ // Epic #583 W5-F1c — surface semantic_session_id (Q5 H1 / Issue #587 completion).
315
+ // current-session.json now carries BOTH the UUID session_id (Claude Code default)
316
+ // AND the semantic_session_id derived from branch+date+mode+history.
317
+ const payload = {
318
+ session_id: sessionId,
319
+ semantic_session_id: semanticSessionId,
320
+ pid: process.pid,
321
+ source,
322
+ timestamp: new Date().toISOString(),
323
+ // Spread AFTER the base fields so the preserved high-water marks survive
324
+ // (and never clobber the identity fields above).
325
+ ...preserved,
326
+ };
327
+ await writeFile(
328
+ sessionFilePath,
329
+ JSON.stringify(payload, null, 2) + '\n',
330
+ 'utf8',
331
+ );
332
+ } catch { /* best effort */ }
333
+
334
+ return { sessionId, semanticSessionId, mode: normalizedMode };
335
+ }
336
+
337
+ /**
338
+ * Shared helper: derive a semantic session-id candidate for the current
339
+ * (branch, date, mode) tuple by consulting resolveSemanticSessionId() with
340
+ * a merged active-sessions view (worktree-local + host-wide registry).
341
+ *
342
+ * Returns the candidate string on success, null on any failure. Never throws.
343
+ *
344
+ * Used by both branches of resolveSessionId() so the semantic_session_id
345
+ * field on the session.lock is consistently populated regardless of whether
346
+ * the SessionStart stdin payload provided a UUID (Claude Code) or nothing
347
+ * (Codex / Cursor).
348
+ *
349
+ * @param {{ projectRoot: string, mode: string }} opts
350
+ * @returns {Promise<string|null>}
351
+ */
352
+ async function deriveSemanticCandidate({ projectRoot, mode }) {
353
+ try {
354
+ const { resolveSemanticSessionId } = await import('../scripts/lib/session-id.mjs');
355
+ const { discoverActiveSessions } = await import('../scripts/lib/session-discovery.mjs');
356
+ const { execSync } = await import('node:child_process');
357
+
358
+ // Derive branch from git (cheap, ~5ms). Fall back to 'main' if outside a repo.
359
+ let branch = 'main';
360
+ try {
361
+ branch = execSync('git rev-parse --abbrev-ref HEAD', {
362
+ cwd: projectRoot,
363
+ stdio: ['ignore', 'pipe', 'ignore'],
364
+ encoding: 'utf8',
365
+ timeout: 1000,
366
+ }).trim();
367
+ if (!branch || branch === 'HEAD') branch = 'main';
368
+ } catch { /* keep default 'main' */ }
369
+
370
+ // Discover other active sessions for n-incrementing. We merge two sources:
371
+ // 1. worktree-local: discoverActiveSessions(projectRoot) reads each worktree's session.lock
372
+ // 2. host-wide: readRegistry() reads the per-host multi-session registry
373
+ // The merge is necessary because the host-wide registry is the single source
374
+ // of truth for cross-repo uniqueness — two unrelated repos on the same host
375
+ // would otherwise collide on the same default `<branch>-<date>-<mode>-1` id.
376
+ // Best-effort: both sources may fail; we proceed with whatever we get.
377
+ const { readRegistry } = await import('../scripts/lib/session-registry.mjs');
378
+ const [localSessions, registryEntries] = await Promise.all([
379
+ discoverActiveSessions(projectRoot).catch(() => []),
380
+ readRegistry().catch(() => []),
381
+ ]);
382
+ const registrySessions = registryEntries.map((r) => ({
383
+ sessionId: r.session_id,
384
+ mode: r.mode ?? 'session',
385
+ }));
386
+ const activeSessions = [...localSessions, ...registrySessions];
387
+
388
+ return await resolveSemanticSessionId({
389
+ branch,
390
+ mode,
391
+ activeSessions,
392
+ repoRoot: projectRoot,
393
+ });
394
+ } catch {
395
+ return null;
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Attempt to collect and emit the host + resource banner. Pure best-effort:
401
+ * any failure (missing lib, no home dir, probe throws) is swallowed so the
402
+ * session-start hook never blocks.
403
+ * @returns {Promise<{host: object, resources: object}|null>}
404
+ */
405
+ async function emitHostBanner(projectRoot) {
406
+ try {
407
+ const [{ getHostFingerprint }, { probe }] = await Promise.all([
408
+ import('../scripts/lib/host-identity.mjs'),
409
+ import('../scripts/lib/resource-probe.mjs'),
410
+ ]);
411
+ const [host, resources] = await Promise.all([
412
+ getHostFingerprint(projectRoot).catch(() => null),
413
+ probe({ skipProcessCounts: false }).catch(() => null),
414
+ ]);
415
+ if (!host || !resources) return null;
416
+
417
+ const hostLine = `🖥️ Host: ${host.host_class} · ${host.ram_total_gb} GB RAM · ${host.platform ?? 'unknown'} · ${host.is_ssh ? 'ssh' : 'local'}`;
418
+ const procSuffix = resources.claude_processes_count === null
419
+ ? ''
420
+ : ` · ${resources.claude_processes_count} Claude process${resources.claude_processes_count === 1 ? '' : 'es'} running`;
421
+ const resourceLine = `📊 Resources: ${resources.ram_free_gb.toFixed(1)} GB free · CPU ${resources.cpu_load_pct}%${procSuffix}`;
422
+ const banner = `${hostLine}\n${resourceLine}`;
423
+
424
+ // systemMessage envelope is the Claude Code hook contract; ignored by
425
+ // consumers that do not read stdout, harmless in all cases.
426
+ console.log(JSON.stringify({ systemMessage: banner }));
427
+
428
+ return { host, resources };
429
+ } catch {
430
+ return null;
431
+ }
432
+ }
433
+
434
+ // ---------------------------------------------------------------------------
435
+ // Main
436
+ // ---------------------------------------------------------------------------
437
+
438
+ async function main() {
439
+ const projectRoot = resolveProjectDir();
440
+
441
+ // Read optional stdin payload in parallel with git info so we don't stall
442
+ // the hook. Both are best-effort and the promise races against a 500 ms cap
443
+ // inside readStdinJson itself.
444
+ const stdinPromise = readStdinJson();
445
+
446
+ // Resolve project name: basename of git toplevel, falling back to cwd basename.
447
+ const topLevel = await gitOutput(['rev-parse', '--show-toplevel'], projectRoot);
448
+ const projectName = topLevel
449
+ ? topLevel.split(/[/\\]/).filter(Boolean).pop() ?? 'unknown'
450
+ : projectRoot.split(/[/\\]/).filter(Boolean).pop() ?? 'unknown';
451
+
452
+ // Resolve current branch; fall back to "unknown" when detached HEAD or no git.
453
+ const branch = (await gitOutput(['branch', '--show-current'], projectRoot)) ?? 'unknown';
454
+
455
+ // v3.1.0 env-aware banner (opt-out via enable-host-banner: false in Session Config).
456
+ // The ask-via-tool nudge rides the same opt-out flag — both are coordinator
457
+ // reminders shown at session start; users who silence one expect silence.
458
+ let bannerData = null;
459
+ if (await isHostBannerEnabled(projectRoot)) {
460
+ bannerData = await emitHostBanner(projectRoot);
461
+ // Always-on nudge: user decisions must go through AskUserQuestion, not inline
462
+ // markdown lists. The coordinator chat stream is dense and prose questions
463
+ // are reliably missed. Full rationale + exceptions in .claude/rules/ask-via-tool.md.
464
+ try {
465
+ console.log(JSON.stringify({
466
+ systemMessage: '🎯 User decisions → AskUserQuestion tool. Inline choice lists = bug (.claude/rules/ask-via-tool.md).',
467
+ }));
468
+ } catch { /* best effort */ }
469
+ }
470
+
471
+ // F1.3 cold-start abandonment fix (PRD 2026-05-21). Emit a one-shot
472
+ // "first session not yet" banner when bootstrap.lock is older than
473
+ // cold-start.nudge-after-hours AND sessions.jsonl has fewer than
474
+ // cold-start.silence-after-sessions entries. Auto-silences after the
475
+ // first session. Master switch: cold-start.enabled (default true).
476
+ //
477
+ // Config keys read with PRD-default fallbacks — I6 wires these into
478
+ // parseSessionConfig(). Until then the detector uses the documented
479
+ // defaults so this code is safe to ship before the config schema lands.
480
+ try {
481
+ const coldStartCfg = await readColdStartConfig(projectRoot);
482
+ if (coldStartCfg.enabled !== false) {
483
+ const decision = await detectColdStart({
484
+ repoRoot: projectRoot,
485
+ nudgeAfterHours: coldStartCfg['nudge-after-hours'] ?? 1,
486
+ silenceAfterSessions: coldStartCfg['silence-after-sessions'] ?? 1,
487
+ enabled: coldStartCfg.enabled !== false,
488
+ });
489
+ if (decision.shouldEmit) {
490
+ try {
491
+ console.log(JSON.stringify({
492
+ systemMessage: decision.bannerLines.join('\n'),
493
+ }));
494
+ } catch { /* best effort — stdout may be closed */ }
495
+ if (decision.markerPath) {
496
+ await consumeMarker(decision.markerPath).catch(() => false);
497
+ }
498
+ }
499
+ }
500
+ } catch { /* silent — cold-start nudge must never block the hook */ }
501
+
502
+ // v3.1.0 multi-session registry (#168). All steps best-effort — failures
503
+ // must never break the hook, which is informational-only.
504
+ const input = await stdinPromise;
505
+ const { sessionId, semanticSessionId, mode } = await resolveSessionId(input, projectRoot);
506
+ const platform = process.env.SO_PLATFORM ?? SO_PLATFORM;
507
+
508
+ // Epic #583 P3 — mechanical session.lock writer (closes D1+D2+D4 gaps).
509
+ // Bootstrap the session-lock so discoverActiveSessions() picks us up even
510
+ // when the coordinator-LLM skips the prose Phase 1.2 acquire-call. The
511
+ // semantic-id is surfaced even when stdin provided a UUID (D4 fix #587).
512
+ // Wrapped in try/catch as a defence-in-depth: bootstrapLock() is already
513
+ // best-effort, but this outer guard ensures the hook stays non-blocking
514
+ // regardless of any future regression in the helper itself.
515
+ try {
516
+ const { bootstrapLock } = await import('./_lib/lock-bootstrap.mjs');
517
+ await bootstrapLock({
518
+ repoRoot: projectRoot,
519
+ sessionId,
520
+ semanticSessionId,
521
+ mode,
522
+ ttlHours: 4,
523
+ });
524
+ } catch { /* hook must remain non-blocking */ }
525
+
526
+ // Epic #724 C7 — own-repo orphaned-lock reaper (reconciliation net). If a
527
+ // dead-lease session.lock survived a crash-before-SessionEnd (the case that
528
+ // blocked this repo's start this morning until a manual force-takeover),
529
+ // archive-move it so it stops blocking. SINGLE-REPO only: no host-wide scan
530
+ // here (that stays CLI-only, scripts/lock-reaper.mjs) to keep hook latency
531
+ // small. Our own freshly-bootstrapped lock (written just above) is protected
532
+ // by the reaper's live-lock guard (fresh heartbeat) AND the currentSessionId
533
+ // guard, so this can never touch it. Best-effort: any failure is swallowed —
534
+ // the hook is informational-only and must never block.
535
+ try {
536
+ const { reapRepoLock } = await import('../scripts/lib/lock-reaper.mjs');
537
+ await reapRepoLock({
538
+ repoRoot: projectRoot,
539
+ currentSessionId: sessionId,
540
+ dryRun: false,
541
+ reapMode: 'auto-own-repo',
542
+ });
543
+ } catch { /* hook must remain non-blocking */ }
544
+
545
+ let peers = [];
546
+ try {
547
+ await sweepZombies().catch(() => ({ removed: [], logged: 0 }));
548
+ try {
549
+ await registerSelf({
550
+ sessionId,
551
+ semanticSessionId, // Epic #583 W5-F1c — registry entry carries semantic id (Q5 H1)
552
+ projectRoot,
553
+ branch,
554
+ platform,
555
+ mode,
556
+ hostClass: bannerData?.host?.host_class ?? null,
557
+ });
558
+ } catch (err) {
559
+ // Registration failed — emit an observability breadcrumb to sweep.log.
560
+ // Do NOT throw, do NOT write to stderr: the hook is informational-only.
561
+ logSweepEvent({ event: 'register-failed', session_id: sessionId, error: err?.message ?? String(err) });
562
+ }
563
+ peers = await detectPeers({ sessionId }).catch(() => []);
564
+ } catch { /* swallow — hook must remain non-blocking */ }
565
+
566
+ // Append a peer line to the host banner when a banner was already emitted
567
+ // and at least one peer is live on this host.
568
+ if (bannerData && peers.length > 0) {
569
+ const threshold = await peerWarnThreshold(projectRoot);
570
+ const icon = peers.length >= threshold ? '⚠️ ' : '';
571
+ const summary = peers
572
+ .map((p) => `${p.repo_name ?? 'unknown'}:${p.branch ?? 'unknown'}:wave-${p.current_wave ?? 0}`)
573
+ .slice(0, 5)
574
+ .join(', ');
575
+ const overflow = peers.length > 5 ? ` +${peers.length - 5} more` : '';
576
+ const peerLine = `${icon}👥 Peers: ${peers.length} active (${summary}${overflow})`;
577
+ try {
578
+ console.log(JSON.stringify({ systemMessage: peerLine }));
579
+ } catch { /* best effort */ }
580
+ }
581
+
582
+ // Epic #583 W3-P3 — Mechanical peer-detection banner (independent of the
583
+ // v3.1.0 registry-driven detectPeers() output). discoverActiveSessions()
584
+ // reads every worktree's session.lock and the host registry; this is the
585
+ // canonical source of truth and fires even when the v3.1.0 path returned
586
+ // an empty set (e.g., the peer's registry write failed but its session.lock
587
+ // was successfully bootstrapped by the lock-bootstrap hook). The two
588
+ // banners coexist: the v3.1.0 line above is per-host; this one is per-repo
589
+ // (mechanical, worktree-scoped) and uses the merged lock + registry source.
590
+ //
591
+ // Gated on `bannerData` (i.e., enable-host-banner: true) to respect the
592
+ // documented opt-out semantics — a user who silenced session-start
593
+ // banners has opted out of ALL session-start banners, including this one.
594
+ // The mechanical lock + STATE.md peer-guard remain active regardless;
595
+ // only the operator-visibility banner is silenced.
596
+ // Best-effort: any failure (import, listWorktrees timeout, etc.) is
597
+ // swallowed — the banner is purely informational.
598
+ if (bannerData) {
599
+ try {
600
+ const { discoverActiveSessions } = await import('../scripts/lib/session-discovery.mjs');
601
+ const allActive = await discoverActiveSessions(projectRoot);
602
+ const mechanicalPeers = allActive.filter((s) => s.sessionId !== sessionId);
603
+ if (mechanicalPeers.length > 0) {
604
+ const summary = mechanicalPeers
605
+ .slice(0, 3)
606
+ .map((p) => `${p.sessionId}:${p.mode ?? 'session'}`)
607
+ .join(', ');
608
+ const overflow = mechanicalPeers.length > 3 ? ` +${mechanicalPeers.length - 3} more` : '';
609
+ const mechanicalLine = `🔍 Mechanical peer-detection: ${mechanicalPeers.length} active in same repo (${summary}${overflow})`;
610
+ try {
611
+ console.log(JSON.stringify({ systemMessage: mechanicalLine }));
612
+ } catch { /* best effort */ }
613
+ }
614
+ } catch { /* best effort — banner is informational, never blocks */ }
615
+ }
616
+
617
+ const payload = {
618
+ platform,
619
+ project: projectName,
620
+ branch,
621
+ session_id: sessionId,
622
+ peer_count: peers.length,
623
+ };
624
+ if (bannerData) {
625
+ payload.host_class = bannerData.host.host_class;
626
+ payload.ram_free_gb = bannerData.resources.ram_free_gb;
627
+ payload.cpu_load_pct = bannerData.resources.cpu_load_pct;
628
+ payload.claude_processes_count = bannerData.resources.claude_processes_count;
629
+ }
630
+ await emitEvent('orchestrator.session.started', payload);
631
+
632
+ // Size-based rotation of events.jsonl (#251). Session-start is the single
633
+ // rotation trigger — per-append overhead is rejected design. Any failure
634
+ // is swallowed: rotation must NEVER block the hook.
635
+ try {
636
+ let rotCfg = { enabled: true, 'max-size-mb': 10, 'max-backups': 5 };
637
+ try {
638
+ const md = await readConfigFile(projectRoot);
639
+ const config = parseSessionConfig(md);
640
+ if (config['events-rotation']) rotCfg = config['events-rotation'];
641
+ } catch { /* missing config → defaults */ }
642
+
643
+ const result = maybeRotate({
644
+ logPath: eventsFilePath(),
645
+ maxSizeMb: rotCfg['max-size-mb'] ?? 10,
646
+ maxBackups: rotCfg['max-backups'] ?? 5,
647
+ enabled: rotCfg.enabled !== false,
648
+ });
649
+ if (result.rotated) {
650
+ console.error(`events-rotation: archived ${result.archivedAs} (${result.sizeBefore} bytes)`);
651
+ }
652
+ } catch (err) {
653
+ console.error(`events-rotation: skipped (${err?.message ?? err})`);
654
+ }
655
+ }
656
+
657
+ // Top-level guard — always exit 0 (non-blocking informational hook).
658
+ main().catch(() => {}).finally(() => {
659
+ process.exit(0);
660
+ });