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,144 @@
1
+ /**
2
+ * loop-readiness-banner.mjs — #633, #767
3
+ *
4
+ * Mechanical session-start readiness probe with three independent
5
+ * silent-failure detections for `/loop`:
6
+ *
7
+ * 1. No `.claude/loop.md` in the repo AND no host-wide `~/.claude/loop.md`
8
+ * baseline — bare `/loop` falls back to Anthropic's generic maintenance
9
+ * prompt instead of a project-tuned loop body. (#633)
10
+ * 2. `CLAUDE_CODE_DISABLE_CRON` set to a non-empty value — the cron
11
+ * scheduler backing `/loop` is disabled outright, independent of
12
+ * whether any loop.md file exists. (#767)
13
+ * 3. A present `.claude/loop.md` (repo) or `~/.claude/loop.md` (user)
14
+ * exceeds `LOOP_MD_MAX_BYTES` — Anthropic silently truncates the loaded
15
+ * body past this size, so the operator-authored tail of the file is
16
+ * never read. Checked independently per file. (#767)
17
+ *
18
+ * Plain-JS — no Zod dependency. Never throws. Returns null (silent no-op)
19
+ * when healthy (no findings) or on bad input. Multiple findings are
20
+ * combined into a SINGLE warn object — never an array, never multiple
21
+ * return values.
22
+ *
23
+ * Mirrors the contract used by other Phase 4 banners
24
+ * (`scripts/lib/vault-staleness-banner.mjs`, `scripts/lib/ci-status-banner.mjs`,
25
+ * `scripts/lib/peer-cards/staleness-banner.mjs`): a single `checkXxx()` entry
26
+ * point that returns `null` or `{ severity, message, ... }`.
27
+ *
28
+ * Cross-references:
29
+ * - `.claude/rules/loop-and-monitor.md` — when to use `/loop` vs Monitor vs Routines.
30
+ * - `templates/_shared/loop.md` — the template body `/bootstrap` copies into a repo.
31
+ * - `skills/session-start/SKILL.md` Phase 4 — banner render site.
32
+ * - Issues #633 (original no-loop.md detection), #767 (DISABLE_CRON + truncation).
33
+ */
34
+
35
+ import { existsSync, statSync } from 'node:fs';
36
+ import { join } from 'node:path';
37
+ import os from 'node:os';
38
+
39
+ /**
40
+ * Upstream (Anthropic) silently truncates a loaded loop.md body past this
41
+ * size — the tail of an oversized file is never read, a silent-failure
42
+ * class distinct from the file simply being absent. (#767)
43
+ */
44
+ const LOOP_MD_MAX_BYTES = 25_000;
45
+
46
+ /**
47
+ * Return `filePath`'s byte size, or null on any stat failure. Never throws.
48
+ * @param {string} filePath
49
+ * @returns {number | null}
50
+ */
51
+ function safeStatSize(filePath) {
52
+ try {
53
+ return statSync(filePath).size;
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Check loop-readiness and produce a session-start banner.
61
+ *
62
+ * Combines up to three independent findings into a single null-or-warn
63
+ * result:
64
+ * - no loop.md anywhere (repo AND user baseline both absent)
65
+ * - `CLAUDE_CODE_DISABLE_CRON` set to a non-empty value
66
+ * - a present loop.md (repo and/or user, checked independently) exceeding
67
+ * `LOOP_MD_MAX_BYTES`
68
+ *
69
+ * @param {{repoRoot: string, homeDir?: string, env?: Record<string, string|undefined>}} opts
70
+ * - `repoRoot`: REQUIRED absolute path to the repo root.
71
+ * - `homeDir`: defaults to `os.homedir()`; exists ONLY for test injection.
72
+ * - `env`: defaults to `process.env`; exists ONLY for test injection.
73
+ * @returns {null | {severity:'warn', message:string, repoLoopMd:boolean, userLoopMd:boolean, disableCron?:boolean, oversize?:string[]}}
74
+ */
75
+ export function checkLoopReadiness({ repoRoot, homeDir, env } = {}) {
76
+ try {
77
+ if (!repoRoot || typeof repoRoot !== 'string') return null;
78
+
79
+ const home = typeof homeDir === 'string' && homeDir ? homeDir : os.homedir();
80
+ const activeEnv = env && typeof env === 'object' ? env : process.env;
81
+
82
+ const repoLoopMdPath = join(repoRoot, '.claude', 'loop.md');
83
+ const userLoopMdPath = join(home, '.claude', 'loop.md');
84
+ const repoLoopMd = existsSync(repoLoopMdPath);
85
+ const userLoopMd = existsSync(userLoopMdPath);
86
+
87
+ const findings = [];
88
+
89
+ // Finding 1 (#633): neither loop.md exists — bare /loop uses the
90
+ // generic Anthropic maintenance prompt instead of a project-tuned body.
91
+ if (!repoLoopMd && !userLoopMd) {
92
+ findings.push(
93
+ 'no .claude/loop.md (repo) and no ~/.claude/loop.md (user baseline) — ' +
94
+ 'bare /loop uses the generic Anthropic maintenance prompt. Copy ' +
95
+ 'templates/_shared/loop.md via /bootstrap or add a host-wide ' +
96
+ '~/.claude/loop.md.'
97
+ );
98
+ }
99
+
100
+ // Finding 2 (#767): CLAUDE_CODE_DISABLE_CRON set — /loop's cron
101
+ // scheduler is disabled outright, independent of loop.md presence.
102
+ const disableCron = Boolean(activeEnv && activeEnv.CLAUDE_CODE_DISABLE_CRON);
103
+ if (disableCron) {
104
+ findings.push(
105
+ 'CLAUDE_CODE_DISABLE_CRON is set — the cron scheduler backing /loop ' +
106
+ 'is disabled; scheduled loop bodies will not fire.'
107
+ );
108
+ }
109
+
110
+ // Finding 3 (#767): a present loop.md (repo and/or user, checked
111
+ // independently) exceeds the truncation ceiling.
112
+ const oversizeChecks = [
113
+ { kind: 'repo', filePath: repoLoopMdPath, exists: repoLoopMd },
114
+ { kind: 'user', filePath: userLoopMdPath, exists: userLoopMd },
115
+ ];
116
+ const oversize = [];
117
+ for (const { kind, filePath, exists } of oversizeChecks) {
118
+ if (!exists) continue;
119
+ const size = safeStatSize(filePath);
120
+ if (typeof size === 'number' && size > LOOP_MD_MAX_BYTES) {
121
+ oversize.push(kind);
122
+ findings.push(
123
+ `${filePath} is ${size} bytes, exceeding the ${LOOP_MD_MAX_BYTES}-byte ` +
124
+ "truncation ceiling — Anthropic silently truncates the loaded loop.md " +
125
+ "body past this size, so the file's tail is never read."
126
+ );
127
+ }
128
+ }
129
+
130
+ if (findings.length === 0) return null;
131
+
132
+ return {
133
+ severity: 'warn',
134
+ message: '⚠ loop-readiness: ' + findings.join(' '),
135
+ repoLoopMd,
136
+ userLoopMd,
137
+ ...(disableCron ? { disableCron: true } : {}),
138
+ ...(oversize.length > 0 ? { oversize } : {}),
139
+ };
140
+ } catch {
141
+ // Defensive catch-all — banner must never throw.
142
+ return null;
143
+ }
144
+ }
@@ -0,0 +1,478 @@
1
+ /**
2
+ * memory-banner.mjs — Phase 6.7 "What I Remembered" banner renderer (issue #505).
3
+ *
4
+ * Produces the session-start banner string the caller (session-start Phase 6.7)
5
+ * then prints. Pure-ish: only `readBannerInputs` does I/O; `_formatBanner` and
6
+ * the helpers are deterministic and unit-testable on their own.
7
+ *
8
+ * Behavioural contract (issue #505 AC):
9
+ * - Header: "📚 Loaded from memory"
10
+ * - Top-5 active learnings (subject, confidence to 1 decimal, type)
11
+ * - Stats line: memory files · sessions ever · days since last cleanup
12
+ * - Peer-card excerpts (USER.md / AGENT.md), one line each when present
13
+ * - Fresh-repo fallback: a single line when no learnings and no sessions
14
+ * - Disabled or persistence=off: returns '' (silent no-op for the caller)
15
+ *
16
+ * Truncation rule: any composed visible line longer than 80 chars is truncated
17
+ * with a trailing ellipsis so the rendered length is ≤ 80.
18
+ *
19
+ * No external deps beyond stdlib + existing intra-repo helpers.
20
+ */
21
+
22
+ import { readFile, readdir } from 'node:fs/promises';
23
+ import { existsSync } from 'node:fs';
24
+ import path from 'node:path';
25
+
26
+ import { resolveMemoryDir } from './memory-paths.mjs';
27
+ import { readDreamSignals } from './auto-dream.mjs';
28
+ import { readPeerCards } from './peer-cards/reader.mjs';
29
+ import { surfaceTopN, decayOptsFromConfig } from './learnings/surface.mjs';
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Constants
33
+ // ---------------------------------------------------------------------------
34
+
35
+ /** Max visible width of any single banner line, including bullet/prefix. */
36
+ const MAX_LINE_WIDTH = 80;
37
+
38
+ /** Header rendered above the body (omitted on fresh-repo fallback). */
39
+ const HEADER_LINE = '📚 Loaded from memory';
40
+
41
+ /** Verbatim fresh-repo fallback line (mandated by AC). */
42
+ const FRESH_LINE =
43
+ "📚 Memory: 0 entries yet (first session). I'll start learning from this session forward.";
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Pure helpers
47
+ // ---------------------------------------------------------------------------
48
+
49
+ /**
50
+ * Truncate a string so its visible length is ≤ MAX_LINE_WIDTH. Appends a
51
+ * single-character horizontal-ellipsis ('…') when truncated. No-ops when the
52
+ * input is already within bounds.
53
+ *
54
+ * Operates on UTF-16 code units via String.length — which is what every
55
+ * terminal renderer Counts anyway for the kinds of latin-script content
56
+ * this banner shows. Multi-codepoint emoji (e.g. the header's 📚) are
57
+ * never inside the truncated portion in normal use, but the function
58
+ * tolerates them by trimming the LAST codepoint of any trailing surrogate
59
+ * pair before appending the ellipsis (defence in depth).
60
+ *
61
+ * @param {string} line
62
+ * @param {number} [width=MAX_LINE_WIDTH]
63
+ * @returns {string}
64
+ */
65
+ export function _truncateLine(line, width = MAX_LINE_WIDTH) {
66
+ if (typeof line !== 'string') return '';
67
+ if (line.length <= width) return line;
68
+ let cut = line.slice(0, width - 1);
69
+ // Avoid splitting a surrogate pair (orphaned high-surrogate).
70
+ const lastCode = cut.charCodeAt(cut.length - 1);
71
+ if (lastCode >= 0xd800 && lastCode <= 0xdbff) {
72
+ cut = cut.slice(0, -1);
73
+ }
74
+ return cut + '…';
75
+ }
76
+
77
+ /**
78
+ * Format a single learning line for the banner.
79
+ *
80
+ * Shape: ` • <subject> (<confidence-1dec>, <type>)`
81
+ * Long subjects are truncated with '…' inside the line so the whole rendered
82
+ * line is ≤ 80 chars.
83
+ *
84
+ * @param {{subject: string, confidence: number, type: string}} learning
85
+ * @returns {string}
86
+ */
87
+ export function _formatLearningLine({ subject, confidence, type }) {
88
+ const subj = typeof subject === 'string' ? subject : '';
89
+ const conf =
90
+ typeof confidence === 'number' && Number.isFinite(confidence)
91
+ ? confidence.toFixed(1)
92
+ : '0.0';
93
+ const ty = typeof type === 'string' && type.length > 0 ? type : 'unknown';
94
+
95
+ // Build naive first; truncate at the line level so the suffix stays intact.
96
+ const naive = ` • ${subj} (${conf}, ${ty})`;
97
+ if (naive.length <= MAX_LINE_WIDTH) return naive;
98
+
99
+ // Trim the subject only — keep the trailing (confidence, type) suffix
100
+ // visible because that's what carries actionable signal.
101
+ const suffix = ` (${conf}, ${ty})`;
102
+ const prefix = ' • ';
103
+ // Budget for subject = MAX - prefix.length - suffix.length - 1 (for '…').
104
+ const budget = MAX_LINE_WIDTH - prefix.length - suffix.length - 1;
105
+ if (budget <= 0) {
106
+ // Suffix alone overshoots — fall back to plain truncation.
107
+ return _truncateLine(naive);
108
+ }
109
+ let trimmed = subj.slice(0, budget);
110
+ // Defensive: avoid orphan high-surrogate at the tail.
111
+ const lastCode = trimmed.charCodeAt(trimmed.length - 1);
112
+ if (lastCode >= 0xd800 && lastCode <= 0xdbff) {
113
+ trimmed = trimmed.slice(0, -1);
114
+ }
115
+ return `${prefix}${trimmed}…${suffix}`;
116
+ }
117
+
118
+ /**
119
+ * Format the stats line. Renders "last cleanup: never" when daysSinceCleanup
120
+ * is null; otherwise renders "last cleanup <K> days ago".
121
+ *
122
+ * @param {{memoryFiles: number, sessionsEver: number, daysSinceCleanup: number|null}} stats
123
+ * @returns {string}
124
+ */
125
+ export function _formatStatsLine({ memoryFiles, sessionsEver, daysSinceCleanup }) {
126
+ const mf = Number.isFinite(memoryFiles) ? memoryFiles : 0;
127
+ const se = Number.isFinite(sessionsEver) ? sessionsEver : 0;
128
+ const cleanup =
129
+ daysSinceCleanup === null || daysSinceCleanup === undefined
130
+ ? 'last cleanup: never'
131
+ : `last cleanup ${daysSinceCleanup} days ago`;
132
+ const line = `${mf} memory files · ${se} sessions ever · ${cleanup}`;
133
+ return _truncateLine(line);
134
+ }
135
+
136
+ /**
137
+ * Extract a short excerpt from a peer-card body. Returns [sectionHeader, firstContentLine].
138
+ *
139
+ * - sectionHeader: text of the first `## <text>` line (without the `## ` prefix), or null.
140
+ * - firstContentLine: first non-blank line AFTER the section header (or the first
141
+ * non-blank line at all when no `##` header exists). Leading whitespace stripped.
142
+ *
143
+ * Returns [null, null] when the body is empty or whitespace-only.
144
+ *
145
+ * @param {string|null|undefined} cardBody
146
+ * @returns {[string|null, string|null]}
147
+ */
148
+ export function _extractCardExcerpt(cardBody) {
149
+ if (typeof cardBody !== 'string' || cardBody.length === 0) return [null, null];
150
+
151
+ const lines = cardBody.split('\n');
152
+ const isBlank = (l) => /^\s*$/.test(l);
153
+
154
+ let headerIdx = -1;
155
+ let header = null;
156
+ for (let i = 0; i < lines.length; i += 1) {
157
+ const line = lines[i];
158
+ const m = line.match(/^##\s+(.+?)\s*$/);
159
+ if (m) {
160
+ header = m[1];
161
+ headerIdx = i;
162
+ break;
163
+ }
164
+ }
165
+
166
+ // Search for the first non-blank line AFTER the header; if no header, scan
167
+ // from the beginning. Skip lines that are themselves `##` headers (a later
168
+ // section header is not "content").
169
+ const startIdx = headerIdx >= 0 ? headerIdx + 1 : 0;
170
+ let content = null;
171
+ for (let i = startIdx; i < lines.length; i += 1) {
172
+ const raw = lines[i];
173
+ if (isBlank(raw)) continue;
174
+ // Skip another header line — we want content text, not the next heading.
175
+ if (/^##\s+/.test(raw)) continue;
176
+ content = raw.replace(/^\s+/, '');
177
+ break;
178
+ }
179
+
180
+ if (header === null && content === null) return [null, null];
181
+ return [header, content];
182
+ }
183
+
184
+ /**
185
+ * Format a peer-card excerpt line. Returns null when the excerpt is empty.
186
+ *
187
+ * @param {'USER.md'|'AGENT.md'} label
188
+ * @param {[string|null, string|null]} excerpt
189
+ * @returns {string|null}
190
+ */
191
+ function formatPeerExcerptLine(label, excerpt) {
192
+ if (!Array.isArray(excerpt)) return null;
193
+ const [section, content] = excerpt;
194
+ if (!section && !content) return null;
195
+
196
+ // When section is missing, fall back to a label-only prefix; when content
197
+ // is missing, drop the trailing colon-content portion.
198
+ let line;
199
+ if (section && content) {
200
+ line = ` ${label} — ${section}: ${content}`;
201
+ } else if (section && !content) {
202
+ line = ` ${label} — ${section}`;
203
+ } else {
204
+ // !section && content
205
+ line = ` ${label} — ${content}`;
206
+ }
207
+ return _truncateLine(line);
208
+ }
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // Pure formatter
212
+ // ---------------------------------------------------------------------------
213
+
214
+ /**
215
+ * Assemble the banner string from pre-cleaned inputs. No I/O, no JSON
216
+ * stringification — every value passed in is already a scalar or a
217
+ * pre-formatted excerpt tuple.
218
+ *
219
+ * Fresh-repo fallback: when `inputs.fresh === true`, the function returns
220
+ * the AC-mandated single line EXACTLY (no header, no stats, no peers).
221
+ *
222
+ * @param {object} inputs
223
+ * @param {Array<{subject:string, confidence:number, type:string}>} inputs.topLearnings
224
+ * @param {{memoryFiles:number, sessionsEver:number, daysSinceCleanup:number|null}|null} inputs.stats
225
+ * @param {{user:[string|null,string|null]|null, agent:[string|null,string|null]|null}} inputs.peerExcerpts
226
+ * @param {boolean} inputs.fresh
227
+ * @returns {string}
228
+ */
229
+ export function _formatBanner(inputs) {
230
+ if (!inputs || typeof inputs !== 'object') return '';
231
+
232
+ if (inputs.fresh === true) {
233
+ return FRESH_LINE;
234
+ }
235
+
236
+ const lines = [HEADER_LINE];
237
+
238
+ const topLearnings = Array.isArray(inputs.topLearnings) ? inputs.topLearnings : [];
239
+ for (const learning of topLearnings) {
240
+ if (!learning || typeof learning !== 'object') continue;
241
+ lines.push(_formatLearningLine(learning));
242
+ }
243
+
244
+ if (inputs.stats && typeof inputs.stats === 'object') {
245
+ lines.push(_formatStatsLine(inputs.stats));
246
+ }
247
+
248
+ const peers = inputs.peerExcerpts ?? {};
249
+ const userLine = formatPeerExcerptLine('USER.md', peers.user);
250
+ if (userLine) lines.push(userLine);
251
+ const agentLine = formatPeerExcerptLine('AGENT.md', peers.agent);
252
+ if (agentLine) lines.push(agentLine);
253
+
254
+ return lines.join('\n');
255
+ }
256
+
257
+ // ---------------------------------------------------------------------------
258
+ // I/O — readBannerInputs
259
+ // ---------------------------------------------------------------------------
260
+
261
+ /**
262
+ * Count lines (newline-terminated entries) in a JSONL file. Missing files
263
+ * resolve to 0; read errors resolve to 0. Empty trailing lines are not
264
+ * counted, matching the JSONL convention.
265
+ *
266
+ * @param {string} filePath
267
+ * @returns {Promise<number>}
268
+ */
269
+ async function countJsonlLines(filePath) {
270
+ if (!existsSync(filePath)) return 0;
271
+ try {
272
+ const raw = await readFile(filePath, 'utf8');
273
+ if (raw.length === 0) return 0;
274
+ return raw.split('\n').filter((l) => l.length > 0).length;
275
+ } catch {
276
+ return 0;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Count `*.md` files in a directory (non-recursive). Missing directory or
282
+ * read errors resolve to 0. MEMORY.md is INCLUDED in the count — the stats
283
+ * line uses "memory files" as a count of all markdown notes in the memory
284
+ * dir, per the AC.
285
+ *
286
+ * @param {string} dir
287
+ * @returns {Promise<number>}
288
+ */
289
+ async function countMemoryFiles(dir) {
290
+ if (!existsSync(dir)) return 0;
291
+ try {
292
+ const entries = await readdir(dir, { withFileTypes: true });
293
+ let count = 0;
294
+ for (const entry of entries) {
295
+ if (!entry.isFile()) continue;
296
+ if (entry.name.toLowerCase().endsWith('.md')) count += 1;
297
+ }
298
+ return count;
299
+ } catch {
300
+ return 0;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Read every input the banner formatter needs. Pure data — no string
306
+ * formatting. Each subsystem is read defensively: errors degrade to a
307
+ * sensible empty value rather than throwing.
308
+ *
309
+ * @param {object} args
310
+ * @param {string} args.repoRoot — absolute path
311
+ * @param {string} [args.memoryDir] — defaults to `resolveMemoryDir()`
312
+ * @param {string} [args.learningsPath] — defaults to `<repoRoot>/.orchestrator/metrics/learnings.jsonl`
313
+ * @param {Date} [args.now] — injectable clock for tests
314
+ * @param {{enabled?: boolean, 'half-life-days'?: number, 'floor-factor'?: number}} [args.evolveDecay]
315
+ * — the kebab-case `evolve.decay` Session Config block (#670). Bridged to the
316
+ * camelCase `surfaceTopN` `opts.decay` shape via `decayOptsFromConfig`. Absent
317
+ * → DECAY_DEFAULTS apply (conservative 90-day half-life, enabled).
318
+ * @returns {Promise<{
319
+ * topLearnings: Array<{subject:string, confidence:number, type:string}>,
320
+ * stats: {memoryFiles:number, sessionsEver:number, daysSinceCleanup:number|null}|null,
321
+ * peerExcerpts: {user:[string|null,string|null]|null, agent:[string|null,string|null]|null},
322
+ * fresh: boolean,
323
+ * }>}
324
+ */
325
+ export async function readBannerInputs({ repoRoot, memoryDir, learningsPath, now, evolveDecay } = {}) {
326
+ if (typeof repoRoot !== 'string' || repoRoot.length === 0) {
327
+ throw new TypeError('readBannerInputs: repoRoot is required (absolute path)');
328
+ }
329
+ const memDir = typeof memoryDir === 'string' && memoryDir.length > 0
330
+ ? memoryDir
331
+ : resolveMemoryDir();
332
+ const learningsFile = typeof learningsPath === 'string' && learningsPath.length > 0
333
+ ? learningsPath
334
+ : path.join(repoRoot, '.orchestrator', 'metrics', 'learnings.jsonl');
335
+ const clock = now instanceof Date ? now : new Date();
336
+
337
+ // --- Top learnings ---------------------------------------------------------
338
+ let topLearnings = [];
339
+ try {
340
+ const surfaced = await surfaceTopN(learningsFile, 5, {
341
+ now: clock,
342
+ // Thread the documented decay knobs (#670) — without this, decay-enabled /
343
+ // decay-half-life-days are parsed but never applied to the banner ranking.
344
+ decay: decayOptsFromConfig(evolveDecay),
345
+ });
346
+ if (Array.isArray(surfaced)) {
347
+ topLearnings = surfaced
348
+ .filter((e) => e && typeof e === 'object')
349
+ .map((e) => ({
350
+ // Fallback to `id` (kebab-case slug, always present) when subject is missing
351
+ // or empty — prevents empty `• (0.9, type)` lines in the banner.
352
+ // Source: deep-2026-05-23-deep-3 Q4 session-reviewer LOW finding (15 historical
353
+ // learnings entries have subject:null and would have rendered blank).
354
+ subject:
355
+ typeof e.subject === 'string' && e.subject.length > 0
356
+ ? e.subject
357
+ : typeof e.id === 'string'
358
+ ? e.id
359
+ : '',
360
+ confidence: typeof e.confidence === 'number' ? e.confidence : 0,
361
+ type: typeof e.type === 'string' ? e.type : 'unknown',
362
+ }));
363
+ }
364
+ } catch {
365
+ topLearnings = [];
366
+ }
367
+
368
+ // --- Stats -----------------------------------------------------------------
369
+ let stats;
370
+ try {
371
+ const signals = await readDreamSignals({ repoRoot, memoryDir: memDir });
372
+ const memoryFiles = await countMemoryFiles(memDir);
373
+ // We deliberately use the actual sessions.jsonl path under repoRoot for
374
+ // the count of "sessions ever" — readDreamSignals exposes sessionsFilePath
375
+ // computed the same way, so we re-derive locally to keep this dependency
376
+ // surface lean and explicit.
377
+ const sessionsPath = path.join(repoRoot, '.orchestrator', 'metrics', 'sessions.jsonl');
378
+ const sessionsEver = await countJsonlLines(sessionsPath);
379
+
380
+ let daysSinceCleanup = null;
381
+ if (typeof signals?.lastCleanupAt === 'string' && signals.lastCleanupAt.length > 0) {
382
+ const cleanupMs = Date.parse(signals.lastCleanupAt);
383
+ if (Number.isFinite(cleanupMs)) {
384
+ const deltaMs = clock.getTime() - cleanupMs;
385
+ daysSinceCleanup = Math.max(0, Math.floor(deltaMs / 86_400_000));
386
+ }
387
+ }
388
+
389
+ stats = { memoryFiles, sessionsEver, daysSinceCleanup };
390
+ } catch {
391
+ // Fall back to zero-state stats so the banner still renders sensibly
392
+ // when the .orchestrator dir is missing entirely.
393
+ stats = { memoryFiles: 0, sessionsEver: 0, daysSinceCleanup: null };
394
+ }
395
+
396
+ // --- Peer-card excerpts ----------------------------------------------------
397
+ let peerExcerpts;
398
+ try {
399
+ const cards = await readPeerCards(repoRoot, { now: clock });
400
+ const userExcerpt =
401
+ cards?.user && typeof cards.user.body === 'string'
402
+ ? _extractCardExcerpt(cards.user.body)
403
+ : null;
404
+ const agentExcerpt =
405
+ cards?.agent && typeof cards.agent.body === 'string'
406
+ ? _extractCardExcerpt(cards.agent.body)
407
+ : null;
408
+
409
+ // Normalize [null, null] tuples to null so the formatter can simply
410
+ // check truthiness — both representations were spec-allowed but the
411
+ // formatter is cleaner with one canonical "absent" sentinel.
412
+ const normalize = (t) => {
413
+ if (!Array.isArray(t)) return null;
414
+ if (t[0] === null && t[1] === null) return null;
415
+ return t;
416
+ };
417
+ peerExcerpts = {
418
+ user: normalize(userExcerpt),
419
+ agent: normalize(agentExcerpt),
420
+ };
421
+ } catch {
422
+ peerExcerpts = { user: null, agent: null };
423
+ }
424
+
425
+ const fresh = topLearnings.length === 0 && (stats?.sessionsEver ?? 0) === 0;
426
+
427
+ return { topLearnings, stats, peerExcerpts, fresh };
428
+ }
429
+
430
+ // ---------------------------------------------------------------------------
431
+ // Top-level entry point
432
+ // ---------------------------------------------------------------------------
433
+
434
+ /**
435
+ * Render the Phase 6.7 banner string. Returns '' when the banner is disabled
436
+ * via Session Config (`config.persistence === false`, or
437
+ * `config.memory.banner.enabled === false`). The caller — session-start
438
+ * Phase 6.7 — is responsible for printing.
439
+ *
440
+ * Defensive against partial / malformed config: a missing `memory.banner`
441
+ * subtree is treated as enabled (default-on), matching the AC.
442
+ *
443
+ * @param {object} opts
444
+ * @param {string} opts.repoRoot
445
+ * @param {string} [opts.memoryDir]
446
+ * @param {object} opts.config — parseSessionConfig result
447
+ * @param {Date} [opts.now]
448
+ * @returns {Promise<string>}
449
+ */
450
+ export async function renderMemoryBanner(opts = {}) {
451
+ const { repoRoot, memoryDir, config, now } = opts;
452
+ if (typeof repoRoot !== 'string' || repoRoot.length === 0) {
453
+ throw new TypeError('renderMemoryBanner: repoRoot is required (absolute path)');
454
+ }
455
+
456
+ // Silent no-op when persistence is off or banner is explicitly disabled.
457
+ if (config && config.persistence === false) return '';
458
+ if (
459
+ config
460
+ && typeof config.memory === 'object'
461
+ && config.memory !== null
462
+ && typeof config.memory.banner === 'object'
463
+ && config.memory.banner !== null
464
+ && config.memory.banner.enabled === false
465
+ ) {
466
+ return '';
467
+ }
468
+
469
+ const inputs = await readBannerInputs({
470
+ repoRoot,
471
+ memoryDir,
472
+ now,
473
+ // `config['evolve.decay']` is the kebab-case block from _parseEvolveDecay;
474
+ // readBannerInputs bridges it to surfaceTopN's camelCase opts.decay (#670).
475
+ evolveDecay: config && config['evolve.decay'],
476
+ });
477
+ return _formatBanner(inputs);
478
+ }