peaks-loop 4.1.3 → 4.1.4

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 (402) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +56 -0
  3. package/README-en.md +1 -1
  4. package/README.md +1 -1
  5. package/dist/cli/commands/asset-command-shared.d.ts +12 -0
  6. package/dist/cli/commands/asset-command-shared.js +45 -0
  7. package/dist/cli/commands/asset-commands.d.ts +6 -1
  8. package/dist/cli/commands/asset-commands.js +11 -372
  9. package/dist/cli/commands/asset-crystallize-command.d.ts +3 -0
  10. package/dist/cli/commands/asset-crystallize-command.js +60 -0
  11. package/dist/cli/commands/asset-crystallize-payload.d.ts +47 -0
  12. package/dist/cli/commands/asset-crystallize-payload.js +85 -0
  13. package/dist/cli/commands/asset-crystallize-runner.d.ts +3 -0
  14. package/dist/cli/commands/asset-crystallize-runner.js +133 -0
  15. package/dist/cli/commands/asset-dispose-command.d.ts +3 -0
  16. package/dist/cli/commands/asset-dispose-command.js +99 -0
  17. package/dist/cli/commands/asset-status-command.d.ts +3 -0
  18. package/dist/cli/commands/asset-status-command.js +100 -0
  19. package/dist/cli/commands/baseline-audit-command.d.ts +3 -0
  20. package/dist/cli/commands/baseline-audit-command.js +64 -0
  21. package/dist/cli/commands/baseline-command-shared.d.ts +23 -0
  22. package/dist/cli/commands/baseline-command-shared.js +39 -0
  23. package/dist/cli/commands/baseline-commands.js +33 -313
  24. package/dist/cli/commands/baseline-freeze-commands.d.ts +4 -0
  25. package/dist/cli/commands/baseline-freeze-commands.js +81 -0
  26. package/dist/cli/commands/baseline-guard-command.d.ts +3 -0
  27. package/dist/cli/commands/baseline-guard-command.js +52 -0
  28. package/dist/cli/commands/baseline-read-commands.d.ts +5 -0
  29. package/dist/cli/commands/baseline-read-commands.js +72 -0
  30. package/dist/cli/commands/baseline-rollback-commands.d.ts +4 -0
  31. package/dist/cli/commands/baseline-rollback-commands.js +88 -0
  32. package/dist/cli/commands/classify-downgrade-command.d.ts +9 -0
  33. package/dist/cli/commands/classify-downgrade-command.js +21 -0
  34. package/dist/cli/commands/classify-run-command.d.ts +9 -0
  35. package/dist/cli/commands/classify-run-command.js +73 -0
  36. package/dist/cli/commands/classify-signals.d.ts +5 -0
  37. package/dist/cli/commands/classify-signals.js +104 -0
  38. package/dist/cli/commands/code-emit-handoff-command.js +40 -3
  39. package/dist/cli/commands/code-gate-step-08-command.js +25 -9
  40. package/dist/cli/commands/codegraph-command-options.d.ts +22 -0
  41. package/dist/cli/commands/codegraph-command-options.js +22 -0
  42. package/dist/cli/commands/codegraph-commands.d.ts +2 -2
  43. package/dist/cli/commands/codegraph-commands.js +14 -397
  44. package/dist/cli/commands/codegraph-config-restore-command.d.ts +3 -0
  45. package/dist/cli/commands/codegraph-config-restore-command.js +200 -0
  46. package/dist/cli/commands/codegraph-proxy-commands.d.ts +10 -0
  47. package/dist/cli/commands/codegraph-proxy-commands.js +159 -0
  48. package/dist/cli/commands/codegraph-repair-commands.d.ts +3 -0
  49. package/dist/cli/commands/codegraph-repair-commands.js +94 -0
  50. package/dist/cli/commands/codegraph-status-command.d.ts +1 -1
  51. package/dist/cli/commands/codegraph-status-command.js +27 -214
  52. package/dist/cli/commands/codegraph-status-integrity.d.ts +44 -0
  53. package/dist/cli/commands/codegraph-status-integrity.js +121 -0
  54. package/dist/cli/commands/codegraph-status-json.d.ts +5 -0
  55. package/dist/cli/commands/codegraph-status-json.js +127 -0
  56. package/dist/cli/commands/container-command-shared.d.ts +60 -0
  57. package/dist/cli/commands/container-command-shared.js +52 -0
  58. package/dist/cli/commands/container-commands.d.ts +1 -1
  59. package/dist/cli/commands/container-commands.js +4 -216
  60. package/dist/cli/commands/container-release-command.d.ts +3 -0
  61. package/dist/cli/commands/container-release-command.js +105 -0
  62. package/dist/cli/commands/container-spawn-command.d.ts +3 -0
  63. package/dist/cli/commands/container-spawn-command.js +148 -0
  64. package/dist/cli/commands/context-check-command.d.ts +3 -0
  65. package/dist/cli/commands/context-check-command.js +81 -0
  66. package/dist/cli/commands/context-commands.d.ts +2 -7
  67. package/dist/cli/commands/context-commands.js +6 -276
  68. package/dist/cli/commands/context-layer-command.d.ts +3 -0
  69. package/dist/cli/commands/context-layer-command.js +34 -0
  70. package/dist/cli/commands/context-layer-fetchers.d.ts +15 -0
  71. package/dist/cli/commands/context-layer-fetchers.js +162 -0
  72. package/dist/cli/commands/context-status-command.d.ts +17 -0
  73. package/dist/cli/commands/context-status-command.js +41 -0
  74. package/dist/cli/commands/contract-write-command.d.ts +3 -0
  75. package/dist/cli/commands/contract-write-command.js +144 -0
  76. package/dist/cli/commands/core/doctor-bindings.d.ts +17 -0
  77. package/dist/cli/commands/core/doctor-bindings.js +30 -0
  78. package/dist/cli/commands/core/doctor-command.d.ts +4 -18
  79. package/dist/cli/commands/core/doctor-command.js +2 -323
  80. package/dist/cli/commands/core/doctor-logs.d.ts +8 -0
  81. package/dist/cli/commands/core/doctor-logs.js +32 -0
  82. package/dist/cli/commands/core/doctor-probes.d.ts +3 -0
  83. package/dist/cli/commands/core/doctor-probes.js +55 -0
  84. package/dist/cli/commands/core/doctor-run-command.d.ts +12 -0
  85. package/dist/cli/commands/core/doctor-run-command.js +172 -0
  86. package/dist/cli/commands/core/doctor-summary.d.ts +7 -0
  87. package/dist/cli/commands/core/doctor-summary.js +39 -0
  88. package/dist/cli/commands/core/memory-command-shared.d.ts +25 -0
  89. package/dist/cli/commands/core/memory-command-shared.js +20 -0
  90. package/dist/cli/commands/core/memory-command.d.ts +1 -1
  91. package/dist/cli/commands/core/memory-command.js +6 -227
  92. package/dist/cli/commands/core/memory-delegated-verbs.d.ts +4 -0
  93. package/dist/cli/commands/core/memory-delegated-verbs.js +178 -0
  94. package/dist/cli/commands/core/memory-extract-command.d.ts +3 -0
  95. package/dist/cli/commands/core/memory-extract-command.js +90 -0
  96. package/dist/cli/commands/core/memory-sync-command.d.ts +3 -0
  97. package/dist/cli/commands/core/memory-sync-command.js +38 -0
  98. package/dist/cli/commands/core/session-command.d.ts +1 -1
  99. package/dist/cli/commands/core/session-command.js +12 -206
  100. package/dist/cli/commands/core/session-info-command.d.ts +3 -0
  101. package/dist/cli/commands/core/session-info-command.js +142 -0
  102. package/dist/cli/commands/core/session-verb-commands.d.ts +5 -0
  103. package/dist/cli/commands/core/session-verb-commands.js +58 -0
  104. package/dist/cli/commands/core/standards-command.d.ts +1 -24
  105. package/dist/cli/commands/core/standards-command.js +33 -201
  106. package/dist/cli/commands/core/standards-init-command.d.ts +3 -0
  107. package/dist/cli/commands/core/standards-init-command.js +87 -0
  108. package/dist/cli/commands/core/standards-lint.d.ts +24 -0
  109. package/dist/cli/commands/core/standards-lint.js +57 -0
  110. package/dist/cli/commands/core/standards-migrate-command.d.ts +3 -0
  111. package/dist/cli/commands/core/standards-migrate-command.js +57 -0
  112. package/dist/cli/commands/cron-scheduler-commands.d.ts +5 -1
  113. package/dist/cli/commands/cron-scheduler-commands.js +36 -206
  114. package/dist/cli/commands/cron-scheduler-run-once-command.d.ts +7 -0
  115. package/dist/cli/commands/cron-scheduler-run-once-command.js +35 -0
  116. package/dist/cli/commands/cron-scheduler-shared.d.ts +6 -0
  117. package/dist/cli/commands/cron-scheduler-shared.js +48 -0
  118. package/dist/cli/commands/cron-scheduler-start-command.d.ts +7 -0
  119. package/dist/cli/commands/cron-scheduler-start-command.js +65 -0
  120. package/dist/cli/commands/cron-scheduler-status-command.d.ts +7 -0
  121. package/dist/cli/commands/cron-scheduler-status-command.js +46 -0
  122. package/dist/cli/commands/cron-scheduler-stop-command.d.ts +7 -0
  123. package/dist/cli/commands/cron-scheduler-stop-command.js +61 -0
  124. package/dist/cli/commands/dispatch-dag-envelope.d.ts +41 -0
  125. package/dist/cli/commands/dispatch-dag-envelope.js +49 -0
  126. package/dist/cli/commands/dispatch-dag-failure.d.ts +18 -0
  127. package/dist/cli/commands/dispatch-dag-failure.js +16 -0
  128. package/dist/cli/commands/dispatch-dag-preflight.d.ts +51 -0
  129. package/dist/cli/commands/dispatch-dag-preflight.js +105 -0
  130. package/dist/cli/commands/dispatch-dag-runners.d.ts +48 -0
  131. package/dist/cli/commands/dispatch-dag-runners.js +73 -0
  132. package/dist/cli/commands/dispatch-from-dag.d.ts +27 -0
  133. package/dist/cli/commands/dispatch-from-dag.js +87 -257
  134. package/dist/cli/commands/final-review-command-envelopes.d.ts +44 -0
  135. package/dist/cli/commands/final-review-command-envelopes.js +100 -0
  136. package/dist/cli/commands/final-review-command-shared.d.ts +52 -0
  137. package/dist/cli/commands/final-review-command-shared.js +35 -0
  138. package/dist/cli/commands/final-review-commands.d.ts +7 -27
  139. package/dist/cli/commands/final-review-commands.js +13 -240
  140. package/dist/cli/commands/final-review-prepare-command.d.ts +3 -0
  141. package/dist/cli/commands/final-review-prepare-command.js +200 -0
  142. package/dist/cli/commands/governance-classify-contract-commands.d.ts +23 -9
  143. package/dist/cli/commands/governance-classify-contract-commands.js +26 -269
  144. package/dist/cli/commands/hooks-command-shared.d.ts +42 -0
  145. package/dist/cli/commands/hooks-command-shared.js +32 -0
  146. package/dist/cli/commands/hooks-commands.d.ts +20 -0
  147. package/dist/cli/commands/hooks-commands.js +75 -309
  148. package/dist/cli/commands/hooks-install-envelopes.d.ts +6 -0
  149. package/dist/cli/commands/hooks-install-envelopes.js +144 -0
  150. package/dist/cli/commands/hooks-status-command.d.ts +3 -0
  151. package/dist/cli/commands/hooks-status-command.js +93 -0
  152. package/dist/cli/commands/hooks-uninstall-command.d.ts +3 -0
  153. package/dist/cli/commands/hooks-uninstall-command.js +43 -0
  154. package/dist/cli/commands/loop-command-shared.d.ts +31 -0
  155. package/dist/cli/commands/loop-command-shared.js +15 -0
  156. package/dist/cli/commands/loop-commands.d.ts +12 -17
  157. package/dist/cli/commands/loop-commands.js +56 -238
  158. package/dist/cli/commands/loop-export-command.d.ts +3 -0
  159. package/dist/cli/commands/loop-export-command.js +73 -0
  160. package/dist/cli/commands/loop-goal-compose-command.d.ts +3 -0
  161. package/dist/cli/commands/loop-goal-compose-command.js +36 -0
  162. package/dist/cli/commands/loop-import-command.d.ts +3 -0
  163. package/dist/cli/commands/loop-import-command.js +86 -0
  164. package/dist/cli/commands/loop-placeholder-commands.d.ts +3 -0
  165. package/dist/cli/commands/loop-placeholder-commands.js +52 -0
  166. package/dist/cli/commands/memory-command-shared.d.ts +59 -0
  167. package/dist/cli/commands/memory-command-shared.js +39 -0
  168. package/dist/cli/commands/memory-commands.d.ts +6 -79
  169. package/dist/cli/commands/memory-commands.js +19 -309
  170. package/dist/cli/commands/memory-ingest-command.d.ts +3 -0
  171. package/dist/cli/commands/memory-ingest-command.js +50 -0
  172. package/dist/cli/commands/memory-list-command.d.ts +16 -0
  173. package/dist/cli/commands/memory-list-command.js +129 -0
  174. package/dist/cli/commands/memory-reindex-command.d.ts +9 -0
  175. package/dist/cli/commands/memory-reindex-command.js +78 -0
  176. package/dist/cli/commands/memory-rotate-command.d.ts +3 -0
  177. package/dist/cli/commands/memory-rotate-command.js +55 -0
  178. package/dist/cli/commands/memory-search-command.d.ts +7 -0
  179. package/dist/cli/commands/memory-search-command.js +46 -0
  180. package/dist/cli/commands/openspec-archive-command.d.ts +3 -0
  181. package/dist/cli/commands/openspec-archive-command.js +55 -0
  182. package/dist/cli/commands/openspec-command-shared.d.ts +62 -0
  183. package/dist/cli/commands/openspec-command-shared.js +135 -0
  184. package/dist/cli/commands/openspec-commands.d.ts +1 -1
  185. package/dist/cli/commands/openspec-commands.js +33 -306
  186. package/dist/cli/commands/openspec-from-doctor-command.d.ts +3 -0
  187. package/dist/cli/commands/openspec-from-doctor-command.js +66 -0
  188. package/dist/cli/commands/openspec-init-command.d.ts +3 -0
  189. package/dist/cli/commands/openspec-init-command.js +49 -0
  190. package/dist/cli/commands/openspec-list-command.d.ts +3 -0
  191. package/dist/cli/commands/openspec-list-command.js +27 -0
  192. package/dist/cli/commands/openspec-render-command.d.ts +3 -0
  193. package/dist/cli/commands/openspec-render-command.js +33 -0
  194. package/dist/cli/commands/openspec-show-command.d.ts +3 -0
  195. package/dist/cli/commands/openspec-show-command.js +33 -0
  196. package/dist/cli/commands/openspec-to-rd-command.d.ts +3 -0
  197. package/dist/cli/commands/openspec-to-rd-command.js +33 -0
  198. package/dist/cli/commands/openspec-validate-command.d.ts +3 -0
  199. package/dist/cli/commands/openspec-validate-command.js +45 -0
  200. package/dist/cli/commands/playwright-browser-command.d.ts +8 -0
  201. package/dist/cli/commands/playwright-browser-command.js +61 -0
  202. package/dist/cli/commands/playwright-commands.d.ts +10 -62
  203. package/dist/cli/commands/playwright-commands.js +77 -400
  204. package/dist/cli/commands/playwright-envelope.d.ts +8 -0
  205. package/dist/cli/commands/playwright-envelope.js +29 -0
  206. package/dist/cli/commands/playwright-ls-stop-commands.d.ts +4 -0
  207. package/dist/cli/commands/playwright-ls-stop-commands.js +74 -0
  208. package/dist/cli/commands/playwright-session-store.d.ts +65 -0
  209. package/dist/cli/commands/playwright-session-store.js +189 -0
  210. package/dist/cli/commands/project-commands.d.ts +19 -0
  211. package/dist/cli/commands/project-commands.js +98 -259
  212. package/dist/cli/commands/project-context-command.d.ts +3 -0
  213. package/dist/cli/commands/project-context-command.js +44 -0
  214. package/dist/cli/commands/project-dashboard-command.d.ts +3 -0
  215. package/dist/cli/commands/project-dashboard-command.js +74 -0
  216. package/dist/cli/commands/project-knowledge-command.d.ts +3 -0
  217. package/dist/cli/commands/project-knowledge-command.js +48 -0
  218. package/dist/cli/commands/project-memories-show-command.d.ts +3 -0
  219. package/dist/cli/commands/project-memories-show-command.js +87 -0
  220. package/dist/cli/commands/project-memory-index-command.d.ts +3 -0
  221. package/dist/cli/commands/project-memory-index-command.js +31 -0
  222. package/dist/cli/commands/qa-archive-screenshots-command.d.ts +3 -0
  223. package/dist/cli/commands/qa-archive-screenshots-command.js +53 -0
  224. package/dist/cli/commands/qa-commands.d.ts +14 -87
  225. package/dist/cli/commands/qa-commands.js +17 -315
  226. package/dist/cli/commands/qa-context-prestep.d.ts +1 -0
  227. package/dist/cli/commands/qa-context-prestep.js +34 -0
  228. package/dist/cli/commands/qa-run-command.d.ts +3 -0
  229. package/dist/cli/commands/qa-run-command.js +105 -0
  230. package/dist/cli/commands/qa-run-options.d.ts +23 -0
  231. package/dist/cli/commands/qa-run-options.js +31 -0
  232. package/dist/cli/commands/qa-run-slice.d.ts +41 -0
  233. package/dist/cli/commands/qa-run-slice.js +145 -0
  234. package/dist/cli/commands/release-canary-command.d.ts +28 -0
  235. package/dist/cli/commands/release-canary-command.js +129 -0
  236. package/dist/cli/commands/release-command-shared.d.ts +13 -0
  237. package/dist/cli/commands/release-command-shared.js +18 -0
  238. package/dist/cli/commands/release-commands.d.ts +10 -18
  239. package/dist/cli/commands/release-commands.js +25 -298
  240. package/dist/cli/commands/release-done-command.d.ts +3 -0
  241. package/dist/cli/commands/release-done-command.js +64 -0
  242. package/dist/cli/commands/release-hotfix-command.d.ts +3 -0
  243. package/dist/cli/commands/release-hotfix-command.js +50 -0
  244. package/dist/cli/commands/release-plan-command.d.ts +3 -0
  245. package/dist/cli/commands/release-plan-command.js +33 -0
  246. package/dist/cli/commands/release-precheck-command.d.ts +3 -0
  247. package/dist/cli/commands/release-precheck-command.js +28 -0
  248. package/dist/cli/commands/release-promote-command.d.ts +3 -0
  249. package/dist/cli/commands/release-promote-command.js +34 -0
  250. package/dist/cli/commands/release-rollback-command.d.ts +3 -0
  251. package/dist/cli/commands/release-rollback-command.js +33 -0
  252. package/dist/cli/commands/release-watch-command.d.ts +3 -0
  253. package/dist/cli/commands/release-watch-command.js +44 -0
  254. package/dist/cli/commands/sediment-argv-flags.d.ts +54 -0
  255. package/dist/cli/commands/sediment-argv-flags.js +116 -0
  256. package/dist/cli/commands/sediment-command-shared.d.ts +15 -0
  257. package/dist/cli/commands/sediment-command-shared.js +5 -0
  258. package/dist/cli/commands/sediment-commands.d.ts +35 -59
  259. package/dist/cli/commands/sediment-commands.js +36 -590
  260. package/dist/cli/commands/sediment-pool-commands.d.ts +9 -0
  261. package/dist/cli/commands/sediment-pool-commands.js +185 -0
  262. package/dist/cli/commands/sediment-query-commands.d.ts +4 -0
  263. package/dist/cli/commands/sediment-query-commands.js +94 -0
  264. package/dist/cli/commands/sediment-release-commands.d.ts +8 -0
  265. package/dist/cli/commands/sediment-release-commands.js +232 -0
  266. package/dist/cli/commands/sop-advance-command.d.ts +3 -0
  267. package/dist/cli/commands/sop-advance-command.js +160 -0
  268. package/dist/cli/commands/sop-check-command.d.ts +3 -0
  269. package/dist/cli/commands/sop-check-command.js +44 -0
  270. package/dist/cli/commands/sop-command-shared.d.ts +23 -0
  271. package/dist/cli/commands/sop-command-shared.js +18 -0
  272. package/dist/cli/commands/sop-commands.d.ts +15 -1
  273. package/dist/cli/commands/sop-commands.js +26 -240
  274. package/dist/cli/commands/sop-init-command.d.ts +3 -0
  275. package/dist/cli/commands/sop-init-command.js +51 -0
  276. package/dist/cli/commands/sop-lint-command.d.ts +3 -0
  277. package/dist/cli/commands/sop-lint-command.js +64 -0
  278. package/dist/cli/commands/sop-register-command.d.ts +3 -0
  279. package/dist/cli/commands/sop-register-command.js +48 -0
  280. package/dist/cli/commands/sop-registry-command.d.ts +3 -0
  281. package/dist/cli/commands/sop-registry-command.js +30 -0
  282. package/dist/cli/commands/statusline-command-shared.d.ts +73 -0
  283. package/dist/cli/commands/statusline-command-shared.js +90 -0
  284. package/dist/cli/commands/statusline-commands.d.ts +1 -19
  285. package/dist/cli/commands/statusline-commands.js +48 -287
  286. package/dist/cli/commands/statusline-compact-command.d.ts +4 -0
  287. package/dist/cli/commands/statusline-compact-command.js +54 -0
  288. package/dist/cli/commands/statusline-install-command.d.ts +3 -0
  289. package/dist/cli/commands/statusline-install-command.js +48 -0
  290. package/dist/cli/commands/statusline-render-command.d.ts +9 -0
  291. package/dist/cli/commands/statusline-render-command.js +55 -0
  292. package/dist/cli/commands/statusline-status-command.d.ts +3 -0
  293. package/dist/cli/commands/statusline-status-command.js +23 -0
  294. package/dist/cli/commands/statusline-uninstall-command.d.ts +3 -0
  295. package/dist/cli/commands/statusline-uninstall-command.js +23 -0
  296. package/dist/cli/commands/test-command-run-helpers.d.ts +27 -0
  297. package/dist/cli/commands/test-command-run-helpers.js +73 -0
  298. package/dist/cli/commands/test-command-runner-resolution.d.ts +57 -0
  299. package/dist/cli/commands/test-command-runner-resolution.js +183 -0
  300. package/dist/cli/commands/test-commands.d.ts +8 -56
  301. package/dist/cli/commands/test-commands.js +26 -249
  302. package/dist/cli/commands/vm-command-shared.d.ts +23 -0
  303. package/dist/cli/commands/vm-command-shared.js +23 -0
  304. package/dist/cli/commands/vm-commands.d.ts +1 -28
  305. package/dist/cli/commands/vm-commands.js +36 -270
  306. package/dist/cli/commands/vm-hypervisor-runtime.d.ts +15 -0
  307. package/dist/cli/commands/vm-hypervisor-runtime.js +64 -0
  308. package/dist/cli/commands/vm-release-command.d.ts +5 -0
  309. package/dist/cli/commands/vm-release-command.js +101 -0
  310. package/dist/cli/commands/vm-spawn-command.d.ts +5 -0
  311. package/dist/cli/commands/vm-spawn-command.js +177 -0
  312. package/dist/cli/commands/web-command-shared.d.ts +12 -0
  313. package/dist/cli/commands/web-command-shared.js +30 -0
  314. package/dist/cli/commands/web-commands.d.ts +7 -14
  315. package/dist/cli/commands/web-commands.js +6 -314
  316. package/dist/cli/commands/web-install-command.d.ts +10 -0
  317. package/dist/cli/commands/web-install-command.js +116 -0
  318. package/dist/cli/commands/web-lifecycle-commands.d.ts +9 -30
  319. package/dist/cli/commands/web-lifecycle-commands.js +14 -322
  320. package/dist/cli/commands/web-login-command.d.ts +14 -0
  321. package/dist/cli/commands/web-login-command.js +189 -0
  322. package/dist/cli/commands/web-op-payload.d.ts +22 -0
  323. package/dist/cli/commands/web-op-payload.js +89 -0
  324. package/dist/cli/commands/web-op-refusals.d.ts +37 -0
  325. package/dist/cli/commands/web-op-refusals.js +73 -0
  326. package/dist/cli/commands/web-op-runner.d.ts +14 -0
  327. package/dist/cli/commands/web-op-runner.js +166 -0
  328. package/dist/cli/commands/web-status-command.d.ts +4 -0
  329. package/dist/cli/commands/web-status-command.js +32 -0
  330. package/dist/cli/commands/web-stop-command.d.ts +10 -0
  331. package/dist/cli/commands/web-stop-command.js +59 -0
  332. package/dist/cli/commands/web-verb-specs.d.ts +18 -0
  333. package/dist/cli/commands/web-verb-specs.js +66 -0
  334. package/dist/cli/commands/workflow-command-shared.d.ts +102 -0
  335. package/dist/cli/commands/workflow-command-shared.js +74 -0
  336. package/dist/cli/commands/workflow-graph-commands.d.ts +3 -0
  337. package/dist/cli/commands/workflow-graph-commands.js +73 -0
  338. package/dist/cli/commands/workflow-init-command.d.ts +3 -0
  339. package/dist/cli/commands/workflow-init-command.js +68 -0
  340. package/dist/cli/commands/workflow-lifecycle-commands.d.ts +9 -59
  341. package/dist/cli/commands/workflow-lifecycle-commands.js +14 -348
  342. package/dist/cli/commands/workflow-node-commands.d.ts +3 -0
  343. package/dist/cli/commands/workflow-node-commands.js +154 -0
  344. package/dist/cli/commands/workflow-terminalize-command.d.ts +3 -0
  345. package/dist/cli/commands/workflow-terminalize-command.js +56 -0
  346. package/dist/services/code/auto-compact-artifacts.d.ts +54 -0
  347. package/dist/services/code/auto-compact-artifacts.js +135 -0
  348. package/dist/services/code/auto-compact-attempt.d.ts +46 -0
  349. package/dist/services/code/auto-compact-attempt.js +88 -0
  350. package/dist/services/code/auto-compact-decision.d.ts +74 -0
  351. package/dist/services/code/auto-compact-decision.js +149 -0
  352. package/dist/services/code/auto-compact-dispatch-gate.d.ts +36 -0
  353. package/dist/services/code/auto-compact-dispatch-gate.js +86 -0
  354. package/dist/services/code/auto-compact-envelopes.d.ts +33 -0
  355. package/dist/services/code/auto-compact-envelopes.js +134 -0
  356. package/dist/services/code/auto-compact-history.d.ts +46 -0
  357. package/dist/services/code/auto-compact-history.js +17 -0
  358. package/dist/services/code/auto-compact-orchestrator.d.ts +11 -240
  359. package/dist/services/code/auto-compact-orchestrator.js +165 -686
  360. package/dist/services/code/auto-compact-run-types.d.ts +123 -0
  361. package/dist/services/code/auto-compact-run-types.js +1 -0
  362. package/dist/services/code/emit-handoff.d.ts +35 -1
  363. package/dist/services/code/emit-handoff.js +128 -7
  364. package/dist/services/code/step-08-gate.d.ts +28 -19
  365. package/dist/services/code/step-08-gate.js +92 -35
  366. package/dist/services/config/config-coercion.d.ts +7 -0
  367. package/dist/services/config/config-coercion.js +156 -0
  368. package/dist/services/config/config-file-io.d.ts +11 -0
  369. package/dist/services/config/config-file-io.js +61 -0
  370. package/dist/services/config/config-get.d.ts +2 -0
  371. package/dist/services/config/config-get.js +36 -0
  372. package/dist/services/config/config-global-loader.d.ts +15 -0
  373. package/dist/services/config/config-global-loader.js +111 -0
  374. package/dist/services/config/config-nested-path.d.ts +3 -0
  375. package/dist/services/config/config-nested-path.js +53 -0
  376. package/dist/services/config/config-primitives.d.ts +16 -0
  377. package/dist/services/config/config-primitives.js +24 -0
  378. package/dist/services/config/config-service.d.ts +9 -33
  379. package/dist/services/config/config-service.js +16 -665
  380. package/dist/services/config/config-validation.d.ts +19 -0
  381. package/dist/services/config/config-validation.js +152 -0
  382. package/dist/services/config/config-workspace.d.ts +10 -0
  383. package/dist/services/config/config-workspace.js +158 -0
  384. package/dist/services/skills/hooks-settings-deny-list.d.ts +61 -0
  385. package/dist/services/skills/hooks-settings-deny-list.js +173 -0
  386. package/dist/services/skills/hooks-settings-envelopes.d.ts +20 -0
  387. package/dist/services/skills/hooks-settings-envelopes.js +79 -0
  388. package/dist/services/skills/hooks-settings-file-shape.d.ts +43 -0
  389. package/dist/services/skills/hooks-settings-file-shape.js +207 -0
  390. package/dist/services/skills/hooks-settings-paths.d.ts +34 -0
  391. package/dist/services/skills/hooks-settings-paths.js +75 -0
  392. package/dist/services/skills/hooks-settings-read-installed.d.ts +39 -0
  393. package/dist/services/skills/hooks-settings-read-installed.js +60 -0
  394. package/dist/services/skills/hooks-settings-service.d.ts +12 -212
  395. package/dist/services/skills/hooks-settings-service.js +71 -657
  396. package/dist/services/skills/hooks-settings-types.d.ts +139 -0
  397. package/dist/services/skills/hooks-settings-types.js +1 -0
  398. package/dist/services/workspace/claude-settings-template-merge.d.ts +89 -0
  399. package/dist/services/workspace/claude-settings-template-merge.js +243 -0
  400. package/dist/services/workspace/claude-settings-template.d.ts +29 -87
  401. package/dist/services/workspace/claude-settings-template.js +81 -236
  402. package/package.json +5 -5
