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,383 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * autopilot.mjs — Phase C-5 headless CLI driver for the /autopilot loop.
4
+ *
5
+ * Issue #302 (Phase C-5). Wires real implementations of the four injectable
6
+ * seams defined by `runLoop` in `scripts/lib/autopilot.mjs` and lets the user
7
+ * run the autopilot loop unattended from the CLI.
8
+ *
9
+ * Usage:
10
+ * node scripts/autopilot.mjs --headless [options]
11
+ *
12
+ * Flags:
13
+ * --headless Required. Activates headless mode.
14
+ * --max-sessions=N Max iterations (1..50, default 5).
15
+ * --max-hours=H Max wall-clock hours (0.5..24.0, default 4.0).
16
+ * --confidence-threshold=0.X Mode confidence gate (0.0..1.0, default 0.85).
17
+ * --dry-run Emit a single record without spawning sessions.
18
+ * --verbose Pipe child process stdio (instead of inherit).
19
+ *
20
+ * Exit codes:
21
+ * 0 — clean termination (max-sessions-reached, max-hours-exceeded, or fallback-to-manual).
22
+ * 1 — uncaught error.
23
+ * 2 — kill_switch=failed-wave, or missing --headless flag.
24
+ *
25
+ * References:
26
+ * scripts/lib/autopilot.mjs — runLoop, parseFlags, writeAutopilotJsonl
27
+ * scripts/lib/build-live-signals.mjs — buildLiveSignals
28
+ * scripts/lib/mode-selector.mjs — selectMode
29
+ * scripts/lib/resource-probe.mjs — probe, evaluate
30
+ * scripts/lib/session-registry.mjs — detectPeers
31
+ * scripts/lib/session-schema.mjs — normalizeSession
32
+ * "/autopilot Loop Command (Phase C)" (#277/#271; archived in the private Meta-Vault)
33
+ */
34
+
35
+ import { readFileSync, existsSync } from 'node:fs';
36
+ import { spawnSync, spawn } from 'node:child_process';
37
+ import { resolve } from 'node:path';
38
+
39
+ import {
40
+ runLoop,
41
+ parseFlags,
42
+ KILL_SWITCHES,
43
+ } from './lib/autopilot.mjs';
44
+ import { buildLiveSignals } from './lib/build-live-signals.mjs';
45
+ import { surfaceTopN, decayOptsFromConfig } from './lib/learnings/surface.mjs';
46
+ import { selectMode } from './lib/mode-selector.mjs';
47
+ import { probe, evaluate } from './lib/resource-probe.mjs';
48
+ import { detectPeers } from './lib/session-registry.mjs';
49
+ import { normalizeSession } from './lib/session-schema.mjs';
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // CLI-level flag extraction
53
+ // ---------------------------------------------------------------------------
54
+
55
+ const argv = process.argv.slice(2);
56
+
57
+ const hasHeadless = argv.includes('--headless');
58
+ const hasVerbose = argv.includes('--verbose');
59
+
60
+ if (!hasHeadless) {
61
+ process.stderr.write('autopilot: headless mode requires --headless flag\n');
62
+ process.exit(2);
63
+ }
64
+
65
+ // Strip CLI-only flags before forwarding to parseFlags (which ignores unknown
66
+ // flags, but being explicit avoids confusion with future parseFlags additions).
67
+ const flagsForParse = argv.filter(
68
+ (a) => a !== '--headless' && a !== '--verbose'
69
+ );
70
+
71
+ const { maxSessions, maxHours, confidenceThreshold, dryRun } = parseFlags(flagsForParse);
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Session Config (parsed once, shared by thresholds + decay readers)
75
+ // ---------------------------------------------------------------------------
76
+
77
+ /**
78
+ * Parse Session Config once by spawning `node scripts/parse-config.mjs`.
79
+ * Returns the parsed config object, or `null` if the spawn fails / yields
80
+ * no usable stdout. Callers fall back to their own defaults on `null`.
81
+ *
82
+ * @returns {object|null}
83
+ */
84
+ function loadConfig() {
85
+ try {
86
+ const scriptPath = resolve(
87
+ new URL('.', import.meta.url).pathname,
88
+ 'parse-config.mjs'
89
+ );
90
+ const result = spawnSync(
91
+ process.execPath,
92
+ [scriptPath],
93
+ { encoding: 'utf8', timeout: 10_000 }
94
+ );
95
+ if (result.status !== 0 || !result.stdout) return null;
96
+ return JSON.parse(result.stdout);
97
+ } catch {
98
+ return null;
99
+ }
100
+ }
101
+
102
+ const config = loadConfig();
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Resource-thresholds from Session Config
106
+ // ---------------------------------------------------------------------------
107
+
108
+ /**
109
+ * Read the `resource-thresholds` block from the parsed Session Config. Falls
110
+ * back to the resource-probe defaults if the field is absent or config is null.
111
+ *
112
+ * @returns {object} thresholds object consumable by evaluate()
113
+ */
114
+ function loadResourceThresholds() {
115
+ // Probe defaults (mirrors resource-probe hard-coded values)
116
+ const DEFAULTS = {
117
+ 'ram-free-min-gb': 2.0,
118
+ 'ram-free-critical-gb': 0.5,
119
+ 'cpu-load-max-pct': 85,
120
+ 'concurrent-sessions-warn': 3,
121
+ };
122
+
123
+ const rt = config && config['resource-thresholds'];
124
+ if (rt && typeof rt === 'object') {
125
+ return { ...DEFAULTS, ...rt };
126
+ }
127
+ return DEFAULTS;
128
+ }
129
+
130
+ const thresholds = loadResourceThresholds();
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // Learnings loader — top-15 active learnings from learnings.jsonl
134
+ // ---------------------------------------------------------------------------
135
+ //
136
+ // Delegates to scripts/lib/learnings/surface.mjs (`surfaceTopN`). Same filter
137
+ // semantics as the original inline implementation: confidence > 0.3 AND
138
+ // (no expires_at OR expires_at > now), sorted by effectiveScore DESC (#670
139
+ // time-decay), then created_at DESC, then sliced to n=15. The `evolve.decay`
140
+ // Session Config block is threaded through `decayOptsFromConfig` so the
141
+ // documented decay knobs (decay-enabled / decay-half-life-days /
142
+ // decay-floor-factor) actually take effect here (#670). Errors swallowed → [].
143
+
144
+ const surfacedLearnings = await surfaceTopN(
145
+ resolve('.orchestrator/metrics/learnings.jsonl'),
146
+ 15,
147
+ { decay: decayOptsFromConfig(config && config['evolve.decay']) }
148
+ );
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Branch detection for autopilot_run_id construction
152
+ // ---------------------------------------------------------------------------
153
+
154
+ function detectBranch() {
155
+ try {
156
+ const result = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
157
+ encoding: 'utf8',
158
+ timeout: 5_000,
159
+ });
160
+ if (result.status === 0 && result.stdout) {
161
+ return result.stdout.trim() || null;
162
+ }
163
+ return null;
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+
169
+ const branch = detectBranch();
170
+
171
+ // ---------------------------------------------------------------------------
172
+ // sessions.jsonl helpers for sessionRunner
173
+ // ---------------------------------------------------------------------------
174
+
175
+ const SESSIONS_JSONL_PATH = resolve('.orchestrator/metrics/sessions.jsonl');
176
+
177
+ /**
178
+ * Count the number of non-empty lines in sessions.jsonl. Returns 0 if missing.
179
+ * @returns {number}
180
+ */
181
+ function countSessionLines() {
182
+ if (!existsSync(SESSIONS_JSONL_PATH)) return 0;
183
+ try {
184
+ const raw = readFileSync(SESSIONS_JSONL_PATH, 'utf8');
185
+ return raw.split('\n').filter((l) => l.trim().length > 0).length;
186
+ } catch {
187
+ return 0;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Read the last non-empty line from sessions.jsonl, parse it, run it through
193
+ * normalizeSession, and project to the sessionRunner return shape.
194
+ *
195
+ * @returns {{session_id: string, agent_summary?: object, effectiveness?: object}}
196
+ */
197
+ function readTailSession() {
198
+ const raw = readFileSync(SESSIONS_JSONL_PATH, 'utf8');
199
+ const lines = raw.split('\n').filter((l) => l.trim().length > 0);
200
+ if (lines.length === 0) {
201
+ throw new Error('sessions.jsonl is empty after session completed');
202
+ }
203
+ const parsed = JSON.parse(lines[lines.length - 1]);
204
+ const normalized = normalizeSession(parsed);
205
+ return {
206
+ session_id: normalized.session_id,
207
+ agent_summary: normalized.agent_summary,
208
+ effectiveness: normalized.effectiveness,
209
+ };
210
+ }
211
+
212
+ // ---------------------------------------------------------------------------
213
+ // Shared resource snapshot (updated by peerCounter on every iteration)
214
+ // ---------------------------------------------------------------------------
215
+
216
+ /** @type {object|null} */
217
+ let cachedProbeSnapshot = null;
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // DI seam implementations
221
+ // ---------------------------------------------------------------------------
222
+
223
+ /**
224
+ * modeSelector — invoked before each iteration.
225
+ * Signals are assembled once (surfacedLearnings surfaced before the loop),
226
+ * but buildLiveSignals is called per-iteration to get fresh STATE.md / sessions.
227
+ *
228
+ * @returns {Promise<{mode: string, confidence: number, rationale?: string, alternatives?: object[]}>}
229
+ */
230
+ async function modeSelector() {
231
+ const signals = await buildLiveSignals({
232
+ learnings: surfacedLearnings,
233
+ backlogLimit: 50,
234
+ });
235
+ return selectMode(signals);
236
+ }
237
+
238
+ /**
239
+ * sessionRunner — spawns `claude` with the recommended mode and awaits exit.
240
+ * Verifies that a new sessions.jsonl record was appended before returning.
241
+ *
242
+ * @param {{mode: string, autopilotRunId: string}} args
243
+ * @returns {Promise<{session_id: string, agent_summary?: object, effectiveness?: object}>}
244
+ */
245
+ async function sessionRunner({ mode, autopilotRunId }) {
246
+ const preCount = countSessionLines();
247
+
248
+ await new Promise((res, rej) => {
249
+ const childStdio = hasVerbose
250
+ ? ['ignore', 'pipe', 'pipe']
251
+ : ['ignore', 'inherit', 'inherit'];
252
+
253
+ const child = spawn(
254
+ 'claude',
255
+ ['-p', `/session ${mode}`],
256
+ {
257
+ env: { ...process.env, AUTOPILOT_RUN_ID: autopilotRunId },
258
+ stdio: childStdio,
259
+ cwd: process.cwd(),
260
+ }
261
+ );
262
+
263
+ if (hasVerbose) {
264
+ child.stdout.pipe(process.stdout);
265
+ child.stderr.pipe(process.stderr);
266
+ }
267
+
268
+ child.on('error', (err) => rej(err));
269
+ child.on('close', (code) => {
270
+ if (code !== 0) {
271
+ rej(new Error(`claude exit ${code}`));
272
+ } else {
273
+ res(undefined);
274
+ }
275
+ });
276
+ });
277
+
278
+ const postCount = countSessionLines();
279
+ if (postCount === preCount) {
280
+ throw new Error('no session record appended');
281
+ }
282
+
283
+ return readTailSession();
284
+ }
285
+
286
+ /**
287
+ * resourceEvaluator — returns the latest cached probe verdict.
288
+ * The cached snapshot is refreshed by peerCounter before each iteration.
289
+ * Falls back to probing inline if the cache is null (first iteration safety).
290
+ *
291
+ * @returns {{verdict: string, reasons: string[], recommended_agents_per_wave_cap: number|null}}
292
+ */
293
+ function resourceEvaluator() {
294
+ if (cachedProbeSnapshot === null) {
295
+ // Synchronous fallback is not possible since probe() is async.
296
+ // Return a conservative 'warn' so the loop does not mis-gate on missing data.
297
+ // The real snapshot will be available after peerCounter runs on the next call.
298
+ return { verdict: 'warn', reasons: ['probe not yet available'], recommended_agents_per_wave_cap: null };
299
+ }
300
+ return evaluate(cachedProbeSnapshot, thresholds);
301
+ }
302
+
303
+ /**
304
+ * peerCounter — refreshes the resource snapshot AND returns the peer count.
305
+ * Using this combined approach lets resourceEvaluator remain synchronous as
306
+ * required by the runLoop contract.
307
+ *
308
+ * @param {string} autopilotRunId — self-id to exclude from peer list.
309
+ * @returns {Promise<number>}
310
+ */
311
+ async function makePeerCounter(autopilotRunId) {
312
+ return async () => {
313
+ const [peers, snapshot] = await Promise.all([
314
+ detectPeers({ sessionId: autopilotRunId, freshnessMin: 15 }),
315
+ probe(),
316
+ ]);
317
+ cachedProbeSnapshot = snapshot;
318
+ return peers.length;
319
+ };
320
+ }
321
+
322
+ // ---------------------------------------------------------------------------
323
+ // AbortController for SIGINT
324
+ // ---------------------------------------------------------------------------
325
+
326
+ const controller = new AbortController();
327
+ process.on('SIGINT', () => {
328
+ controller.abort();
329
+ });
330
+
331
+ // ---------------------------------------------------------------------------
332
+ // Main
333
+ // ---------------------------------------------------------------------------
334
+
335
+ async function main() {
336
+ // Build the autopilotRunId via runLoop's defaultRunId (driven by branch opt).
337
+ // We don't construct it ourselves — runLoop builds it from branch + timestamp.
338
+ // We need it for peerCounter BEFORE runLoop starts. So we replicate the
339
+ // defaultRunId logic here to derive the same id. However, runLoop accepts
340
+ // an explicit `runId` override, so we just pre-compute one and pass it in.
341
+ const now = Date.now();
342
+ function pad2(n) { return n < 10 ? `0${n}` : String(n); }
343
+ const d = new Date(now);
344
+ const ymd = `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
345
+ const hhmm = `${pad2(d.getUTCHours())}${pad2(d.getUTCMinutes())}`;
346
+ const safeBranch = (branch ?? 'unknown').replace(/[^A-Za-z0-9._-]+/g, '-');
347
+ const autopilotRunId = `${safeBranch}-${ymd}-${hhmm}-autopilot`;
348
+
349
+ const peerCounter = await makePeerCounter(autopilotRunId);
350
+
351
+ const state = await runLoop({
352
+ maxSessions,
353
+ maxHours,
354
+ confidenceThreshold,
355
+ dryRun,
356
+ modeSelector,
357
+ sessionRunner,
358
+ resourceEvaluator,
359
+ peerCounter,
360
+ abortSignal: controller.signal,
361
+ runId: autopilotRunId,
362
+ branch: branch ?? undefined,
363
+ });
364
+
365
+ const sessionIds = state.sessions.join(', ') || '(none)';
366
+ const summary =
367
+ `${state.autopilot_run_id} ` +
368
+ `kill_switch=${state.kill_switch ?? 'none'} ` +
369
+ `iterations=${state.iterations_completed} ` +
370
+ `sessions=[${sessionIds}] ` +
371
+ `duration=${state.duration_seconds}s`;
372
+ process.stdout.write(summary + '\n');
373
+
374
+ if (state.kill_switch === KILL_SWITCHES.FAILED_WAVE) {
375
+ process.exit(2);
376
+ }
377
+ process.exit(0);
378
+ }
379
+
380
+ main().catch((err) => {
381
+ process.stderr.write(`autopilot: fatal error: ${err?.message ?? String(err)}\n`);
382
+ process.exit(1);
383
+ });
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * backfill-abandoned-sessions.mjs — one-time historical migration CLI (#724 C1).
4
+ *
5
+ * Scans `.orchestrator/metrics/events.jsonl` for every distinct
6
+ * `orchestrator.session.started` UUID that has no counterpart in
7
+ * `.orchestrator/metrics/sessions.jsonl`, bridges each to its semantic id via
8
+ * `orchestrator.session.lock.acquired` where available, and synthesizes a
9
+ * `status: 'abandoned'` stub through the shared backfill core
10
+ * (`scripts/lib/session-close-backfill.mjs`).
11
+ *
12
+ * SAFETY: `--dry-run` is the DEFAULT — nothing is written unless `--apply` is
13
+ * passed. Dry-run is idempotent (creates no marker files, appends nothing) so
14
+ * you can safely preview counts, then apply once against a copy or the live
15
+ * store at the operator's discretion.
16
+ *
17
+ * node scripts/backfill-abandoned-sessions.mjs [--dry-run|--apply] [--json]
18
+ * [--repo-root PATH]
19
+ * [--assume-dead-before ISO]
20
+ *
21
+ * DEAD-BY-AGE RELAXATION (#731): every CLI run happens FROM an active
22
+ * session, so `.orchestrator/session.lock` is ALWAYS live at run-time — the
23
+ * foreign-live-lock guard in the shared core (session-close-backfill.mjs)
24
+ * would otherwise block every historical candidate unconditionally. This CLI
25
+ * therefore ALWAYS passes `relaxDeadByAge: true`, so a candidate whose last
26
+ * known event is older than the lock's own default TTL
27
+ * (`session-lock.mjs` `DEFAULT_TTL_HOURS`) bypasses the current lock. The
28
+ * optional `--assume-dead-before <ISO>` flag additionally bypasses the guard
29
+ * for any candidate whose last known event predates the given cutoff,
30
+ * regardless of the TTL window. This relaxation is scoped to THIS CLI only —
31
+ * `hooks/on-session-end.mjs` never passes it (see the comment there).
32
+ *
33
+ * Exit codes (cli-design.md):
34
+ * 0 — completed (dry-run or apply)
35
+ * 1 — user/input error (bad args, invalid --assume-dead-before)
36
+ * 2 — system error (unreadable events file, etc.)
37
+ */
38
+
39
+ import fs from 'node:fs';
40
+ import path from 'node:path';
41
+ import { parseArgs } from 'node:util';
42
+ import { fileURLToPath } from 'node:url';
43
+
44
+ import { backfillAbandonedSession } from './lib/session-close-backfill.mjs';
45
+ import { SO_PROJECT_DIR } from './lib/platform.mjs';
46
+
47
+ const LOCK_ACQUIRED = 'orchestrator.session.lock.acquired';
48
+ const SESSION_STARTED = 'orchestrator.session.started';
49
+
50
+ /** Read a JSONL file into parsed objects; missing → []; malformed lines skipped. */
51
+ function readJsonl(filePath) {
52
+ let raw;
53
+ try {
54
+ raw = fs.readFileSync(filePath, 'utf8');
55
+ } catch {
56
+ return [];
57
+ }
58
+ const out = [];
59
+ for (const line of raw.split('\n')) {
60
+ const t = line.trim();
61
+ if (!t) continue;
62
+ try {
63
+ out.push(JSON.parse(t));
64
+ } catch {
65
+ /* skip malformed */
66
+ }
67
+ }
68
+ return out;
69
+ }
70
+
71
+ /**
72
+ * Enumerate distinct sessions worth evaluating: every unique
73
+ * session.started UUID, each bridged to its semantic id via lock.acquired
74
+ * where one exists. Preserves first-seen order.
75
+ *
76
+ * @param {{ repoRoot: string }} args
77
+ * @returns {Array<{ sessionId: string, semanticSessionId: string|null }>}
78
+ */
79
+ export function planSessions({ repoRoot }) {
80
+ const events = readJsonl(path.join(repoRoot, '.orchestrator', 'metrics', 'events.jsonl'));
81
+
82
+ const semanticByUuid = new Map();
83
+ for (const ev of events) {
84
+ if (
85
+ ev.event === LOCK_ACQUIRED &&
86
+ typeof ev.session_id === 'string' &&
87
+ typeof ev.semantic_session_id === 'string'
88
+ ) {
89
+ semanticByUuid.set(ev.session_id, ev.semantic_session_id);
90
+ }
91
+ }
92
+
93
+ const seen = new Set();
94
+ const plan = [];
95
+ for (const ev of events) {
96
+ if (ev.event !== SESSION_STARTED || typeof ev.session_id !== 'string') continue;
97
+ if (seen.has(ev.session_id)) continue;
98
+ seen.add(ev.session_id);
99
+ plan.push({ sessionId: ev.session_id, semanticSessionId: semanticByUuid.get(ev.session_id) ?? null });
100
+ }
101
+ return plan;
102
+ }
103
+
104
+ /**
105
+ * Run the migration over every planned session.
106
+ *
107
+ * `relaxDeadByAge: true` is ALWAYS passed to the shared core (#731) — see the
108
+ * module docblock for why. `assumeDeadBeforeMs` is forwarded as-is (null when
109
+ * `--assume-dead-before` was not given).
110
+ *
111
+ * @param {{ repoRoot: string, apply: boolean, assumeDeadBeforeMs?: number|null }} args
112
+ * @returns {Promise<object>} aggregate summary
113
+ */
114
+ export async function runMigration({ repoRoot, apply, assumeDeadBeforeMs = null }) {
115
+ const plan = planSessions({ repoRoot });
116
+ const summary = {
117
+ repoRoot,
118
+ mode: apply ? 'apply' : 'dry-run',
119
+ total: plan.length,
120
+ backfilled: 0,
121
+ would_backfill: 0,
122
+ dead_by_age: 0,
123
+ errors: 0,
124
+ skipped: {},
125
+ };
126
+
127
+ // Dry-run has no incremental sessions.jsonl write, so two started-UUIDs that
128
+ // bridge to the SAME semantic id (a session that cleared/compacted mid-run)
129
+ // would both report 'would-backfill' and over-count. Track projected ids
130
+ // here so the dry-run total matches what --apply actually writes.
131
+ const projected = new Set();
132
+
133
+ for (const item of plan) {
134
+ const res = await backfillAbandonedSession({
135
+ repoRoot,
136
+ sessionId: item.sessionId,
137
+ semanticSessionId: item.semanticSessionId,
138
+ dryRun: !apply,
139
+ relaxDeadByAge: true,
140
+ assumeDeadBeforeMs,
141
+ });
142
+ switch (res.action) {
143
+ case 'backfilled':
144
+ summary.backfilled += 1;
145
+ if (res.deadByAge) summary.dead_by_age += 1;
146
+ break;
147
+ case 'would-backfill':
148
+ if (projected.has(res.sessionId)) {
149
+ summary.skipped['skipped-already-recorded'] =
150
+ (summary.skipped['skipped-already-recorded'] ?? 0) + 1;
151
+ } else {
152
+ projected.add(res.sessionId);
153
+ summary.would_backfill += 1;
154
+ if (res.deadByAge) summary.dead_by_age += 1;
155
+ }
156
+ break;
157
+ case 'error':
158
+ summary.errors += 1;
159
+ break;
160
+ default:
161
+ summary.skipped[res.action] = (summary.skipped[res.action] ?? 0) + 1;
162
+ }
163
+ }
164
+ return summary;
165
+ }
166
+
167
+ function renderHuman(summary) {
168
+ const lines = [];
169
+ lines.push(`Backfill abandoned sessions — ${summary.mode}`);
170
+ lines.push(` repo: ${summary.repoRoot}`);
171
+ lines.push(` sessions seen: ${summary.total}`);
172
+ if (summary.mode === 'apply') {
173
+ lines.push(` backfilled: ${summary.backfilled}`);
174
+ } else {
175
+ lines.push(` would backfill: ${summary.would_backfill}`);
176
+ }
177
+ if (summary.dead_by_age > 0) {
178
+ lines.push(` dead-by-age: ${summary.dead_by_age} (relaxed past a live foreign session.lock)`);
179
+ }
180
+ lines.push(` errors: ${summary.errors}`);
181
+ const skips = Object.entries(summary.skipped);
182
+ if (skips.length > 0) {
183
+ lines.push(' skipped:');
184
+ for (const [reason, n] of skips) lines.push(` ${reason}: ${n}`);
185
+ }
186
+ return lines.join('\n') + '\n';
187
+ }
188
+
189
+ async function main() {
190
+ let parsed;
191
+ try {
192
+ parsed = parseArgs({
193
+ args: process.argv.slice(2),
194
+ options: {
195
+ apply: { type: 'boolean', default: false },
196
+ 'dry-run': { type: 'boolean', default: false },
197
+ json: { type: 'boolean', default: false },
198
+ 'repo-root': { type: 'string' },
199
+ 'assume-dead-before': { type: 'string' },
200
+ help: { type: 'boolean', short: 'h', default: false },
201
+ },
202
+ allowPositionals: false,
203
+ });
204
+ } catch (err) {
205
+ process.stderr.write(`backfill-abandoned-sessions: ${err.message}\n`);
206
+ process.exit(1);
207
+ }
208
+
209
+ const { values } = parsed;
210
+
211
+ if (values.help) {
212
+ process.stdout.write(
213
+ 'Usage: node scripts/backfill-abandoned-sessions.mjs [--dry-run|--apply] [--json]\n' +
214
+ ' [--repo-root PATH]\n' +
215
+ ' [--assume-dead-before ISO]\n' +
216
+ ' --dry-run preview only (DEFAULT — nothing is written)\n' +
217
+ ' --apply synthesize + append abandoned-session stubs\n' +
218
+ ' --json emit the summary as JSON to stdout\n' +
219
+ ' --repo-root override the project root (default: resolved SO_PROJECT_DIR)\n' +
220
+ ' --assume-dead-before ISO-8601 cutoff; a candidate whose last known event\n' +
221
+ ' predates it bypasses a live foreign session.lock\n' +
222
+ 'Exit codes: 0 ok, 1 arg error, 2 system error\n'
223
+ );
224
+ process.exit(0);
225
+ }
226
+
227
+ // --apply is an explicit opt-in; absent it (or with --dry-run) we never write.
228
+ const apply = values.apply === true && values['dry-run'] !== true;
229
+ const repoRoot = values['repo-root'] || SO_PROJECT_DIR;
230
+
231
+ let assumeDeadBeforeMs = null;
232
+ if (typeof values['assume-dead-before'] === 'string' && values['assume-dead-before'].length > 0) {
233
+ const ms = Date.parse(values['assume-dead-before']);
234
+ if (Number.isNaN(ms)) {
235
+ process.stderr.write(
236
+ `backfill-abandoned-sessions: --assume-dead-before is not a valid ISO-8601 timestamp: "${values['assume-dead-before']}"\n`
237
+ );
238
+ process.exit(1);
239
+ }
240
+ assumeDeadBeforeMs = ms;
241
+ }
242
+
243
+ let summary;
244
+ try {
245
+ summary = await runMigration({ repoRoot, apply, assumeDeadBeforeMs });
246
+ } catch (err) {
247
+ process.stderr.write(`backfill-abandoned-sessions: ${err?.message ?? String(err)}\n`);
248
+ process.exit(2);
249
+ }
250
+
251
+ if (values.json) {
252
+ process.stdout.write(JSON.stringify(summary) + '\n');
253
+ } else {
254
+ process.stdout.write(renderHuman(summary));
255
+ }
256
+ process.exit(0);
257
+ }
258
+
259
+ const isDirectRun = process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1];
260
+ if (isDirectRun) {
261
+ main().catch((err) => {
262
+ process.stderr.write(`backfill-abandoned-sessions: unexpected error: ${err?.stack ?? err}\n`);
263
+ process.exit(2);
264
+ });
265
+ }