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,294 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * on-stop.mjs — consolidated Stop + SubagentStop hook.
4
+ *
5
+ * Replaces hooks/on-stop.sh and hooks/on-subagent-stop.sh. Handles both Claude Code
6
+ * hook events in a single file, discriminating by the `hook_event_name` field first,
7
+ * then falling back to presence of `agent_type` (SubagentStop) vs absence (Stop).
8
+ *
9
+ * Part of v3.0.0 Windows-native migration. Issue #141.
10
+ *
11
+ * Exit codes: 0 always (informational hooks must never block).
12
+ *
13
+ * JSONL format (`.orchestrator/metrics/events.jsonl`) — emitted via the canonical
14
+ * `emitEvent()` so the JSONL record and the optional Clank webhook always carry the
15
+ * SAME dotted event name (was: bare `stop`/`subagent_stop` in JSONL vs dotted in webhook):
16
+ * Stop: {"timestamp":<ISO>,"event":"orchestrator.session.stopped","session_id":"...","wave":<int>,"branch":"...","commit":"...","duration_ms":<int>}
17
+ * SubagentStop: {"timestamp":<ISO>,"event":"orchestrator.agent.stopped","agent":"<name>"}
18
+ */
19
+
20
+ import path from 'node:path';
21
+ import { promises as fs } from 'node:fs';
22
+ import { $ } from 'zx';
23
+
24
+ import { shouldRunHook } from './_lib/profile-gate.mjs';
25
+ // #211: exit 0 immediately (silent allow) when this hook is disabled via profile/env
26
+ if (!shouldRunHook('on-stop')) process.exit(0);
27
+
28
+ import { emitEvent } from '../scripts/lib/events.mjs';
29
+ import { SO_PROJECT_DIR } from '../scripts/lib/platform.mjs';
30
+ import { deregisterSelf, logSweepEvent } from '../scripts/lib/session-registry.mjs';
31
+ import { updateHeartbeat } from '../scripts/lib/session-lock.mjs';
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // stdin reading (inline — no io.mjs because Stop hooks exit 0 always, never deny)
35
+ // ---------------------------------------------------------------------------
36
+
37
+ /**
38
+ * Read stdin to EOF and parse as JSON. Returns null on empty or parse failure.
39
+ * @returns {Promise<object|null>}
40
+ */
41
+ async function readStdinJson() {
42
+ return new Promise((resolve) => {
43
+ const chunks = [];
44
+ const timer = setTimeout(() => {
45
+ process.stdin.destroy();
46
+ resolve(null);
47
+ }, 8000); // generous guard; contract says 5s (Stop) / 3s (SubagentStop)
48
+
49
+ if (process.stdin.readableEnded) {
50
+ clearTimeout(timer);
51
+ resolve(null);
52
+ return;
53
+ }
54
+
55
+ process.stdin.setEncoding('utf8');
56
+ process.stdin.on('data', (chunk) => chunks.push(chunk));
57
+ process.stdin.on('end', () => {
58
+ clearTimeout(timer);
59
+ const raw = chunks.join('').trim();
60
+ if (!raw) { resolve(null); return; }
61
+ try { resolve(JSON.parse(raw)); } catch { resolve(null); }
62
+ });
63
+ process.stdin.on('error', () => { clearTimeout(timer); resolve(null); });
64
+ process.stdin.resume();
65
+ });
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // discriminate hook event type
70
+ // ---------------------------------------------------------------------------
71
+
72
+ /**
73
+ * Determine whether the parsed stdin represents a Stop or SubagentStop event.
74
+ * Precedence: hook_event_name field → presence of agent_type field → default Stop.
75
+ * @param {object|null} input
76
+ * @returns {"stop"|"subagent_stop"}
77
+ */
78
+ function discriminate(input) {
79
+ if (!input) return 'stop';
80
+ const name = input.hook_event_name;
81
+ if (typeof name === 'string') {
82
+ if (name === 'SubagentStop') return 'subagent_stop';
83
+ return 'stop';
84
+ }
85
+ // Fallback: SubagentStop always provides agent_type; Stop does not.
86
+ if (typeof input.agent_type === 'string') return 'subagent_stop';
87
+ return 'stop';
88
+ }
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // git helpers
92
+ // ---------------------------------------------------------------------------
93
+
94
+ /**
95
+ * Returns { commit, branch } from the git repo at projectRoot, or null values
96
+ * if git is unavailable or the directory is not a git repo.
97
+ * @param {string} projectRoot — working directory for git commands
98
+ * @returns {Promise<{commit:string|null, branch:string|null}>}
99
+ */
100
+ async function gitInfo(projectRoot) {
101
+ $.verbose = false;
102
+ $.quiet = true;
103
+ const opts = projectRoot ? { cwd: projectRoot } : {};
104
+ try {
105
+ const commitResult = await $({ ...opts })`git rev-parse HEAD`;
106
+ const branchResult = await $({ ...opts })`git rev-parse --abbrev-ref HEAD`;
107
+ return {
108
+ commit: commitResult.stdout.trim() || null,
109
+ branch: branchResult.stdout.trim() || null,
110
+ };
111
+ } catch {
112
+ return { commit: null, branch: null };
113
+ }
114
+ }
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // wave-scope.json helpers
118
+ // ---------------------------------------------------------------------------
119
+
120
+ /**
121
+ * Try to read the wave number from .claude/wave-scope.json (or .codex / .cursor / .pi).
122
+ * Returns 0 if no scope file is found or the file cannot be parsed.
123
+ * @param {string} projectRoot
124
+ * @returns {Promise<number>}
125
+ */
126
+ async function readWaveNumber(projectRoot) {
127
+ const dirs = ['.pi', '.claude', '.codex', '.cursor'];
128
+ for (const dir of dirs) {
129
+ const scopePath = path.join(projectRoot, dir, 'wave-scope.json');
130
+ try {
131
+ const raw = await fs.readFile(scopePath, 'utf8');
132
+ const obj = JSON.parse(raw);
133
+ const wave = typeof obj.wave === 'number' ? obj.wave : 0;
134
+ return wave;
135
+ } catch {
136
+ // file missing or unparseable — try next
137
+ }
138
+ }
139
+ return 0;
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------
143
+ // event handlers
144
+ // ---------------------------------------------------------------------------
145
+
146
+ /**
147
+ * Resolve this session's id. Stdin payload wins. If Claude Code did not pass
148
+ * one (Codex / Cursor paths, or older harnesses), fall back to
149
+ * `.orchestrator/current-session.json` which on-session-start.mjs writes.
150
+ *
151
+ * @param {object|null} input
152
+ * @param {string} projectRoot
153
+ * @returns {Promise<string|null>}
154
+ */
155
+ async function resolveSessionId(input, projectRoot) {
156
+ const fromStdin = input?.session_id ?? input?.sessionId ?? null;
157
+ if (typeof fromStdin === 'string' && fromStdin.length > 0) return fromStdin;
158
+ try {
159
+ const raw = await fs.readFile(
160
+ path.join(projectRoot, '.orchestrator', 'current-session.json'),
161
+ 'utf8',
162
+ );
163
+ const parsed = JSON.parse(raw);
164
+ if (typeof parsed.session_id === 'string' && parsed.session_id.length > 0) {
165
+ return parsed.session_id;
166
+ }
167
+ } catch { /* missing or unparseable is fine */ }
168
+ return null;
169
+ }
170
+
171
+ /**
172
+ * Handle a Stop event. Reads wave from scope file + git info, appends JSONL.
173
+ * @param {object|null} input
174
+ */
175
+ async function handleStop(input) {
176
+ const projectRoot = SO_PROJECT_DIR;
177
+
178
+ const wave = await readWaveNumber(projectRoot);
179
+ const { commit, branch } = await gitInfo(projectRoot);
180
+
181
+ const sessionId = await resolveSessionId(input, projectRoot);
182
+
183
+ // v3.1.0 multi-session registry (#169) — best-effort deregister. Missing
184
+ // entry is fine (zombie sweep handles crashed sessions). Failures are logged
185
+ // to sweep.log for observability but never re-thrown (hook must remain silent).
186
+ if (sessionId) {
187
+ try {
188
+ await deregisterSelf(sessionId);
189
+ } catch (err) {
190
+ // Deregistration failed — emit an observability breadcrumb to sweep.log.
191
+ // Do NOT throw, do NOT write to stderr: the hook is informational-only.
192
+ logSweepEvent({ event: 'deregister-failed', session_id: sessionId, error: err?.message ?? String(err) });
193
+ }
194
+
195
+ // Epic #583 W5-F1c — refresh session.lock heartbeat on every turn-end.
196
+ // Augments PostToolBatch's heartbeat (closes W4-Q3 H2 cadence finding:
197
+ // a session with no PostToolBatch activity would otherwise go heartbeat-stale).
198
+ // Best-effort: never throws, never blocks the Stop hook.
199
+ try {
200
+ updateHeartbeat({ sessionId, repoRoot: projectRoot });
201
+ } catch { /* best-effort */ }
202
+ }
203
+
204
+ // duration_ms: if input provides a start time we compute from it, else 0
205
+ const durationMs =
206
+ typeof input?.start_ms === 'number' ? Date.now() - input.start_ms : 0;
207
+
208
+ // Single emission path: emitEvent writes the canonical {timestamp, event, ...payload}
209
+ // JSONL record AND fires the optional Clank webhook with the SAME event name — no
210
+ // more bare-`stop` (JSONL) vs dotted-`stopped` (webhook) divergence.
211
+ await emitEvent('orchestrator.session.stopped', {
212
+ ...(sessionId !== null ? { session_id: sessionId } : {}),
213
+ wave,
214
+ ...(branch !== null ? { branch } : {}),
215
+ ...(commit !== null ? { commit } : {}),
216
+ duration_ms: durationMs,
217
+ });
218
+ }
219
+
220
+ /**
221
+ * Handle a SubagentStop event. Extracts agent name, emits orchestrator.agent.stopped.
222
+ * Returns an optional additionalContext string (v2.1.163+) to feed back to the
223
+ * coordinator turn. Currently always returns null (no inline warning from this
224
+ * handler) — the slot is reserved for future SubagentStop feedback.
225
+ * @param {object|null} input
226
+ * @returns {Promise<string|null>} additionalContext or null
227
+ */
228
+ async function handleSubagentStop(input) {
229
+ const agent = input?.agent_type ?? 'unknown';
230
+ await emitEvent('orchestrator.agent.stopped', { agent });
231
+ return null;
232
+ }
233
+
234
+ // ---------------------------------------------------------------------------
235
+ // main
236
+ // ---------------------------------------------------------------------------
237
+
238
+ async function main() {
239
+ const input = await readStdinJson();
240
+ const eventType = discriminate(input);
241
+
242
+ if (eventType === 'subagent_stop') {
243
+ const additionalContext = await handleSubagentStop(input);
244
+ // v2.1.163+: emit hookSpecificOutput for SubagentStop path.
245
+ // If handleSubagentStop returns a non-empty context string, feed it back
246
+ // to the coordinator turn. Currently returns null (no inline warning from
247
+ // this handler), but the slot is live for future SubagentStop feedback.
248
+ // terminalSequence is a Stop-only field — not emitted for SubagentStop.
249
+ if (typeof additionalContext === 'string' && additionalContext.length > 0) {
250
+ process.stdout.write(JSON.stringify({
251
+ hookSpecificOutput: {
252
+ hookEventName: 'SubagentStop',
253
+ additionalContext,
254
+ },
255
+ }));
256
+ }
257
+ } else {
258
+ // terminalSequence must be emitted even when handleStop() throws (e.g.
259
+ // emitEvent's fs.appendFile fails on a full / read-only disk). Wrap the
260
+ // Stop branch in try/finally so the desktop notification is always sent.
261
+ // SubagentStop is intentionally outside this block — it must never emit
262
+ // terminalSequence.
263
+ try {
264
+ await handleStop(input);
265
+ } finally {
266
+ // terminalSequence is only meaningful for Stop (session-level) events.
267
+ process.stdout.write(buildTerminalSequenceJson());
268
+ }
269
+ }
270
+ }
271
+
272
+ // ---------------------------------------------------------------------------
273
+ // terminal notification
274
+ // ---------------------------------------------------------------------------
275
+
276
+ /**
277
+ * Emit a cross-platform desktop notification via the CC 2.1.141+ terminalSequence
278
+ * output field. Supports OSC 9 (iTerm2, Windows Terminal, WezTerm, ConEmu) and
279
+ * OSC 777 (Ghostty, urxvt, Warp). Both sequences are emitted together; unsupported
280
+ * terminals silently ignore. Returns the JSON string to write to stdout.
281
+ * @returns {string}
282
+ */
283
+ function buildTerminalSequenceJson() {
284
+ const title = 'Claude Code';
285
+ const body = 'Session stopped — your turn';
286
+ const osc9 = `\x1b]9;${title}: ${body}\x07`;
287
+ const osc777 = `\x1b]777;notify;${title};${body}\x07`;
288
+ return JSON.stringify({ terminalSequence: osc9 + osc777 });
289
+ }
290
+
291
+ // Exit 0 always — informational hook must never block Claude.
292
+ main()
293
+ .catch(() => {})
294
+ .finally(() => process.exit(0));
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * operator-steer.mjs — PostToolBatch hook for operator in-band steering.
4
+ *
5
+ * Hook event: PostToolBatch (issue #409).
6
+ * Fires after a batch of tool invocations completes within a single wave turn.
7
+ * Reads `.orchestrator/STEER.md` and, if non-empty, emits its contents as a
8
+ * `systemMessage` payload to stdout so Claude Code injects the guidance into
9
+ * the active session context. The file is then truncated (set to empty) so the
10
+ * message fires exactly once per write — a one-shot handshake.
11
+ *
12
+ * Operator workflow:
13
+ * echo "Focus on error handling in wave 3" > .orchestrator/STEER.md
14
+ * # Claude picks it up at the next PostToolBatch boundary, clears the file.
15
+ *
16
+ * Decision flow:
17
+ * 1. shouldRunHook gate — exit 0 immediately when the hook is disabled.
18
+ * 2. Resolve steerPath: $SO_PROJECT_DIR/.orchestrator/STEER.md
19
+ * 3. If the file is absent or whitespace-only → exit 0 silently.
20
+ * 4. If non-empty: emit { systemMessage: <contents> } to stdout, then
21
+ * truncate the file to '' so it fires only once.
22
+ *
23
+ * Output contract (PostToolBatch):
24
+ * stdout: JSON — { systemMessage: string }
25
+ * stderr: nothing (diagnostic errors swallowed)
26
+ * exit code: 0 always (informational — must never block Claude)
27
+ *
28
+ * TODO(#409): Cursor support — hooks-cursor.json uses a different event model
29
+ * (no PostToolBatch equivalent) and is not wired here. Register this hook
30
+ * in hooks-cursor.json when Cursor gains a suitable between-batch event.
31
+ */
32
+
33
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
34
+ import path from 'node:path';
35
+
36
+ import { shouldRunHook } from './_lib/profile-gate.mjs';
37
+ // Exit 0 immediately when disabled via SO_HOOK_PROFILE / SO_DISABLED_HOOKS.
38
+ if (!shouldRunHook('operator-steer')) process.exit(0);
39
+
40
+ import { SO_PROJECT_DIR } from '../scripts/lib/platform.mjs';
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Main
44
+ // ---------------------------------------------------------------------------
45
+
46
+ async function main() {
47
+ const steerPath = path.join(SO_PROJECT_DIR, '.orchestrator', 'STEER.md');
48
+
49
+ // File absent — nothing to do.
50
+ if (!existsSync(steerPath)) return;
51
+
52
+ // Read contents and check for meaningful (non-whitespace) content.
53
+ const contents = readFileSync(steerPath, 'utf8');
54
+ if (!contents.trim()) return;
55
+
56
+ // Emit the systemMessage payload so Claude Code injects it into the session.
57
+ console.log(JSON.stringify({ systemMessage: contents }));
58
+
59
+ // Truncate the file — one-shot handshake, fires exactly once per write.
60
+ writeFileSync(steerPath, '', 'utf8');
61
+ }
62
+
63
+ // Exit 0 always — informational hook must never block Claude.
64
+ main().catch(() => {}).finally(() => process.exit(0));
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * post-edit-validate.mjs — PostToolUse hook for incremental validation after Edit/Write/MultiEdit.
4
+ *
5
+ * Node.js port of hooks/post-edit-validate.sh. Part of v3.0.0 Windows-native migration.
6
+ * Issue: github.com/Kanevry/session-orchestrator/issues/139
7
+ *
8
+ * Runs incremental typecheck on the file that was just edited.
9
+ * This is informational only — it NEVER blocks (always exits 0).
10
+ *
11
+ * Decision flow:
12
+ * G1 stdin null → silent exit 0
13
+ * G2 tool_name filter — only Edit/Write/MultiEdit trigger typecheck
14
+ * G3 file_path present
15
+ * G4 file extension filter — only .ts|.tsx|.js|.jsx|.mjs|.cjs
16
+ * G5 gate check — wave-scope.json.gates['post-edit-validate'] === false → exit 0
17
+ * G6 resolve typecheck command: Session Config → tsgo → tsc → npx tsc → skip
18
+ * G7 run typecheck with 2s AbortController timeout
19
+ * G8 emit JSONL result to stderr
20
+ *
21
+ * Output (stderr): {"check":"typecheck","status":"pass|fail|skip","file":"<rel>","duration_ms":<int>}
22
+ * Exit codes: 0 — always (PostToolUse hooks are informational)
23
+ *
24
+ * SECURITY notes:
25
+ * REQ-01 top-level try/catch → silent exit 0 on unexpected error (never blocks)
26
+ * REQ-02 typecheck process uses AbortController (not shell `timeout` — cross-platform)
27
+ * REQ-03 relative path computed via path.relative(projectRoot, absFilePath)
28
+ */
29
+
30
+ import path from 'node:path';
31
+ import { spawnSync } from 'node:child_process';
32
+ import { performance } from 'node:perf_hooks';
33
+
34
+ import { shouldRunHook } from './_lib/profile-gate.mjs';
35
+ // #211: exit 0 immediately (silent allow) when this hook is disabled via profile/env
36
+ if (!shouldRunHook('post-edit-validate')) process.exit(0);
37
+
38
+ import { readStdin } from '../scripts/lib/io.mjs';
39
+ import { resolveProjectDir } from '../scripts/lib/platform.mjs';
40
+ import { findScopeFile, gateEnabled } from '../scripts/lib/hardening.mjs';
41
+ import { readConfigFile, parseSessionConfig } from '../scripts/lib/config.mjs';
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Internal helpers
45
+ // ---------------------------------------------------------------------------
46
+
47
+ /** File extensions that trigger typecheck. */
48
+ const TS_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
49
+
50
+ /**
51
+ * Emit the JSONL result line to stderr.
52
+ * @param {string} file - relative file path
53
+ * @param {'pass'|'fail'|'skip'} status
54
+ * @param {number} [duration_ms] - omit for skip
55
+ * @param {string} [reason] - human-readable reason for skip or fail
56
+ * @param {string} [remediation] - actionable fix hint for fail status only
57
+ */
58
+ function emitResult(file, status, duration_ms, reason, remediation) {
59
+ const obj = { check: 'typecheck', status, file };
60
+ if (typeof duration_ms === 'number') obj.duration_ms = duration_ms;
61
+ if (reason !== undefined) obj.reason = reason;
62
+ if (remediation !== undefined) obj.remediation = remediation;
63
+ process.stderr.write(JSON.stringify(obj) + '\n');
64
+ }
65
+
66
+ /**
67
+ * Try to resolve the typecheck command.
68
+ * Order: Session Config typecheck-command → tsgo → tsc → npx tsc → null
69
+ *
70
+ * @param {string} projectRoot
71
+ * @returns {Promise<{cmd: string, args: string[]}|null>}
72
+ */
73
+ async function resolveTypecheckCommand(projectRoot) {
74
+ // 1. Session Config typecheck-command
75
+ try {
76
+ const md = await readConfigFile(projectRoot);
77
+ const config = parseSessionConfig(md);
78
+ const cmd = config['typecheck-command'];
79
+ if (cmd && typeof cmd === 'string') {
80
+ const parts = cmd.trim().split(/\s+/);
81
+ return { cmd: parts[0], args: parts.slice(1) };
82
+ }
83
+ } catch {
84
+ // config unavailable — fall through
85
+ }
86
+
87
+ // 2. tsgo
88
+ const tsgoParts = _tryWhich('tsgo');
89
+ if (tsgoParts) return { cmd: tsgoParts, args: ['--noEmit'] };
90
+
91
+ // 3. tsc
92
+ const tscParts = _tryWhich('tsc');
93
+ if (tscParts) return { cmd: tscParts, args: ['--noEmit'] };
94
+
95
+ // 4. npx tsc
96
+ const npxParts = _tryWhich('npx');
97
+ if (npxParts) return { cmd: npxParts, args: ['tsc', '--noEmit'] };
98
+
99
+ return null;
100
+ }
101
+
102
+ /**
103
+ * Check whether an executable exists on PATH using `which` / `where` (sync).
104
+ * Returns the executable name if found, null otherwise. Never throws.
105
+ *
106
+ * @param {string} name
107
+ * @returns {string|null}
108
+ */
109
+ function _tryWhich(name) {
110
+ const whichCmd = process.platform === 'win32' ? 'where' : 'which';
111
+ try {
112
+ const result = spawnSync(whichCmd, [name], { encoding: 'utf8', timeout: 2000 });
113
+ if (result.status === 0 && result.stdout.trim()) return name;
114
+ } catch {
115
+ // ignore
116
+ }
117
+ return null;
118
+ }
119
+
120
+ /**
121
+ * Run the typecheck command with a 2s AbortController timeout.
122
+ *
123
+ * @param {string} cmd
124
+ * @param {string[]} args
125
+ * @returns {{status: 'pass'|'fail', duration_ms: number, reason?: string}}
126
+ */
127
+ function runTypecheck(cmd, args) {
128
+ const controller = new AbortController();
129
+ const timer = setTimeout(() => controller.abort(), 2000);
130
+
131
+ const start = performance.now();
132
+ let spawnResult;
133
+ try {
134
+ spawnResult = spawnSync(cmd, args, {
135
+ signal: controller.signal,
136
+ encoding: 'utf8',
137
+ stdio: ['ignore', 'pipe', 'pipe'],
138
+ timeout: 2000,
139
+ });
140
+ } finally {
141
+ clearTimeout(timer);
142
+ }
143
+
144
+ const duration_ms = Math.max(0, Math.round(performance.now() - start));
145
+
146
+ // AbortError or SIGTERM from timeout
147
+ if (spawnResult.error?.name === 'AbortError' || spawnResult.signal === 'SIGTERM') {
148
+ return { status: 'fail', duration_ms, reason: 'typecheck timed out after 2s' };
149
+ }
150
+
151
+ if (spawnResult.status !== 0) {
152
+ // Capture the first non-empty line of stderr/stdout as a compact reason.
153
+ const combined = ((spawnResult.stderr ?? '') + (spawnResult.stdout ?? '')).trim();
154
+ const firstLine = combined.split('\n').find((l) => l.trim()) ?? 'typecheck exited non-zero';
155
+ return { status: 'fail', duration_ms, reason: firstLine.slice(0, 256) };
156
+ }
157
+
158
+ return { status: 'pass', duration_ms };
159
+ }
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Main
163
+ // ---------------------------------------------------------------------------
164
+
165
+ async function main() {
166
+ // G1: null stdin → silent exit 0
167
+ let input;
168
+ try {
169
+ input = await readStdin();
170
+ } catch {
171
+ process.exit(0);
172
+ }
173
+ if (!input) process.exit(0);
174
+
175
+ const toolName = input.tool_name;
176
+ const filePath = input?.tool_input?.file_path;
177
+
178
+ // G2: only Edit, Write, and MultiEdit trigger typecheck
179
+ if (toolName !== 'Edit' && toolName !== 'Write' && toolName !== 'MultiEdit') process.exit(0);
180
+
181
+ // G3: file_path must be present
182
+ if (!filePath || typeof filePath !== 'string') process.exit(0);
183
+
184
+ // G4: extension filter — only TS/JS variants
185
+ const ext = path.extname(filePath).toLowerCase();
186
+ if (!TS_EXTS.has(ext)) process.exit(0);
187
+
188
+ const projectRoot = resolveProjectDir();
189
+
190
+ // Compute relative path (REQ-03)
191
+ const absFilePath = path.isAbsolute(filePath)
192
+ ? filePath
193
+ : path.resolve(projectRoot, filePath);
194
+ const relPath = path.relative(projectRoot, absFilePath);
195
+
196
+ // G5: per-gate toggle — skip if post-edit-validate gate is disabled
197
+ const scopeFile = findScopeFile(projectRoot);
198
+ if (scopeFile && !gateEnabled(scopeFile, 'post-edit-validate')) {
199
+ process.exit(0);
200
+ }
201
+
202
+ // G6: resolve typecheck command
203
+ const tc = await resolveTypecheckCommand(projectRoot);
204
+ if (!tc) {
205
+ emitResult(relPath, 'skip', undefined, 'no typecheck command found');
206
+ process.exit(0);
207
+ }
208
+
209
+ // G7: run typecheck with 2s timeout (REQ-02)
210
+ const { status, duration_ms, reason } = runTypecheck(tc.cmd, tc.args);
211
+
212
+ // G8: emit JSONL result to stderr
213
+ const remediation =
214
+ status === 'fail'
215
+ ? 'Run `npm run typecheck` to see full error context, then fix the type at the cited location.'
216
+ : undefined;
217
+ emitResult(relPath, status, duration_ms, reason, remediation);
218
+
219
+ process.exit(0);
220
+ }
221
+
222
+ // REQ-01: top-level catch — PostToolUse must never block; always exit 0
223
+ main().catch(() => {
224
+ process.exit(0);
225
+ });