@@ -1,324 +1,26 @@
1
1
  /**
2
+ * `peaks qa run` — the peaks-qa slice surface, and `peaks qa archive-screenshots`
3
+ * — the Contract 1 remediation. The verbs live beside this file:
2
4
  *
3
- * `peaks qa run` — runs a peaks-qa slice for the active project.
5
+ * `qa-run-command.ts` the slice action (I/O + envelope)
6
+ * `qa-run-slice.ts` the pure gate list it drives
7
+ * `qa-run-options.ts` the `--no-X` flag contract
8
+ * `qa-context-prestep.ts` Plan 1 / Task 9 context build
9
+ * `qa-archive-screenshots-command.ts` the stray-screenshot sweep
4
10
  *
5
- * The slice is the user-facing surface for the QA gate family
6
- * (functional / security / browser E2E). The browser-E2E gate
7
- * specifically is what the restart-loop detector guards. The
8
- * detector is wired into the slice here:
9
- *
10
- * 1. We construct a `BrowserRestartDetector` (configurable via
11
- * `--max-browser-restarts` / `--no-restart-detector`).
12
- * 2. We construct a `BrowserEventLogger` that writes the
13
- * per-slice JSONL log to
14
- * `.peaks/_runtime/<session-id>/qa/browser-events.jsonl`.
15
- * 3. The slice entry exposes `runQaSlice` so tests can
16
- * feed a synthetic event log and assert the diagnostic.
17
- *
18
- * CLI surface (PRD G5 + AC4/AC5/AC6):
19
- * peaks qa run --project <X> [--no-browser] [--max-browser-restarts N]
20
- * [--no-restart-detector] [--session-id <sid>] [--json]
21
- *
22
- * `--no-browser` (G5) skips the browser E2E gate entirely. The
23
- * resulting gate list marks the browser gate as `status: skipped`
24
- * with reason `--no-browser`. This is a slice-level opt-out for
25
- * backend-only or already-covered-by-unit-tests work.
26
- */
27
- import { join, resolve } from 'node:path';
28
- import { addJsonOption, printResult } from '../cli-helpers.js';
29
- import { fail, ok } from 'peaks-loop-shared/result';
30
- import { archiveScreenshots } from '../../services/qa/screenshot-archive-service.js';
31
- import { isUnsafePathInput } from '../../shared/path-safety.js';
32
- import { getSessionId } from '../../services/session/session-manager.js';
33
- import { BrowserRestartDetector } from '../../services/qa/browser-restart-detector.js';
34
- import { BrowserEventLogger } from '../../services/qa/browser-event-logger.js';
35
- import { BROWSER_REUSE_HINT } from '../../services/qa/browser-reuse-hint.js';
36
- // Plan 1 / Task 9 — auto-build peaks-context before peaks-qa runs.
37
- import { buildContext } from '../../services/context/context-builder.js';
38
- // Plan 1 / Task 10 — production fetcher (replaces mockFetcher).
39
- import { createDocCacheFetcher } from '../../services/context/doc-cache-fetcher.js';
40
- // Plan 2 / Task 8 — consume MUT.sig from peaks-mut into verdict envelope.
41
- import { loadMutReport, mutReportPath } from 'peaks-loop-mut';
42
- function buildDocFetcher(sid) {
43
- return createDocCacheFetcher({
44
- cacheDir: `.peaks/_runtime/${sid}/doc-cache`
45
- // remoteFetcher wired in a future slice.
46
- });
47
- }
48
- async function ensureContextForQa(goal, project, sid) {
49
- const out = `.peaks/_runtime/${sid}/context.json`;
50
- try {
51
- await buildContext({
52
- goal,
53
- project,
54
- audience: 'peaks-qa',
55
- depsMode: 'locked',
56
- docBudgetTokens: 8000,
57
- out,
58
- fetcher: buildDocFetcher(sid)
59
- });
60
- }
61
- catch (error) {
62
- // Plan 1 / Task 9 — context is a pre-step, not a precondition.
63
- // Task 11 will upgrade this to a hard precondition once the qa
64
- // slice actually consumes context.json.
65
- const message = error instanceof Error ? error.message : 'unknown context build failure';
66
- process.stderr.write(`[peaks-context] qa pre-step skipped: ${message}\n`);
67
- }
68
- }
69
- export const DEFAULT_MAX_BROWSER_RESTARTS = 3;
70
- export function runQaSlice(input) {
71
- // Sid axis: this is the join for `qa/browser-events.jsonl`. The `qa gate run`
72
- // action guards before calling in, but the function is exported for tests and
73
- // states its own contract at the join.
74
- if (isUnsafePathInput(input.sessionId)) {
75
- throw new Error(`Invalid session id: ${input.sessionId} (must be a single path segment)`);
76
- }
77
- const detector = new BrowserRestartDetector({
78
- maxRestarts: input.maxRestarts,
79
- enabled: input.detectorEnabled
80
- });
81
- const logPath = join(input.project, '.peaks', '_runtime', input.sessionId, 'qa', 'browser-events.jsonl');
82
- const logger = new BrowserEventLogger({ filePath: logPath });
83
- let pendingCloseTs = null;
84
- // PRD AC4 + P1: when browser E2E is off, the detector must NOT
85
- // record events at all (otherwise a user passing both
86
- // --no-browser AND a hot detector would see spurious
87
- // detectorTriggered=true and exit code 2).
88
- if (input.browserEnabled) {
89
- for (const ev of input.events) {
90
- detector.record(ev);
91
- if (ev.tool === 'browser_close') {
92
- pendingCloseTs = ev.ts;
93
- }
94
- else if (ev.tool === 'browser_navigate' && pendingCloseTs !== null) {
95
- const closeMs = Date.parse(pendingCloseTs);
96
- const navMs = Date.parse(ev.ts);
97
- logger.append({
98
- kind: 'spurious_restart',
99
- ts: ev.ts,
100
- sessionId: input.sessionId,
101
- closeTs: pendingCloseTs,
102
- navigateTs: ev.ts,
103
- deltaMs: navMs - closeMs
104
- });
105
- pendingCloseTs = null;
106
- }
107
- else if (ev.tool === 'browser_navigate') {
108
- pendingCloseTs = null;
109
- }
110
- }
111
- }
112
- const browserGate = input.browserEnabled
113
- ? detector.shouldHalt()
114
- ? { name: 'browser-e2e', status: 'failed', reason: detector.diagnostic() }
115
- : { name: 'browser-e2e', status: 'passed' }
116
- : { name: 'browser-e2e', status: 'skipped', reason: '--no-browser' };
117
- // Plan 2 / Task 8 — MUT.sig gate.
118
- // Gate semantics (per spec lines 1292-1341):
119
- // - `skipped` when peaks-mut was not run (no report) OR --no-mutation
120
- // - `passed` when the report's `thresholds.passed` is true
121
- // - `failed` when the report's `thresholds.passed` is false
122
- // "Skipped" is NOT a failure — the gate is a no-op so existing
123
- // sessions that have not yet adopted peaks-mut keep passing.
124
- const mutationGate = !input.mutationEnabled
125
- ? { name: 'mutation', status: 'skipped', reason: '--no-mutation' }
126
- : input.mutationReport === null
127
- ? { name: 'mutation', status: 'skipped', reason: 'peaks mut not run' }
128
- : input.mutationReport.thresholds.passed
129
- ? {
130
- name: 'mutation',
131
- status: 'passed',
132
- mutSig: input.mutationReport.sha256
133
- }
134
- : {
135
- name: 'mutation',
136
- status: 'failed',
137
- reason: deriveMutationFailureReason(input.mutationReport),
138
- mutSig: input.mutationReport.sha256
139
- };
140
- const gates = [
141
- { name: 'functional', status: 'passed' },
142
- { name: 'security', status: 'passed' },
143
- browserGate,
144
- mutationGate
145
- ];
146
- return {
147
- sessionId: input.sessionId,
148
- project: input.project,
149
- browserEnabled: input.browserEnabled,
150
- gates,
151
- detectorTriggered: detector.shouldHalt(),
152
- ...(detector.shouldHalt() ? { diagnostic: detector.diagnostic() } : {}),
153
- subAgentPromptHint: BROWSER_REUSE_HINT,
154
- // Surface MUT.sig ONLY when the gate is actually evaluated
155
- // (mutation enabled AND a report was loaded). --no-mutation or
156
- // missing report -> undefined, so downstream consumers cannot
157
- // mistake a skipped gate for a chain-trail anchor.
158
- ...(input.mutationEnabled && input.mutationReport !== null
159
- ? { mutSig: input.mutationReport.sha256 }
160
- : {})
161
- };
162
- }
163
- /**
164
- * Plan 2 / Task 8 — pure helper that explains WHY the mutation gate
165
- * failed. Used only when the report's `thresholds.passed` is false.
166
- * Reads the threshold block from the report itself (already
167
- * CLI-computed by `buildMutReport`) so the message matches what
168
- * peaks-mut's CLI surface prints.
11
+ * This module owns only the `qa` parent (hidden) and the registrar order, and
12
+ * re-exports every symbol it used to define so existing importers need no edit.
169
13
  */
