peaks-loop 4.1.2 → 4.1.3

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 (323) hide show
  1. package/.claude-plugin/marketplace.json +136 -47
  2. package/CHANGELOG.md +56 -0
  3. package/README-en.md +1 -1
  4. package/README.md +1 -1
  5. package/contracts/readonly-argv-whitelist.json +211 -0
  6. package/dist/cli/commands/audit-artifact-runners.d.ts +16 -0
  7. package/dist/cli/commands/audit-artifact-runners.js +170 -0
  8. package/dist/cli/commands/audit-command-shared.d.ts +97 -0
  9. package/dist/cli/commands/audit-command-shared.js +60 -0
  10. package/dist/cli/commands/audit-commands.d.ts +7 -31
  11. package/dist/cli/commands/audit-commands.js +64 -473
  12. package/dist/cli/commands/audit-goal-runners.d.ts +17 -0
  13. package/dist/cli/commands/audit-goal-runners.js +114 -0
  14. package/dist/cli/commands/audit-red-lines-runners.d.ts +11 -0
  15. package/dist/cli/commands/audit-red-lines-runners.js +43 -0
  16. package/dist/cli/commands/audit-refusal-data.d.ts +23 -0
  17. package/dist/cli/commands/audit-refusal-data.js +69 -0
  18. package/dist/cli/commands/audit-static-runners.d.ts +13 -0
  19. package/dist/cli/commands/audit-static-runners.js +139 -0
  20. package/dist/cli/commands/await-runners.d.ts +11 -0
  21. package/dist/cli/commands/await-runners.js +148 -0
  22. package/dist/cli/commands/code-auto-compact-command.d.ts +3 -0
  23. package/dist/cli/commands/code-auto-compact-command.js +124 -0
  24. package/dist/cli/commands/code-auto-compact-envelope.d.ts +22 -0
  25. package/dist/cli/commands/code-auto-compact-envelope.js +39 -0
  26. package/dist/cli/commands/code-context-audit-command.d.ts +3 -0
  27. package/dist/cli/commands/code-context-audit-command.js +68 -0
  28. package/dist/cli/commands/code-context-now-command.d.ts +3 -0
  29. package/dist/cli/commands/code-context-now-command.js +124 -0
  30. package/dist/cli/commands/code-context-now-envelope.d.ts +66 -0
  31. package/dist/cli/commands/code-context-now-envelope.js +136 -0
  32. package/dist/cli/commands/code-context-now-mapping.d.ts +27 -0
  33. package/dist/cli/commands/code-context-now-mapping.js +43 -0
  34. package/dist/cli/commands/code-emit-handoff-command.d.ts +3 -0
  35. package/dist/cli/commands/code-emit-handoff-command.js +99 -0
  36. package/dist/cli/commands/code-gate-step-08-command.d.ts +3 -0
  37. package/dist/cli/commands/code-gate-step-08-command.js +139 -0
  38. package/dist/cli/commands/code-post-compact-detect-command.d.ts +3 -0
  39. package/dist/cli/commands/code-post-compact-detect-command.js +50 -0
  40. package/dist/cli/commands/code-runtime-commands.d.ts +9 -43
  41. package/dist/cli/commands/code-runtime-commands.js +20 -672
  42. package/dist/cli/commands/code-runtime-session.d.ts +1 -0
  43. package/dist/cli/commands/code-runtime-session.js +15 -0
  44. package/dist/cli/commands/compact-command.d.ts +6 -2
  45. package/dist/cli/commands/compact-command.js +12 -559
  46. package/dist/cli/commands/compact-dry-run-command.d.ts +3 -0
  47. package/dist/cli/commands/compact-dry-run-command.js +87 -0
  48. package/dist/cli/commands/compact-force-command.d.ts +3 -0
  49. package/dist/cli/commands/compact-force-command.js +98 -0
  50. package/dist/cli/commands/compact-harness-window-command.d.ts +3 -0
  51. package/dist/cli/commands/compact-harness-window-command.js +174 -0
  52. package/dist/cli/commands/compact-history-command.d.ts +3 -0
  53. package/dist/cli/commands/compact-history-command.js +89 -0
  54. package/dist/cli/commands/compact-read-commands.d.ts +3 -0
  55. package/dist/cli/commands/compact-read-commands.js +123 -0
  56. package/dist/cli/commands/compact-settle-command.d.ts +3 -0
  57. package/dist/cli/commands/compact-settle-command.js +130 -0
  58. package/dist/cli/commands/compact-shared.d.ts +9 -0
  59. package/dist/cli/commands/compact-shared.js +26 -0
  60. package/dist/cli/commands/core/skill-command.d.ts +1 -44
  61. package/dist/cli/commands/core/skill-command.js +13 -541
  62. package/dist/cli/commands/core/skill-context-verdict.d.ts +38 -0
  63. package/dist/cli/commands/core/skill-context-verdict.js +63 -0
  64. package/dist/cli/commands/core/skill-generated-config-notice.d.ts +41 -0
  65. package/dist/cli/commands/core/skill-generated-config-notice.js +75 -0
  66. package/dist/cli/commands/core/skill-heartbeat-commands.d.ts +3 -0
  67. package/dist/cli/commands/core/skill-heartbeat-commands.js +50 -0
  68. package/dist/cli/commands/core/skill-presence-commands.d.ts +3 -0
  69. package/dist/cli/commands/core/skill-presence-commands.js +123 -0
  70. package/dist/cli/commands/core/skill-presence-housekeeping-commands.d.ts +3 -0
  71. package/dist/cli/commands/core/skill-presence-housekeeping-commands.js +165 -0
  72. package/dist/cli/commands/core/skill-registry-commands.d.ts +3 -0
  73. package/dist/cli/commands/core/skill-registry-commands.js +117 -0
  74. package/dist/cli/commands/core/skill-runbook-command.d.ts +3 -0
  75. package/dist/cli/commands/core/skill-runbook-command.js +29 -0
  76. package/dist/cli/commands/dispatch-command-spec.d.ts +2 -0
  77. package/dist/cli/commands/dispatch-command-spec.js +62 -0
  78. package/dist/cli/commands/dispatch-commands.js +159 -775
  79. package/dist/cli/commands/dispatch-detached-branch.d.ts +3 -0
  80. package/dist/cli/commands/dispatch-detached-branch.js +58 -0
  81. package/dist/cli/commands/dispatch-envelope.d.ts +36 -0
  82. package/dist/cli/commands/dispatch-envelope.js +104 -0
  83. package/dist/cli/commands/dispatch-isolation-lease.d.ts +17 -0
  84. package/dist/cli/commands/dispatch-isolation-lease.js +149 -0
  85. package/dist/cli/commands/dispatch-preflight.d.ts +7 -0
  86. package/dist/cli/commands/dispatch-preflight.js +105 -0
  87. package/dist/cli/commands/dispatch-prompt-blocks.d.ts +10 -0
  88. package/dist/cli/commands/dispatch-prompt-blocks.js +56 -0
  89. package/dist/cli/commands/dispatch-prompt-composition.d.ts +30 -0
  90. package/dist/cli/commands/dispatch-prompt-composition.js +171 -0
  91. package/dist/cli/commands/dispatch-record-write.d.ts +24 -0
  92. package/dist/cli/commands/dispatch-record-write.js +96 -0
  93. package/dist/cli/commands/dispatch-tool-call.d.ts +15 -0
  94. package/dist/cli/commands/dispatch-tool-call.js +128 -0
  95. package/dist/cli/commands/evolution-command-shared.d.ts +78 -0
  96. package/dist/cli/commands/evolution-command-shared.js +107 -0
  97. package/dist/cli/commands/evolution-commands.d.ts +11 -1
  98. package/dist/cli/commands/evolution-commands.js +19 -350
  99. package/dist/cli/commands/evolution-evaluate-command.d.ts +24 -0
  100. package/dist/cli/commands/evolution-evaluate-command.js +138 -0
  101. package/dist/cli/commands/evolution-propose-command.d.ts +23 -0
  102. package/dist/cli/commands/evolution-propose-command.js +145 -0
  103. package/dist/cli/commands/evolution-status-command.d.ts +17 -0
  104. package/dist/cli/commands/evolution-status-command.js +41 -0
  105. package/dist/cli/commands/evolution-verdict-commands.d.ts +30 -0
  106. package/dist/cli/commands/evolution-verdict-commands.js +100 -0
  107. package/dist/cli/commands/finalize-accumulator.d.ts +44 -0
  108. package/dist/cli/commands/finalize-accumulator.js +55 -0
  109. package/dist/cli/commands/finalize-branches.d.ts +34 -0
  110. package/dist/cli/commands/finalize-branches.js +119 -0
  111. package/dist/cli/commands/finalize-runners.d.ts +3 -0
  112. package/dist/cli/commands/finalize-runners.js +92 -0
  113. package/dist/cli/commands/finalize-selection.d.ts +65 -0
  114. package/dist/cli/commands/finalize-selection.js +35 -0
  115. package/dist/cli/commands/gate-commands.js +26 -8
  116. package/dist/cli/commands/job-checkpoint-commands.d.ts +3 -0
  117. package/dist/cli/commands/job-checkpoint-commands.js +157 -0
  118. package/dist/cli/commands/job-command-shared.d.ts +109 -0
  119. package/dist/cli/commands/job-command-shared.js +72 -0
  120. package/dist/cli/commands/job-commands.d.ts +4 -64
  121. package/dist/cli/commands/job-commands.js +42 -552
  122. package/dist/cli/commands/job-cost-check-command.d.ts +3 -0
  123. package/dist/cli/commands/job-cost-check-command.js +41 -0
  124. package/dist/cli/commands/job-init-status-commands.d.ts +3 -0
  125. package/dist/cli/commands/job-init-status-commands.js +149 -0
  126. package/dist/cli/commands/job-run-commands.d.ts +3 -0
  127. package/dist/cli/commands/job-run-commands.js +97 -0
  128. package/dist/cli/commands/job-state-root.d.ts +35 -0
  129. package/dist/cli/commands/job-state-root.js +76 -0
  130. package/dist/cli/commands/loop-eval-capture-index.d.ts +4 -0
  131. package/dist/cli/commands/loop-eval-capture-index.js +44 -0
  132. package/dist/cli/commands/loop-eval-commands.d.ts +8 -5
  133. package/dist/cli/commands/loop-eval-commands.js +12 -626
  134. package/dist/cli/commands/loop-eval-eval-command.d.ts +3 -0
  135. package/dist/cli/commands/loop-eval-eval-command.js +168 -0
  136. package/dist/cli/commands/loop-eval-monotonic-command.d.ts +3 -0
  137. package/dist/cli/commands/loop-eval-monotonic-command.js +90 -0
  138. package/dist/cli/commands/loop-eval-parents.d.ts +7 -0
  139. package/dist/cli/commands/loop-eval-parents.js +20 -0
  140. package/dist/cli/commands/loop-eval-run-code.d.ts +7 -0
  141. package/dist/cli/commands/loop-eval-run-code.js +40 -0
  142. package/dist/cli/commands/loop-eval-run-command.d.ts +3 -0
  143. package/dist/cli/commands/loop-eval-run-command.js +113 -0
  144. package/dist/cli/commands/loop-eval-spec-commands.d.ts +3 -0
  145. package/dist/cli/commands/loop-eval-spec-commands.js +165 -0
  146. package/dist/cli/commands/loop-eval-spec-lint-command.d.ts +3 -0
  147. package/dist/cli/commands/loop-eval-spec-lint-command.js +42 -0
  148. package/dist/cli/commands/loop-eval-workflow-commands.d.ts +3 -0
  149. package/dist/cli/commands/loop-eval-workflow-commands.js +141 -0
  150. package/dist/cli/commands/mcp-commands.d.ts +10 -0
  151. package/dist/cli/commands/mcp-commands.js +157 -0
  152. package/dist/cli/commands/request-command-options.d.ts +49 -0
  153. package/dist/cli/commands/request-command-options.js +1 -0
  154. package/dist/cli/commands/request-commands.d.ts +3 -9
  155. package/dist/cli/commands/request-commands.js +17 -522
  156. package/dist/cli/commands/request-init-command.d.ts +3 -0
  157. package/dist/cli/commands/request-init-command.js +100 -0
  158. package/dist/cli/commands/request-lint-command.d.ts +3 -0
  159. package/dist/cli/commands/request-lint-command.js +50 -0
  160. package/dist/cli/commands/request-list-command.d.ts +10 -0
  161. package/dist/cli/commands/request-list-command.js +53 -0
  162. package/dist/cli/commands/request-repair-status-command.d.ts +3 -0
  163. package/dist/cli/commands/request-repair-status-command.js +61 -0
  164. package/dist/cli/commands/request-show-command.d.ts +3 -0
  165. package/dist/cli/commands/request-show-command.js +56 -0
  166. package/dist/cli/commands/request-transition-command.d.ts +3 -0
  167. package/dist/cli/commands/request-transition-command.js +122 -0
  168. package/dist/cli/commands/request-transition-failures.d.ts +8 -0
  169. package/dist/cli/commands/request-transition-failures.js +90 -0
  170. package/dist/cli/commands/request-transition-hooks.d.ts +50 -0
  171. package/dist/cli/commands/request-transition-hooks.js +115 -0
  172. package/dist/cli/commands/request-transition-preflight.d.ts +10 -0
  173. package/dist/cli/commands/request-transition-preflight.js +107 -0
  174. package/dist/cli/commands/scan-command-shared.d.ts +96 -0
  175. package/dist/cli/commands/scan-command-shared.js +83 -0
  176. package/dist/cli/commands/scan-commands.d.ts +3 -2
  177. package/dist/cli/commands/scan-commands.js +23 -463
  178. package/dist/cli/commands/scan-inventory-commands.d.ts +3 -0
  179. package/dist/cli/commands/scan-inventory-commands.js +96 -0
  180. package/dist/cli/commands/scan-project-commands.d.ts +3 -0
  181. package/dist/cli/commands/scan-project-commands.js +65 -0
  182. package/dist/cli/commands/scan-scope-commands.d.ts +3 -0
  183. package/dist/cli/commands/scan-scope-commands.js +149 -0
  184. package/dist/cli/commands/scan-scope-helpers.d.ts +8 -0
  185. package/dist/cli/commands/scan-scope-helpers.js +54 -0
  186. package/dist/cli/commands/scan-structural-commands.d.ts +3 -0
  187. package/dist/cli/commands/scan-structural-commands.js +113 -0
  188. package/dist/cli/commands/share-commands.d.ts +12 -68
  189. package/dist/cli/commands/share-commands.js +47 -556
  190. package/dist/cli/commands/share-error-hints.d.ts +14 -0
  191. package/dist/cli/commands/share-error-hints.js +38 -0
  192. package/dist/cli/commands/share-identity.d.ts +13 -0
  193. package/dist/cli/commands/share-identity.js +22 -0
  194. package/dist/cli/commands/share-record-paths.d.ts +37 -0
  195. package/dist/cli/commands/share-record-paths.js +68 -0
  196. package/dist/cli/commands/share-runners.d.ts +3 -0
  197. package/dist/cli/commands/share-runners.js +158 -0
  198. package/dist/cli/commands/shared-read-runners.d.ts +3 -0
  199. package/dist/cli/commands/shared-read-runners.js +51 -0
  200. package/dist/cli/commands/slice-check-command.d.ts +3 -0
  201. package/dist/cli/commands/slice-check-command.js +54 -0
  202. package/dist/cli/commands/slice-commands.d.ts +2 -22
  203. package/dist/cli/commands/slice-commands.js +18 -517
  204. package/dist/cli/commands/slice-decompose-artifacts.d.ts +18 -0
  205. package/dist/cli/commands/slice-decompose-artifacts.js +79 -0
  206. package/dist/cli/commands/slice-decompose-command.d.ts +3 -0
  207. package/dist/cli/commands/slice-decompose-command.js +123 -0
  208. package/dist/cli/commands/slice-list-commands.d.ts +3 -0
  209. package/dist/cli/commands/slice-list-commands.js +182 -0
  210. package/dist/cli/commands/slice-pick-command.d.ts +3 -0
  211. package/dist/cli/commands/slice-pick-command.js +60 -0
  212. package/dist/cli/commands/slice-plan-command.d.ts +24 -0
  213. package/dist/cli/commands/slice-plan-command.js +111 -0
  214. package/dist/cli/commands/workflow-commands.d.ts +10 -1
  215. package/dist/cli/commands/workflow-commands.js +6 -594
  216. package/dist/cli/commands/workflow-gate-commands.d.ts +3 -0
  217. package/dist/cli/commands/workflow-gate-commands.js +116 -0
  218. package/dist/cli/commands/workflow-plan-helpers.d.ts +48 -0
  219. package/dist/cli/commands/workflow-plan-helpers.js +103 -0
  220. package/dist/cli/commands/workflow-planning-commands.d.ts +3 -0
  221. package/dist/cli/commands/workflow-planning-commands.js +56 -0
  222. package/dist/cli/commands/workflow-swarm-actions.d.ts +7 -0
  223. package/dist/cli/commands/workflow-swarm-actions.js +109 -0
  224. package/dist/cli/commands/workflow-swarm-commands.d.ts +3 -0
  225. package/dist/cli/commands/workflow-swarm-commands.js +138 -0
  226. package/dist/cli/commands/workflow-tech-actions.d.ts +10 -0
  227. package/dist/cli/commands/workflow-tech-actions.js +150 -0
  228. package/dist/cli/commands/workspace/init-actions.d.ts +10 -0
  229. package/dist/cli/commands/workspace/init-actions.js +199 -0
  230. package/dist/cli/commands/workspace/init-codegraph-stake.d.ts +10 -0
  231. package/dist/cli/commands/workspace/init-codegraph-stake.js +54 -0
  232. package/dist/cli/commands/workspace/init-command.d.ts +8 -124
  233. package/dist/cli/commands/workspace/init-command.js +59 -623
  234. package/dist/cli/commands/workspace/init-context.d.ts +58 -0
  235. package/dist/cli/commands/workspace/init-context.js +121 -0
  236. package/dist/cli/commands/workspace/init-envelope.d.ts +3 -0
  237. package/dist/cli/commands/workspace/init-envelope.js +34 -0
  238. package/dist/cli/commands/workspace/init-failures.d.ts +3 -0
  239. package/dist/cli/commands/workspace/init-failures.js +84 -0
  240. package/dist/cli/commands/workspace/init-hooks-decision.d.ts +24 -0
  241. package/dist/cli/commands/workspace/init-hooks-decision.js +189 -0
  242. package/dist/cli/commands/workspace/init-options.d.ts +102 -0
  243. package/dist/cli/commands/workspace/init-options.js +1 -0
  244. package/dist/cli/commands/worktree-lease-commands.d.ts +10 -6
  245. package/dist/cli/commands/worktree-lease-commands.js +42 -512
  246. package/dist/cli/commands/worktree-lease-gc-command.d.ts +12 -0
  247. package/dist/cli/commands/worktree-lease-gc-command.js +117 -0
  248. package/dist/cli/commands/worktree-lease-git.d.ts +22 -0
  249. package/dist/cli/commands/worktree-lease-git.js +48 -0
  250. package/dist/cli/commands/worktree-lease-list-command.d.ts +12 -0
  251. package/dist/cli/commands/worktree-lease-list-command.js +100 -0
  252. package/dist/cli/commands/worktree-lease-load.d.ts +37 -0
  253. package/dist/cli/commands/worktree-lease-load.js +28 -0
  254. package/dist/cli/commands/worktree-lease-release-command.d.ts +13 -0
  255. package/dist/cli/commands/worktree-lease-release-command.js +105 -0
  256. package/dist/cli/commands/worktree-lease-renew-command.d.ts +11 -0
  257. package/dist/cli/commands/worktree-lease-renew-command.js +99 -0
  258. package/dist/cli/commands/worktree-lease-session.d.ts +22 -0
  259. package/dist/cli/commands/worktree-lease-session.js +29 -0
  260. package/dist/cli/commands/worktree-lease-spawn-command.d.ts +11 -0
  261. package/dist/cli/commands/worktree-lease-spawn-command.js +119 -0
  262. package/dist/cli/commands/worktree-lease-status-command.d.ts +11 -0
  263. package/dist/cli/commands/worktree-lease-status-command.js +86 -0
  264. package/dist/cli/commands/worktree-lease-store.d.ts +19 -0
  265. package/dist/cli/commands/worktree-lease-store.js +24 -0
  266. package/dist/cli/program.js +5 -0
  267. package/dist/services/distribution/mcp-install-runner.d.ts +21 -0
  268. package/dist/services/distribution/mcp-install-runner.js +59 -0
  269. package/dist/services/distribution/mcp-install.d.ts +95 -0
  270. package/dist/services/distribution/mcp-install.js +179 -0
  271. package/dist/services/distribution/plugin-manifest.d.ts +97 -0
  272. package/dist/services/distribution/plugin-manifest.js +126 -0
  273. package/dist/services/hooks/mcp-surface-gate.d.ts +19 -0
  274. package/dist/services/hooks/mcp-surface-gate.js +87 -0
  275. package/dist/services/ide/adapters/claude-code-adapter.d.ts +4 -35
  276. package/dist/services/ide/adapters/claude-code-adapter.js +48 -171
  277. package/dist/services/ide/adapters/claude-code-local-state.d.ts +28 -0
  278. package/dist/services/ide/adapters/claude-code-local-state.js +112 -0
  279. package/dist/services/ide/adapters/claude-code-model-window.d.ts +37 -0
  280. package/dist/services/ide/adapters/claude-code-model-window.js +113 -0
  281. package/dist/services/ide/ide-mcp-install-types.d.ts +78 -0
  282. package/dist/services/ide/ide-mcp-install-types.js +104 -0
  283. package/dist/services/ide/ide-types.d.ts +45 -1
  284. package/dist/services/ide/mcp-tool-matcher.d.ts +34 -0
  285. package/dist/services/ide/mcp-tool-matcher.js +84 -0
  286. package/dist/services/lint/npx-resolver.js +7 -0
  287. package/dist/services/mcp/cli-executor.d.ts +36 -0
  288. package/dist/services/mcp/cli-executor.js +97 -0
  289. package/dist/services/mcp/json-rpc.d.ts +81 -0
  290. package/dist/services/mcp/json-rpc.js +116 -0
  291. package/dist/services/mcp/memory-tool.d.ts +3 -0
  292. package/dist/services/mcp/memory-tool.js +62 -0
  293. package/dist/services/mcp/server-main.d.ts +1 -0
  294. package/dist/services/mcp/server-main.js +66 -0
  295. package/dist/services/mcp/server.d.ts +22 -0
  296. package/dist/services/mcp/server.js +152 -0
  297. package/dist/services/mcp/surface.d.ts +62 -0
  298. package/dist/services/mcp/surface.js +198 -0
  299. package/dist/services/mcp/tool-core.d.ts +42 -0
  300. package/dist/services/mcp/tool-core.js +137 -0
  301. package/dist/services/mcp/tools.d.ts +13 -0
  302. package/dist/services/mcp/tools.js +58 -0
  303. package/dist/services/readonly-surface/argv-guard.d.ts +32 -0
  304. package/dist/services/readonly-surface/argv-guard.js +164 -0
  305. package/dist/services/readonly-surface/readonly-whitelist.d.ts +147 -0
  306. package/dist/services/readonly-surface/readonly-whitelist.js +107 -0
  307. package/dist/services/readonly-surface/whitelist-generator.d.ts +64 -0
  308. package/dist/services/readonly-surface/whitelist-generator.js +212 -0
  309. package/dist/services/skills/hooks-codegate-superpowers.d.ts +1 -0
  310. package/dist/services/skills/hooks-codegate-superpowers.js +26 -0
  311. package/dist/services/skills/hooks-settings-service.js +10 -2
  312. package/package.json +17 -6
  313. package/scripts/install-skills-bundles.mjs +233 -0
  314. package/scripts/install-skills-fs.mjs +148 -0
  315. package/scripts/install-skills-ide.mjs +279 -0
  316. package/scripts/install-skills-output-style-default.mjs +196 -0
  317. package/scripts/install-skills-output-styles.mjs +121 -0
  318. package/scripts/install-skills-report.mjs +42 -0
  319. package/scripts/install-skills-user-config.mjs +198 -0
  320. package/scripts/install-skills.mjs +36 -1066
  321. package/scripts/watch-tree.mjs +140 -0
  322. package/scripts/watch.mjs +4 -126
  323. package/skills/peaks-status/SKILL.md +31 -13
