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,453 @@
1
+ /**
2
+ * session-schema/validator.mjs — ValidationError class + validateSession.
3
+ *
4
+ * Extracted from scripts/lib/session-schema.mjs (W1A3 split).
5
+ * Imports: constants.mjs (leaf). No imports from siblings (normalizer,
6
+ * timestamps, aliases) or parent barrel.
7
+ *
8
+ * Exports: ValidationError, validateSession
9
+ * Module-private: isPlainObject, _validateSchemaVersion,
10
+ * _validateRequiredFields, _validateSessionId, _validateSessionType,
11
+ * _validateTimestamps, _validateWaves, _validateAgentSummary,
12
+ * _validateOptionalFields
13
+ */
14
+
15
+ import {
16
+ CURRENT_SESSION_SCHEMA_VERSION,
17
+ VALID_SESSION_TYPES,
18
+ REQUIRED_FIELDS,
19
+ AGENT_SUMMARY_FIELDS,
20
+ } from './constants.mjs';
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Module-private enums + regex
24
+ // ---------------------------------------------------------------------------
25
+
26
+ /** Valid values for the optional `expected_cost_tier` field (ADR-364). */
27
+ const EXPECTED_COST_TIERS = Object.freeze(['quick', 'standard', 'deep']);
28
+
29
+ /**
30
+ * Valid values for the optional `status` field (Epic #724 C1).
31
+ * `completed` — record written by a normal /close flow.
32
+ * `abandoned` — stub backfilled by the SessionEnd hook because the session
33
+ * terminated without running /close.
34
+ */
35
+ const SESSION_STATUS = Object.freeze(['completed', 'abandoned']);
36
+
37
+ /**
38
+ * Canonical ISO-8601 UTC timestamp regex — accepts `YYYY-MM-DDTHH:MM:SSZ`
39
+ * and `YYYY-MM-DDTHH:MM:SS.SSSZ` (exactly 3 fractional digits).
40
+ *
41
+ * Issue #540 defense-in-depth layer (b): block malformed timestamp strings
42
+ * that `Date.parse` accepts as NaN OR (worse) accepts as valid but
43
+ * non-canonical (e.g. `.3NZ`, `.3Z`, `.300000Z`). The strict regex closes
44
+ * the gap left by `Date.parse` alone, which returned NaN for `.3NZ` in some
45
+ * inputs and silently coerced others.
46
+ */
47
+ const ISO_8601_UTC_MS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Error class
51
+ // ---------------------------------------------------------------------------
52
+
53
+ export class ValidationError extends Error {
54
+ constructor(message) {
55
+ super(message);
56
+ this.name = 'ValidationError';
57
+ }
58
+ }
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Internal helper
62
+ // ---------------------------------------------------------------------------
63
+
64
+ function isPlainObject(v) {
65
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Sub-validators (module-private)
70
+ // ---------------------------------------------------------------------------
71
+ //
72
+ // Each helper throws ValidationError on the first violation it detects,
73
+ // preserving the original error message + ordering of the monolithic
74
+ // validateSession() body. Helpers are intentionally not exported; the
75
+ // public contract is validateSession() alone.
76
+
77
+ /**
78
+ * Validate session entry's schema_version field.
79
+ *
80
+ * Accepted versions: 0 (legacy / pre-versioning), 1 (pre-#372 writes),
81
+ * 2 (current writes per CURRENT_SESSION_SCHEMA_VERSION, bumped via #372),
82
+ * 3 (ADR-364 follow-ups, commit eb820ca).
83
+ *
84
+ * Additive contract: as the schema evolves, older historical entries must remain readable.
85
+ * #576 expanded this from `0 | 1` to `0 | 1 | 2 | 3` after discovering schema_version=3 entries
86
+ * in production data (.orchestrator/metrics/sessions.jsonl line 11, session main-2026-05-24-0510-housekeeping).
87
+ * #372 bumped CURRENT_SESSION_SCHEMA_VERSION from 1 to 2 — the accepted set here was already
88
+ * wide enough (#576), so no change to ACCEPTED_VERSIONS was required for the bump itself.
89
+ *
90
+ * Cross-references:
91
+ * - Issue: #576, #372
92
+ * - Constant: CURRENT_SESSION_SCHEMA_VERSION in ./constants.mjs (current=2; bump when adding fields)
93
+ * - PRD: docs/prd/<future-schema-evolution> when v4 is introduced
94
+ *
95
+ * @throws {ValidationError} when schema_version is set but not in [0, 1, 2, 3]
96
+ */
97
+ function _validateSchemaVersion(entry) {
98
+ if ('schema_version' in entry && entry.schema_version !== undefined) {
99
+ const ACCEPTED_VERSIONS = [0, 1, 2, 3];
100
+ if (!ACCEPTED_VERSIONS.includes(entry.schema_version)) {
101
+ throw new ValidationError(
102
+ `schema_version must be one of [0 (legacy), 1, 2, 3], got: ${entry.schema_version}`
103
+ );
104
+ }
105
+ }
106
+ }
107
+
108
+ function _validateRequiredFields(entry) {
109
+ for (const field of REQUIRED_FIELDS) {
110
+ if (!(field in entry)) {
111
+ throw new ValidationError(`session missing required field: ${field}`);
112
+ }
113
+ }
114
+ }
115
+
116
+ function _validateSessionId(entry) {
117
+ if (typeof entry.session_id !== 'string' || entry.session_id.length === 0) {
118
+ throw new ValidationError('session_id must be a non-empty string');
119
+ }
120
+ }
121
+
122
+ function _validateSessionType(entry) {
123
+ if (!VALID_SESSION_TYPES.includes(entry.session_type)) {
124
+ throw new ValidationError(
125
+ `session_type must be one of ${VALID_SESSION_TYPES.join('|')}, got: ${entry.session_type}`
126
+ );
127
+ }
128
+ }
129
+
130
+ function _validateTimestamps(entry) {
131
+ if (typeof entry.started_at !== 'string') {
132
+ throw new ValidationError('started_at must be an ISO timestamp string');
133
+ }
134
+ const startedMs = Date.parse(entry.started_at);
135
+ if (Number.isNaN(startedMs)) {
136
+ throw new ValidationError(`started_at is not a parsable timestamp: ${entry.started_at}`);
137
+ }
138
+ // Issue #540 defense-in-depth layer (b): strict canonical ISO-8601 UTC
139
+ // format guard. `Date.parse` alone accepted malformed inputs like `.3NZ`
140
+ // as NaN, but the failure mode is the same as a non-canonical accepted
141
+ // shape. Require explicit `YYYY-MM-DDTHH:MM:SS[.SSS]Z`.
142
+ if (!ISO_8601_UTC_MS_RE.test(entry.started_at)) {
143
+ throw new ValidationError(
144
+ `started_at must match ISO-8601 UTC ms format (YYYY-MM-DDTHH:MM:SS[.SSS]Z), got: ${entry.started_at}`
145
+ );
146
+ }
147
+ if (typeof entry.completed_at !== 'string') {
148
+ throw new ValidationError('completed_at must be an ISO timestamp string');
149
+ }
150
+ const completedMs = Date.parse(entry.completed_at);
151
+ if (Number.isNaN(completedMs)) {
152
+ throw new ValidationError(`completed_at is not a parsable timestamp: ${entry.completed_at}`);
153
+ }
154
+ if (!ISO_8601_UTC_MS_RE.test(entry.completed_at)) {
155
+ throw new ValidationError(
156
+ `completed_at must match ISO-8601 UTC ms format (YYYY-MM-DDTHH:MM:SS[.SSS]Z), got: ${entry.completed_at}`
157
+ );
158
+ }
159
+ if (completedMs < startedMs) {
160
+ throw new ValidationError(
161
+ `completed_at (${entry.completed_at}) must be >= started_at (${entry.started_at})`
162
+ );
163
+ }
164
+ }
165
+
166
+ function _validateWaves(entry) {
167
+ // total_waves — non-negative number.
168
+ if (typeof entry.total_waves !== 'number' || entry.total_waves < 0) {
169
+ throw new ValidationError(
170
+ `total_waves must be a non-negative number, got: ${entry.total_waves}`
171
+ );
172
+ }
173
+
174
+ // waves — array, entries shape-checked.
175
+ if (!Array.isArray(entry.waves)) {
176
+ throw new ValidationError(`waves must be an array, got: ${typeof entry.waves}`);
177
+ }
178
+ for (let i = 0; i < entry.waves.length; i++) {
179
+ const w = entry.waves[i];
180
+ if (!isPlainObject(w)) {
181
+ throw new ValidationError(`waves[${i}] must be an object`);
182
+ }
183
+ if (typeof w.wave !== 'number' || w.wave < 1) {
184
+ throw new ValidationError(`waves[${i}].wave must be a number >= 1, got: ${w.wave}`);
185
+ }
186
+ if (typeof w.role !== 'string' || w.role.length === 0) {
187
+ throw new ValidationError(`waves[${i}].role must be a non-empty string`);
188
+ }
189
+ }
190
+ }
191
+
192
+ function _validateAgentSummary(entry) {
193
+ if (!isPlainObject(entry.agent_summary)) {
194
+ throw new ValidationError('agent_summary must be an object');
195
+ }
196
+ for (const f of AGENT_SUMMARY_FIELDS) {
197
+ if (!(f in entry.agent_summary)) {
198
+ throw new ValidationError(`agent_summary missing required field: ${f}`);
199
+ }
200
+ const v = entry.agent_summary[f];
201
+ if (typeof v !== 'number' || v < 0) {
202
+ throw new ValidationError(`agent_summary.${f} must be a non-negative number, got: ${v}`);
203
+ }
204
+ }
205
+
206
+ // total_agents / total_files_changed — non-negative numbers.
207
+ if (typeof entry.total_agents !== 'number' || entry.total_agents < 0) {
208
+ throw new ValidationError(
209
+ `total_agents must be a non-negative number, got: ${entry.total_agents}`
210
+ );
211
+ }
212
+ if (typeof entry.total_files_changed !== 'number' || entry.total_files_changed < 0) {
213
+ throw new ValidationError(
214
+ `total_files_changed must be a non-negative number, got: ${entry.total_files_changed}`
215
+ );
216
+ }
217
+ }
218
+
219
+ function _validateOptionalFields(entry) {
220
+ if (entry.effectiveness !== undefined && entry.effectiveness !== null) {
221
+ if (!isPlainObject(entry.effectiveness)) {
222
+ throw new ValidationError('effectiveness must be an object or null');
223
+ }
224
+ }
225
+ if (entry.discovery_stats !== undefined && entry.discovery_stats !== null) {
226
+ if (!isPlainObject(entry.discovery_stats)) {
227
+ throw new ValidationError('discovery_stats must be an object or null');
228
+ }
229
+ }
230
+ if (entry.review_stats !== undefined && entry.review_stats !== null) {
231
+ if (!isPlainObject(entry.review_stats)) {
232
+ throw new ValidationError('review_stats must be an object or null');
233
+ }
234
+ }
235
+ if (entry.platform !== undefined && entry.platform !== null) {
236
+ if (typeof entry.platform !== 'string') {
237
+ throw new ValidationError('platform must be a string or null');
238
+ }
239
+ }
240
+ if (entry.branch !== undefined && entry.branch !== null) {
241
+ if (typeof entry.branch !== 'string') {
242
+ throw new ValidationError('branch must be a string or null');
243
+ }
244
+ }
245
+ if (entry.base_branch !== undefined && entry.base_branch !== null) {
246
+ if (typeof entry.base_branch !== 'string') {
247
+ throw new ValidationError('base_branch must be a string or null');
248
+ }
249
+ }
250
+ if (entry.notes !== undefined && entry.notes !== null) {
251
+ if (typeof entry.notes !== 'string') {
252
+ throw new ValidationError('notes must be a string or null');
253
+ }
254
+ }
255
+ if (entry.duration_seconds !== undefined && entry.duration_seconds !== null) {
256
+ if (typeof entry.duration_seconds !== 'number' || entry.duration_seconds < 0) {
257
+ throw new ValidationError(
258
+ `duration_seconds must be a non-negative number or null, got: ${entry.duration_seconds}`
259
+ );
260
+ }
261
+ }
262
+ if (entry.issues_closed !== undefined) {
263
+ if (
264
+ !Array.isArray(entry.issues_closed) ||
265
+ entry.issues_closed.some((n) => typeof n !== 'number')
266
+ ) {
267
+ throw new ValidationError('issues_closed must be an array of numbers');
268
+ }
269
+ }
270
+ if (entry.issues_created !== undefined) {
271
+ if (
272
+ !Array.isArray(entry.issues_created) ||
273
+ entry.issues_created.some((n) => typeof n !== 'number')
274
+ ) {
275
+ throw new ValidationError('issues_created must be an array of numbers');
276
+ }
277
+ }
278
+
279
+ // ADR-364 optional additive fields — remote-agent substrate thin-slice.
280
+ // All are nullable; null is treated as "not provided" and passes without
281
+ // further checks. Only non-null present values are type/range validated.
282
+
283
+ if (entry.agent_identity !== undefined && entry.agent_identity !== null) {
284
+ if (typeof entry.agent_identity !== 'string' || entry.agent_identity.length === 0) {
285
+ throw new ValidationError('agent_identity must be a non-empty string or null');
286
+ }
287
+ }
288
+ if (entry.worktree_path !== undefined && entry.worktree_path !== null) {
289
+ if (typeof entry.worktree_path !== 'string' || entry.worktree_path.length === 0) {
290
+ throw new ValidationError('worktree_path must be a non-empty string or null');
291
+ }
292
+ }
293
+ if (entry.parent_run_id !== undefined && entry.parent_run_id !== null) {
294
+ if (typeof entry.parent_run_id !== 'string' || entry.parent_run_id.length === 0) {
295
+ throw new ValidationError('parent_run_id must be a non-empty string or null');
296
+ }
297
+ }
298
+ if (entry.lease_acquired_at !== undefined && entry.lease_acquired_at !== null) {
299
+ if (typeof entry.lease_acquired_at !== 'string') {
300
+ throw new ValidationError('lease_acquired_at must be an ISO 8601 timestamp string or null');
301
+ }
302
+ if (Number.isNaN(Date.parse(entry.lease_acquired_at))) {
303
+ throw new ValidationError(
304
+ `lease_acquired_at is not a parsable timestamp: ${entry.lease_acquired_at}`
305
+ );
306
+ }
307
+ // Issue #540 defense-in-depth layer (b): strict canonical guard for the
308
+ // ADR-364 optional lease timestamp. Matches the `started_at` / `completed_at`
309
+ // policy enforced above.
310
+ if (!ISO_8601_UTC_MS_RE.test(entry.lease_acquired_at)) {
311
+ throw new ValidationError(
312
+ `lease_acquired_at must match ISO-8601 UTC ms format (YYYY-MM-DDTHH:MM:SS[.SSS]Z), got: ${entry.lease_acquired_at}`
313
+ );
314
+ }
315
+ }
316
+ if (entry.lease_ttl_seconds !== undefined && entry.lease_ttl_seconds !== null) {
317
+ if (!Number.isFinite(entry.lease_ttl_seconds) || entry.lease_ttl_seconds < 0) {
318
+ throw new ValidationError(
319
+ `lease_ttl_seconds must be a non-negative finite number or null, got: ${entry.lease_ttl_seconds}`
320
+ );
321
+ }
322
+ }
323
+ if (entry.expected_cost_tier !== undefined && entry.expected_cost_tier !== null) {
324
+ if (!EXPECTED_COST_TIERS.includes(entry.expected_cost_tier)) {
325
+ throw new ValidationError(
326
+ `expected_cost_tier must be one of ${EXPECTED_COST_TIERS.join('|')} or null, got: ${entry.expected_cost_tier}`
327
+ );
328
+ }
329
+ }
330
+
331
+ // Epic #644 — session-level token rollup fields (additive, v1-compatible).
332
+ // total_token_input / total_token_output: non-negative finite number or null.
333
+ // Number.isFinite rejects NaN/Infinity (mirrors lease_ttl_seconds above) — a typeof-only
334
+ // guard let NaN through because NaN < 0 is false (W4 session-review WARN, #644).
335
+ if (entry.total_token_input !== undefined && entry.total_token_input !== null) {
336
+ if (!Number.isFinite(entry.total_token_input) || entry.total_token_input < 0) {
337
+ throw new ValidationError(
338
+ `total_token_input must be a non-negative finite number or null, got: ${entry.total_token_input}`
339
+ );
340
+ }
341
+ }
342
+ if (entry.total_token_output !== undefined && entry.total_token_output !== null) {
343
+ if (!Number.isFinite(entry.total_token_output) || entry.total_token_output < 0) {
344
+ throw new ValidationError(
345
+ `total_token_output must be a non-negative finite number or null, got: ${entry.total_token_output}`
346
+ );
347
+ }
348
+ }
349
+ // subagents_with_tokens: non-negative integer (never null — it is always a count, defaulting to 0).
350
+ if (entry.subagents_with_tokens !== undefined && entry.subagents_with_tokens !== null) {
351
+ if (
352
+ typeof entry.subagents_with_tokens !== 'number' ||
353
+ !Number.isInteger(entry.subagents_with_tokens) ||
354
+ entry.subagents_with_tokens < 0
355
+ ) {
356
+ throw new ValidationError(
357
+ `subagents_with_tokens must be a non-negative integer, got: ${entry.subagents_with_tokens}`
358
+ );
359
+ }
360
+ }
361
+
362
+ // Epic #724 C1 — SessionEnd close-through backfill provenance fields.
363
+ // All additive-optional; null/absent passes without further checks so that
364
+ // pre-#724 records (and every normally-closed record) validate cleanly.
365
+ if (entry.status !== undefined && entry.status !== null) {
366
+ if (!SESSION_STATUS.includes(entry.status)) {
367
+ throw new ValidationError(
368
+ `status must be one of ${SESSION_STATUS.join('|')} or null, got: ${entry.status}`
369
+ );
370
+ }
371
+ }
372
+ if (entry._backfill_source !== undefined && entry._backfill_source !== null) {
373
+ if (typeof entry._backfill_source !== 'string' || entry._backfill_source.length === 0) {
374
+ throw new ValidationError('_backfill_source must be a non-empty string or null');
375
+ }
376
+ }
377
+ if (entry._backfill_incomplete_fields !== undefined && entry._backfill_incomplete_fields !== null) {
378
+ if (
379
+ !Array.isArray(entry._backfill_incomplete_fields) ||
380
+ entry._backfill_incomplete_fields.some((f) => typeof f !== 'string')
381
+ ) {
382
+ throw new ValidationError('_backfill_incomplete_fields must be an array of strings or null');
383
+ }
384
+ }
385
+ if (entry._session_type_inferred !== undefined && entry._session_type_inferred !== null) {
386
+ if (typeof entry._session_type_inferred !== 'boolean') {
387
+ throw new ValidationError('_session_type_inferred must be a boolean or null');
388
+ }
389
+ }
390
+ if (entry._synthetic_session_id !== undefined && entry._synthetic_session_id !== null) {
391
+ if (typeof entry._synthetic_session_id !== 'boolean') {
392
+ throw new ValidationError('_synthetic_session_id must be a boolean or null');
393
+ }
394
+ }
395
+
396
+ // Issue #773 — Handover-Alignment-Gate open-question telemetry (additive,
397
+ // v1-compatible). Each field is a non-negative integer count surfaced by the
398
+ // session-end Phase 1.65 gate: how many open questions were surfaced in the
399
+ // triage AUQ (`_asked`), how many the operator answered (`_answered`), and how
400
+ // many stayed unanswered / over-cap and roundtripped to the next session
401
+ // (`_deferred`). Absent/null = the gate did not run or the session was not
402
+ // measured (fail-open skip, headless, pre-#773 record) — never coerced to 0,
403
+ // so "not measured" stays distinguishable from "zero questions". Same
404
+ // non-negative-integer contract as subagents_with_tokens above.
405
+ for (const field of ['open_questions_asked', 'open_questions_answered', 'open_questions_deferred']) {
406
+ if (entry[field] !== undefined && entry[field] !== null) {
407
+ if (
408
+ typeof entry[field] !== 'number' ||
409
+ !Number.isInteger(entry[field]) ||
410
+ entry[field] < 0
411
+ ) {
412
+ throw new ValidationError(
413
+ `${field} must be a non-negative integer, got: ${entry[field]}`
414
+ );
415
+ }
416
+ }
417
+ }
418
+ }
419
+
420
+ // ---------------------------------------------------------------------------
421
+ // Public API
422
+ // ---------------------------------------------------------------------------
423
+
424
+ /**
425
+ * Validate a session entry for writing. Throws ValidationError on any
426
+ * required-field/type/range violation. Returns a NEW object (input is not
427
+ * mutated) with `schema_version` stamped to CURRENT_SESSION_SCHEMA_VERSION
428
+ * if absent. Does NOT apply SESSION_KEY_ALIASES — aliasing is the read-path
429
+ * concern of normalizeSession.
430
+ *
431
+ * @param {object} entry
432
+ * @returns {object} validated entry (new object)
433
+ */
434
+ export function validateSession(entry) {
435
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
436
+ throw new ValidationError('session must be an object');
437
+ }
438
+
439
+ _validateSchemaVersion(entry);
440
+ _validateRequiredFields(entry);
441
+ _validateSessionId(entry);
442
+ _validateSessionType(entry);
443
+ _validateTimestamps(entry);
444
+ _validateWaves(entry);
445
+ _validateAgentSummary(entry);
446
+ _validateOptionalFields(entry);
447
+
448
+ // Return a NEW object — stamp schema_version if missing.
449
+ return {
450
+ ...entry,
451
+ schema_version: entry.schema_version ?? CURRENT_SESSION_SCHEMA_VERSION,
452
+ };
453
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * session-schema.mjs — canonical schema lock for sessions.jsonl entries.
3
+ *
4
+ * Issues #249, #304. Companion to `scripts/lib/learnings.mjs`. Plain-JS
5
+ * validator + normalizer for session records written to
6
+ * `.orchestrator/metrics/sessions.jsonl`. No Zod — plain-JS matches the
7
+ * repo convention for script-layer utilities.
8
+ *
9
+ * ── CANONICAL SCHEMA (schema_version: 2) ─────────────────────────────────
10
+ *
11
+ * Two historical shapes coexist in sessions.jsonl on disk (#304: 73% of
12
+ * records were mirror-invalid before the migration helper shipped):
13
+ *
14
+ * OLD SHAPE (pre-v3, schema_version: 0 or absent):
15
+ * agents_dispatched number — total agents scheduled (scalar)
16
+ * agents_complete number — succeeded
17
+ * agents_partial number — partial success
18
+ * agents_failed number — failed
19
+ * waves_completed number — scalar wave count (no array)
20
+ *
21
+ * NEW SHAPE (v3+, schema_version: 1 or 2) — THIS IS THE CANONICAL SHAPE.
22
+ * The 1 -> 2 bump (#372) is additive-only — the shape below is unchanged:
23
+ * total_agents number — sum of all dispatched agents
24
+ * total_files_changed number — total files touched across all waves
25
+ * agent_summary object — { complete, partial, failed, spiral }
26
+ * waves array — [{ wave, role, ...waveMetrics }]
27
+ *
28
+ * Required fields for a valid schema_version=2 record (unchanged since v1):
29
+ * session_id, session_type, started_at, completed_at,
30
+ * total_waves, waves, agent_summary, total_agents, total_files_changed
31
+ *
32
+ * Migration: `scripts/migrate-sessions-jsonl.mjs` maps old → new shape.
33
+ * Backfill (apply to entire file): `scripts/backfill-sessions.mjs`.
34
+ *
35
+ * ── CONTRACT SUMMARY ─────────────────────────────────────────────────────
36
+ *
37
+ * validateSession(entry):
38
+ * Throws ValidationError on required-field/type/range violations.
39
+ * Returns a NEW object with `schema_version` stamped to
40
+ * CURRENT_SESSION_SCHEMA_VERSION (2) if absent. Unknown fields pass
41
+ * through (additive contract). Does NOT apply SESSION_KEY_ALIASES.
42
+ * Used by scripts/emit-session.mjs as the write-path gate — any entry
43
+ * that fails validation is rejected before it reaches disk.
44
+ *
45
+ * normalizeSession(entry):
46
+ * Never throws. Applies SAFE key aliases (same-shape renames only).
47
+ * Missing `schema_version` on read is tagged as 0 (pre-versioning
48
+ * legacy, distinct from CURRENT_SESSION_SCHEMA_VERSION=2 stamped on
49
+ * new writes). Emits a deduplicated WARN per session_id per process.
50
+ *
51
+ * Unsafe value-transforming aliases (e.g., `waves_executed` scalar →
52
+ * `waves` array, `duration_min` → `duration_seconds`) are explicitly OUT
53
+ * of scope here and belong in the migration / backfill scripts.
54
+ *
55
+ * ── MODULE STRUCTURE ─────────────────────────────────────────────────────
56
+ *
57
+ * This file is a thin barrel. All logic lives in submodules:
58
+ * session-schema/constants.mjs — CURRENT_SESSION_SCHEMA_VERSION,
59
+ * SESSION_KEY_ALIASES, VALID_SESSION_TYPES,
60
+ * REQUIRED_FIELDS, AGENT_SUMMARY_FIELDS
61
+ * session-schema/validator.mjs — ValidationError, validateSession
62
+ * session-schema/normalizer.mjs — normalizeSession
63
+ * session-schema/timestamps.mjs — clampTimestampsMonotonic
64
+ * session-schema/aliases.mjs — aliasLegacyEndedAt
65
+ */
66
+
67
+ export { CURRENT_SESSION_SCHEMA_VERSION, SESSION_KEY_ALIASES } from './session-schema/constants.mjs';
68
+ export { ValidationError, validateSession } from './session-schema/validator.mjs';
69
+ export { normalizeSession } from './session-schema/normalizer.mjs';
70
+ export { clampTimestampsMonotonic } from './session-schema/timestamps.mjs';
71
+ export { aliasLegacyEndedAt } from './session-schema/aliases.mjs';
@@ -0,0 +1,137 @@
1
+ /**
2
+ * session-token-rollup.mjs — session-level token aggregation from subagents.jsonl.
3
+ *
4
+ * Reads `.orchestrator/metrics/subagents.jsonl` (or a caller-supplied path),
5
+ * filters to a given `parent_session_id`, and sums `token_input` /
6
+ * `token_output` across all matched records, skipping null/undefined values.
7
+ *
8
+ * Design notes:
9
+ * - Pure function — no top-level side effects, no writes.
10
+ * - File-absent or all-null-token sessions return a sentinel shape with null
11
+ * totals (not 0) so callers can distinguish "session had no token data" from
12
+ * "session was genuinely free / cost $0".
13
+ * - Malformed JSONL lines are silently skipped (resilience over strictness).
14
+ * - `subagents_with_tokens` counts distinct agent_ids that have at least one
15
+ * record with a non-null token_input or token_output value (coverage metric).
16
+ *
17
+ * @module session-token-rollup
18
+ */
19
+
20
+ import { readFileSync } from 'node:fs';
21
+ import { resolve } from 'node:path';
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Default subagents.jsonl path (relative to cwd, mirroring the rest of the
25
+ // metrics layer which uses process.cwd() + relative paths).
26
+ // ---------------------------------------------------------------------------
27
+ const DEFAULT_SUBAGENTS_PATH = '.orchestrator/metrics/subagents.jsonl';
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Public API
31
+ // ---------------------------------------------------------------------------
32
+
33
+ /**
34
+ * @typedef {Object} TokenRollupResult
35
+ * @property {number|null} total_token_input - Sum of token_input across matched records; null when no record had a non-null value.
36
+ * @property {number|null} total_token_output - Sum of token_output across matched records; null when no record had a non-null value.
37
+ * @property {number} subagents_with_tokens - Count of distinct agent_ids that had at least one non-null token value.
38
+ * @property {number} matched_records - Total count of JSONL records matched by parentSessionId (includes null-token records).
39
+ */
40
+
41
+ /**
42
+ * Aggregate token usage from subagents.jsonl for a single session.
43
+ *
44
+ * @param {object} opts
45
+ * @param {string} opts.parentSessionId - The UUID to filter on (`parent_session_id` field in JSONL).
46
+ * @param {string} [opts.subagentsPath] - Absolute or cwd-relative path to subagents.jsonl.
47
+ * Defaults to `.orchestrator/metrics/subagents.jsonl`.
48
+ * @returns {TokenRollupResult}
49
+ */
50
+ export function rollupSessionTokens({
51
+ parentSessionId,
52
+ subagentsPath = DEFAULT_SUBAGENTS_PATH,
53
+ }) {
54
+ /** @type {TokenRollupResult} */
55
+ const ZERO = {
56
+ total_token_input: null,
57
+ total_token_output: null,
58
+ subagents_with_tokens: 0,
59
+ matched_records: 0,
60
+ };
61
+
62
+ if (typeof parentSessionId !== 'string' || parentSessionId.length === 0) {
63
+ return { ...ZERO };
64
+ }
65
+
66
+ // Resolve path — support both absolute and cwd-relative.
67
+ const resolvedPath = resolve(process.cwd(), subagentsPath);
68
+
69
+ // Read the file; absent file is a valid state (sparse early sessions).
70
+ let raw;
71
+ try {
72
+ raw = readFileSync(resolvedPath, 'utf8');
73
+ } catch (err) {
74
+ if (err.code === 'ENOENT') {
75
+ return { ...ZERO };
76
+ }
77
+ throw err;
78
+ }
79
+
80
+ // Parse JSONL — skip malformed lines, filter to parentSessionId.
81
+ const lines = raw.split('\n');
82
+ const matched = [];
83
+ for (const line of lines) {
84
+ const trimmed = line.trim();
85
+ if (!trimmed) continue;
86
+ let record;
87
+ try {
88
+ record = JSON.parse(trimmed);
89
+ } catch {
90
+ // Malformed line — skip silently.
91
+ continue;
92
+ }
93
+ if (record && record.parent_session_id === parentSessionId) {
94
+ matched.push(record);
95
+ }
96
+ }
97
+
98
+ if (matched.length === 0) {
99
+ return { ...ZERO };
100
+ }
101
+
102
+ // Aggregate — skip null/undefined token values.
103
+ let sumInput = null;
104
+ let sumOutput = null;
105
+
106
+ // Track distinct agent_ids that contributed at least one non-null token.
107
+ const agentsWithTokens = new Set();
108
+
109
+ for (const record of matched) {
110
+ const inp = record.token_input;
111
+ const out = record.token_output;
112
+
113
+ if (typeof inp === 'number' && inp >= 0) {
114
+ sumInput = (sumInput ?? 0) + inp;
115
+ }
116
+ if (typeof out === 'number' && out >= 0) {
117
+ sumOutput = (sumOutput ?? 0) + out;
118
+ }
119
+
120
+ // Count this agent as having tokens if either field is a non-null number.
121
+ if (
122
+ (typeof inp === 'number' && inp >= 0) ||
123
+ (typeof out === 'number' && out >= 0)
124
+ ) {
125
+ if (record.agent_id !== undefined && record.agent_id !== null) {
126
+ agentsWithTokens.add(record.agent_id);
127
+ }
128
+ }
129
+ }
130
+
131
+ return {
132
+ total_token_input: sumInput,
133
+ total_token_output: sumOutput,
134
+ subagents_with_tokens: agentsWithTokens.size,
135
+ matched_records: matched.length,
136
+ };
137
+ }