170
- function deriveMutationFailureReason(report) {
171
- const t = report.thresholds;
172
- const fragments = [];
173
- if (report.mutation.killRate < t.mutationKillRateMin) {
174
- fragments.push(`mutation kill rate ${report.mutation.killRate.toFixed(2)} < ${t.mutationKillRateMin.toFixed(2)}`);
175
- }
176
- if (report.assertions.weakRate > t.weakAssertionRateMax) {
177
- fragments.push(`weak assertion rate ${report.assertions.weakRate.toFixed(2)} > ${t.weakAssertionRateMax.toFixed(2)}`);
178
- }
179
- if (fragments.length === 0) {
180
- return `mutation thresholds failed (MUT.sig=${report.sha256})`;
181
- }
182
- return `${fragments.join('; ')} (MUT.sig=${report.sha256})`;
183
- }
184
- function resolveMaxRestarts(raw) {
185
- if (raw === undefined)
186
- return DEFAULT_MAX_BROWSER_RESTARTS;
187
- const n = Number.parseInt(raw, 10);
188
- if (Number.isNaN(n) || n < 1) {
189
- return DEFAULT_MAX_BROWSER_RESTARTS;
190
- }
191
- return n;
192
- }
193
- /**
194
- * Commander 12.x sets `options.X = false` for `--no-X` (POSITIVE form),
195
- * not `options.noX = true`. Reads use the positive form; the default is
196
- * `true` and the boolean form is `false` only when the user passes `--no-X`.
197
- *
198
- * Exported for unit testing the parser contract in isolation from
199
- * the rest of the action handler.
200
- */
201
- export function readQaRunOptions(options) {
202
- return {
203
- browserEnabled: options.browser !== false,
204
- detectorEnabled: options.restartDetector !== false,
205
- maxRestarts: resolveMaxRestarts(options.maxBrowserRestarts),
206
- mutationEnabled: options.mutation !== false
207
- };
208
- }
14
+ import { registerQaArchiveScreenshotsCommand } from './qa-archive-screenshots-command.js';
15
+ import { registerQaRunCommand } from './qa-run-command.js';
209
16
  export function registerQaCommands(program, io) {
210
17
  const qa = program
211
18
  .command('qa', { hidden: true })
212
19
  .description('peaks-qa slice: run QA gates (functional / security / browser E2E / mutation) for the active project');
213
- addJsonOption(qa
214
- .command('run')
215
- .description('Run the peaks-qa slice (PRD 2026-06-16-playwright-restart-loop; Plan 2 mut gate)')
216
- .option('--project <path>', 'project the gates evaluate against (default: current directory)', '.')
217
- .option('--session-id <sid>', 'session id; defaults to "ad-hoc" for one-shot runs', 'ad-hoc')
218
- .option('--no-browser', 'skip the browser E2E gate entirely (PRD G5 / AC4)')
219
- .option('--max-browser-restarts <n>', 'halt threshold for close->navigate pairs in this slice (default 3, PRD AC5)', String(DEFAULT_MAX_BROWSER_RESTARTS))
220
- .option('--no-restart-detector', 'disable the restart-loop detector escape hatch (PRD AC6)')
221
- // Plan 2 / Task 8 — MUT.sig gate opt-out (mirrors --no-browser).
222
- .option('--no-mutation', 'skip the mutation gate even if .peaks/_runtime/<sid>/mut/mut-report.json exists')).action(async (options) => {
223
- try {
224
- const { browserEnabled, detectorEnabled, maxRestarts, mutationEnabled } = readQaRunOptions(options);
225
- // Plan 1 / Task 9 — pre-build peaks-context before peaks-qa runs.
226
- // Goal is audience-scoped doc retrieval only; pass a placeholder
227
- // when the user did not supply one.
228
- const qaProject = options.project;
229
- const qaSid = options.sessionId ?? 'ad-hoc';
230
- // Sid axis. `--session-id` reaches three consumers below — the context
231
- // pre-build, `loadMutReport`, and `runQaSlice`'s
232
- // `qa/browser-events.jsonl` join — so one guard at resolution covers all
233
- // three. (`peaks qa archive-screenshots` has its own, separate join.)
234
- if (isUnsafePathInput(qaSid)) {
235
- printResult(io, fail('qa.gate', 'INVALID_SESSION_ID', `Invalid session id: ${qaSid} (must be a single path segment)`, { provided: qaSid }, ['Pass a session id that is a single path segment']), options.json);
236
- process.exitCode = 1;
237
- return;
238
- }
239
- await ensureContextForQa('qa gate run', qaProject, qaSid);
240
- // Plan 2 / Task 8 — load peaks-mut's report (MUT.sig) if present.
241
- // Returns null when peaks-mut was not run; the gate treats that
242
- // as `skipped`, never as `failed`. loadMutReport itself never
243
- // throws (per its docstring) so this is safe in the action.
244
- const mutationReport = mutationEnabled ? await loadMutReport(qaSid) : null;
245
- // Production slice: no synthetic events to feed; in real
246
- // dogfood the LLM tool dispatcher would push events into the
247
- // detector. Here we record an empty event log so the
248
- // gate-list shape is stable for downstream parsers.
249
- const result = runQaSlice({
250
- project: options.project,
251
- sessionId: options.sessionId ?? 'ad-hoc',
252
- browserEnabled,
253
- maxRestarts,
254
- detectorEnabled,
255
- events: [],
256
- mutationReport,
257
- mutationEnabled
258
- });
259
- const mutationGate = result.gates.find((g) => g.name === 'mutation');
260
- const mutationFailed = mutationGate?.status === 'failed';
261
- const nextActions = result.detectorTriggered
262
- ? [
263
- 'Stop the slice and inspect the diagnostic above',
264
- 'Re-run with --no-restart-detector if the close/reopen was intentional',
265
- 'See .peaks/memory/playwright-restart-loop-2026-06-16.md'
266
- ]
267
- : mutationFailed
268
- ? [
269
- 'Re-run peaks mut and address the threshold breaches (see reason)',
270
- 'Re-run with --no-mutation to bypass the gate for this slice',
271
- `mut-report path: ${mutReportPath(qaSid)}`
272
- ]
273
- : browserEnabled
274
- ? ['No action required; browser gate passed']
275
- : ['Browser E2E skipped; run without --no-browser when the slice needs E2E'];
276
- printResult(io, ok('qa.run', result, [], nextActions), options.json);
277
- if (result.detectorTriggered || mutationFailed) {
278
- process.exitCode = 2;
279
- }
280
- }
281
- catch (error) {
282
- printResult(io, fail('qa.run', 'QA_RUN_FAILED', error instanceof Error ? error.message : 'Unknown error', { project: options.project }, ['Check the project path and rerun']), options.json);
283
- process.exitCode = 1;
284
- }
285
- });
286
- // Enforces peaks-qa SKILL.md "Hard contracts for browser validation"
287
- // Contract 1: every Playwright `browser_take_screenshot` MUST land under
288
- // `.peaks/_runtime/<sessionId>/qa/screenshots/`, not at the project root.
289
- // When the LLM forgets to pass `filename`, Playwright MCP scatters
290
- // `.png` files at the repo top level. This subcommand is the
291
- // remediation: scan `--source` (default: project root) and move stray
292
- // screenshots into `.peaks/_runtime/<session-id>/qa/screenshots/`.
293
- addJsonOption(qa
294
- .command('archive-screenshots')
295
- .description('Move stray Playwright screenshots (.png/.jpg/.jpeg) from the ' +
296
- 'project root into .peaks/_runtime/<session-id>/qa/screenshots/. ' +
297
- 'Enforces peaks-qa SKILL.md Contract 1.')
298
- .option('--source <dir>', 'directory to scan for stray screenshots (default: project root)', '.')
299
- .option('--project <path>', 'project root (default: cwd)', '.')
300
- .option('--session-id <sid>', 'target session id; defaults to the active session', '')).action((options) => {
301
- try {
302
- const projectRoot = resolve(options.project);
303
- const sid = options.sessionId?.trim() || getSessionId(projectRoot) || 'ad-hoc';
304
- // Sid axis. Guarded after resolution so the flag value and the session
305
- // binding are both covered. `archiveScreenshots` cannot do this itself:
306
- // it only ever sees a fully-resolved `targetDir`.
307
- if (isUnsafePathInput(sid)) {
308
- throw new Error(`Invalid session id: ${sid} (must be a single path segment)`);
309
- }
310
- const targetDir = join(projectRoot, '.peaks', '_runtime', sid, 'qa', 'screenshots');
311
- const envelope = archiveScreenshots({ sourceDir: options.source, targetDir });
312
- printResult(io, ok('qa.archive-screenshots', envelope, [], envelope.moved.length === 0
313
- ? ['No stray screenshots found in ' + envelope.scannedSource]
314
- : [
315
- `Moved ${envelope.moved.length} file(s) to ${envelope.targetDir}`,
316
- 'Re-run peaks qa run to verify the gate passes'
317
- ]), options.json);
318
- }
319
- catch (error) {
320
- process.exitCode = 1;
321
- printResult(io, fail('qa.archive-screenshots', 'ARCHIVE_FAILED', error instanceof Error ? error.message : 'Unknown error', { project: options.project, source: options.source }, ['Verify the source dir exists and is readable']), options.json);
322
- }
323
- });
20
+ registerQaRunCommand(qa, io);
21
+ registerQaArchiveScreenshotsCommand(qa, io);
324
22
  }
