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,232 @@
1
+ /**
2
+ * state-md-peer-guard.mjs — Issue #588 (STATE.md peer-guard)
3
+ *
4
+ * Belt-and-suspenders defense for session-start Phase 1b.
5
+ *
6
+ * Even with parallel-aware-preamble (Phase 0.5) and session-lock acquire
7
+ * (Phase 1.2) in place, a session can miss an active peer when:
8
+ * - The peer's session.lock was force-deleted (stale-PID sweep) but
9
+ * STATE.md still shows status:active.
10
+ * - A registry entry was orphaned but not yet swept.
11
+ *
12
+ * `checkPeerStateMd` reads the repo's STATE.md frontmatter and reports
13
+ * whether a *different* active session currently owns it. Callers
14
+ * (session-start Phase 1b, skill body) use the result to decide whether to
15
+ * fire the Worktree-Promotion AUQ before overwriting STATE.md.
16
+ *
17
+ * Never throws — all errors are surfaced via the `reason` field with value
18
+ * `'malformed-state-md'` so callers can always act on the return value.
19
+ *
20
+ * @module state-md-peer-guard
21
+ */
22
+
23
+ import { existsSync, readFileSync } from 'node:fs';
24
+ import { join } from 'node:path';
25
+ import { parseStateMd } from './state-md.mjs';
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Canonical STATE.md path candidates (same order as frontmatter-mutators.mjs)
29
+ // ---------------------------------------------------------------------------
30
+
31
+ const STATE_MD_CANDIDATES = ['.claude/STATE.md', '.codex/STATE.md', '.cursor/STATE.md', '.pi/STATE.md'];
32
+
33
+ function preferredStateMdCandidate() {
34
+ switch (process.env.SO_PLATFORM) {
35
+ case 'codex': return '.codex/STATE.md';
36
+ case 'cursor': return '.cursor/STATE.md';
37
+ case 'pi': return '.pi/STATE.md';
38
+ default: return '.claude/STATE.md';
39
+ }
40
+ }
41
+
42
+ function orderedStateMdCandidates() {
43
+ const preferred = preferredStateMdCandidate();
44
+ return [
45
+ preferred,
46
+ ...STATE_MD_CANDIDATES.filter((candidate) => candidate !== preferred),
47
+ ];
48
+ }
49
+
50
+ /**
51
+ * Resolve the first existing STATE.md path under repoRoot, checking the active
52
+ * platform first. Falls back to the active platform path when none exist.
53
+ *
54
+ * @param {string} repoRoot
55
+ * @returns {string} Absolute path (may not exist on disk).
56
+ */
57
+ function _resolveStateMdPath(repoRoot) {
58
+ const candidates = orderedStateMdCandidates();
59
+ for (const candidate of candidates) {
60
+ const abs = join(repoRoot, candidate);
61
+ if (existsSync(abs)) return abs;
62
+ }
63
+ return join(repoRoot, candidates[0]);
64
+ }
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Age calculation helper
68
+ // ---------------------------------------------------------------------------
69
+
70
+ /**
71
+ * Return age in decimal hours from an ISO-8601 `started_at` string to now.
72
+ * Returns Infinity on unparseable input so callers treat malformed dates as
73
+ * "very old" (safe-side: allow overwrite).
74
+ *
75
+ * DIVERGENCE NOTE: `_ageHoursFrom` in peer-discovery.mjs returns undefined on
76
+ * unparseable input so callers can omit the ageHours field rather than emit a
77
+ * misleading number. This function returns Infinity instead — a fail-safe
78
+ * semantics: a malformed date is treated as "infinitely old/definitely-stale"
79
+ * which permits the overwrite rather than blocking on an indeterminate age.
80
+ * The divergence is intentional: peer-guard needs a conservative yes/no
81
+ * decision, so Infinity is the correct safe default; peer-discovery emits
82
+ * structured data, so undefined (field omission) is correct. Do NOT merge
83
+ * or unify these helpers.
84
+ *
85
+ * @param {string|null|undefined} startedAt
86
+ * @returns {number} Hours elapsed (may be Infinity).
87
+ */
88
+ function _ageHoursFromStartedAt(startedAt) {
89
+ if (typeof startedAt !== 'string' || startedAt.trim() === '') return Infinity;
90
+ const ms = Date.now() - new Date(startedAt).getTime();
91
+ if (!Number.isFinite(ms)) return Infinity;
92
+ return ms / (1000 * 60 * 60);
93
+ }
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Public API
97
+ // ---------------------------------------------------------------------------
98
+
99
+ /**
100
+ * Detect whether a peer session owns the current repo's STATE.md.
101
+ *
102
+ * Decision tree:
103
+ * 1. File missing → { peer: null, reason: 'no STATE.md' }
104
+ * 2. Malformed frontmatter → { peer: null, reason: 'malformed-state-md' }
105
+ * 3. status completed|idle → { peer: null, reason: 'status: <X>' }
106
+ * 4. status active + session === mySessionId
107
+ * → { peer: null, reason: 'own session' }
108
+ * 5. status active + different session + age > maxAgeHours
109
+ * → { peer: null, reason: 'ABANDONED (age > maxAgeHours)' }
110
+ * 6. status active + different session + age ≤ maxAgeHours
111
+ * → { peer: { sessionId, startedAt, currentWave, mode, ageHours },
112
+ * reason: 'ACTIVE peer detected' }
113
+ *
114
+ * @param {string} repoRoot Absolute path to the repository root.
115
+ * @param {string|null} mySessionId Current session's id (UUID or semantic);
116
+ * null means "no session yet" — any active
117
+ * session counts as a peer.
118
+ * @param {object} [opts]
119
+ * @param {number} [opts.maxAgeHours=4] STATE.md older than this is
120
+ * treated as abandoned (allow overwrite).
121
+ * @returns {{
122
+ * peer: {
123
+ * sessionId: string,
124
+ * startedAt: string,
125
+ * currentWave: number,
126
+ * mode: string|null,
127
+ * ageHours: number
128
+ * } | null,
129
+ * reason: string | null
130
+ * }}
131
+ */
132
+ export function checkPeerStateMd(repoRoot, mySessionId, opts = {}) {
133
+ const maxAgeHours =
134
+ typeof opts.maxAgeHours === 'number' && opts.maxAgeHours > 0 ? opts.maxAgeHours : 4;
135
+
136
+ // ------------------------------------------------------------------
137
+ // Step 1: resolve + read STATE.md
138
+ // ------------------------------------------------------------------
139
+ const stateMdPath = _resolveStateMdPath(repoRoot);
140
+
141
+ let raw;
142
+ try {
143
+ raw = readFileSync(stateMdPath, 'utf8');
144
+ } catch (err) {
145
+ // ENOENT is expected for fresh repos; other FS errors also treated as
146
+ // "no STATE.md" — fail-open (allow overwrite) rather than blocking.
147
+ if (err.code === 'ENOENT') {
148
+ return { peer: null, reason: 'no STATE.md' };
149
+ }
150
+ return { peer: null, reason: 'no STATE.md' };
151
+ }
152
+
153
+ // ------------------------------------------------------------------
154
+ // Step 2: parse frontmatter (parseStateMd never throws per its contract)
155
+ // ------------------------------------------------------------------
156
+ let parsed;
157
+ try {
158
+ parsed = parseStateMd(raw);
159
+ } catch {
160
+ return { peer: null, reason: 'malformed-state-md' };
161
+ }
162
+
163
+ if (parsed === null || parsed.frontmatter === null) {
164
+ return { peer: null, reason: 'malformed-state-md' };
165
+ }
166
+
167
+ const fm = parsed.frontmatter;
168
+
169
+ // ------------------------------------------------------------------
170
+ // Step 3: check status field
171
+ // ------------------------------------------------------------------
172
+ const status = typeof fm.status === 'string' ? fm.status.toLowerCase().trim() : '';
173
+
174
+ if (status === 'completed' || status === 'idle') {
175
+ return { peer: null, reason: `status: ${status}` };
176
+ }
177
+
178
+ // Any non-active value (missing, unknown) → treat as non-blocking.
179
+ if (status !== 'active') {
180
+ return { peer: null, reason: `status: ${status || 'unknown'}` };
181
+ }
182
+
183
+ // ------------------------------------------------------------------
184
+ // Step 4: check session identity
185
+ // ------------------------------------------------------------------
186
+ // PRECONDITION (invariant): `mySessionId` and `fm.session` MUST be expressed
187
+ // in the SAME id-space (both semantic OR both UUID). The equality check below
188
+ // is plain string-equality — a semantic-vs-UUID mismatch for the SAME logical
189
+ // session would be misclassified as a foreign peer (fail-safe: extra AUQ, never
190
+ // a missed peer). When `mySessionId === null` ("no session yet"), the ownership
191
+ // short-circuit is skipped and any active session with a `session` field counts
192
+ // as a peer.
193
+ const sessionField = typeof fm.session === 'string' ? fm.session : null;
194
+
195
+ // No session field → cannot identify a peer; allow overwrite.
196
+ if (sessionField === null) {
197
+ return { peer: null, reason: 'no session field' };
198
+ }
199
+
200
+ // Session matches ours → we own STATE.md already.
201
+ if (mySessionId !== null && sessionField === mySessionId) {
202
+ return { peer: null, reason: 'own session' };
203
+ }
204
+
205
+ // ------------------------------------------------------------------
206
+ // Step 5: check age of the active entry
207
+ // ------------------------------------------------------------------
208
+ const startedAt = typeof fm['started_at'] === 'string' ? fm['started_at'] : null;
209
+ const ageHours = _ageHoursFromStartedAt(startedAt);
210
+
211
+ if (ageHours > maxAgeHours) {
212
+ return { peer: null, reason: 'ABANDONED (age > maxAgeHours)' };
213
+ }
214
+
215
+ // ------------------------------------------------------------------
216
+ // Step 6: active peer detected
217
+ // ------------------------------------------------------------------
218
+ const currentWave = typeof fm['current-wave'] === 'number' ? fm['current-wave'] : 0;
219
+ // `session-type` is the frontmatter key used for mode (e.g. 'deep', 'feature').
220
+ const mode = typeof fm['session-type'] === 'string' ? fm['session-type'] : null;
221
+
222
+ return {
223
+ peer: {
224
+ sessionId: sessionField,
225
+ startedAt: startedAt ?? '',
226
+ currentWave,
227
+ mode,
228
+ ageHours,
229
+ },
230
+ reason: 'ACTIVE peer detected',
231
+ };
232
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * STATE.md helpers (issue #184).
3
+ *
4
+ * Thin barrel — re-exports all 25 public symbols from the split submodules.
5
+ * Implementation lives in scripts/lib/state-md/*.mjs.
6
+ *
7
+ * @see scripts/lib/state-md/yaml-parser.mjs parseStateMd, serializeStateMd
8
+ * @see scripts/lib/state-md/frontmatter-mutators.mjs touchUpdatedField, updateFrontmatterFields
9
+ * @see scripts/lib/state-md/body-sections.mjs readCurrentTask, appendDeviation, markExpressPathComplete, appendWhatNotToRetry, readWhatNotToRetry, readOpenQuestions, appendOpenQuestion, markOpenQuestionAnswered
10
+ * @see scripts/lib/state-md/mission-status.mjs parseMissionStatus, writeMissionStatus, setMissionStatus, readMissionStatus
11
+ * @see scripts/lib/state-md/recommendations.mjs parseRecommendations
12
+ */
13
+
14
+ export { parseStateMd, serializeStateMd } from './state-md/yaml-parser.mjs';
15
+
16
+ export {
17
+ touchUpdatedField,
18
+ updateFrontmatterFields,
19
+ resolveStateMdPath,
20
+ writeStateMd,
21
+ updateFrontmatterFieldsOnDisk,
22
+ touchUpdatedFieldOnDisk,
23
+ } from './state-md/frontmatter-mutators.mjs';
24
+
25
+ export {
26
+ readCurrentTask,
27
+ appendDeviation,
28
+ markExpressPathComplete,
29
+ recordAutoCommit,
30
+ appendDeviationOnDisk,
31
+ recordAutoCommitOnDisk,
32
+ markExpressPathCompleteOnDisk,
33
+ appendWhatNotToRetry,
34
+ readWhatNotToRetry,
35
+ appendWhatNotToRetryOnDisk,
36
+ readOpenQuestions,
37
+ appendOpenQuestion,
38
+ markOpenQuestionAnswered,
39
+ appendOpenQuestionOnDisk,
40
+ markOpenQuestionAnsweredOnDisk,
41
+ MAX_OPEN_QUESTIONS_STORED,
42
+ } from './state-md/body-sections.mjs';
43
+
44
+ export {
45
+ parseMissionStatus,
46
+ writeMissionStatus,
47
+ setMissionStatus,
48
+ readMissionStatus,
49
+ writeMissionStatusOnDisk,
50
+ setMissionStatusOnDisk,
51
+ } from './state-md/mission-status.mjs';
52
+
53
+ export { parseRecommendations } from './state-md/recommendations.mjs';
@@ -0,0 +1,309 @@
1
+ /**
2
+ * subagents-schema.mjs — schema module for subagent lifecycle records.
3
+ *
4
+ * Mirrors learnings.mjs style: Zod-free, custom ValidationError, validate /
5
+ * normalize / migrate / append / read functions. No top-level side effects.
6
+ *
7
+ * Part of issue #342 (PostToolUseFailure + PostToolBatch + SubagentStart/Stop
8
+ * hook handlers). W1-Part1 scope: schema module only.
9
+ *
10
+ * Canonical schema (schema_version: 1):
11
+ * timestamp ISO 8601 string — when the event occurred
12
+ * event 'start' | 'stop' — lifecycle event type
13
+ * agent_id string — unique identifier for the subagent instance
14
+ * schema_version 1 (integer)
15
+ *
16
+ * Required for event='stop':
17
+ * duration_ms positive integer — wall-clock time from start to stop
18
+ *
19
+ * Optional:
20
+ * agent_type string | null — e.g. 'explore', 'writer', 'test-writer'
21
+ * parent_session_id string | null — session that spawned this subagent
22
+ * token_input integer | null — prompt token count for this subagent
23
+ * token_output integer | null — completion token count for this subagent
24
+ * total_cost_usd number | null — native total cost in USD (#624, fractional,
25
+ * best-effort: null when the harness does not
26
+ * expose it; no rate table is applied)
27
+ *
28
+ * OTel aliases (optional, stop-only, additive — #411, schema_version=1 backwards-compat):
29
+ * gen_ai.usage.input_tokens integer | null — alias of token_input
30
+ * gen_ai.usage.output_tokens integer | null — alias of token_output
31
+ * gen_ai.system 'anthropic' — AI provider identifier
32
+ */
33
+
34
+ import { readFile, appendFile, mkdir } from 'node:fs/promises';
35
+ import { existsSync } from 'node:fs';
36
+ import path from 'node:path';
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Constants
40
+ // ---------------------------------------------------------------------------
41
+
42
+ /** Current subagent-record schema version. */
43
+ export const CURRENT_SCHEMA_VERSION = 1;
44
+
45
+ /** Allowed event values. */
46
+ export const VALID_EVENTS = Object.freeze(['start', 'stop']);
47
+
48
+ // ---------------------------------------------------------------------------
49
+ // ValidationError
50
+ // ---------------------------------------------------------------------------
51
+
52
+ export class ValidationError extends Error {
53
+ /**
54
+ * @param {string} message
55
+ * @param {string|undefined} field — optional field name that triggered the error
56
+ */
57
+ constructor(message, field) {
58
+ super(message);
59
+ this.name = 'ValidationError';
60
+ this.field = field;
61
+ }
62
+ }
63
+
64
+ // ---------------------------------------------------------------------------
65
+ // Validate
66
+ // ---------------------------------------------------------------------------
67
+
68
+ /**
69
+ * Validate a subagent record. Throws ValidationError on any constraint
70
+ * violation. Does NOT mutate the input.
71
+ *
72
+ * Required fields: timestamp, event, agent_id, schema_version.
73
+ * Additional requirement when event='stop': duration_ms (positive integer).
74
+ * Optional: agent_type, parent_session_id, token_input, token_output.
75
+ *
76
+ * @param {object} entry
77
+ * @returns {object} the entry (unchanged) — validation is side-effect-free
78
+ * @throws {ValidationError}
79
+ */
80
+ export function validateSubagent(entry) {
81
+ if (!entry || typeof entry !== 'object') {
82
+ throw new ValidationError('subagent record must be a non-null object');
83
+ }
84
+
85
+ // schema_version
86
+ if (entry.schema_version !== CURRENT_SCHEMA_VERSION) {
87
+ throw new ValidationError(
88
+ `schema_version must be ${CURRENT_SCHEMA_VERSION}, got: ${entry.schema_version}`,
89
+ 'schema_version',
90
+ );
91
+ }
92
+
93
+ // timestamp
94
+ if (typeof entry.timestamp !== 'string' || !entry.timestamp.trim()) {
95
+ throw new ValidationError('timestamp must be a non-empty ISO 8601 string', 'timestamp');
96
+ }
97
+ if (Number.isNaN(Date.parse(entry.timestamp))) {
98
+ throw new ValidationError(
99
+ `timestamp is not a valid ISO 8601 date: ${entry.timestamp}`,
100
+ 'timestamp',
101
+ );
102
+ }
103
+
104
+ // event
105
+ if (!VALID_EVENTS.includes(entry.event)) {
106
+ throw new ValidationError(
107
+ `event must be one of ${VALID_EVENTS.join('|')}, got: ${entry.event}`,
108
+ 'event',
109
+ );
110
+ }
111
+
112
+ // agent_id
113
+ if (typeof entry.agent_id !== 'string' || !entry.agent_id.trim()) {
114
+ throw new ValidationError('agent_id must be a non-empty string', 'agent_id');
115
+ }
116
+
117
+ // duration_ms — required for stop events
118
+ if (entry.event === 'stop') {
119
+ if (
120
+ typeof entry.duration_ms !== 'number' ||
121
+ !Number.isInteger(entry.duration_ms) ||
122
+ entry.duration_ms < 0
123
+ ) {
124
+ throw new ValidationError(
125
+ 'duration_ms must be a non-negative integer when event=stop',
126
+ 'duration_ms',
127
+ );
128
+ }
129
+ }
130
+
131
+ // agent_type (optional)
132
+ if (entry.agent_type !== undefined && entry.agent_type !== null && typeof entry.agent_type !== 'string') {
133
+ throw new ValidationError('agent_type must be a string or null', 'agent_type');
134
+ }
135
+
136
+ // parent_session_id (optional)
137
+ if (
138
+ entry.parent_session_id !== undefined &&
139
+ entry.parent_session_id !== null &&
140
+ typeof entry.parent_session_id !== 'string'
141
+ ) {
142
+ throw new ValidationError('parent_session_id must be a string or null', 'parent_session_id');
143
+ }
144
+
145
+ // token_input (optional)
146
+ if (entry.token_input !== undefined && entry.token_input !== null) {
147
+ if (typeof entry.token_input !== 'number' || !Number.isInteger(entry.token_input) || entry.token_input < 0) {
148
+ throw new ValidationError('token_input must be a non-negative integer or null', 'token_input');
149
+ }
150
+ }
151
+
152
+ // token_output (optional)
153
+ if (entry.token_output !== undefined && entry.token_output !== null) {
154
+ if (typeof entry.token_output !== 'number' || !Number.isInteger(entry.token_output) || entry.token_output < 0) {
155
+ throw new ValidationError('token_output must be a non-negative integer or null', 'token_output');
156
+ }
157
+ }
158
+
159
+ // total_cost_usd (optional, #624) — fractional number (not integer), best-effort.
160
+ if (entry.total_cost_usd !== undefined && entry.total_cost_usd !== null) {
161
+ if (typeof entry.total_cost_usd !== 'number' || !Number.isFinite(entry.total_cost_usd) || entry.total_cost_usd < 0) {
162
+ throw new ValidationError('total_cost_usd must be a non-negative number or null', 'total_cost_usd');
163
+ }
164
+ }
165
+
166
+ // OTel alias — #411 additive, schema_version=1 backwards-compat
167
+ const otelInputTokens = entry['gen_ai.usage.input_tokens'];
168
+ if (otelInputTokens !== undefined && otelInputTokens !== null) {
169
+ if (typeof otelInputTokens !== 'number' || !Number.isInteger(otelInputTokens) || otelInputTokens < 0) {
170
+ throw new ValidationError('gen_ai.usage.input_tokens must be a non-negative integer or null', 'gen_ai.usage.input_tokens');
171
+ }
172
+ }
173
+
174
+ // OTel alias — #411 additive, schema_version=1 backwards-compat
175
+ const otelOutputTokens = entry['gen_ai.usage.output_tokens'];
176
+ if (otelOutputTokens !== undefined && otelOutputTokens !== null) {
177
+ if (typeof otelOutputTokens !== 'number' || !Number.isInteger(otelOutputTokens) || otelOutputTokens < 0) {
178
+ throw new ValidationError('gen_ai.usage.output_tokens must be a non-negative integer or null', 'gen_ai.usage.output_tokens');
179
+ }
180
+ }
181
+
182
+ // OTel alias — #411 additive, schema_version=1 backwards-compat
183
+ if (entry['gen_ai.system'] !== undefined && entry['gen_ai.system'] !== null) {
184
+ if (typeof entry['gen_ai.system'] !== 'string') {
185
+ throw new ValidationError('gen_ai.system must be a string or null', 'gen_ai.system');
186
+ }
187
+ }
188
+
189
+ return entry;
190
+ }
191
+
192
+ // ---------------------------------------------------------------------------
193
+ // Normalize
194
+ // ---------------------------------------------------------------------------
195
+
196
+ /**
197
+ * Normalize a subagent record read from disk. Applies defaults for optional
198
+ * fields so callers can treat legacy and new entries uniformly.
199
+ * Does NOT throw — malformed entries are passed through unchanged.
200
+ *
201
+ * @param {object} entry
202
+ * @returns {object} entry with optional fields defaulted to null / CURRENT_SCHEMA_VERSION
203
+ */
204
+ export function normalizeSubagent(entry) {
205
+ if (!entry || typeof entry !== 'object') return entry;
206
+ return {
207
+ ...entry,
208
+ schema_version: entry.schema_version ?? CURRENT_SCHEMA_VERSION,
209
+ agent_type: entry.agent_type ?? null,
210
+ parent_session_id: entry.parent_session_id ?? null,
211
+ token_input: entry.token_input ?? null,
212
+ token_output: entry.token_output ?? null,
213
+ // total_cost_usd — #624 additive, best-effort native cost (null when absent)
214
+ total_cost_usd: entry.total_cost_usd ?? null,
215
+ // OTel alias — #411 additive, schema_version=1 backwards-compat
216
+ 'gen_ai.usage.input_tokens': entry['gen_ai.usage.input_tokens'] ?? null,
217
+ 'gen_ai.usage.output_tokens': entry['gen_ai.usage.output_tokens'] ?? null,
218
+ 'gen_ai.system': entry['gen_ai.system'] ?? null,
219
+ };
220
+ }
221
+
222
+ // ---------------------------------------------------------------------------
223
+ // Migrate
224
+ // ---------------------------------------------------------------------------
225
+
226
+ /**
227
+ * Migrate a legacy / partial subagent record to the canonical v1 shape.
228
+ * Idempotent — calling it on an already-canonical record is a safe no-op.
229
+ * No-op for v1; reserved for future schema bumps.
230
+ *
231
+ * The caller MUST still run validateSubagent() on the result before writing.
232
+ *
233
+ * @param {object} entry
234
+ * @returns {object} record with schema_version stamped
235
+ */
236
+ export function migrateLegacySubagent(entry) {
237
+ if (!entry || typeof entry !== 'object') return entry;
238
+ const out = { ...entry };
239
+ if (out.schema_version === undefined || out.schema_version === null) {
240
+ out.schema_version = CURRENT_SCHEMA_VERSION;
241
+ }
242
+ return out;
243
+ }
244
+
245
+ // ---------------------------------------------------------------------------
246
+ // Append
247
+ // ---------------------------------------------------------------------------
248
+
249
+ /**
250
+ * Append a single subagent record to a JSONL file.
251
+ *
252
+ * Steps:
253
+ * 1. Stamp schema_version if missing.
254
+ * 2. Normalize (apply optional-field defaults).
255
+ * 3. Validate — throws ValidationError on bad input.
256
+ * 4. Serialize to JSON + newline.
257
+ * 5. mkdir(dirname, recursive: true).
258
+ * 6. appendFile (POSIX append ≤ PIPE_BUF is atomic for typical JSONL lines).
259
+ *
260
+ * @param {string} filePath — absolute path to target .jsonl file
261
+ * @param {object} entry — candidate subagent record
262
+ * @returns {Promise<object>} the validated + normalized entry that was written
263
+ * @throws {ValidationError} when the entry fails schema validation
264
+ */
265
+ export async function appendSubagent(filePath, entry) {
266
+ const stamped = {
267
+ ...entry,
268
+ schema_version: entry?.schema_version ?? CURRENT_SCHEMA_VERSION,
269
+ };
270
+ const normalized = normalizeSubagent(stamped);
271
+ const validated = validateSubagent(normalized);
272
+ const line = JSON.stringify(validated) + '\n';
273
+ await mkdir(path.dirname(filePath), { recursive: true });
274
+ await appendFile(filePath, line, 'utf8');
275
+ return validated;
276
+ }
277
+
278
+ // ---------------------------------------------------------------------------
279
+ // Read
280
+ // ---------------------------------------------------------------------------
281
+
282
+ /**
283
+ * Read all valid subagent records from a JSONL file. Malformed lines are
284
+ * skipped with a stderr warning — never throws.
285
+ *
286
+ * @param {string} filePath — absolute path to target .jsonl file
287
+ * @returns {Promise<object[]>} array of normalized subagent records
288
+ */
289
+ export async function readSubagents(filePath) {
290
+ if (!existsSync(filePath)) return [];
291
+ let raw;
292
+ try {
293
+ raw = await readFile(filePath, 'utf8');
294
+ } catch (err) {
295
+ process.stderr.write(`[subagents-schema] WARN: could not read ${filePath}: ${err?.message ?? err}\n`);
296
+ return [];
297
+ }
298
+ const lines = raw.split('\n').filter((l) => l.trim().length > 0);
299
+ const entries = [];
300
+ for (const line of lines) {
301
+ try {
302
+ const parsed = JSON.parse(line);
303
+ entries.push(normalizeSubagent(parsed));
304
+ } catch {
305
+ process.stderr.write(`[subagents-schema] WARN: skipping malformed JSONL line: ${line.slice(0, 120)}\n`);
306
+ }
307
+ }
308
+ return entries;
309
+ }