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,196 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * backfill-learnings-expires.mjs — one-shot backfill helper for `expires_at`.
4
+ *
5
+ * Closes issue #323. Surfaced by 2026-05-07 W1 D2 surface-map: 1/129 records
6
+ * in .orchestrator/metrics/learnings.jsonl was missing `expires_at` (id:
7
+ * `archive-en-masse-residual-policy-2026-05-01`).
8
+ *
9
+ * For each record without `expires_at`, derives one from `created_at` + `type`
10
+ * via `deriveExpiresAt()` from `scripts/lib/learnings.mjs`. Records that
11
+ * already have `expires_at` pass through untouched.
12
+ *
13
+ * Forensics: every patched record gets a `_backfilled_expires_at: true` tag
14
+ * so downstream readers can identify backfilled vs originally-stamped values.
15
+ *
16
+ * Usage:
17
+ * node scripts/backfill-learnings-expires.mjs [--source <path>] [--dry-run] [--apply]
18
+ *
19
+ * Flags:
20
+ * --source <path> Path to learnings.jsonl (default: .orchestrator/metrics/learnings.jsonl)
21
+ * --dry-run Preview changes without writing (DEFAULT)
22
+ * --apply Write patched records back; backup original to <path>.bak.<isoDate>
23
+ *
24
+ * Exit codes:
25
+ * 0 Success (including no-op when nothing needs backfilling)
26
+ * 1 Input/validation error
27
+ * 2 I/O error
28
+ *
29
+ * Idempotent: a second --apply run produces 0 to_backfill (every record now
30
+ * has expires_at; the `_backfilled_expires_at` tag is preserved).
31
+ *
32
+ * Output (stdout — single JSON summary line):
33
+ * {"total":N,"already_has_expires":A,"to_backfill":B,"parse_errors":P,"applied":bool}
34
+ *
35
+ * Per-record narration goes to stderr so stdout stays machine-parseable.
36
+ */
37
+
38
+ import { existsSync, readFileSync, writeFileSync, renameSync, copyFileSync, mkdirSync } from 'node:fs';
39
+ import { dirname } from 'node:path';
40
+ import { deriveExpiresAt } from './lib/learnings.mjs';
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Arg parsing
44
+ // ---------------------------------------------------------------------------
45
+
46
+ const args = process.argv.slice(2);
47
+ if (args.includes('--help') || args.includes('-h')) {
48
+ process.stdout.write(
49
+ `Usage: backfill-learnings-expires.mjs [--source <path>] [--dry-run] [--apply]
50
+
51
+ Options:
52
+ --source <path> Path to learnings.jsonl (default: .orchestrator/metrics/learnings.jsonl)
53
+ --dry-run Preview changes without writing (DEFAULT)
54
+ --apply Write patched records; backup original to <path>.bak.<isoDate>
55
+
56
+ Exit codes: 0 success 1 input error 2 I/O error
57
+ `
58
+ );
59
+ process.exit(0);
60
+ }
61
+
62
+ const applyFlag = args.includes('--apply');
63
+ const dryRun = !applyFlag;
64
+
65
+ const sourceIdx = args.indexOf('--source');
66
+ const sourcePath =
67
+ sourceIdx !== -1 && args[sourceIdx + 1]
68
+ ? args[sourceIdx + 1]
69
+ : '.orchestrator/metrics/learnings.jsonl';
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Load
73
+ // ---------------------------------------------------------------------------
74
+
75
+ if (!existsSync(sourcePath)) {
76
+ process.stderr.write(`backfill-learnings-expires: source file not found: ${sourcePath}\n`);
77
+ process.exit(1);
78
+ }
79
+
80
+ let raw;
81
+ try {
82
+ raw = readFileSync(sourcePath, 'utf8');
83
+ } catch (err) {
84
+ process.stderr.write(
85
+ `backfill-learnings-expires: failed to read ${sourcePath}: ${err.message}\n`
86
+ );
87
+ process.exit(2);
88
+ }
89
+
90
+ const lines = raw.split('\n').filter((l) => l.trim().length > 0);
91
+
92
+ // ---------------------------------------------------------------------------
93
+ // Backfill
94
+ // ---------------------------------------------------------------------------
95
+
96
+ let countAlready = 0;
97
+ let countToBackfill = 0;
98
+ let countParseErrors = 0;
99
+ const outputLines = [];
100
+
101
+ for (const line of lines) {
102
+ let parsed;
103
+ try {
104
+ parsed = JSON.parse(line);
105
+ } catch {
106
+ countParseErrors++;
107
+ process.stderr.write(
108
+ `backfill-learnings-expires: WARN skipping malformed JSON line: ${line.slice(0, 80)}\n`
109
+ );
110
+ // Preserve original line — never destroy data
111
+ outputLines.push(line);
112
+ continue;
113
+ }
114
+
115
+ const hasExpires =
116
+ typeof parsed.expires_at === 'string' && parsed.expires_at.length > 0;
117
+ if (hasExpires) {
118
+ countAlready++;
119
+ outputLines.push(JSON.stringify(parsed));
120
+ continue;
121
+ }
122
+
123
+ // Derive expires_at from created_at + type. deriveExpiresAt() falls back
124
+ // to Date.now() when created_at is missing/unparseable, so we always
125
+ // produce a valid ISO timestamp.
126
+ const newExpires = deriveExpiresAt(parsed.created_at, parsed.type);
127
+ const patched = {
128
+ ...parsed,
129
+ expires_at: newExpires,
130
+ _backfilled_expires_at: true,
131
+ };
132
+ countToBackfill++;
133
+ outputLines.push(JSON.stringify(patched));
134
+ process.stderr.write(
135
+ `backfill-learnings-expires: patched id=${parsed.id ?? '<no id>'} type=${parsed.type ?? '<no type>'} expires_at=${newExpires}\n`
136
+ );
137
+ }
138
+
139
+ // ---------------------------------------------------------------------------
140
+ // Write (--apply only)
141
+ // ---------------------------------------------------------------------------
142
+
143
+ let applied = false;
144
+ if (!dryRun && countToBackfill > 0) {
145
+ // Backup first
146
+ const isoDate = new Date().toISOString().replace(/[:.]/g, '-');
147
+ const backupPath = `${sourcePath}.bak.${isoDate}`;
148
+ try {
149
+ copyFileSync(sourcePath, backupPath);
150
+ } catch (err) {
151
+ process.stderr.write(
152
+ `backfill-learnings-expires: ERROR failed to create backup ${backupPath}: ${err.message}\n`
153
+ );
154
+ process.exit(2);
155
+ }
156
+
157
+ // Atomic write via tmp + rename
158
+ const body = outputLines.join('\n') + '\n';
159
+ const tmp = `${sourcePath}.backfill-tmp-${process.pid}-${Date.now()}`;
160
+ try {
161
+ mkdirSync(dirname(sourcePath), { recursive: true });
162
+ writeFileSync(tmp, body, 'utf8');
163
+ renameSync(tmp, sourcePath);
164
+ applied = true;
165
+ process.stderr.write(
166
+ `backfill-learnings-expires: backup written to ${backupPath}\n`
167
+ );
168
+ } catch (err) {
169
+ process.stderr.write(
170
+ `backfill-learnings-expires: ERROR failed to write ${sourcePath}: ${err.message}\n`
171
+ );
172
+ try {
173
+ if (existsSync(tmp)) renameSync(tmp, tmp + '.failed');
174
+ } catch {
175
+ /* ignore */
176
+ }
177
+ process.exit(2);
178
+ }
179
+ }
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // Summary (single JSON line on stdout)
183
+ // ---------------------------------------------------------------------------
184
+
185
+ const summary = {
186
+ total: lines.length,
187
+ already_has_expires: countAlready,
188
+ to_backfill: countToBackfill,
189
+ parse_errors: countParseErrors,
190
+ applied,
191
+ dry_run: dryRun,
192
+ source: sourcePath,
193
+ };
194
+ process.stdout.write(JSON.stringify(summary) + '\n');
195
+
196
+ process.exit(0);
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * backfill-learnings.mjs — normalize producer DIALECTS in learnings.jsonl.
4
+ *
5
+ * Epic #723 B2. The live corpus historically carried the rule-conversion scope
6
+ * under `files` (not the canonical `file_paths`), duplicated `source_session`
7
+ * into `session_id`, used `last_seen` instead of `updated_at`, and left
8
+ * `next_review: null` / non-canonical (no-millis) timestamps. This one-shot
9
+ * backfill routes every line through the schema SSOT (`migrateLegacyLearning`,
10
+ * which applies `normalizeDialects` + the insight/subject alias chain + a
11
+ * `schema_version:1` stamp), gates the result with `validateLearning`, and
12
+ * rewrites the file where a safe normalization exists.
13
+ *
14
+ * Data-loss safety (three guarantees):
15
+ * - A line that fails `JSON.parse` is preserved byte-identical and counted
16
+ * (`parse_errors`) — never dropped.
17
+ * - A record that still fails `validateLearning` AFTER migration is passed
18
+ * through byte-identical and counted (`invalid_after_migration`) — never
19
+ * mutated, never flagged.
20
+ * - `--apply` writes atomically (copy-to-`.bak-<ISO>` → tmp → rename), so the
21
+ * canonical file always exists holding either the old or the new content.
22
+ *
23
+ * This script duplicates NO normalization logic — all shape work lives in
24
+ * `scripts/lib/learnings/schema.mjs`.
25
+ *
26
+ * Usage:
27
+ * node scripts/backfill-learnings.mjs [--file PATH] [--apply|--dry-run]
28
+ *
29
+ * Modes:
30
+ * (default / --dry-run) compute + report intended rewrites per line; does
31
+ * not touch the file
32
+ * --apply write the normalized file atomically via tmp+rename,
33
+ * after copying the original to `${file}.bak-<ISO>`
34
+ *
35
+ * Exit codes:
36
+ * 0 — completed (dry-run or apply)
37
+ * 1 — I/O error (file not found, unreadable, write failed)
38
+ * 2 — usage error (unknown argument)
39
+ *
40
+ * Output: JSON summary on stdout (single line)
41
+ * {"scanned":N,"normalized":N,"unchanged":N,"parse_errors":N,
42
+ * "invalid_after_migration":N,"applied":bool,"dry_run":bool,"backup":"<path>|null","file":"<path>"}
43
+ */
44
+
45
+ import { readFileSync, writeFileSync, renameSync, copyFileSync, existsSync } from 'node:fs';
46
+ import { join, dirname, basename } from 'node:path';
47
+ import {
48
+ migrateLegacyLearning,
49
+ normalizeDialects,
50
+ validateLearning,
51
+ ValidationError,
52
+ } from './lib/learnings/schema.mjs';
53
+
54
+ const DEFAULT_FILE = '.orchestrator/metrics/learnings.jsonl';
55
+
56
+ function parseArgs(argv) {
57
+ const args = { file: DEFAULT_FILE, apply: false };
58
+ for (let i = 0; i < argv.length; i++) {
59
+ const a = argv[i];
60
+ if (a === '--file') args.file = argv[++i];
61
+ else if (a === '--apply') args.apply = true;
62
+ else if (a === '--dry-run') args.apply = false;
63
+ else if (a === '--help' || a === '-h') {
64
+ process.stdout.write(
65
+ 'Usage: node scripts/backfill-learnings.mjs [--file PATH] [--apply|--dry-run]\n' +
66
+ ' --file target learnings.jsonl (default: .orchestrator/metrics/learnings.jsonl)\n' +
67
+ ' --dry-run report normalizations; do not modify file (default)\n' +
68
+ ' --apply rewrite file atomically with a .bak-<ISO> backup\n'
69
+ );
70
+ process.exit(0);
71
+ } else {
72
+ process.stderr.write(`backfill-learnings: unknown argument: ${a}\n`);
73
+ process.exit(2);
74
+ }
75
+ }
76
+ return args;
77
+ }
78
+
79
+ /**
80
+ * Classify + transform a single parsed record via the schema SSOT.
81
+ *
82
+ * Returns { outcome, line } where outcome is one of:
83
+ * - 'unchanged' : migration is a semantic no-op (serialized form matches input)
84
+ * - 'normalized' : migration changed the record AND it validates
85
+ * - 'invalid' : migration result still fails validateLearning → keep original
86
+ *
87
+ * @param {object} parsed — the JSON.parse'd record
88
+ * @param {string} originalLine — the verbatim source line (returned untouched on 'invalid')
89
+ * @returns {{ outcome: 'unchanged'|'normalized'|'invalid', line: string }}
90
+ */
91
+ function processRecord(parsed, originalLine) {
92
+ // Two SSOT calls, no duplicated normalization logic:
93
+ // 1. migrateLegacyLearning — aliases + schema_version:1 stamp + dialects
94
+ // (files→file_paths, session_id/last_seen/next_review), byte-exact timestamps.
95
+ // 2. normalizeDialects (full) — canonicalize timestamp FORMAT to millis+Z.
96
+ // Idempotent for every other dialect (already handled in step 1).
97
+ const migrated = normalizeDialects(migrateLegacyLearning(parsed));
98
+
99
+ // Gate: a record that cannot pass the schema after migration is passed
100
+ // through byte-identical (never mutated, never flagged).
101
+ try {
102
+ validateLearning(migrated);
103
+ } catch (err) {
104
+ if (err instanceof ValidationError) {
105
+ return { outcome: 'invalid', line: originalLine };
106
+ }
107
+ throw err;
108
+ }
109
+
110
+ const migratedLine = JSON.stringify(migrated);
111
+ // Semantic-equality against the re-serialized parsed input: a migration that
112
+ // reorders nothing and changes no value is a no-op.
113
+ if (migratedLine === JSON.stringify(parsed)) {
114
+ return { outcome: 'unchanged', line: migratedLine };
115
+ }
116
+ return { outcome: 'normalized', line: migratedLine };
117
+ }
118
+
119
+ function main() {
120
+ const args = parseArgs(process.argv.slice(2));
121
+
122
+ if (!args.file || !existsSync(args.file)) {
123
+ process.stderr.write(`backfill-learnings: file not found: ${args.file}\n`);
124
+ process.exit(1);
125
+ }
126
+
127
+ let lines;
128
+ try {
129
+ lines = readFileSync(args.file, 'utf8').split('\n').filter((l) => l.length > 0);
130
+ } catch (err) {
131
+ process.stderr.write(`backfill-learnings: read failed: ${err.message}\n`);
132
+ process.exit(1);
133
+ }
134
+
135
+ const outputLines = [];
136
+ const counts = {
137
+ scanned: 0,
138
+ normalized: 0,
139
+ unchanged: 0,
140
+ parse_errors: 0,
141
+ invalid_after_migration: 0,
142
+ };
143
+
144
+ for (const line of lines) {
145
+ counts.scanned++;
146
+ let parsed;
147
+ try {
148
+ parsed = JSON.parse(line);
149
+ } catch {
150
+ counts.parse_errors++;
151
+ outputLines.push(line); // byte-identical preservation — never drop
152
+ continue;
153
+ }
154
+
155
+ const { outcome, line: outLine } = processRecord(parsed, line);
156
+ if (outcome === 'invalid') counts.invalid_after_migration++;
157
+ else counts[outcome]++;
158
+ outputLines.push(outLine);
159
+ }
160
+
161
+ const summary = {
162
+ scanned: counts.scanned,
163
+ normalized: counts.normalized,
164
+ unchanged: counts.unchanged,
165
+ parse_errors: counts.parse_errors,
166
+ invalid_after_migration: counts.invalid_after_migration,
167
+ applied: false,
168
+ dry_run: !args.apply,
169
+ backup: null,
170
+ file: args.file,
171
+ };
172
+
173
+ if (!args.apply) {
174
+ process.stdout.write(JSON.stringify(summary) + '\n');
175
+ return;
176
+ }
177
+
178
+ // Apply path — POSIX atomic replace, self-contained (no io.mjs dependency).
179
+ // 1. copyFileSync: canonical → .bak-<ISO> (backup; canonical still present)
180
+ // 2. writeFileSync: normalized → tmp (new content; canonical still present)
181
+ // 3. renameSync: tmp → canonical (atomic replace per POSIX)
182
+ // The canonical file exists at every step, holding old or new content.
183
+ const iso = new Date().toISOString().replace(/[:.]/g, '-');
184
+ const backupPath = `${args.file}.bak-${iso}`;
185
+ const tmpPath = join(dirname(args.file), `.${basename(args.file)}.tmp-${process.pid}`);
186
+ try {
187
+ copyFileSync(args.file, backupPath);
188
+ writeFileSync(tmpPath, outputLines.join('\n') + '\n', 'utf8');
189
+ renameSync(tmpPath, args.file);
190
+ summary.applied = true;
191
+ summary.backup = backupPath;
192
+ } catch (err) {
193
+ const recoveryHint = existsSync(backupPath)
194
+ ? `Canonical file is intact; backup at ${backupPath}.`
195
+ : 'Backup was not created.';
196
+ process.stderr.write(`backfill-learnings: write failed: ${err.message}. ${recoveryHint}\n`);
197
+ process.exit(1);
198
+ }
199
+
200
+ process.stdout.write(JSON.stringify(summary) + '\n');
201
+ }
202
+
203
+ main();
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * backfill-sessions.mjs — normalize legacy shapes in sessions.jsonl.
4
+ *
5
+ * Issue #249 follow-up. Reads a sessions.jsonl file and rewrites each line
6
+ * into the canonical schema_version=2 shape (bumped 1 -> 2 via #372) where a
7
+ * safe deterministic mapping exists. Entries that cannot be safely mapped are
8
+ * tagged `_deprecated: true` (preserved but flagged — never dropped).
9
+ *
10
+ * Usage:
11
+ * node scripts/backfill-sessions.mjs [--file PATH] [--apply] [--mark-deprecated-only]
12
+ *
13
+ * Modes:
14
+ * (default / --dry-run) reports intended rewrites + deprecations per line;
15
+ * does not touch the file
16
+ * --apply writes the rewritten file atomically via temp+rename;
17
+ * creates a `.bak-<ISO>` backup of the original
18
+ * --mark-deprecated-only same as --apply but only tags unmappable entries
19
+ * with `_deprecated: true`; leaves mappable entries
20
+ * untouched (conservative path)
21
+ *
22
+ * Exit codes:
23
+ * 0 — completed (dry-run or apply)
24
+ * 1 — I/O error (unreadable file, write failed)
25
+ * 2 — usage error
26
+ *
27
+ * Output: JSON summary on stdout
28
+ * {"mode":"dry-run|apply|mark-deprecated-only","total":N,"rewritten":N,"deprecated":N,"unchanged":N,"backup":"<path>|null"}
29
+ */
30
+
31
+ import { readFileSync, writeFileSync, renameSync, copyFileSync, existsSync } from 'node:fs';
32
+ import { join, dirname, basename } from 'node:path';
33
+ import { validateSession, normalizeSession, ValidationError } from './lib/session-schema.mjs';
34
+
35
+ const DEFAULT_FILE = '.orchestrator/metrics/sessions.jsonl';
36
+
37
+ /**
38
+ * Line numbers (1-indexed) known to be unmappable per D1 inventory. These
39
+ * entries have fundamentally divergent shape (e.g., `waves: null` scalar
40
+ * counts, alternative telemetry models) that cannot be deterministically
41
+ * converted without data loss. Marked `_deprecated: true` on apply.
42
+ *
43
+ * The logic below also independently detects unmappable entries by shape,
44
+ * so this list is informational — identification is structural, not
45
+ * positional. If the file is truncated or reordered, the shape-check still
46
+ * fires.
47
+ */
48
+ const KNOWN_UNMAPPABLE_SHAPES = Object.freeze({
49
+ // `waves` is null (scalar counts via waves_completed/waves_total — array
50
+ // cannot be reconstructed):
51
+ wavesIsNull: (e) => e.waves === null,
52
+ // `waves` is a number (integer count, not an array):
53
+ wavesIsNumber: (e) => typeof e.waves === 'number',
54
+ // `waves_executed` scalar instead of `waves` array — array not reconstructible:
55
+ wavesExecutedScalar: (e) => typeof e.waves_executed === 'number' && !('waves' in e),
56
+ // head_ref + metrics-object variant (windows-native experiment) — no
57
+ // canonical mapping for the `metrics` bag:
58
+ metricsObjectShape: (e) => 'metrics' in e && !('agent_summary' in e),
59
+ });
60
+
61
+ /**
62
+ * Value-transforming aliases not safe for session-schema.mjs (which only
63
+ * does same-shape renames). Applied here because backfill has full context.
64
+ */
65
+ function applyValueAliases(e) {
66
+ const next = { ...e };
67
+ // duration_min / duration_minutes → duration_seconds (multiply by 60)
68
+ if ('duration_min' in next && !('duration_seconds' in next)) {
69
+ if (typeof next.duration_min === 'number' && next.duration_min >= 0) {
70
+ next.duration_seconds = next.duration_min * 60;
71
+ }
72
+ }
73
+ if ('duration_minutes' in next && !('duration_seconds' in next)) {
74
+ if (typeof next.duration_minutes === 'number' && next.duration_minutes >= 0) {
75
+ next.duration_seconds = next.duration_minutes * 60;
76
+ }
77
+ }
78
+ // agent_summary reconstruction from agents_complete/partial/failed/dispatched
79
+ // ONLY when waves scalar does NOT indicate a fundamentally different shape.
80
+ // Ambiguous without `spiral` — synthesize as 0 if reconstruction is attempted.
81
+ if (
82
+ !('agent_summary' in next) &&
83
+ typeof next.agents_complete === 'number' &&
84
+ typeof next.agents_partial === 'number' &&
85
+ typeof next.agents_failed === 'number'
86
+ ) {
87
+ next.agent_summary = {
88
+ complete: next.agents_complete,
89
+ partial: next.agents_partial,
90
+ failed: next.agents_failed,
91
+ spiral: typeof next.agents_spiral === 'number' ? next.agents_spiral : 0,
92
+ };
93
+ }
94
+ // total_agents: derive from agents_dispatched if missing
95
+ if (!('total_agents' in next) && typeof next.agents_dispatched === 'number') {
96
+ next.total_agents = next.agents_dispatched;
97
+ }
98
+ // total_files_changed: derive from files_changed scalar (if a number)
99
+ if (!('total_files_changed' in next) && typeof next.files_changed === 'number') {
100
+ next.total_files_changed = next.files_changed;
101
+ }
102
+ // total_waves: derive from waves_total or waves_completed scalar
103
+ if (!('total_waves' in next)) {
104
+ if (typeof next.waves_total === 'number') next.total_waves = next.waves_total;
105
+ else if (typeof next.waves_completed === 'number') next.total_waves = next.waves_completed;
106
+ }
107
+ return next;
108
+ }
109
+
110
+ function detectUnmappableReason(entry) {
111
+ for (const [name, check] of Object.entries(KNOWN_UNMAPPABLE_SHAPES)) {
112
+ if (check(entry)) return name;
113
+ }
114
+ return null;
115
+ }
116
+
117
+ function parseArgs(argv) {
118
+ const args = { file: DEFAULT_FILE, mode: 'dry-run' };
119
+ for (let i = 0; i < argv.length; i++) {
120
+ const a = argv[i];
121
+ if (a === '--file') args.file = argv[++i];
122
+ else if (a === '--apply') args.mode = 'apply';
123
+ else if (a === '--dry-run') args.mode = 'dry-run';
124
+ else if (a === '--mark-deprecated-only') args.mode = 'mark-deprecated-only';
125
+ else if (a === '--help' || a === '-h') {
126
+ process.stdout.write(
127
+ 'Usage: node scripts/backfill-sessions.mjs [--file PATH] [--apply|--dry-run|--mark-deprecated-only]\n' +
128
+ ' --file target sessions.jsonl (default: .orchestrator/metrics/sessions.jsonl)\n' +
129
+ ' --dry-run report rewrites; do not modify file (default)\n' +
130
+ ' --apply rewrite file atomically with .bak-<ISO> backup\n' +
131
+ ' --mark-deprecated-only tag only unmappable entries with _deprecated:true\n'
132
+ );
133
+ process.exit(0);
134
+ } else {
135
+ process.stderr.write(`backfill-sessions: unknown argument: ${a}\n`);
136
+ process.exit(2);
137
+ }
138
+ }
139
+ return args;
140
+ }
141
+
142
+ /**
143
+ * Process a single entry. Returns { outcome, entry } where outcome is one
144
+ * of: 'unchanged' | 'rewritten' | 'deprecated'.
145
+ *
146
+ * - 'unchanged': transforms are a no-op (entry already canonical byte-equivalent)
147
+ * - 'rewritten': entry was transformed (safe aliases + value-transforming aliases)
148
+ * and the result validates as v1
149
+ * - 'deprecated': structurally unmappable OR validation still fails after
150
+ * transforms; tagged with _deprecated:true
151
+ */
152
+ function processEntry(raw) {
153
+ const structuralReason = detectUnmappableReason(raw);
154
+ if (structuralReason) {
155
+ return {
156
+ outcome: 'deprecated',
157
+ entry: { ...raw, _deprecated: true, _deprecation_reason: `structural: ${structuralReason}` },
158
+ };
159
+ }
160
+
161
+ // Always run the transform pipeline so value-alias reconstruction happens
162
+ // even on entries that would pass validation without it.
163
+ let transformed = normalizeSession(raw);
164
+ transformed = applyValueAliases(transformed);
165
+ // Drop normalizeSession's read-path schema_version:0 stamp so validateSession
166
+ // stamps the canonical 1 on successful rewrites.
167
+ if (transformed.schema_version === 0 && !('schema_version' in raw)) {
168
+ delete transformed.schema_version;
169
+ }
170
+
171
+ let validated;
172
+ try {
173
+ validated = validateSession(transformed);
174
+ } catch (err) {
175
+ if (err instanceof ValidationError) {
176
+ return {
177
+ outcome: 'deprecated',
178
+ entry: { ...raw, _deprecated: true, _deprecation_reason: err.message },
179
+ };
180
+ }
181
+ throw err;
182
+ }
183
+
184
+ // "Unchanged" means: the serialized form matches the serialized original.
185
+ // This preserves byte-identical behavior for already-canonical entries
186
+ // while still classifying entries that needed any transform as rewritten.
187
+ if (JSON.stringify(validated) === JSON.stringify(raw)) {
188
+ return { outcome: 'unchanged', entry: raw };
189
+ }
190
+ return { outcome: 'rewritten', entry: validated };
191
+ }
192
+
193
+ async function main() {
194
+ const args = parseArgs(process.argv.slice(2));
195
+
196
+ if (!existsSync(args.file)) {
197
+ process.stderr.write(`backfill-sessions: file not found: ${args.file}\n`);
198
+ process.exit(1);
199
+ }
200
+
201
+ let lines;
202
+ try {
203
+ lines = readFileSync(args.file, 'utf8').split('\n').filter((l) => l.length > 0);
204
+ } catch (err) {
205
+ process.stderr.write(`backfill-sessions: read failed: ${err.message}\n`);
206
+ process.exit(1);
207
+ }
208
+
209
+ const perLine = [];
210
+ const rewritten = [];
211
+ const counts = { unchanged: 0, rewritten: 0, deprecated: 0, parseError: 0 };
212
+
213
+ for (let i = 0; i < lines.length; i++) {
214
+ const lineNum = i + 1;
215
+ let raw;
216
+ try {
217
+ raw = JSON.parse(lines[i]);
218
+ } catch (err) {
219
+ counts.parseError++;
220
+ perLine.push({ line: lineNum, outcome: 'parse-error', reason: err.message });
221
+ rewritten.push(lines[i]); // preserve original line verbatim
222
+ continue;
223
+ }
224
+ const { outcome, entry } = processEntry(raw);
225
+ counts[outcome]++;
226
+ perLine.push({ line: lineNum, outcome, session_id: raw.session_id ?? null });
227
+ if (args.mode === 'mark-deprecated-only' && outcome === 'rewritten') {
228
+ // Conservative: leave mappable entries as-is.
229
+ rewritten.push(lines[i]);
230
+ } else {
231
+ rewritten.push(JSON.stringify(entry));
232
+ }
233
+ }
234
+
235
+ const summary = {
236
+ mode: args.mode,
237
+ file: args.file,
238
+ total: lines.length,
239
+ unchanged: counts.unchanged,
240
+ rewritten: counts.rewritten,
241
+ deprecated: counts.deprecated,
242
+ parse_errors: counts.parseError,
243
+ backup: null,
244
+ };
245
+
246
+ if (args.mode === 'dry-run') {
247
+ process.stdout.write(JSON.stringify(summary) + '\n');
248
+ process.stdout.write(JSON.stringify({ detail: perLine }) + '\n');
249
+ return;
250
+ }
251
+
252
+ // Apply path — POSIX atomic replace (tmp → rename-over-canonical) preceded
253
+ // by a pre-write copy-to-backup. This eliminates the crash window where the
254
+ // canonical path could be briefly missing if the rename dance were split:
255
+ // 1. copyFileSync: canonical → .bak-<ISO> (backup; canonical still present)
256
+ // 2. writeFileSync: rewritten → tmp (new content; canonical still present)
257
+ // 3. renameSync: tmp → canonical (atomic replace per POSIX)
258
+ // At every point between steps, the canonical file exists and holds either
259
+ // the old content or the new content. Recovery artifact: .bak-<ISO>.
260
+ const iso = new Date().toISOString().replace(/[:.]/g, '-');
261
+ const backupPath = `${args.file}.bak-${iso}`;
262
+ const tmpPath = join(dirname(args.file), `.${basename(args.file)}.tmp-${process.pid}`);
263
+ try {
264
+ copyFileSync(args.file, backupPath);
265
+ writeFileSync(tmpPath, rewritten.join('\n') + '\n', 'utf8');
266
+ renameSync(tmpPath, args.file);
267
+ summary.backup = backupPath;
268
+ } catch (err) {
269
+ const recoveryHint = existsSync(backupPath)
270
+ ? `Canonical file is intact; backup at ${backupPath}.`
271
+ : 'Backup was not created.';
272
+ process.stderr.write(`backfill-sessions: write failed: ${err.message}. ${recoveryHint}\n`);
273
+ process.exit(1);
274
+ }
275
+
276
+ process.stdout.write(JSON.stringify(summary) + '\n');
277
+ }
278
+
279
+ main().catch((err) => {
280
+ process.stderr.write(`backfill-sessions: unexpected error: ${err?.stack ?? err}\n`);
281
+ process.exit(1);
282
+ });