23
+ // Re-export for tests / external consumers; the implementations moved to the
24
+ // modules above with the split.
25
+ export { readQaRunOptions } from './qa-run-options.js';
26
+ export { DEFAULT_MAX_BROWSER_RESTARTS, runQaSlice } from './qa-run-slice.js';
@@ -0,0 +1 @@
1
+ export declare function ensureContextForQa(goal: string, project: string, sid: string): Promise<void>;
@@ -0,0 +1,34 @@
1
+ // src/cli/commands/qa-context-prestep.ts
2
+ //
3
+ // Plan 1 / Task 9 — the peaks-context build that runs BEFORE a peaks-qa slice.
4
+ // Extracted from `qa-commands.ts`; the cache dir, the token budget and the
5
+ // never-block contract are unchanged.
6
+ import { buildContext } from '../../services/context/context-builder.js';
7
+ import { createDocCacheFetcher } from '../../services/context/doc-cache-fetcher.js';
8
+ function buildDocFetcher(sid) {
9
+ return createDocCacheFetcher({
10
+ cacheDir: `.peaks/_runtime/${sid}/doc-cache`
11
+ // remoteFetcher wired in a future slice.
12
+ });
13
+ }
14
+ export async function ensureContextForQa(goal, project, sid) {
15
+ const out = `.peaks/_runtime/${sid}/context.json`;
16
+ try {
17
+ await buildContext({
18
+ goal,
19
+ project,
20
+ audience: 'peaks-qa',
21
+ depsMode: 'locked',
22
+ docBudgetTokens: 8000,
23
+ out,
24
+ fetcher: buildDocFetcher(sid)
25
+ });
26
+ }
27
+ catch (error) {
28
+ // Plan 1 / Task 9 — context is a pre-step, not a precondition.
29
+ // Task 11 will upgrade this to a hard precondition once the qa
30
+ // slice actually consumes context.json.
31
+ const message = error instanceof Error ? error.message : 'unknown context build failure';
32
+ process.stderr.write(`[peaks-context] qa pre-step skipped: ${message}\n`);
33
+ }
34
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import { type ProgramIO } from '../cli-helpers.js';
3
+ export declare function registerQaRunCommand(qa: Command, io: ProgramIO): void;
@@ -0,0 +1,105 @@
1
+ // src/cli/commands/qa-run-command.ts
2
+ //
3
+ // `peaks qa run` — the peaks-qa slice (functional / security / browser E2E /
4
+ // mutation gates) for the active project. Extracted from `qa-commands.ts`:
5
+ //
6
+ // 1. `--no-browser` (G5) skips the browser E2E gate entirely; the resulting
7
+ // gate list marks it `status: skipped`, reason `--no-browser`. This is a
8
+ // slice-level opt-out for backend-only or already-covered-by-unit-tests
9
+ // work.
10
+ // 2. Plan 2 / Task 8 — `loadMutReport` supplies the MUT.sig gate; a missing
11
+ // report is `skipped`, never `failed`.
12
+ // 3. The LLM tool dispatcher would push browser events into the detector in
13
+ // real dogfood; here the slice records an empty event log so the gate-list
14
+ // shape stays stable for downstream parsers.
15
+ //
16
+ // The registered name, description, options, envelope and exit codes are
17
+ // unchanged.
18
+ import { fail, ok } from 'peaks-loop-shared/result';
19
+ import { loadMutReport, mutReportPath } from 'peaks-loop-mut';
20
+ import { isUnsafePathInput } from '../../shared/path-safety.js';
21
+ import { addJsonOption, printResult } from '../cli-helpers.js';
22
+ import { ensureContextForQa } from './qa-context-prestep.js';
23
+ import { readQaRunOptions } from './qa-run-options.js';
24
+ import { DEFAULT_MAX_BROWSER_RESTARTS, runQaSlice } from './qa-run-slice.js';
25
+ export function registerQaRunCommand(qa, io) {
26
+ addJsonOption(qaRunCommand(qa)).action((options) => runQaRun(io, options));
27
+ }
28
+ /** The `run` verb's description and its six options, verbatim. */
29
+ function qaRunCommand(qa) {
30
+ return (qa
31
+ .command('run')
32
+ .description('Run the peaks-qa slice (PRD 2026-06-16-playwright-restart-loop; Plan 2 mut gate)')
33
+ .option('--project <path>', 'project the gates evaluate against (default: current directory)', '.')
34
+ .option('--session-id <sid>', 'session id; defaults to "ad-hoc" for one-shot runs', 'ad-hoc')
35
+ .option('--no-browser', 'skip the browser E2E gate entirely (PRD G5 / AC4)')
36
+ .option('--max-browser-restarts <n>', 'halt threshold for close->navigate pairs in this slice (default 3, PRD AC5)', String(DEFAULT_MAX_BROWSER_RESTARTS))
37
+ .option('--no-restart-detector', 'disable the restart-loop detector escape hatch (PRD AC6)')
38
+ // Plan 2 / Task 8 — MUT.sig gate opt-out (mirrors --no-browser).
39
+ .option('--no-mutation', 'skip the mutation gate even if .peaks/_runtime/<sid>/mut/mut-report.json exists'));
40
+ }
41
+ async function runQaRun(io, options) {
42
+ try {
43
+ const { browserEnabled, detectorEnabled, maxRestarts, mutationEnabled } = readQaRunOptions(options);
44
+ const qaSid = options.sessionId ?? 'ad-hoc';
45
+ // Sid axis. `--session-id` reaches three consumers below — the context
46
+ // pre-build, `loadMutReport`, and `runQaSlice`'s
47
+ // `qa/browser-events.jsonl` join — so one guard at resolution covers all
48
+ // three. (`peaks qa archive-screenshots` has its own, separate join.)
49
+ if (isUnsafePathInput(qaSid)) {
50
+ printResult(io, unsafeSessionEnvelope(qaSid), options.json);
51
+ process.exitCode = 1;
52
+ return;
53
+ }
54
+ // Plan 1 / Task 9 — pre-build peaks-context before peaks-qa runs.
55
+ // Goal is audience-scoped doc retrieval only; pass a placeholder
56
+ // when the user did not supply one.
57
+ await ensureContextForQa('qa gate run', options.project, qaSid);
58
+ const mutationReport = mutationEnabled
59
+ ? await loadMutReport(qaSid)
60
+ : null;
61
+ const result = runQaSlice({
62
+ project: options.project,
63
+ sessionId: qaSid,
64
+ browserEnabled,
65
+ maxRestarts,
66
+ detectorEnabled,
67
+ events: [],
68
+ mutationReport,
69
+ mutationEnabled
70
+ });
71
+ const mutationFailed = result.gates.find((g) => g.name === 'mutation')?.status === 'failed';
72
+ printResult(io, ok('qa.run', result, [], qaRunNextActions({ result, browserEnabled, mutationFailed, qaSid })), options.json);
73
+ if (result.detectorTriggered || mutationFailed) {
74
+ process.exitCode = 2;
75
+ }
76
+ }
77
+ catch (error) {
78
+ printResult(io, fail('qa.run', 'QA_RUN_FAILED', error instanceof Error ? error.message : 'Unknown error', { project: options.project }, ['Check the project path and rerun']), options.json);
79
+ process.exitCode = 1;
80
+ }
81
+ }
82
+ /** The refusal for a `--session-id` that is not a single path segment. */
83
+ function unsafeSessionEnvelope(qaSid) {
84
+ return fail('qa.gate', 'INVALID_SESSION_ID', `Invalid session id: ${qaSid} (must be a single path segment)`, { provided: qaSid }, ['Pass a session id that is a single path segment']);
85
+ }
86
+ /** What the caller should do next, by the gate that decided the slice's outcome. */
87
+ function qaRunNextActions(input) {
88
+ if (input.result.detectorTriggered) {
89
+ return [
90
+ 'Stop the slice and inspect the diagnostic above',
91
+ 'Re-run with --no-restart-detector if the close/reopen was intentional',
92
+ 'See .peaks/memory/playwright-restart-loop-2026-06-16.md'
93
+ ];
94
+ }
95
+ if (input.mutationFailed) {
96
+ return [
97
+ 'Re-run peaks mut and address the threshold breaches (see reason)',
98
+ 'Re-run with --no-mutation to bypass the gate for this slice',
99
+ `mut-report path: ${mutReportPath(input.qaSid)}`
100
+ ];
101
+ }
102
+ return input.browserEnabled
103
+ ? ['No action required; browser gate passed']
104
+ : ['Browser E2E skipped; run without --no-browser when the slice needs E2E'];
105
+ }
@@ -0,0 +1,23 @@
1
+ export type QaRunOptions = {
2
+ project: string;
3
+ browser?: boolean;
4
+ restartDetector?: boolean;
5
+ maxBrowserRestarts?: string;
6
+ sessionId?: string;
7
+ json?: boolean;
8
+ mutation?: boolean;
9
+ };
10
+ /**
11
+ * Commander 12.x sets `options.X = false` for `--no-X` (POSITIVE form),
12
+ * not `options.noX = true`. Reads use the positive form; the default is
13
+ * `true` and the boolean form is `false` only when the user passes `--no-X`.
14
+ *
15
+ * Exported for unit testing the parser contract in isolation from
16
+ * the rest of the action handler.
17
+ */
18
+ export declare function readQaRunOptions(options: QaRunOptions): {
19
+ readonly browserEnabled: boolean;
20
+ readonly detectorEnabled: boolean;
21
+ readonly maxRestarts: number;
22
+ readonly mutationEnabled: boolean;
23
+ };
@@ -0,0 +1,31 @@
1
+ // src/cli/commands/qa-run-options.ts
2
+ //
3
+ // The `peaks qa run` flag contract, parsed in isolation from the action handler
4
+ // so unit tests can assert it without a project on disk. Extracted from
5
+ // `qa-commands.ts`; every default and every reading is unchanged.
6
+ import { DEFAULT_MAX_BROWSER_RESTARTS } from './qa-run-slice.js';
7
+ function resolveMaxRestarts(raw) {
8
+ if (raw === undefined)
9
+ return DEFAULT_MAX_BROWSER_RESTARTS;
10
+ const n = Number.parseInt(raw, 10);
11
+ if (Number.isNaN(n) || n < 1) {
12
+ return DEFAULT_MAX_BROWSER_RESTARTS;
13
+ }
14
+ return n;
15
+ }
16
+ /**
17
+ * Commander 12.x sets `options.X = false` for `--no-X` (POSITIVE form),
18
+ * not `options.noX = true`. Reads use the positive form; the default is
19
+ * `true` and the boolean form is `false` only when the user passes `--no-X`.
20
+ *
21
+ * Exported for unit testing the parser contract in isolation from
22
+ * the rest of the action handler.
23
+ */
24
+ export function readQaRunOptions(options) {
25
+ return {
26
+ browserEnabled: options.browser !== false,
27
+ detectorEnabled: options.restartDetector !== false,
28
+ maxRestarts: resolveMaxRestarts(options.maxBrowserRestarts),
29
+ mutationEnabled: options.mutation !== false
30
+ };
31
+ }
@@ -0,0 +1,41 @@
1
+ import type { MutReportJson } from 'peaks-loop-mut';
2
+ import { type BrowserEvent } from '../../services/qa/browser-restart-detector.js';
3
+ export type QaGateStatus = {
4
+ readonly name: string;
5
+ readonly status: 'passed' | 'skipped' | 'failed';
6
+ readonly reason?: string;
7
+ /**
8
+ * Plan 2 / Task 8 — when the gate consumes an artifact with a
9
+ * deterministic signature, this field carries that signature for
10
+ * downstream audit-trail consumers. Currently set only on the
11
+ * `mutation` gate to MUT.sig (the `sha256` of mut-report.json).
12
+ */
13
+ readonly mutSig?: string;
14
+ };
15
+ export type QaRunResult = {
16
+ readonly sessionId: string;
17
+ readonly project: string;
18
+ readonly browserEnabled: boolean;
19
+ readonly gates: readonly QaGateStatus[];
20
+ readonly detectorTriggered: boolean;
21
+ readonly diagnostic?: string;
22
+ readonly subAgentPromptHint: string;
23
+ /**
24
+ * Plan 2 / Task 8 — MUT.sig when peaks-mut ran in this session.
25
+ * Undefined when peaks-mut was not run (no mut-report.json) or
26
+ * the user passed --no-mutation.
27
+ */
28
+ readonly mutSig?: string;
29
+ };
30
+ export type RunQaSliceInput = {
31
+ readonly project: string;
32
+ readonly sessionId: string;
33
+ readonly browserEnabled: boolean;
34
+ readonly maxRestarts: number;
35
+ readonly detectorEnabled: boolean;
36
+ readonly events: readonly BrowserEvent[];
37
+ readonly mutationReport: MutReportJson | null;
38
+ readonly mutationEnabled: boolean;
39
+ };
40
+ export declare const DEFAULT_MAX_BROWSER_RESTARTS = 3;
41
+ export declare function runQaSlice(input: RunQaSliceInput): QaRunResult;