@@ -0,0 +1,171 @@
1
+ // The prompt `peaks sub-agent dispatch` hands a sub-agent: the adapter check, the
2
+ // optional preflight blocks (memory / codegraph / UI library / fresh context /
3
+ // context probe / session capsule), the isolation and must-ls-files blocks, and the
4
+ // warning list the envelope carries.
5
+ import { fail, getErrorMessage } from 'peaks-loop-shared/result';
6
+ import { printResult } from '../cli-helpers.js';
7
+ import { detectInstalledIde } from '../../services/ide/ide-detector.js';
8
+ import { getAdapter } from '../../services/ide/ide-registry.js';
9
+ import { resolveOuterSessionId } from '../../services/session/binding-status-service.js';
10
+ import { loadPreferences } from '../../services/preferences/preferences-service.js';
11
+ import { DEFAULT_PREFERENCES } from '../../services/preferences/preferences-types.js';
12
+ import { MemoryPreflightService, deriveMemoryQuery } from '../../services/context/memory-preflight-service.js';
13
+ import { buildDispatchSystemPrompt } from '../../services/context/build-dispatch-system-prompt.js';
14
+ import { readSessionCapsule } from '../../services/dispatch/session-capsule.js';
15
+ import { computeUiLibraryDispatchBlock } from '../../services/standards/ui-library-dispatch-block.js';
16
+ import { readFreshContextBlock } from '../../services/fresh-context/fresh-context-block.js';
17
+ import { deprecatedReviewerWarnings } from './sub-agent-shared.js';
18
+ import { buildIsolationBlock, buildMustLsFilesBlock } from './dispatch-prompt-blocks.js';
19
+ // loadPreferences can throw on schema mismatch; we fall back to defaults
20
+ // to avoid breaking the dispatch on a stale preferences.json file.
21
+ function loadProjectPreferences(projectRoot) {
22
+ try {
23
+ return loadPreferences(projectRoot);
24
+ }
25
+ catch {
26
+ // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
27
+ // Keep default preferences.
28
+ return DEFAULT_PREFERENCES;
29
+ }
30
+ }
31
+ function rejectUnsupportedIde(io, ide, role, asJson) {
32
+ printResult(io, fail('sub-agent.dispatch', 'IDE_NOT_SUPPORTED', `IDE ${ide} does not support role "${role}"`, { role, toolCall: null, dispatchRecordPath: null }, ['Switch to a registered IDE (e.g. claude-code) or pick a role the current IDE supports.']), asJson);
33
+ process.exitCode = 1;
34
+ return null;
35
+ }
36
+ // memory preflight block (or silently skip when unavailable) via the
37
+ // pure-function builder.
38
+ function loadMemoryBlock(projectRoot, projectPrefs, role, prompt) {
39
+ const preflightService = new MemoryPreflightService(projectRoot, projectPrefs);
40
+ // task at hand (role + first line of the brief), not the bare role.
41
+ return preflightService.fetchBlock(deriveMemoryQuery(role, prompt));
42
+ }
43
+ // codegraph preflight for RD planning. BEFORE the RD sub-agent's
44
+ // prompt is composed, ensure the index exists (init + index best-effort
45
+ // when `.codegraph/` is absent) and read a BOUNDED structure summary.
46
+ // `rd` only — other roles keep the legacy prompt byte-identical.
47
+ // Fail-soft: any failure degrades and dispatch proceeds. On failure the
48
+ // preflight's NOTE — the upstream cause — travels as the same value as
49
+ // the block, so the reason cannot be dropped while the block survives.
50
+ // The old `block : null` dropped it, so every degraded dispatch read as success.
51
+ async function loadCodegraphBlock(projectRoot, role) {
52
+ let codegraphBlock;
53
+ if (role === 'rd') {
54
+ try {
55
+ const { buildCodegraphPreflightBlock } = await import('../../services/codegraph/codegraph-preflight-service.js');
56
+ const preflight = await buildCodegraphPreflightBlock(projectRoot);
57
+ codegraphBlock = preflight.available ? preflight.block : preflight.note;
58
+ }
59
+ catch (error) {
60
+ codegraphBlock = `codegraph preflight threw: ${getErrorMessage(error)}`;
61
+ }
62
+ }
63
+ return codegraphBlock;
64
+ }
65
+ // component library (+ CSS framework + build tool) in the RD/UI
66
+ // dispatch system prompt so the sub-agent prefers the library over
67
+ // hand-rolled native DOM. Only injected for frontend-generating roles
68
+ // (rd + ui) — qa/sc/txt/prd keep the legacy prompt byte-identical.
69
+ // Fail-soft inside the wrapper: a detection error degrades to null.
70
+ function loadProjectStackBlock(projectRoot, role) {
71
+ let projectStackBlock;
72
+ if (role === 'rd' || role === 'ui') {
73
+ projectStackBlock = computeUiLibraryDispatchBlock(projectRoot);
74
+ }
75
+ return projectStackBlock;
76
+ }
77
+ // Slice 2026-09-07-search-first-preflight: read the orchestrator-
78
+ // synthesized fresh-context block for rd + prd dispatches. The block
79
+ // was written to .peaks/_runtime/<sid>/fresh-context.md when the
80
+ // preflight triggered; it carries ≤5 binding directives that hedge
81
+ // model training-data lag. Fail-soft: a missing / unreadable file, or
82
+ // a file without the `## Fresh context` heading, degrades to null so
83
+ // the prompt stays byte-identical to the legacy shape. Other roles
84
+ // (qa/sc/txt/ui) keep the legacy prompt unchanged.
85
+ function loadFreshContextBlock(projectRoot, sid, role) {
86
+ let freshContextBlock;
87
+ if (role === 'rd' || role === 'prd') {
88
+ freshContextBlock = readFreshContextBlock(projectRoot, sid);
89
+ }
90
+ return freshContextBlock;
91
+ }
92
+ // authoritative context-fill probe before composing the
93
+ // dispatch prompt. The probe is token-counted (IDE adapter's
94
+ // `compact` env-var), not a byte estimate. The composer
95
+ // prepends a `## Context window` block so the dispatched
96
+ // sub-agent reads the actual ratio instead of guessing
97
+ // from message length (char/4 estimates diverge by 2-4x
98
+ // and have caused false "context too low" reports at 60%+
99
+ // free).
100
+ async function loadContextProbe(projectRoot, sid) {
101
+ let contextProbe = null;
102
+ try {
103
+ const { readContextPercent } = await import('../../services/context/auto-compact-reader.js');
104
+ const outerSessionId = resolveOuterSessionId(projectRoot, sid);
105
+ contextProbe = readContextPercent({
106
+ projectRoot,
107
+ sessionId: sid,
108
+ outerSessionId,
109
+ env: process.env
110
+ });
111
+ }
112
+ catch {
113
+ // Probe is best-effort; the composer renders a
114
+ // "no probe available" hint instead of failing the
115
+ // dispatch.
116
+ }
117
+ return contextProbe;
118
+ }
119
+ async function composeMemoryAugmentedBody(input, projectPrefs) {
120
+ const { projectRoot, sid, rid, role, prompt } = input;
121
+ const memoryBlock = await loadMemoryBlock(projectRoot, projectPrefs, role, prompt);
122
+ const codegraphBlock = await loadCodegraphBlock(projectRoot, role);
123
+ const projectStackBlock = loadProjectStackBlock(projectRoot, role);
124
+ const freshContextBlock = loadFreshContextBlock(projectRoot, sid, role);
125
+ const contextProbe = await loadContextProbe(projectRoot, sid);
126
+ // capsule published by the orchestrator via `peaks sub-agent share`.
127
+ // Absent capsule → no pointer and no precedence line (byte-identical
128
+ // legacy prompt).
129
+ const capsuleRef = readSessionCapsule({ projectRoot, sid, rid });
130
+ return buildDispatchSystemPrompt({
131
+ taskTitle: role,
132
+ taskBody: prompt,
133
+ memoryBlock,
134
+ // unified Test Tool Detection injection for every role.
135
+ contextProbe,
136
+ // exactOptionalPropertyTypes: only set codegraphBlock when the rd
137
+ // preflight actually produced a value (null = attempted-unavailable,
138
+ // undefined = not requested → legacy prompt unchanged).
139
+ ...(codegraphBlock !== undefined ? { codegraphBlock } : {}),
140
+ // Same optionality contract for the project-stack block: set only
141
+ // when the rd/ui detection ran (null = no library → no block,
142
+ // undefined = non-frontend role → legacy prompt unchanged).
143
+ ...(projectStackBlock !== undefined ? { projectStackBlock } : {}),
144
+ // Same optionality contract for the fresh-context block: set only
145
+ // when the rd/prd read ran (null = no block on disk → no block,
146
+ // undefined = non-rd/prd role → legacy prompt unchanged).
147
+ ...(freshContextBlock !== undefined ? { freshContextBlock } : {}),
148
+ // §4: advisory session capsule pointer + precedence line.
149
+ ...(capsuleRef !== null
150
+ ? {
151
+ capsule: { batchId: capsuleRef.batchId, key: capsuleRef.key, bytes: capsuleRef.bytes }
152
+ }
153
+ : {})
154
+ });
155
+ }
156
+ export async function composeDispatchPrompt(io, input) {
157
+ const { projectRoot, role, options, isolationMode, leaseId, worktreePath, worktreeBranch, decision, asJson } = input;
158
+ const projectPrefs = loadProjectPreferences(projectRoot);
159
+ const ide = detectInstalledIde(projectRoot) ?? 'claude-code';
160
+ const adapter = getAdapter(ide);
161
+ if (!adapter.subAgentDispatcher.supportsRole(role)) {
162
+ return rejectUnsupportedIde(io, ide, role, asJson);
163
+ }
164
+ const memoryAugmentedBody = await composeMemoryAugmentedBody(input, projectPrefs);
165
+ const isolationBlock = buildIsolationBlock(isolationMode, leaseId, worktreePath, worktreeBranch);
166
+ const { mustLsFilesVerification, mustLsFilesBlock } = buildMustLsFilesBlock(options, projectRoot);
167
+ const effectivePrompt = `${memoryAugmentedBody}${isolationBlock}${mustLsFilesBlock}`;
168
+ // + rerouted here, never refused — rationale on the helper itself.
169
+ const warnings = [...decision.warnings, ...deprecatedReviewerWarnings(role)];
170
+ return { adapter, effectivePrompt, warnings, mustLsFilesVerification };
171
+ }
@@ -0,0 +1,24 @@
1
+ import { noteDispatched } from '../../services/dispatch/batch-counter.js';
2
+ import { type ArtifactMeta } from '../../services/context/artifact-meta.js';
3
+ import { type SubAgentToolCall } from '../../services/dispatch/sub-agent-dispatcher.js';
4
+ import { type DispatchOptions } from './sub-agent-shared.js';
5
+ export interface WriteDispatchRecordInput {
6
+ options: DispatchOptions;
7
+ projectRoot: string;
8
+ sid: string;
9
+ rid: string;
10
+ role: string;
11
+ effectivePrompt: string;
12
+ toolCall: SubAgentToolCall;
13
+ batchId: string;
14
+ isolationMode: 'worktree' | 'container' | 'vm' | null;
15
+ leaseId: string | null;
16
+ /** The dispatch's warning list — this function appends to it, as the inline block did. */
17
+ warnings: string[];
18
+ }
19
+ export interface DispatchRecordWrite {
20
+ artifactMeta: ArtifactMeta | null;
21
+ dispatchRecordPath: string;
22
+ counter: ReturnType<typeof noteDispatched>;
23
+ }
24
+ export declare function writeDispatchRecord(input: WriteDispatchRecordInput): DispatchRecordWrite;
@@ -0,0 +1,96 @@
1
+ // The `peaks sub-agent dispatch` record write: the optional G7 artifact meta, the graph
2
+ // node binding, the dispatch record itself, and the batch counter.
3
+ import { existsSync } from 'node:fs';
4
+ import { getErrorMessage } from 'peaks-loop-shared/result';
5
+ import { noteDispatched } from '../../services/dispatch/batch-counter.js';
6
+ import { writeInitialDispatchRecord } from '../../services/dispatch/dispatch-record-writer.js';
7
+ import { provisionDispatchNode } from '../../services/workflow/provision-dispatch-node.js';
8
+ import { buildArtifactMeta } from '../../services/context/artifact-meta.js';
9
+ import { assertSafeArtifactPath } from 'peaks-loop-shared-channel';
10
+ // G7 — optional --write-artifact: build ArtifactMeta, attach to record.
11
+ function resolveArtifactMeta(input) {
12
+ const { options, projectRoot, rid, role, warnings } = input;
13
+ let artifactMeta = null;
14
+ if (typeof options.writeArtifact === 'string' && options.writeArtifact.length > 0) {
15
+ try {
16
+ assertSafeArtifactPath(options.writeArtifact, projectRoot);
17
+ if (!existsSync(options.writeArtifact)) {
18
+ warnings.push('ARTIFACT_NOT_FOUND');
19
+ }
20
+ else {
21
+ artifactMeta = buildArtifactMeta({
22
+ path: options.writeArtifact,
23
+ rid,
24
+ role,
25
+ idx: 1, // single dispatch, idx=1
26
+ summary: null
27
+ });
28
+ }
29
+ }
30
+ catch (err) {
31
+ warnings.push(`ARTIFACT_PATH_INVALID: ${getErrorMessage(err)}`);
32
+ }
33
+ }
34
+ return artifactMeta;
35
+ }
36
+ // Slice 4.0.8 RD §4 D4c: bind this dispatch to a graph node. When the
37
+ // caller names none, provision one — that is what collapses the
38
+ // documented three-step ritual (create graph -> `peaks workflow node
39
+ // prepare` -> dispatch) into a single call. Those three fields were
40
+ // also never passed to the writer, so the record's graph binding was
41
+ // always null and the writer's transition never fired: the feature was
42
+ // inert, and only its precondition (the required flag) was real.
43
+ function resolveGraphBinding(options, projectRoot, sid, role) {
44
+ if (typeof options.graphNode === 'string' && options.graphNode.length > 0) {
45
+ return {
46
+ nodeId: options.graphNode,
47
+ workflowId: options.workflowId ?? null,
48
+ graphRef: options.graphRef ?? null
49
+ };
50
+ }
51
+ const provisioned = provisionDispatchNode({
52
+ projectRoot,
53
+ sessionId: sid,
54
+ role,
55
+ workflowId: options.workflowId,
56
+ graphRef: options.graphRef
57
+ });
58
+ return {
59
+ nodeId: provisioned.nodeId,
60
+ workflowId: provisioned.workflowId,
61
+ graphRef: provisioned.graphRef
62
+ };
63
+ }
64
+ export function writeDispatchRecord(input) {
65
+ const { options, projectRoot, sid, rid, role, effectivePrompt, toolCall, batchId, isolationMode, leaseId, warnings } = input;
66
+ const artifactMeta = resolveArtifactMeta(input);
67
+ const graphBinding = resolveGraphBinding(options, projectRoot, sid, role);
68
+ const { path: dispatchRecordPath } = writeInitialDispatchRecord({
69
+ projectRoot,
70
+ sessionId: sid,
71
+ requestId: rid,
72
+ role,
73
+ prompt: effectivePrompt,
74
+ workflowId: graphBinding.workflowId,
75
+ graphNodeId: graphBinding.nodeId,
76
+ graphRef: graphBinding.graphRef,
77
+ toolCall,
78
+ batchId,
79
+ // lease id on the dispatch record so the finalize-time
80
+ // release hook (markCompleted / heartbeat --status done) can
81
+ // auto-fire `peaks worktree release` when the sub-agent
82
+ // completes. Null when --isolation was not requested.
83
+ leaseId,
84
+ // ISO timestamp when the isolation mode was set up. Null
85
+ // when --isolation was not requested. The dashboard reads
86
+ // this directly off the dispatch record to compute
87
+ // isolation duration without cross-referencing the
88
+ // metrics stream.
89
+ isolationStartedAt: isolationMode !== null ? new Date().toISOString() : null
90
+ });
91
+ const counter = noteDispatched(projectRoot, sid, batchId);
92
+ if (counter.warning) {
93
+ warnings.push(counter.warning.message);
94
+ }
95
+ return { artifactMeta, dispatchRecordPath, counter };
96
+ }
@@ -0,0 +1,15 @@
1
+ import { type ProgramIO } from '../cli-helpers.js';
2
+ import { getAdapter } from '../../services/ide/ide-registry.js';
3
+ import { type SubAgentToolCall } from '../../services/dispatch/sub-agent-dispatcher.js';
4
+ export interface BuildDispatchToolCallInput {
5
+ adapter: ReturnType<typeof getAdapter>;
6
+ role: string;
7
+ effectivePrompt: string;
8
+ rid: string;
9
+ sid: string;
10
+ projectRoot: string;
11
+ isolationMode: 'worktree' | 'container' | 'vm' | null;
12
+ leaseId: string | null;
13
+ asJson: boolean;
14
+ }
15
+ export declare function buildDispatchToolCall(io: ProgramIO, input: BuildDispatchToolCallInput): SubAgentToolCall | null;
@@ -0,0 +1,128 @@
1
+ // The tool call `peaks sub-agent dispatch` returns: built by the active adapter, then
2
+ // stamped with the isolation lease, the provenance token, the Playwright profile env
3
+ // and the observability event.
4
+ import { fail } from 'peaks-loop-shared/result';
5
+ import { printResult } from '../cli-helpers.js';
6
+ import { SubAgentNotSupportedError } from '../../services/dispatch/sub-agent-dispatcher.js';
7
+ import { emitObservabilityEvent, OBSERVABILITY_SUBAGENT_ROLES } from '../../services/observability/observability-service.js';
8
+ import { createDispatchProvenanceToken, DISPATCH_PROVENANCE_ENV, writeDispatchProvenance } from '../../services/worktree/dispatch-provenance.js';
9
+ import { playwrightProfilePaths } from '../../services/worktree/playwright-profile.js';
10
+ function writeWorktreeProvenance(input) {
11
+ const { projectRoot, sid, rid, leaseId, provenanceToken } = input;
12
+ writeDispatchProvenance({
13
+ projectRoot,
14
+ record: {
15
+ schemaVersion: 1,
16
+ token: provenanceToken,
17
+ sessionId: sid,
18
+ requestId: rid,
19
+ leaseId,
20
+ isolation: 'worktree',
21
+ issuedAt: new Date().toISOString()
22
+ }
23
+ });
24
+ }
25
+ // Part 2.C: stamp the toolCall with `isolation` + a sub-agent
26
+ // env block so adapters that surface it (Claude Code's Task
27
+ // tool) propagate the lease id to the spawned process. The
28
+ // env block is the canonical hook the PreToolUse gate reads
29
+ // (gate-commands.ts: process.env.PEAKS_WORKTREE_LEASE_ID).
30
+ function applyIsolationStamp(toolCall, input) {
31
+ const { projectRoot, sid, rid, isolationMode, leaseId } = input;
32
+ if (isolationMode !== null && leaseId !== null) {
33
+ const existingEnv = toolCall.args['env'] ?? {};
34
+ const provenanceToken = createDispatchProvenanceToken({
35
+ sessionId: sid,
36
+ requestId: rid,
37
+ leaseId
38
+ });
39
+ if (isolationMode === 'worktree') {
40
+ writeWorktreeProvenance({ projectRoot, sid, rid, leaseId, provenanceToken });
41
+ }
42
+ // two Playwright profile-isolation env vars so the sub-agent's
43
+ // browser MCP session lands in a deterministic
44
+ // `.peaks/_runtime/<sid>/pw-profiles/<dispatchId>/` directory
45
+ // (see src/services/worktree/playwright-profile.ts). Without
46
+ // these, concurrent dispatches share the user's default
47
+ // Chromium profile and corrupt cookies / localStorage.
48
+ const profile = playwrightProfilePaths({
49
+ projectRoot,
50
+ sessionId: sid,
51
+ dispatchId: rid
52
+ });
53
+ toolCall = {
54
+ ...toolCall,
55
+ args: {
56
+ ...toolCall.args,
57
+ isolation: isolationMode,
58
+ env: {
59
+ ...existingEnv,
60
+ PEAKS_WORKTREE_LEASE_ID: leaseId,
61
+ PEAKS_PLAYWRIGHT_USER_DATA_DIR: profile.userDataDir,
62
+ PEAKS_PLAYWRIGHT_PROFILE_NAME: profile.profileName,
63
+ ...(isolationMode === 'worktree' ? { [DISPATCH_PROVENANCE_ENV]: provenanceToken } : {})
64
+ }
65
+ }
66
+ };
67
+ }
68
+ return toolCall;
69
+ }
70
+ // Slice C of v2.11.1 — observability hook #2/7. Fire-and-forget
71
+ // per PRD Q4 (full-auto must never fail-loud). The
72
+ // synchronous emit returns {written:false} on disk-full; we
73
+ // deliberately swallow the result so dispatch contract is
74
+ // unchanged. role is only included when it matches the schema's
75
+ // known sub-agent role set; otherwise it's omitted (non-standard
76
+ // roles like 'qa-business' would otherwise drop the event
77
+ // through schema rejection).
78
+ function emitDispatchObservability(input) {
79
+ const { adapter, role, effectivePrompt, sid, rid, projectRoot } = input;
80
+ const KNOWN_ROLES = new Set(OBSERVABILITY_SUBAGENT_ROLES);
81
+ const knownRole = KNOWN_ROLES.has(role)
82
+ ? role
83
+ : null;
84
+ emitObservabilityEvent({
85
+ schemaVersion: 1,
86
+ ts: new Date().toISOString(),
87
+ sessionId: sid,
88
+ category: 'dispatch',
89
+ ...(knownRole !== null ? { role: knownRole } : {}),
90
+ detail: {
91
+ requestId: rid,
92
+ ide: adapter.subAgentDispatcher.label,
93
+ promptBytes: effectivePrompt.length
94
+ }
95
+ }, { projectRoot });
96
+ }
97
+ function rejectUnsupportedAdapter(io, role, error, asJson) {
98
+ printResult(io, fail('sub-agent.dispatch', 'IDE_NOT_SUPPORTED', error.message, { role, toolCall: null, dispatchRecordPath: null }, ['Switch IDE or pick a role the current IDE supports.']), asJson);
99
+ process.exitCode = 1;
100
+ return null;
101
+ }
102
+ export function buildDispatchToolCall(io, input) {
103
+ const { adapter, role, effectivePrompt, rid, sid, projectRoot, isolationMode, leaseId, asJson } = input;
104
+ let toolCall;
105
+ try {
106
+ toolCall = adapter.subAgentDispatcher.buildToolCall({
107
+ role,
108
+ prompt: effectivePrompt,
109
+ requestId: rid,
110
+ sessionId: sid
111
+ });
112
+ toolCall = applyIsolationStamp(toolCall, {
113
+ projectRoot,
114
+ sid,
115
+ rid,
116
+ isolationMode,
117
+ leaseId
118
+ });
119
+ emitDispatchObservability({ adapter, role, effectivePrompt, sid, rid, projectRoot });
120
+ }
121
+ catch (error) {
122
+ if (error instanceof SubAgentNotSupportedError) {
123
+ return rejectUnsupportedAdapter(io, role, error, asJson);
124
+ }
125
+ throw error;
126
+ }
127
+ return toolCall;
128
+ }
@@ -0,0 +1,78 @@
1
+ import { EvolutionService, type EvolutionIntegrityError } from '../../services/evolution/evolution-service.js';
2
+ import { type EvolutionTargetKind } from '../../services/evolution/evolution-types.js';
3
+ import { type ProgramIO } from '../cli-helpers.js';
4
+ import { type ResultEnvelope } from 'peaks-loop-shared/result';
5
+ /** A parsed `--target <kind:id>` flag. */
6
+ export interface EvolutionTarget {
7
+ kind: EvolutionTargetKind;
8
+ id: string;
9
+ }
10
+ /**
11
+ * Parse `--target <kind:id>`. Returns the kind + id, or `null` on
12
+ * failure. Validates `kind` against the EVOLUTION_TARGET_KINDS
13
+ * union.
14
+ */
15
+ export declare function parseTargetFlag(raw: string): EvolutionTarget | null;
16
+ /** The shared `--target` parse failure envelope (`propose` + `status`). */
17
+ export declare function invalidTargetFailure(command: string, target: string): ResultEnvelope<{
18
+ target: string;
19
+ }>;
20
+ /** The shared "no such proposal" failure envelope. */
21
+ export declare function proposalNotFoundFailure(command: string, proposalId: string, nextActions: string[]): ResultEnvelope<{
22
+ proposalId: string;
23
+ }>;
24
+ /**
25
+ * Helper: collect repeatable `--risk-tag` values into an array.
26
+ * Commander's `collect` is not always available; we read
27
+ * `previous` from the default value.
28
+ */
29
+ export declare function collectRepeatable(value: string, previous: string[]): string[];
30
+ /** Upper bound of the 0..10 score scale used by proposal + evaluator scores. */
31
+ export declare const SCORE_SCALE_MAX = 10;
32
+ /** True when `value` is a finite number on the 0..10 score scale. */
33
+ export declare function isScoreInRange(value: number): boolean;
34
+ /** Inputs for {@link scoreRangeFailure}. */
35
+ export interface ScoreRangeFailureArgs {
36
+ command: string;
37
+ code: string;
38
+ /** Message label, e.g. `before_score`. */
39
+ label: string;
40
+ /** CLI flag named in the hint, e.g. `--before-score`. */
41
+ flag: string;
42
+ /** `data` key carrying the raw value, e.g. `beforeScore`. */
43
+ key: string;
44
+ /** The raw, unparsed flag value. */
45
+ raw: string;
46
+ }
47
+ /** The shared "[0, 10] finite number" validation failure envelope. */
48
+ export declare function scoreRangeFailure(args: ScoreRangeFailureArgs): ResultEnvelope<Record<string, string>>;
49
+ /** The `--delta-min` validation failure envelope. */
50
+ export declare function deltaMinFailure(command: string, raw: string): ResultEnvelope<Record<string, string>>;
51
+ /** Run `body` against a fresh EvolutionService, closing the DB after. */
52
+ export declare function withEvolutionDb<T>(project: string | undefined, body: (svc: EvolutionService) => T): T;
53
+ /** `await`-friendly sibling of {@link withEvolutionDb}. */
54
+ export declare function withEvolutionDbAsync<T>(project: string | undefined, body: (svc: EvolutionService) => Promise<T>): Promise<T>;
55
+ /** Params for {@link reportIntegrityFailure}. */
56
+ export interface IntegrityFailureReport {
57
+ io: ProgramIO;
58
+ command: string;
59
+ error: EvolutionIntegrityError;
60
+ nextActions: string[];
61
+ /** `options.json` — the caller's `--json` flag, possibly absent. */
62
+ asJson?: boolean | undefined;
63
+ }
64
+ /** Print an `EvolutionIntegrityError` envelope and set exit code 1. */
65
+ export declare function reportIntegrityFailure(report: IntegrityFailureReport): void;
66
+ /** Params for {@link reportFailure}. */
67
+ export interface CommandFailureReport {
68
+ io: ProgramIO;
69
+ command: string;
70
+ code: string;
71
+ error: unknown;
72
+ data: Record<string, unknown>;
73
+ nextActions: string[];
74
+ /** `options.json` — the caller's `--json` flag, possibly absent. */
75
+ asJson?: boolean | undefined;
76
+ }
77
+ /** Print a generic `<command>_FAILED` envelope and set exit code 1. */
78
+ export declare function reportFailure(report: CommandFailureReport): void;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Shared helpers for the `peaks evolution *` subcommand modules
3
+ * (propose / evaluate / mark-keep / revert / status). Split out of
4
+ * `evolution-commands.ts` in the size-debt batch: every command name,
5
+ * option, envelope key, error code and exit-code site is unchanged.
6
+ *
7
+ * Nothing here holds module-level mutable state: each helper takes
8
+ * parameters and returns a value, and the DB helpers own the
9
+ * open/close pair so callers never see a half-closed handle.
10
+ */
11
+ import { existsSync, mkdirSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { findProjectRoot } from '../../services/config/config-safety.js';
14
+ import { EvolutionService } from '../../services/evolution/evolution-service.js';
15
+ import { EVOLUTION_TARGET_KINDS } from '../../services/evolution/evolution-types.js';
16
+ import { openStateDb } from '../../services/skillhub/sqlite-store.js';
17
+ import { getErrorMessage, printResult } from '../cli-helpers.js';
18
+ import { fail } from 'peaks-loop-shared/result';
19
+ /**
20
+ * Parse `--target <kind:id>`. Returns the kind + id, or `null` on
21
+ * failure. Validates `kind` against the EVOLUTION_TARGET_KINDS
22
+ * union.
23
+ */
24
+ export function parseTargetFlag(raw) {
25
+ const idx = raw.indexOf(':');
26
+ if (idx <= 0 || idx === raw.length - 1)
27
+ return null;
28
+ const kind = raw.slice(0, idx);
29
+ const id = raw.slice(idx + 1);
30
+ if (!EVOLUTION_TARGET_KINDS.includes(kind))
31
+ return null;
32
+ return { kind: kind, id };
33
+ }
34
+ /** The shared `--target` parse failure envelope (`propose` + `status`). */
35
+ export function invalidTargetFailure(command, target) {
36
+ return fail(command, 'EVOLUTION_INVALID_TARGET', `--target must be '<kind>:<id>' where kind ∈ {${EVOLUTION_TARGET_KINDS.join(',')}}`, { target }, ['Pass --target loop:<loop-id> or --target bee:<bee-id>.']);
37
+ }
38
+ /** The shared "no such proposal" failure envelope. */
39
+ export function proposalNotFoundFailure(command, proposalId, nextActions) {
40
+ return fail(command, 'EVOLUTION_PROPOSAL_NOT_FOUND', `proposal '${proposalId}' not found`, { proposalId }, nextActions);
41
+ }
42
+ /**
43
+ * Helper: collect repeatable `--risk-tag` values into an array.
44
+ * Commander's `collect` is not always available; we read
45
+ * `previous` from the default value.
46
+ */
47
+ export function collectRepeatable(value, previous) {
48
+ if (Array.isArray(previous))
49
+ return [...previous, value];
50
+ return [value];
51
+ }
52
+ /** Upper bound of the 0..10 score scale used by proposal + evaluator scores. */
53
+ export const SCORE_SCALE_MAX = 10;
54
+ /** True when `value` is a finite number on the 0..10 score scale. */
55
+ export function isScoreInRange(value) {
56
+ return Number.isFinite(value) && value >= 0 && value <= SCORE_SCALE_MAX;
57
+ }
58
+ /** The shared "[0, 10] finite number" validation failure envelope. */
59
+ export function scoreRangeFailure(args) {
60
+ return fail(args.command, args.code, `${args.label} must be a finite number in [0, 10] (got "${args.raw}")`, { [args.key]: args.raw }, [`Pass a numeric ${args.flag} in [0, 10].`]);
61
+ }
62
+ /** The `--delta-min` validation failure envelope. */
63
+ export function deltaMinFailure(command, raw) {
64
+ return fail(command, 'EVOLUTION_INVALID_DELTA_MIN', `delta_min must be a finite number >= 0 (got "${raw}")`, { deltaMin: raw }, ['Pass a numeric --delta-min >= 0 (default 1.0).']);
65
+ }
66
+ /**
67
+ * Resolve the project root, bootstrap an empty `.peaks/` dir when it
68
+ * is missing (so tests do not need a full peaks project) and open the
69
+ * state DB.
70
+ */
71
+ function openEvolutionDb(project) {
72
+ const projectRoot = project ?? findProjectRoot(process.cwd()) ?? process.cwd();
73
+ if (!existsSync(join(projectRoot, '.peaks'))) {
74
+ mkdirSync(join(projectRoot, '.peaks'), { recursive: true });
75
+ }
76
+ return openStateDb(join(projectRoot, '.peaks', 'state.db'));
77
+ }
78
+ /** Run `body` against a fresh EvolutionService, closing the DB after. */
79
+ export function withEvolutionDb(project, body) {
80
+ const db = openEvolutionDb(project);
81
+ try {
82
+ return body(new EvolutionService(db));
83
+ }
84
+ finally {
85
+ db.close();
86
+ }
87
+ }
88
+ /** `await`-friendly sibling of {@link withEvolutionDb}. */
89
+ export async function withEvolutionDbAsync(project, body) {
90
+ const db = openEvolutionDb(project);
91
+ try {
92
+ return await body(new EvolutionService(db));
93
+ }
94
+ finally {
95
+ db.close();
96
+ }
97
+ }
98
+ /** Print an `EvolutionIntegrityError` envelope and set exit code 1. */
99
+ export function reportIntegrityFailure(report) {
100
+ printResult(report.io, fail(report.command, report.error.code, report.error.message, { findings: report.error.findings }, report.nextActions), report.asJson);
101
+ process.exitCode = 1;
102
+ }
103
+ /** Print a generic `<command>_FAILED` envelope and set exit code 1. */
104
+ export function reportFailure(report) {
105
+ printResult(report.io, fail(report.command, report.code, getErrorMessage(report.error), report.data, report.nextActions), report.asJson);
106
+ process.exitCode = 1;
107
+ }
@@ -20,7 +20,17 @@
20
20
  *
21
21
  * Defense in depth: the EvolutionService enforces the ratchet
22
22
  * into the service payload.
23
+ *
24
+ * Size-debt split: each verb's registration and action body now lives
25
+ * in its own sibling module — `evolution-propose-command.ts`,
26
+ * `evolution-evaluate-command.ts`, `evolution-verdict-commands.ts`
27
+ * (mark-keep + revert) and `evolution-status-command.ts` — over the
28
+ * shared parse / validate / DB / failure helpers in
29
+ * `evolution-command-shared.ts`. This file keeps the parent and the
30
+ * delegation only; every command name, option, envelope key, error
31
+ * code and exit-code site is unchanged.
23
32
  */
24
33
  import type { Command } from 'commander';
25
- import { type ProgramIO } from '../cli-helpers.js';
34
+ import type { ProgramIO } from '../cli-helpers.js';
35
+ export type { EvolutionTarget } from './evolution-command-shared.js';
26
36
  export declare function registerEvolutionCommands(program: Command, io: ProgramIO): void;