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
@@ -27,154 +27,84 @@
27
27
  * The CLI does NOT bundle `playwright-mcp`; it shells out to
28
28
  * `npx playwright-mcp@latest` (G22 / NG3). peaks-loop is the lifecycle
29
29
  * orchestrator, not the install medium.
30
+ *
31
+ * The verb implementations live beside this file: `playwright-session-store.ts`
32
+ * (port range, terminal-id derivation, session records, spawn),
33
+ * `playwright-ls-stop-commands.ts` (`ls` / `stop`) and
34
+ * `playwright-browser-command.ts` (`peaks browser action`). Every symbol this
35
+ * path used to export is still exported from it, so importers are unaffected.
30
36
  */
31
- import { createHash } from 'node:crypto';
32
- import { spawn } from 'node:child_process';
33
- import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from 'node:fs';
34
- import { join, dirname, resolve } from 'node:path';
35
37
  import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
36
- import { isUnsafePathInput } from '../../shared/path-safety.js';
37
38
  import { getErrorMessage } from '../cli-helpers.js';
38
- import { runBrowserAction } from '../../services/qa/browser-wrapper-service.js';
39
- export const DEFAULT_PORT = 8931;
40
- export const MAX_PORT = 8949;
41
- const BROWSERS = ['chromium', 'firefox', 'webkit'];
42
- export const PLAYWRIGHT_SESSIONS_DIR = 'playwright-sessions';
43
- export function playwrightSessionsDir(projectRoot) {
44
- return join(projectRoot, '.peaks', '_runtime', PLAYWRIGHT_SESSIONS_DIR);
45
- }
46
- export function sessionFilePath(projectRoot, terminalId) {
47
- // Terminal-id axis. The derived id is already sanitised (`deriveTerminalId`),
48
- // but `--terminal` is caller-supplied and reaches this join unsanitised.
49
- // Measured (repair cycle 1, item 1): `playwright stop --terminal ../../../../X`
50
- // read a session record planted OUTSIDE the project root, sent SIGTERM to the
51
- // pid it named, unlinked that file, and returned `ok: true` — arbitrary
52
- // process termination plus an arbitrary file delete, one flag away. This is
53
- // the join every reader/writer of a session record goes through, so this is
54
- // where the invariant lives.
55
- if (isUnsafePathInput(terminalId)) {
56
- throw new Error(`Invalid terminal id: ${terminalId} (must be a single path segment)`);
57
- }
58
- return join(playwrightSessionsDir(projectRoot), `${terminalId}.json`);
59
- }
60
- /**
61
- * Derive a stable terminal id from the process environment. Prefers
62
- * the platform's own terminal-session id (macOS Terminal, Windows
63
- * Terminal) and falls back to a hash of (ppid, tty).
64
- */
65
- export function deriveTerminalId(env = process.env, ppid = process.ppid) {
66
- const termSession = env.TERM_SESSION_ID;
67
- if (termSession && termSession.length > 0) {
68
- return sanitizeTerminalId(termSession);
69
- }
70
- const wtSession = env.WT_SESSION;
71
- if (wtSession && wtSession.length > 0) {
72
- return sanitizeTerminalId(`wt-${wtSession}`);
73
- }
74
- const tty = env.SSH_TTY ?? 'no-tty';
75
- const hash = createHash('sha256').update(`${ppid}-${tty}`).digest('hex').slice(0, 16);
76
- return `tty-${hash}`;
77
- }
78
- function sanitizeTerminalId(raw) {
79
- return raw.replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 64);
80
- }
39
+ import { BROWSERS, DEFAULT_PORT, MAX_PORT, MAX_TCP_PORT, MIN_PORT, defaultUserDataDir, deriveTerminalId, findFreePort, readSession, resolveUserDataDir, sessionFilePath, spawnPlaywrightMcp, writeSession } from './playwright-session-store.js';
40
+ import { registerBrowserActionCommand } from './playwright-browser-command.js';
41
+ import { registerPlaywrightLsCommand, registerPlaywrightStopCommand } from './playwright-ls-stop-commands.js';
42
+ import { emitFailure, emitSuccess } from './playwright-envelope.js';
43
+ // Re-exported so the split is invisible to importers of THIS path.
44
+ export { DEFAULT_PORT, MAX_PORT, PLAYWRIGHT_SESSIONS_DIR, playwrightSessionsDir, sessionFilePath, deriveTerminalId, findFreePort, listSessions, readSession, writeSession, removeSession, spawnPlaywrightMcp, resolveUserDataDir } from './playwright-session-store.js';
45
+ export { registerBrowserActionCommand } from './playwright-browser-command.js';
81
46
  /**
82
- * Walk port range starting at `start` and return the first port
83
- * that is NOT bound. Defaults: 8931 → 8949. If the range is exhausted,
84
- * returns null.
47
+ * Report an already-running session for this terminal. True when the caller
48
+ * must stop: either the reuse arm returned the existing port, or the conflict
49
+ * arm refused. Conflict: G21 / AC18.
85
50
  */
