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,518 @@
1
+ /**
2
+ * learnings/schema.mjs — schema, validators, and migration for learnings entries.
3
+ *
4
+ * Extracted from scripts/lib/learnings.mjs (issue #358 Q3 follow-up).
5
+ * Pure leaf module — imports only stdlib. No imports from sibling modules
6
+ * (io.mjs, filters.mjs) or parent (../learnings.mjs). This breaks the
7
+ * circular-import topology flagged by Q3 architect review. ("Pure leaf" refers
8
+ * to the import graph, not side-effect purity: {@link normalizeDialects}
9
+ * emits a deduped stderr WARN on a session_id/source_session conflict.)
10
+ *
11
+ * The parent ../learnings.mjs re-exports symbols from this module to
12
+ * preserve the public API. Sibling modules (io.mjs, filters.mjs) import
13
+ * directly from this file, NOT from ../learnings.mjs.
14
+ *
15
+ * Canonical schema (schema_version: 1) — ALL required fields:
16
+ * id UUID v4 string (crypto.randomUUID())
17
+ * type string — e.g. 'fragile-file', 'effective-sizing', 'recurring-issue'
18
+ * subject string — pattern subject
19
+ * insight string — human-readable description (NOT 'description'/'recommendation')
20
+ * evidence string — data points supporting the pattern
21
+ * confidence number [0, 1]
22
+ * source_session string — non-empty kebab-slug (e.g. 'main-2026-04-27-1942')
23
+ * created_at ISO 8601 string
24
+ * expires_at ISO 8601 string
25
+ * schema_version 1
26
+ *
27
+ * Extended fields (optional, defaulted on read):
28
+ * scope: 'local' | 'private' | 'public' (default: 'local')
29
+ * host_class: string | null (default: null)
30
+ * anonymized: boolean (default: false)
31
+ * anonymization_version: number | undefined (bumped when redaction rules change)
32
+ * file_paths: string[] | undefined (repo-relative scope paths;
33
+ * canonical rename of legacy `files`)
34
+ * updated_at: ISO 8601 string | undefined (canonical rename of legacy `last_seen`)
35
+ * evidence_sessions: string[] | undefined (OPTIONAL corroborating session ids;
36
+ * a documented array field — never
37
+ * collapsed into source_session)
38
+ *
39
+ * Producer-dialect normalization (Epic #723 B2 — {@link normalizeDialects}):
40
+ * Legacy producers emitted `files`, a duplicate `session_id`, `last_seen`,
41
+ * and a literal `next_review: null`. normalizeDialects() renames/reconciles
42
+ * these on every read (normalizeLearning) and every migration
43
+ * (migrateLegacyLearning) so downstream code sees ONE canonical shape. See
44
+ * the function doc for the exact rules. Note: `evidence` MAY legally be an
45
+ * array in some legacy records and is deliberately NOT coerced (validateLearning
46
+ * does not type-check it), so the shape is preserved verbatim.
47
+ */
48
+
49
+ import { randomUUID } from 'node:crypto';
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Constants
53
+ // ---------------------------------------------------------------------------
54
+
55
+ export const VALID_SCOPES = Object.freeze(['local', 'private', 'public']);
56
+
57
+ /** Current anonymization ruleset version. Bump when C3 redaction rules change. */
58
+ export const CURRENT_ANONYMIZATION_VERSION = 1;
59
+
60
+ /**
61
+ * Type capability registry (Epic #723 I1, issue #733 Teil b) — the single
62
+ * source of truth for every learning `type`'s TTL policy AND its two
63
+ * cross-module capability axes. Before this registry existed, three modules
64
+ * independently hand-maintained overlapping type lists that drifted out of
65
+ * sync (`memory-proposals/schema.mjs` PROPOSAL_TYPES, `reconcile/eligibility.mjs`
66
+ * CONVERT_TYPES, and this file's own LEARNING_TTL_DAYS) — e.g. `convention`,
67
+ * `architecture-pattern`, and `design-pattern` were CONVERT-eligible in the
68
+ * reconcile engine but had no TTL entry here and could never be proposed via
69
+ * memory.propose(). Both consumer modules now DERIVE their type sets from
70
+ * this registry instead of maintaining their own literal.
71
+ *
72
+ * Capability axes:
73
+ * - ttlDays: `expires_at` retention window (see deriveExpiresAt below).
74
+ * - agentProposable: may appear in `memory-proposals/schema.mjs` PROPOSAL_TYPES
75
+ * (i.e. a wave-agent may `memory.propose()` this type).
76
+ * - ruleConvertible: may appear in `reconcile/eligibility.mjs` CONVERT_TYPES
77
+ * (i.e. the reconcile engine may convert this type into a
78
+ * conditional `.claude/rules/*.md` rule proposal).
79
+ */
80
+ export const LEARNING_TYPE_REGISTRY = Object.freeze({
81
+ 'mode-selector-accuracy': Object.freeze({ ttlDays: 30, agentProposable: true, ruleConvertible: false }),
82
+ 'hardware-pattern': Object.freeze({ ttlDays: 60, agentProposable: true, ruleConvertible: false }),
83
+ 'fragile-file': Object.freeze({ ttlDays: 45, agentProposable: true, ruleConvertible: true }),
84
+ 'effective-sizing': Object.freeze({ ttlDays: 45, agentProposable: true, ruleConvertible: false }),
85
+ 'recurring-issue': Object.freeze({ ttlDays: 45, agentProposable: true, ruleConvertible: true }),
86
+ 'workflow-pattern': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: false }),
87
+ 'proven-pattern': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: false }),
88
+ 'anti-pattern': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: true }),
89
+ 'autopilot-effectiveness': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: false }),
90
+ // autonomy-verdict (#683): repo/scope readiness synthesis from autopilot
91
+ // effectiveness plus skill-judge signals. 90d matches the operational
92
+ // autopilot-effectiveness horizon it depends on. Analyzer-only — never
93
+ // agent-proposable.
94
+ 'autonomy-verdict': Object.freeze({ ttlDays: 90, agentProposable: false, ruleConvertible: false }),
95
+ // domain-regression (#638): a sidecar-sourced regression flag (metric baseline→recent
96
+ // delta) surfaced via /evolve extra-sources. 60d aligns with the moderate-decay tier
97
+ // (hardware-pattern / default) — a regression signal should age out if it stops recurring.
98
+ 'domain-regression': Object.freeze({ ttlDays: 60, agentProposable: true, ruleConvertible: false }),
99
+ 'convention': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: true }),
100
+ 'architecture-pattern': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: true }),
101
+ 'design-pattern': Object.freeze({ ttlDays: 90, agentProposable: true, ruleConvertible: true }),
102
+ // fragile-pattern / stagnation-class-frequency: 0 live instances as of
103
+ // 2026-07-02 (see reconcile/eligibility.mjs census) — CONVERT-eligible but
104
+ // NOT agent-proposable (analyzer-synthesized classes, not agent-observed).
105
+ 'fragile-pattern': Object.freeze({ ttlDays: 45, agentProposable: false, ruleConvertible: true }),
106
+ 'stagnation-class-frequency': Object.freeze({ ttlDays: 60, agentProposable: false, ruleConvertible: true }),
107
+ });
108
+
109
+ /**
110
+ * Per-type TTL policy (in days) for `expires_at` derivation. Derived from
111
+ * {@link LEARNING_TYPE_REGISTRY} — see parent module documentation for tier
112
+ * rationale and policy lookup contract.
113
+ */
114
+ export const LEARNING_TTL_DAYS = Object.freeze({
115
+ ...Object.fromEntries(
116
+ Object.entries(LEARNING_TYPE_REGISTRY).map(([type, meta]) => [type, meta.ttlDays])
117
+ ),
118
+ default: 60,
119
+ });
120
+
121
+ /**
122
+ * Derive an ISO 8601 `expires_at` timestamp from `created_at` + type-specific TTL.
123
+ *
124
+ * Policy lookup: `LEARNING_TTL_DAYS[type] ?? LEARNING_TTL_DAYS.default`.
125
+ * If `createdAt` is missing or unparseable, falls back to `new Date()`
126
+ * (so a derivable expiry is always returned — the caller never gets undefined).
127
+ *
128
+ * @param {string|undefined} createdAt — ISO 8601 string or any Date.parse-able input
129
+ * @param {string|undefined} type — learning record type
130
+ * @returns {string} ISO 8601 expires_at
131
+ */
132
+ export function deriveExpiresAt(createdAt, type) {
133
+ const ttlDays = LEARNING_TTL_DAYS[type] ?? LEARNING_TTL_DAYS.default;
134
+ let baseMs = typeof createdAt === 'string' ? Date.parse(createdAt) : NaN;
135
+ if (!Number.isFinite(baseMs)) {
136
+ baseMs = Date.now();
137
+ }
138
+ return new Date(baseMs + ttlDays * 86400 * 1000).toISOString();
139
+ }
140
+
141
+ /**
142
+ * Current learnings-record schema version.
143
+ *
144
+ * History:
145
+ * - 0: legacy pre-versioning shape (no `schema_version` field). Still accepted
146
+ * on read for backward compatibility. Treated as implicit v0.
147
+ * - 1: current shape. All NEW appends are stamped with `schema_version: 1`.
148
+ */
149
+ export const CURRENT_SCHEMA_VERSION = 1;
150
+
151
+ /** Legacy schema fields expected on every learning (pre-v1). */
152
+ const LEGACY_REQUIRED_FIELDS = Object.freeze([
153
+ 'id',
154
+ 'type',
155
+ 'subject',
156
+ 'insight',
157
+ 'evidence',
158
+ 'confidence',
159
+ 'source_session',
160
+ 'created_at',
161
+ 'expires_at',
162
+ ]);
163
+
164
+ /**
165
+ * ISO-8601 timestamp fields re-serialized (verlustfrei, same instant) during
166
+ * dialect normalization. A value Date.parse cannot handle is left verbatim.
167
+ */
168
+ const TIMESTAMP_FIELDS = Object.freeze(['created_at', 'updated_at', 'expires_at', 'next_review']);
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // Validation
172
+ // ---------------------------------------------------------------------------
173
+
174
+ export class ValidationError extends Error {
175
+ constructor(message) {
176
+ super(message);
177
+ this.name = 'ValidationError';
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Validate a learning entry for writing. Enforces the privacy contract plus
183
+ * basic shape checks on the legacy fields. Returns the (possibly normalized)
184
+ * entry ready for JSONL serialization.
185
+ *
186
+ * Throws ValidationError on contract violations. Does NOT mutate input.
187
+ *
188
+ * @param {object} entry — candidate learning
189
+ * @returns {object} normalized entry with scope/host_class/anonymized defaulted
190
+ */
191
+ export function validateLearning(entry) {
192
+ if (!entry || typeof entry !== 'object') {
193
+ throw new ValidationError('learning must be an object');
194
+ }
195
+
196
+ // schema_version: 0 (implicit/legacy), 1 (current). Both accepted.
197
+ const schemaVersion = entry.schema_version ?? 0;
198
+ if (schemaVersion !== 0 && schemaVersion !== 1) {
199
+ throw new ValidationError(
200
+ `schema_version must be 0 (legacy) or 1, got: ${schemaVersion}`
201
+ );
202
+ }
203
+
204
+ for (const field of LEGACY_REQUIRED_FIELDS) {
205
+ if (!(field in entry)) {
206
+ throw new ValidationError(`learning missing required field: ${field}`);
207
+ }
208
+ }
209
+
210
+ if (typeof entry.confidence !== 'number' || entry.confidence < 0 || entry.confidence > 1) {
211
+ throw new ValidationError(`confidence must be a number in [0, 1], got: ${entry.confidence}`);
212
+ }
213
+
214
+ const scope = entry.scope ?? 'local';
215
+ if (!VALID_SCOPES.includes(scope)) {
216
+ throw new ValidationError(`scope must be one of ${VALID_SCOPES.join('|')}, got: ${scope}`);
217
+ }
218
+
219
+ const hostClass = entry.host_class ?? null;
220
+ if (hostClass !== null && typeof hostClass !== 'string') {
221
+ throw new ValidationError(`host_class must be string or null, got: ${typeof hostClass}`);
222
+ }
223
+
224
+ const anonymized = entry.anonymized ?? false;
225
+ if (typeof anonymized !== 'boolean') {
226
+ throw new ValidationError(`anonymized must be boolean, got: ${typeof anonymized}`);
227
+ }
228
+
229
+ // Privacy contract
230
+ if (scope === 'public' && !anonymized) {
231
+ throw new ValidationError(
232
+ 'scope=public requires anonymized=true (privacy contract violation)'
233
+ );
234
+ }
235
+ if (scope === 'public' && hostClass === null) {
236
+ throw new ValidationError(
237
+ 'scope=public requires host_class to be set (otherwise the entry cannot be grouped on export)'
238
+ );
239
+ }
240
+
241
+ const normalized = {
242
+ ...entry,
243
+ schema_version: schemaVersion,
244
+ scope,
245
+ host_class: hostClass,
246
+ anonymized,
247
+ };
248
+
249
+ if (anonymized && normalized.anonymization_version === undefined) {
250
+ normalized.anonymization_version = CURRENT_ANONYMIZATION_VERSION;
251
+ }
252
+ if (!anonymized && 'anonymization_version' in normalized) {
253
+ delete normalized.anonymization_version;
254
+ }
255
+
256
+ return normalized;
257
+ }
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // Migration
261
+ // ---------------------------------------------------------------------------
262
+
263
+ /** Module-level dedupe set for session_id↔source_session conflict warnings. */
264
+ const _warnedSessionIdConflict = new Set();
265
+
266
+ /**
267
+ * Normalize known producer DIALECTS to the canonical schema shape. Deliberately
268
+ * does NOT touch `schema_version`, `scope`, or the insight/subject alias chain —
269
+ * schema_version stamping is a WRITE concern (migrateLegacyLearning /
270
+ * appendLearning), and the alias chain lives in migrateLegacyLearning.
271
+ *
272
+ * Applied on BOTH the read funnel (normalizeLearning) and the migration/write
273
+ * funnel (migrateLegacyLearning) so every reader and the backfill writer see a
274
+ * single canonical shape. Pure except a deduped stderr WARN on a
275
+ * session_id/source_session conflict (see below); idempotent; never throws;
276
+ * non-objects (and arrays) pass through unchanged. Does NOT mutate its input.
277
+ *
278
+ * Dialect rules (Epic #723 B2 — census 2026-07-02):
279
+ * - `files` → `file_paths` — verbatim value move; an empty array is
280
+ * preserved as an empty `file_paths`; a canonical
281
+ * `file_paths` already present wins (legacy `files` dropped).
282
+ * - `session_id` → dropped when it EXACTLY duplicates `source_session`; on a
283
+ * genuine conflict, `source_session` is canonical, BOTH keys
284
+ * are kept, and the conflict is logged once per record id.
285
+ * An orphan `session_id` (no source_session) is left as-is.
286
+ * - `last_seen` → `updated_at` ONLY when `updated_at` is missing/null; when
287
+ * both are present, both are preserved.
288
+ * - `next_review` literal `null` → key dropped entirely (a real timestamp is
289
+ * kept and re-serialized when `reserializeTimestamps`).
290
+ * - timestamps re-serialized via `new Date(x).toISOString()` (same instant,
291
+ * canonical millis + `Z`) when parseable; left verbatim
292
+ * otherwise. Gated by `reserializeTimestamps` (default true):
293
+ * the READ funnel + the backfill canonicalize timestamp
294
+ * FORMAT, but `migrateLegacyLearning` passes `false` to keep
295
+ * its existing byte-exact "does not overwrite an existing
296
+ * expires_at" contract — a schema/alias migration must not
297
+ * silently reformat a caller's timestamps.
298
+ *
299
+ * Documented NON-actions (invariants callers rely on):
300
+ * - `evidence_sessions[]` is an OPTIONAL array field — never collapsed here.
301
+ * - `evidence` may legally be an array in some legacy records — NOT coerced.
302
+ *
303
+ * @param {object} entry — raw record (possibly a producer dialect shape)
304
+ * @param {{ reserializeTimestamps?: boolean }} [opts] — when false, timestamp
305
+ * fields are left byte-exact (used by migrateLegacyLearning).
306
+ * @returns {object} record with dialects normalized (schema_version untouched)
307
+ */
308
+ export function normalizeDialects(entry, { reserializeTimestamps = true } = {}) {
309
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return entry;
310
+
311
+ const out = { ...entry };
312
+
313
+ // files → file_paths (verbatim value move; canonical wins; empty array kept).
314
+ if ('files' in out) {
315
+ if (!('file_paths' in out)) {
316
+ out.file_paths = out.files;
317
+ }
318
+ delete out.files;
319
+ }
320
+
321
+ // session_id reconciliation against the canonical source_session.
322
+ if ('session_id' in out) {
323
+ const hasSource =
324
+ typeof out.source_session === 'string' && out.source_session.length > 0;
325
+ if (hasSource && out.session_id === out.source_session) {
326
+ // Exact duplicate — drop the redundant alias.
327
+ delete out.session_id;
328
+ } else if (hasSource && out.session_id !== out.source_session) {
329
+ // Genuine conflict: source_session wins; keep BOTH; warn once per id.
330
+ const warnKey = out.id ?? '<unknown>';
331
+ if (!_warnedSessionIdConflict.has(warnKey)) {
332
+ _warnedSessionIdConflict.add(warnKey);
333
+ console.error(
334
+ `[learnings] WARN: session_id (${out.session_id}) conflicts with source_session (${out.source_session}) (id=${warnKey}); source_session wins, keeping both`
335
+ );
336
+ }
337
+ }
338
+ // No source_session present → leave the orphan session_id untouched.
339
+ }
340
+
341
+ // last_seen → updated_at only when updated_at is absent/null; else keep both.
342
+ if ('last_seen' in out) {
343
+ const updMissing = out.updated_at === undefined || out.updated_at === null;
344
+ if (updMissing) {
345
+ out.updated_at = out.last_seen;
346
+ delete out.last_seen;
347
+ }
348
+ }
349
+
350
+ // next_review literal null → drop the key entirely.
351
+ if (out.next_review === null) {
352
+ delete out.next_review;
353
+ }
354
+
355
+ // Timestamp re-serialization — canonicalize to millis + Z, same instant.
356
+ // Skipped when the caller (migrateLegacyLearning) needs byte-exact timestamps.
357
+ if (reserializeTimestamps) {
358
+ for (const field of TIMESTAMP_FIELDS) {
359
+ const v = out[field];
360
+ if (typeof v === 'string' && v.length > 0) {
361
+ const ms = Date.parse(v);
362
+ if (Number.isFinite(ms)) {
363
+ out[field] = new Date(ms).toISOString();
364
+ }
365
+ }
366
+ }
367
+ }
368
+
369
+ return out;
370
+ }
371
+
372
+ /**
373
+ * Migrate a legacy learning record to the canonical schema_version:1 shape.
374
+ * Idempotent — calling it on an already-canonical record is a safe no-op.
375
+ *
376
+ * Alias precedence for insight: insight > description > recommendation > observation > lesson
377
+ *
378
+ * Producer dialects (`files`→`file_paths`, duplicate `session_id`, `last_seen`,
379
+ * `next_review: null`) are normalized by {@link normalizeDialects} as the final
380
+ * step. Timestamp FORMAT is deliberately NOT reformatted here (byte-exact
381
+ * contract preserved); the read funnel + backfill canonicalize timestamps.
382
+ *
383
+ * The caller MUST still run validateLearning() on the result to confirm the
384
+ * migrated record passes the full schema gate before writing.
385
+ *
386
+ * @param {object} entry — raw record from JSONL, possibly legacy shape
387
+ * @returns {object} record with canonical field names (NOT validated)
388
+ */
389
+ export function migrateLegacyLearning(entry) {
390
+ if (!entry || typeof entry !== 'object') return entry;
391
+
392
+ const out = { ...entry };
393
+
394
+ if (!out.id) {
395
+ out.id = randomUUID();
396
+ }
397
+
398
+ if (!out.subject && typeof out.name === 'string') {
399
+ out.subject = out.name;
400
+ delete out.name;
401
+ } else if (out.subject && 'name' in out) {
402
+ delete out.name;
403
+ }
404
+
405
+ if (!out.insight) {
406
+ if (typeof out.description === 'string') {
407
+ out.insight = out.description;
408
+ delete out.description;
409
+ } else if (typeof out.recommendation === 'string') {
410
+ out.insight = out.recommendation;
411
+ delete out.recommendation;
412
+ } else if (typeof out.observation === 'string') {
413
+ out.insight = out.observation;
414
+ delete out.observation;
415
+ } else if (typeof out.lesson === 'string') {
416
+ out.insight = out.lesson;
417
+ delete out.lesson;
418
+ }
419
+ } else {
420
+ delete out.description;
421
+ delete out.recommendation;
422
+ delete out.observation;
423
+ delete out.lesson;
424
+ }
425
+
426
+ if (!('evidence' in out)) {
427
+ out.evidence = '';
428
+ }
429
+
430
+ const COERCIBLE_SCOPES = new Set(['vault-tools', 'deep-sessions', 'wave-executor', 'coordinator']);
431
+ if (out.scope && !VALID_SCOPES.includes(out.scope) && COERCIBLE_SCOPES.has(out.scope)) {
432
+ out.scope = 'local';
433
+ }
434
+
435
+ if (
436
+ (out.source_session === undefined || out.source_session === null || out.source_session === '')
437
+ && Array.isArray(out.sessions)
438
+ && out.sessions.length > 0
439
+ && typeof out.sessions[0] === 'string'
440
+ && out.sessions[0].length > 0
441
+ ) {
442
+ out.source_session = out.sessions[0];
443
+ }
444
+
445
+ if (!('expires_at' in out) && typeof out.created_at === 'string') {
446
+ const createdMs = Date.parse(out.created_at);
447
+ if (!Number.isNaN(createdMs)) {
448
+ out.expires_at = new Date(createdMs + 30 * 86400 * 1000).toISOString();
449
+ }
450
+ }
451
+
452
+ if (out.schema_version === undefined || out.schema_version === null) {
453
+ out.schema_version = CURRENT_SCHEMA_VERSION;
454
+ }
455
+
456
+ // Normalize producer dialects last (files→file_paths, session_id/last_seen/
457
+ // next_review reconciliation) — schema_version is preserved by normalizeDialects.
458
+ // reserializeTimestamps:false keeps migrateLegacyLearning's byte-exact timestamp
459
+ // contract (it does schema/alias migration, not timestamp reformatting). The
460
+ // READ funnel (normalizeLearning) and the backfill canonicalize timestamp format.
461
+ return normalizeDialects(out, { reserializeTimestamps: false });
462
+ }
463
+
464
+ // Module-level dedupe sets for warnings (per-process).
465
+ const _warnedMissingSchemaVersion = new Set();
466
+ const _warnedMissingRequiredKeys = new Set();
467
+
468
+ /**
469
+ * Normalize a learning entry read from disk. Applies defaults for the
470
+ * extended fields so callers can treat legacy and new entries uniformly.
471
+ * Does NOT throw — a malformed entry is passed through unchanged.
472
+ *
473
+ * @param {object} entry
474
+ * @returns {object} entry with scope/host_class/anonymized defaulted
475
+ */
476
+ export function normalizeLearning(entry) {
477
+ if (!entry || typeof entry !== 'object') return entry;
478
+
479
+ // Normalize producer dialects (files→file_paths, session_id/last_seen/
480
+ // next_review reconciliation, timestamp re-serialization) so every reader
481
+ // sees the canonical scope key. schema_version behaviour is UNCHANGED:
482
+ // normalizeDialects never touches it, and a missing version still reads as 0.
483
+ const d = normalizeDialects(entry);
484
+
485
+ let schemaVersion;
486
+ if ('schema_version' in d && d.schema_version !== undefined) {
487
+ schemaVersion = d.schema_version;
488
+ } else {
489
+ schemaVersion = 0;
490
+ const warnKey = d.id ?? '<unknown>';
491
+ if (!_warnedMissingSchemaVersion.has(warnKey)) {
492
+ _warnedMissingSchemaVersion.add(warnKey);
493
+ console.error(
494
+ `[learnings] WARN: record missing schema_version (id=${warnKey}); treating as schema_version=0 (pre-versioning legacy)`
495
+ );
496
+ }
497
+ }
498
+
499
+ const missing = LEGACY_REQUIRED_FIELDS.filter((f) => !(f in d));
500
+ if (missing.length > 0) {
501
+ const warnId = d.id ?? '<unknown>';
502
+ const warnKey = `${warnId}|${missing.join(',')}`;
503
+ if (!_warnedMissingRequiredKeys.has(warnKey)) {
504
+ _warnedMissingRequiredKeys.add(warnKey);
505
+ console.error(
506
+ `[learnings] WARN: record missing required legacy field(s) [${missing.join(', ')}] (id=${warnId}); passing through unchanged`
507
+ );
508
+ }
509
+ }
510
+
511
+ return {
512
+ ...d,
513
+ schema_version: schemaVersion,
514
+ scope: d.scope ?? 'local',
515
+ host_class: d.host_class ?? null,
516
+ anonymized: d.anonymized ?? false,
517
+ };
518
+ }