86
- export async function findFreePort(start = DEFAULT_PORT, max = MAX_PORT, probe = defaultPortProbe) {
87
- for (let p = start; p <= max; p += 1) {
88
- if (await probe(p))
89
- return p;
51
+ function reportExistingSession(json, reuse, existing, terminalId) {
52
+ if (reuse) {
53
+ emitSuccess(json, { reused: true, session: existing }, `reusing existing playwright session on port ${existing.port} (terminal ${terminalId})`);
54
+ return true;
90
55
  }
91
- return null;
92
- }
93
- async function defaultPortProbe(port) {
94
- return new Promise((resolveProbe) => {
95
- const net = require('node:net');
96
- const server = net.createServer();
97
- server.once('error', () => resolveProbe(false));
98
- server.once('listening', () => {
99
- server.close(() => resolveProbe(true));
100
- });
101
- server.listen(port, '127.0.0.1');
102
- });
56
+ emitFailure(json, `CONFLICT: another playwright MCP is already running on port ${existing.port} (terminal ${terminalId}). Reuse it (--reuse) or pick a new port (--port <n>).`, 'CONFLICT');
57
+ return true;
103
58
  }
104
- export function listSessions(projectRoot) {
105
- const dir = playwrightSessionsDir(projectRoot);
106
- if (!existsSync(dir))
107
- return [];
108
- const out = [];
109
- for (const entry of readdirSync(dir)) {
110
- if (!entry.endsWith('.json'))
111
- continue;
112
- try {
113
- const raw = readFileSync(join(dir, entry), 'utf8');
114
- const session = JSON.parse(raw);
115
- out.push(session);
116
- }
117
- catch {
118
- // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
119
- // skip malformed session file
120
- }
59
+ /** Resolve the starting port; null (+ envelope) when `--port` is out of range. */
60
+ function resolveStartPort(json, raw) {
61
+ const startPort = typeof raw === 'number' && Number.isFinite(raw) ? raw : DEFAULT_PORT;
62
+ if (startPort < MIN_PORT || startPort > MAX_TCP_PORT) {
63
+ emitFailure(json, `INVALID_PORT: --port must be between ${MIN_PORT} and ${MAX_TCP_PORT} (got ${startPort})`);
64
+ return null;
121
65
  }
122
- return out;
66
+ return startPort;
123
67
  }
124
- export function readSession(projectRoot, terminalId) {
125
- const path = sessionFilePath(projectRoot, terminalId);
126
- if (!existsSync(path))
127
- return null;
68
+ async function runPlaywrightStart(opts) {
128
69
  try {
129
- return JSON.parse(readFileSync(path, 'utf8'));
130
- }
131
- catch {
132
- // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
133
- return null;
70
+ const projectRoot = resolveCanonicalProjectRoot(opts.project ?? process.cwd());
71
+ const browser = BROWSERS.includes(opts.browser)
72
+ ? opts.browser
73
+ : 'chromium';
74
+ const terminalId = deriveTerminalId();
75
+ const existing = readSession(projectRoot, terminalId);
76
+ if (existing && reportExistingSession(opts.json, opts.reuse, existing, terminalId))
77
+ return;
78
+ const startPort = resolveStartPort(opts.json, opts.port);
79
+ if (startPort === null)
80
+ return;
81
+ const port = await findFreePort(startPort, MAX_PORT);
82
+ if (port === null) {
83
+ emitFailure(opts.json, `PORT_EXHAUSTED: no free port in ${startPort}..${MAX_PORT} range`, 'PORT_EXHAUSTED');
84
+ return;
85
+ }
86
+ const userDataDir = opts.userDataDir
87
+ ? resolveUserDataDir(opts.userDataDir, projectRoot)
88
+ : defaultUserDataDir(projectRoot, terminalId);
89
+ // Spawn the MCP via npx. Detached so it survives our exit.
90
+ const { pid, child } = spawnPlaywrightMcp(port, browser, userDataDir, projectRoot);
91
+ child.unref();
92
+ const session = {
93
+ terminalId,
94
+ port,
95
+ browser,
96
+ userDataDir,
97
+ startedAt: new Date().toISOString(),
98
+ ...(pid !== undefined ? { pid } : {})
99
+ };
100
+ writeSession(projectRoot, session);
101
+ emitSuccess(opts.json, { session, sessionFile: sessionFilePath(projectRoot, terminalId) }, `playwright MCP started on port ${port} (browser=${browser}, terminal=${terminalId})`);
134
102
  }
135
- }
136
- export function writeSession(projectRoot, session) {
137
- const path = sessionFilePath(projectRoot, session.terminalId);
138
- const dir = dirname(path);
139
- if (!existsSync(dir)) {
140
- mkdirSync(dir, { recursive: true });
103
+ catch (error) {
104
+ emitFailure(opts.json, getErrorMessage(error));
141
105
  }
142
- writeFileSync(path, JSON.stringify(session, null, 2) + '\n', 'utf8');
143
- }
144
- export function removeSession(projectRoot, terminalId) {
145
- const path = sessionFilePath(projectRoot, terminalId);
146
- if (!existsSync(path))
147
- return false;
148
- unlinkSync(path);
149
- return true;
150
- }
151
- /**
152
- * Spawn the playwright MCP via npx. We do NOT bundle the binary;
153
- * we just orchestrate the lifecycle. Returns the child PID so the
154
- * session file can record it.
155
- */
156
- export function spawnPlaywrightMcp(port, browser, userDataDir, projectRoot) {
157
- const child = spawn('npx', [
158
- 'playwright-mcp@latest',
159
- `--port=${port}`,
160
- `--browser=${browser}`,
161
- `--user-data-dir=${userDataDir}`
162
- ], {
163
- cwd: projectRoot,
164
- env: process.env,
165
- stdio: 'ignore',
166
- detached: true,
167
- windowsHide: true
168
- });
169
- return { pid: child.pid, child };
170
106
  }
171
- export function registerPlaywrightCommands(program, _io) {
172
- const playwright = program
173
- .command('playwright')
174
- .description('Multi-terminal Playwright MCP lifecycle. `peaks playwright start` allocates a unique port ' +
175
- '(8931→8949) and writes a session file; `ls` lists running sessions; `stop` tears them down. ' +
176
- 'Does NOT bundle the playwright-mcp binary (uses `npx playwright-mcp@latest`). ' +
177
- '(slice 2.5.0 sub-fix C)');
107
+ function registerPlaywrightStartCommand(playwright) {
178
108
  playwright
179
109
  .command('start')
180
110
  .description('Start a Playwright MCP server on a free port; write a session record.')
@@ -184,273 +114,20 @@ export function registerPlaywrightCommands(program, _io) {
184
114
  .option('--reuse', 'if a session is already running for this terminal, return its port instead of erroring')
185
115
  .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
186
116
  .option('--json', 'emit a JSON envelope { ok, data } to stdout')
187
- .action(async (opts) => {
188
- try {
189
- const projectRoot = resolveCanonicalProjectRoot(opts.project ?? process.cwd());
190
- const browser = BROWSERS.includes(opts.browser)
191
- ? opts.browser
192
- : 'chromium';
193
- const terminalId = deriveTerminalId();
194
- // Existing session for this terminal?
195
- const existing = readSession(projectRoot, terminalId);
196
- if (existing) {
197
- if (opts.reuse) {
198
- if (opts.json === true) {
199
- process.stdout.write(JSON.stringify({
200
- ok: true,
201
- data: { reused: true, session: existing }
202
- }) + '\n');
203
- }
204
- else {
205
- process.stdout.write(`reusing existing playwright session on port ${existing.port} (terminal ${terminalId})\n`);
206
- }
207
- return;
208
- }
209
- // Conflict: G21 / AC18
210
- const msg = `CONFLICT: another playwright MCP is already running on port ${existing.port} (terminal ${terminalId}). Reuse it (--reuse) or pick a new port (--port <n>).`;
211
- if (opts.json === true) {
212
- process.stdout.write(JSON.stringify({ ok: false, error: msg, code: 'CONFLICT' }) + '\n');
213
- }
214
- else {
215
- process.stderr.write(msg + '\n');
216
- }
217
- process.exitCode = 1;
218
- return;
219
- }
220
- // Port allocation
221
- const startPort = typeof opts.port === 'number' && Number.isFinite(opts.port) ? opts.port : DEFAULT_PORT;
222
- if (startPort < 1024 || startPort > 65535) {
223
- const msg = `INVALID_PORT: --port must be between 1024 and 65535 (got ${startPort})`;
224
- if (opts.json === true) {
225
- process.stdout.write(JSON.stringify({ ok: false, error: msg }) + '\n');
226
- }
227
- else {
228
- process.stderr.write(msg + '\n');
229
- }
230
- process.exitCode = 1;
231
- return;
232
- }
233
- const port = await findFreePort(startPort, MAX_PORT);
234
- if (port === null) {
235
- const msg = `PORT_EXHAUSTED: no free port in ${startPort}..${MAX_PORT} range`;
236
- if (opts.json === true) {
237
- process.stdout.write(JSON.stringify({ ok: false, error: msg, code: 'PORT_EXHAUSTED' }) + '\n');
238
- }
239
- else {
240
- process.stderr.write(msg + '\n');
241
- }
242
- process.exitCode = 1;
243
- return;
244
- }
245
- // userDataDir default
246
- const userDataDir = opts.userDataDir
247
- ? resolveUserDataDir(opts.userDataDir, projectRoot)
248
- : join(projectRoot, '.peaks', '_runtime', 'playwright-userdata', terminalId);
249
- // Spawn the MCP via npx. Detached so it survives our exit.
250
- const { pid, child } = spawnPlaywrightMcp(port, browser, userDataDir, projectRoot);
251
- // Detach: do not wait for it.
252
- child.unref();
253
- const session = {
254
- terminalId,
255
- port,
256
- browser,
257
- userDataDir,
258
- startedAt: new Date().toISOString(),
259
- ...(pid !== undefined ? { pid } : {})
260
- };
261
- writeSession(projectRoot, session);
262
- if (opts.json === true) {
263
- process.stdout.write(JSON.stringify({
264
- ok: true,
265
- data: { session, sessionFile: sessionFilePath(projectRoot, terminalId) }
266
- }) + '\n');
267
- }
268
- else {
269
- process.stdout.write(`playwright MCP started on port ${port} (browser=${browser}, terminal=${terminalId})\n`);
270
- }
271
- }
272
- catch (error) {
273
- if (opts.json === true) {
274
- process.stdout.write(JSON.stringify({ ok: false, error: getErrorMessage(error) }) + '\n');
275
- }
276
- else {
277
- process.stderr.write(getErrorMessage(error) + '\n');
278
- }
279
- process.exitCode = 1;
280
- }
281
- });
282
- playwright
283
- .command('ls')
284
- .description('List running Playwright MCP sessions from .peaks/_runtime/playwright-sessions/*.json')
285
- .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
286
- .option('--json', 'emit a JSON envelope { ok, data: { sessions } }')
287
- .action((opts) => {
288
- try {
289
- const projectRoot = resolveCanonicalProjectRoot(opts.project ?? process.cwd());
290
- const sessions = listSessions(projectRoot);
291
- if (opts.json === true) {
292
- process.stdout.write(JSON.stringify({ ok: true, data: { sessions } }) + '\n');
293
- }
294
- else if (sessions.length === 0) {
295
- process.stdout.write('no playwright sessions running\n');
296
- }
297
- else {
298
- for (const s of sessions) {
299
- process.stdout.write(`port=${s.port}\tbrowser=${s.browser}\tterminal=${s.terminalId}\tpid=${s.pid ?? '?'}\tstarted=${s.startedAt}\n`);
300
- }
301
- }
302
- }
303
- catch (error) {
304
- if (opts.json === true) {
305
- process.stdout.write(JSON.stringify({ ok: false, error: getErrorMessage(error) }) + '\n');
306
- }
307
- else {
308
- process.stderr.write(getErrorMessage(error) + '\n');
309
- }
310
- process.exitCode = 1;
311
- }
312
- });
313
- playwright
314
- .command('stop')
315
- .description('Stop a running Playwright MCP session (best-effort kill + remove session file).')
316
- .option('--terminal <id>', "terminal id to stop (default: this shell's derived terminal id)")
317
- .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
318
- .option('--json', 'emit a JSON envelope { ok, data }')
319
- .action((opts) => {
320
- try {
321
- const projectRoot = resolveCanonicalProjectRoot(opts.project ?? process.cwd());
322
- const terminalId = opts.terminal ?? deriveTerminalId();
323
- const session = readSession(projectRoot, terminalId);
324
- if (!session) {
325
- const msg = `NO_SESSION: no playwright session for terminal ${terminalId}`;
326
- if (opts.json === true) {
327
- process.stdout.write(JSON.stringify({ ok: false, error: msg }) + '\n');
328
- }
329
- else {
330
- process.stderr.write(msg + '\n');
331
- }
332
- process.exitCode = 1;
333
- return;
334
- }
335
- // Best-effort kill
336
- if (session.pid !== undefined && session.pid !== null) {
337
- try {
338
- process.kill(session.pid, 'SIGTERM');
339
- }
340
- catch {
341
- // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
342
- /* process may have already exited */
343
- }
344
- }
345
- removeSession(projectRoot, terminalId);
346
- if (opts.json === true) {
347
- process.stdout.write(JSON.stringify({ ok: true, data: { stopped: session } }) + '\n');
348
- }
349
- else {
350
- process.stdout.write(`stopped playwright session on port ${session.port} (terminal ${terminalId})\n`);
351
- }
352
- }
353
- catch (error) {
354
- if (opts.json === true) {
355
- process.stdout.write(JSON.stringify({ ok: false, error: getErrorMessage(error) }) + '\n');
356
- }
357
- else {
358
- process.stderr.write(getErrorMessage(error) + '\n');
359
- }
360
- process.exitCode = 1;
361
- }
362
- });
117
+ .action((opts) => runPlaywrightStart(opts));
118
+ }
119
+ export function registerPlaywrightCommands(program, io) {
120
+ const playwright = program
121
+ .command('playwright')
122
+ .description('Multi-terminal Playwright MCP lifecycle. `peaks playwright start` allocates a unique port ' +
123
+ '(8931→8949) and writes a session file; `ls` lists running sessions; `stop` tears them down. ' +
124
+ 'Does NOT bundle the playwright-mcp binary (uses `npx playwright-mcp@latest`). ' +
125
+ '(slice 2.5.0 sub-fix C)');
126
+ registerPlaywrightStartCommand(playwright);
127
+ registerPlaywrightLsCommand(playwright, io);
128
+ registerPlaywrightStopCommand(playwright, io);
363
129
  // Slice 3: `peaks browser action <intent> [args...]` — thin wrapper
364
130
  // around 5 Playwright MCP intents. One MCP call per invocation; no
365
131
  // auto-snapshot between intents. See src/services/qa/browser-wrapper-service.ts.
366
132
  registerBrowserActionCommand(program);
367
133
  }
368
- /**
369
- * Wire `peaks browser action <intent>`. The wrapper is a thin adapter
370
- * for the 5 intents. The real MCP caller is provided by the IDE / agent
371
- * harness — this CLI surface is invoked by tests and skills to drive
372
- * browser flows without hand-shelling the MCP protocol.
373
- */
374
- export function registerBrowserActionCommand(program) {
375
- const browser = program
376
- .command('browser')
377
- .description('Browser action helpers (slice 3: thin Playwright MCP wrapper, 5 intents only)');
378
- browser
379
- .command('action')
380
- .description('Run one of 5 browser intents: navigate, click, fill, snapshot, extract')
381
- .argument('<intent>', 'one of: navigate, click, fill, snapshot, extract')
382
- .option('--url <url>', 'URL (navigate)')
383
- .option('--selector <selector>', 'simple selector: #id, .class, tag, tag#id, tag.class')
384
- .option('--value <value>', 'value to fill')
385
- .option('--expression <expr>', 'JS expression to evaluate (extract)')
386
- .option('--json', 'emit JSON envelope')
387
- .action(async (intent, opts) => {
388
- try {
389
- if (!isSupportedIntent(intent)) {
390
- throw new Error(`unknown intent "${intent}" — fall back to raw MCP (supported: navigate, click, fill, snapshot, extract)`);
391
- }
392
- // The IDE/agent harness bridges `mcp__playwright__browser_*` tools.
393
- // Outside the harness, we use a pass-through caller that records
394
- // the intent + args so skills and tests can route the call.
395
- const result = await runBrowserAction(intent, {
396
- url: opts.url,
397
- selector: opts.selector,
398
- value: opts.value,
399
- expression: opts.expression
400
- }, mockOrPassThroughCaller);
401
- if (opts.json === true) {
402
- process.stdout.write(JSON.stringify({ ok: true, data: result }) + '\n');
403
- }
404
- else {
405
- process.stdout.write(`intent=${result.intent} ok=${result.ok} elapsedMs=${result.elapsedMs}\n`);
406
- }
407
- }
408
- catch (error) {
409
- if (opts.json === true) {
410
- process.stdout.write(JSON.stringify({ ok: false, error: getErrorMessage(error) }) + '\n');
411
- }
412
- else {
413
- process.stderr.write(getErrorMessage(error) + '\n');
414
- }
415
- process.exitCode = 1;
416
- }
417
- });
418
- }
419
- function isSupportedIntent(value) {
420
- return (value === 'navigate' ||
421
- value === 'click' ||
422
- value === 'fill' ||
423
- value === 'snapshot' ||
424
- value === 'extract');
425
- }
426
- /**
427
- * Resolve and validate a caller-supplied `--user-data-dir`. The dir must
428
- * live under `projectRoot` so a malicious `--user-data-dir /etc/foo`
429
- * cannot coerce the playwright-mcp browser into writing state to an
430
- *
431
- * Resolves `..` segments before checking, so a path like
432
- * `<projectRoot>/../escape` is correctly normalized and rejected.
433
- *
434
- * Throws `Error('INVALID_USER_DATA_DIR: ...')` on validation failure;
435
- * the action handler catches and emits the JSON envelope.
436
- */
437
- export function resolveUserDataDir(raw, projectRoot) {
438
- const resolved = resolve(projectRoot, raw);
439
- const rootResolved = resolve(projectRoot) + (projectRoot.endsWith('/') || projectRoot.endsWith('\\') ? '' : '/');
440
- // Use the projectRoot + sep as the prefix; require either an exact
441
- // match or a child path. The `+ '/'` guard prevents sibling-prefix
442
- // collisions (e.g. /home/A/proj2 passes the check for /home/A/proj).
443
- if (resolved !== resolve(projectRoot) && !resolved.startsWith(rootResolved)) {
444
- throw new Error(`INVALID_USER_DATA_DIR: --user-data-dir must resolve to a path under project root ${projectRoot} (got ${resolved})`);
445
- }
446
- return resolved;
447
- }
448
- /**
449
- * Pass-through caller used when the CLI surface is invoked outside the
450
- * harness. In production the IDE/agent harness intercepts the wrapper's
451
- * output and routes the underlying MCP call. Tests inject a stub via
452
- * the `runBrowserAction(..., caller)` overload.
453
- */
454
- async function mockOrPassThroughCaller(tool, args) {
455
- return { tool, args, routedBy: 'peaks-loop-browser-wrapper' };
456
- }
@@ -0,0 +1,8 @@
1
+ /** `{ ok: true, data }` on `--json`, the human line otherwise. */
2
+ export declare function emitSuccess(json: boolean | undefined, data: unknown, text: string): void;
3
+ /**
4
+ * `{ ok: false, error, code? }` on `--json`, the message on stderr otherwise.
5
+ * Always marks the run failed — every call site in the playwright verbs is a
6
+ * failure path.
7
+ */
8
+ export declare function emitFailure(json: boolean | undefined, message: string, code?: string): void;
@@ -0,0 +1,29 @@
1
+ // src/cli/commands/playwright-envelope.ts
2
+ //
3
+ // The two envelope writers every `peaks playwright` action handler shares.
4
+ // Split out of `playwright-commands.ts` so the extracted verb modules emit
5
+ // byte-identical envelopes without repeating the branch.
6
+ /** `{ ok: true, data }` on `--json`, the human line otherwise. */
7
+ export function emitSuccess(json, data, text) {
8
+ if (json === true) {
9
+ process.stdout.write(JSON.stringify({ ok: true, data }) + '\n');
10
+ }
11
+ else {
12
+ process.stdout.write(text + '\n');
13
+ }
14
+ }
15
+ /**
16
+ * `{ ok: false, error, code? }` on `--json`, the message on stderr otherwise.
17
+ * Always marks the run failed — every call site in the playwright verbs is a
18
+ * failure path.
19
+ */
20
+ export function emitFailure(json, message, code) {
21
+ if (json === true) {
22
+ const payload = code === undefined ? { ok: false, error: message } : { ok: false, error: message, code };
23
+ process.stdout.write(JSON.stringify(payload) + '\n');
24
+ }
25
+ else {
26
+ process.stderr.write(message + '\n');
27
+ }
28
+ process.exitCode = 1;
29
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import { type ProgramIO } from '../cli-helpers.js';
3
+ export declare function registerPlaywrightLsCommand(playwright: Command, io: ProgramIO): void;
4
+ export declare function registerPlaywrightStopCommand(playwright: Command, io: ProgramIO): void;
@@ -0,0 +1,74 @@
1
+ // src/cli/commands/playwright-ls-stop-commands.ts
2
+ //
3
+ // `peaks playwright ls` and `peaks playwright stop`. Split out of
4
+ // `playwright-commands.ts`; the registered names, descriptions, options and
5
+ // envelopes are unchanged.
6
+ import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
7
+ import { getErrorMessage } from '../cli-helpers.js';
8
+ import { deriveTerminalId, listSessions, readSession, removeSession } from './playwright-session-store.js';
9
+ import { emitFailure, emitSuccess } from './playwright-envelope.js';
10
+ export function registerPlaywrightLsCommand(playwright, io) {
11
+ // These two verbs write straight to the process streams — a caller-supplied
12
+ // `io` must not intercept a session listing. `io` stays in the signature for
13
+ // the two-argument registrar contract `_register.ts` selects on.
14
+ void io;
15
+ playwright
16
+ .command('ls')
17
+ .description('List running Playwright MCP sessions from .peaks/_runtime/playwright-sessions/*.json')
18
+ .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
19
+ .option('--json', 'emit a JSON envelope { ok, data: { sessions } }')
20
+ .action((opts) => {
21
+ try {
22
+ const projectRoot = resolveCanonicalProjectRoot(opts.project ?? process.cwd());
23
+ const sessions = listSessions(projectRoot);
24
+ if (opts.json === true) {
25
+ process.stdout.write(JSON.stringify({ ok: true, data: { sessions } }) + '\n');
26
+ }
27
+ else if (sessions.length === 0) {
28
+ process.stdout.write('no playwright sessions running\n');
29
+ }
30
+ else {
31
+ for (const s of sessions) {
32
+ process.stdout.write(`port=${s.port}\tbrowser=${s.browser}\tterminal=${s.terminalId}\tpid=${s.pid ?? '?'}\tstarted=${s.startedAt}\n`);
33
+ }
34
+ }
35
+ }
36
+ catch (error) {
37
+ emitFailure(opts.json, getErrorMessage(error));
38
+ }
39
+ });
40
+ }
41
+ export function registerPlaywrightStopCommand(playwright, io) {
42
+ void io;
43
+ playwright
44
+ .command('stop')
45
+ .description('Stop a running Playwright MCP session (best-effort kill + remove session file).')
46
+ .option('--terminal <id>', "terminal id to stop (default: this shell's derived terminal id)")
47
+ .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
48
+ .option('--json', 'emit a JSON envelope { ok, data }')
49
+ .action((opts) => {
50
+ try {
51
+ const projectRoot = resolveCanonicalProjectRoot(opts.project ?? process.cwd());
52
+ const terminalId = opts.terminal ?? deriveTerminalId();
53
+ const session = readSession(projectRoot, terminalId);
54
+ if (!session) {
55
+ emitFailure(opts.json, `NO_SESSION: no playwright session for terminal ${terminalId}`);
56
+ return;
57
+ }
58
+ if (session.pid !== undefined && session.pid !== null) {
59
+ try {
60
+ process.kill(session.pid, 'SIGTERM');
61
+ }
62
+ catch {
63
+ // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
64
+ /* process may have already exited */
65
+ }
66
+ }
67
+ removeSession(projectRoot, terminalId);
68
+ emitSuccess(opts.json, { stopped: session }, `stopped playwright session on port ${session.port} (terminal ${terminalId})`);
69
+ }
70
+ catch (error) {
71
+ emitFailure(opts.json, getErrorMessage(error));
72
+ }
73
+ });
74
+ }