@wrongstack/cli 0.295.1 → 0.296.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/data/providers.json +0 -24
  2. package/dist/acp-A5OSIU2P.js +824 -0
  3. package/dist/acp-A5OSIU2P.js.map +7 -0
  4. package/dist/acp-server-agent.d.ts.map +1 -1
  5. package/dist/arg-parser.d.ts.map +1 -1
  6. package/dist/audit-2ZSFGNIF.js +102 -0
  7. package/dist/audit-2ZSFGNIF.js.map +7 -0
  8. package/dist/auth-CJWQJVRH.js +504 -0
  9. package/dist/auth-CJWQJVRH.js.map +7 -0
  10. package/dist/auth-menu/auth-menu-audit.d.ts +0 -4
  11. package/dist/auth-menu/auth-menu-audit.d.ts.map +1 -1
  12. package/dist/bench-7ZDWSNEF.js +278 -0
  13. package/dist/bench-7ZDWSNEF.js.map +7 -0
  14. package/dist/boot/brain-decision-log.d.ts +7 -5
  15. package/dist/boot/brain-decision-log.d.ts.map +1 -1
  16. package/dist/boot/dispatch-webui.d.ts +5 -8
  17. package/dist/boot/dispatch-webui.d.ts.map +1 -1
  18. package/dist/boot/system-prompt-builder.d.ts +3 -0
  19. package/dist/boot/system-prompt-builder.d.ts.map +1 -1
  20. package/dist/boot/tui-coordinator-callbacks.d.ts +45 -0
  21. package/dist/boot/tui-coordinator-callbacks.d.ts.map +1 -0
  22. package/dist/boot/tui-project-switch.d.ts +2 -3
  23. package/dist/boot/tui-project-switch.d.ts.map +1 -1
  24. package/dist/boot/tui-runtime-state.d.ts +5 -6
  25. package/dist/boot/tui-runtime-state.d.ts.map +1 -1
  26. package/dist/boot/tui-session-resume.d.ts.map +1 -1
  27. package/dist/boot/tui-settings-adapter.d.ts +2 -3
  28. package/dist/boot/tui-settings-adapter.d.ts.map +1 -1
  29. package/dist/boot.d.ts.map +1 -1
  30. package/dist/brain-menu/panel-service.d.ts.map +1 -1
  31. package/dist/chimera-review-task.d.ts +6 -0
  32. package/dist/chimera-review-task.d.ts.map +1 -0
  33. package/dist/chimera-reviewer-policy.d.ts +34 -0
  34. package/dist/chimera-reviewer-policy.d.ts.map +1 -0
  35. package/dist/chronicle-QQEQFSSE.js +256 -0
  36. package/dist/chronicle-QQEQFSSE.js.map +7 -0
  37. package/dist/chunk-5N34EWJR.js +418 -0
  38. package/dist/chunk-5N34EWJR.js.map +7 -0
  39. package/dist/chunk-66T43Q4Y.js +90 -0
  40. package/dist/chunk-66T43Q4Y.js.map +7 -0
  41. package/dist/chunk-7OCVIDC7.js +11 -0
  42. package/dist/chunk-7OCVIDC7.js.map +7 -0
  43. package/dist/chunk-ABXK4VVY.js +84 -0
  44. package/dist/chunk-ABXK4VVY.js.map +7 -0
  45. package/dist/chunk-AXVZMEWG.js +306 -0
  46. package/dist/chunk-AXVZMEWG.js.map +7 -0
  47. package/dist/chunk-AZESNNIC.js +216 -0
  48. package/dist/chunk-AZESNNIC.js.map +7 -0
  49. package/dist/chunk-BGFM3PD7.js +41 -0
  50. package/dist/chunk-BGFM3PD7.js.map +7 -0
  51. package/dist/chunk-BQCAJ7FI.js +425 -0
  52. package/dist/chunk-BQCAJ7FI.js.map +7 -0
  53. package/dist/chunk-DPJZQCVP.js +13 -0
  54. package/dist/chunk-DPJZQCVP.js.map +7 -0
  55. package/dist/chunk-F4PEGAJZ.js +176 -0
  56. package/dist/chunk-F4PEGAJZ.js.map +7 -0
  57. package/dist/chunk-IHBYBYGA.js +443 -0
  58. package/dist/chunk-IHBYBYGA.js.map +7 -0
  59. package/dist/chunk-JBSQ7ONN.js +1023 -0
  60. package/dist/chunk-JBSQ7ONN.js.map +7 -0
  61. package/dist/chunk-JBTFWWKV.js +1325 -0
  62. package/dist/chunk-JBTFWWKV.js.map +7 -0
  63. package/dist/chunk-JUHRI6OV.js +100 -0
  64. package/dist/chunk-JUHRI6OV.js.map +7 -0
  65. package/dist/chunk-OI7GWJDS.js +3303 -0
  66. package/dist/chunk-OI7GWJDS.js.map +7 -0
  67. package/dist/chunk-OP47B3IX.js +142 -0
  68. package/dist/chunk-OP47B3IX.js.map +7 -0
  69. package/dist/chunk-PJHET45A.js +158 -0
  70. package/dist/chunk-PJHET45A.js.map +7 -0
  71. package/dist/chunk-Q5GTM25S.js +17 -0
  72. package/dist/chunk-Q5GTM25S.js.map +7 -0
  73. package/dist/chunk-QD544J2B.js +19 -0
  74. package/dist/chunk-QD544J2B.js.map +7 -0
  75. package/dist/chunk-QUNHS6O3.js +258 -0
  76. package/dist/chunk-QUNHS6O3.js.map +7 -0
  77. package/dist/chunk-TADVX644.js +480 -0
  78. package/dist/chunk-TADVX644.js.map +7 -0
  79. package/dist/chunk-TGDHN4LM.js +81 -0
  80. package/dist/chunk-TGDHN4LM.js.map +7 -0
  81. package/dist/chunk-TYO2OVAD.js +50 -0
  82. package/dist/chunk-TYO2OVAD.js.map +7 -0
  83. package/dist/chunk-VCYZ3WZV.js +14 -0
  84. package/dist/chunk-VCYZ3WZV.js.map +7 -0
  85. package/dist/chunk-VJUEZZYB.js +29 -0
  86. package/dist/chunk-VJUEZZYB.js.map +7 -0
  87. package/dist/chunk-WHOIR577.js +1 -0
  88. package/dist/chunk-WHOIR577.js.map +7 -0
  89. package/dist/chunk-WY7KKOUK.js +460 -0
  90. package/dist/chunk-WY7KKOUK.js.map +7 -0
  91. package/dist/chunk-XJXDOF63.js +28 -0
  92. package/dist/chunk-XJXDOF63.js.map +7 -0
  93. package/dist/chunk-XWEGWYDU.js +560 -0
  94. package/dist/chunk-XWEGWYDU.js.map +7 -0
  95. package/dist/chunk-YWUPHRGB.js +346 -0
  96. package/dist/chunk-YWUPHRGB.js.map +7 -0
  97. package/dist/chunk-Z7YGASQP.js +313 -0
  98. package/dist/chunk-Z7YGASQP.js.map +7 -0
  99. package/dist/cli-entry-main.d.ts +2 -0
  100. package/dist/cli-entry-main.d.ts.map +1 -0
  101. package/dist/cli-entry-point.d.ts +3 -3
  102. package/dist/cli-entry-point.d.ts.map +1 -1
  103. package/dist/cli-main-RTY35OPD.js +29268 -0
  104. package/dist/cli-main-RTY35OPD.js.map +7 -0
  105. package/dist/cli-main-helpers.d.ts +21 -0
  106. package/dist/cli-main-helpers.d.ts.map +1 -0
  107. package/dist/cli-main.d.ts +25 -1
  108. package/dist/cli-main.d.ts.map +1 -1
  109. package/dist/context-limit.d.ts +48 -0
  110. package/dist/context-limit.d.ts.map +1 -1
  111. package/dist/diag-doctor-OQ3AA63O.js +170 -0
  112. package/dist/diag-doctor-OQ3AA63O.js.map +7 -0
  113. package/dist/execute-deps.d.ts +11 -12
  114. package/dist/execute-deps.d.ts.map +1 -1
  115. package/dist/execution-O7I5DYE6.js +4682 -0
  116. package/dist/execution-O7I5DYE6.js.map +7 -0
  117. package/dist/execution-chimera-ask.d.ts +10 -0
  118. package/dist/execution-chimera-ask.d.ts.map +1 -0
  119. package/dist/execution-chimera-cascade.d.ts +15 -0
  120. package/dist/execution-chimera-cascade.d.ts.map +1 -0
  121. package/dist/execution-cleanup.d.ts +23 -0
  122. package/dist/execution-cleanup.d.ts.map +1 -0
  123. package/dist/execution-kanban-dispatch.d.ts +10 -0
  124. package/dist/execution-kanban-dispatch.d.ts.map +1 -0
  125. package/dist/execution-repl-fleet-callbacks.d.ts +11 -0
  126. package/dist/execution-repl-fleet-callbacks.d.ts.map +1 -0
  127. package/dist/execution-storage-observability.d.ts +3 -0
  128. package/dist/execution-storage-observability.d.ts.map +1 -0
  129. package/dist/execution-tui-next-step-callbacks.d.ts +20 -0
  130. package/dist/execution-tui-next-step-callbacks.d.ts.map +1 -0
  131. package/dist/execution.d.ts +2 -139
  132. package/dist/execution.d.ts.map +1 -1
  133. package/dist/export-TPORYVRZ.js +64 -0
  134. package/dist/export-TPORYVRZ.js.map +7 -0
  135. package/dist/fleet/host-acp-runner-cache.d.ts +9 -0
  136. package/dist/fleet/host-acp-runner-cache.d.ts.map +1 -0
  137. package/dist/fleet/host-acp.d.ts +3 -0
  138. package/dist/fleet/host-acp.d.ts.map +1 -0
  139. package/dist/fleet/host-concurrency.d.ts +2 -0
  140. package/dist/fleet/host-concurrency.d.ts.map +1 -0
  141. package/dist/fleet/host-context.d.ts +5 -0
  142. package/dist/fleet/host-context.d.ts.map +1 -0
  143. package/dist/fleet/host-director-builder.d.ts +24 -0
  144. package/dist/fleet/host-director-builder.d.ts.map +1 -0
  145. package/dist/fleet/host-director-event-bridges.d.ts +37 -0
  146. package/dist/fleet/host-director-event-bridges.d.ts.map +1 -0
  147. package/dist/fleet/host-director-services.d.ts +20 -0
  148. package/dist/fleet/host-director-services.d.ts.map +1 -0
  149. package/dist/fleet/host-event-bridge.d.ts +17 -0
  150. package/dist/fleet/host-event-bridge.d.ts.map +1 -0
  151. package/dist/fleet/host-helpers.d.ts +22 -0
  152. package/dist/fleet/host-helpers.d.ts.map +1 -0
  153. package/dist/fleet/host-learning-tracker.d.ts +11 -0
  154. package/dist/fleet/host-learning-tracker.d.ts.map +1 -0
  155. package/dist/fleet/host-learning.d.ts +4 -0
  156. package/dist/fleet/host-learning.d.ts.map +1 -0
  157. package/dist/fleet/host-lifecycle-events.d.ts +4 -0
  158. package/dist/fleet/host-lifecycle-events.d.ts.map +1 -0
  159. package/dist/fleet/host-paths.d.ts +3 -0
  160. package/dist/fleet/host-paths.d.ts.map +1 -0
  161. package/dist/fleet/host-provider.d.ts +22 -0
  162. package/dist/fleet/host-provider.d.ts.map +1 -0
  163. package/dist/fleet/host-session-writer.d.ts +3 -0
  164. package/dist/fleet/host-session-writer.d.ts.map +1 -0
  165. package/dist/fleet/host-shadow-pass.d.ts +21 -0
  166. package/dist/fleet/host-shadow-pass.d.ts.map +1 -0
  167. package/dist/fleet/host-spawn-types.d.ts +25 -0
  168. package/dist/fleet/host-spawn-types.d.ts.map +1 -0
  169. package/dist/fleet/host-status.d.ts +48 -0
  170. package/dist/fleet/host-status.d.ts.map +1 -0
  171. package/dist/fleet/host-subagent-factory.d.ts +16 -0
  172. package/dist/fleet/host-subagent-factory.d.ts.map +1 -0
  173. package/dist/fleet/host-supervisor.d.ts +16 -0
  174. package/dist/fleet/host-supervisor.d.ts.map +1 -0
  175. package/dist/fleet/host-task-result-report.d.ts +11 -0
  176. package/dist/fleet/host-task-result-report.d.ts.map +1 -0
  177. package/dist/fleet/host-types.d.ts +89 -0
  178. package/dist/fleet/host-types.d.ts.map +1 -0
  179. package/dist/fleet/host.d.ts +10 -357
  180. package/dist/fleet/host.d.ts.map +1 -1
  181. package/dist/hq-JUYKUNJX.js +547 -0
  182. package/dist/hq-JUYKUNJX.js.map +7 -0
  183. package/dist/hq-command-controller.d.ts +2 -2
  184. package/dist/hq-command-controller.d.ts.map +1 -1
  185. package/dist/hq-server/auth.d.ts +15 -4
  186. package/dist/hq-server/auth.d.ts.map +1 -1
  187. package/dist/hq-server/project-root.d.ts +5 -0
  188. package/dist/hq-server/project-root.d.ts.map +1 -0
  189. package/dist/hq-server/routes/auth-handlers.d.ts +25 -0
  190. package/dist/hq-server/routes/auth-handlers.d.ts.map +1 -0
  191. package/dist/hq-server/routes/session-handlers.d.ts +8 -0
  192. package/dist/hq-server/routes/session-handlers.d.ts.map +1 -0
  193. package/dist/hq-server/routes.d.ts +8 -6
  194. package/dist/hq-server/routes.d.ts.map +1 -1
  195. package/dist/hq-server/snapshot.d.ts +44 -0
  196. package/dist/hq-server/snapshot.d.ts.map +1 -1
  197. package/dist/hq-server/types.d.ts +22 -4
  198. package/dist/hq-server/types.d.ts.map +1 -1
  199. package/dist/hq-server/utils.d.ts +8 -0
  200. package/dist/hq-server/utils.d.ts.map +1 -1
  201. package/dist/hq-server/ws.d.ts +1 -1
  202. package/dist/hq-server/ws.d.ts.map +1 -1
  203. package/dist/hq-server-6AQ3BXZA.js +39 -0
  204. package/dist/hq-server-6AQ3BXZA.js.map +7 -0
  205. package/dist/hq-server.d.ts +3 -3
  206. package/dist/hq-server.d.ts.map +1 -1
  207. package/dist/hq-ttl-U2FAYFAT.js +8 -0
  208. package/dist/hq-ttl-U2FAYFAT.js.map +7 -0
  209. package/dist/hq-tunnel-RFKGC4HI.js +114 -0
  210. package/dist/hq-tunnel-RFKGC4HI.js.map +7 -0
  211. package/dist/hq-tunnel.d.ts +1 -1
  212. package/dist/hq-tunnel.d.ts.map +1 -1
  213. package/dist/index.d.ts +2 -1
  214. package/dist/index.d.ts.map +1 -1
  215. package/dist/index.js +2503 -53026
  216. package/dist/index.js.map +4 -4
  217. package/dist/init-E2NDDOHI.js +27 -0
  218. package/dist/init-E2NDDOHI.js.map +7 -0
  219. package/dist/kanban-dispatch-route.d.ts +14 -0
  220. package/dist/kanban-dispatch-route.d.ts.map +1 -0
  221. package/dist/kanban-hq-sync.d.ts +2 -0
  222. package/dist/kanban-hq-sync.d.ts.map +1 -1
  223. package/dist/kanban-run-mirror-EKVNGXWW.js +12 -0
  224. package/dist/kanban-run-mirror-EKVNGXWW.js.map +7 -0
  225. package/dist/live-settings-input.d.ts +69 -0
  226. package/dist/live-settings-input.d.ts.map +1 -0
  227. package/dist/mailbox-serve-2UWHEN3M.js +302 -0
  228. package/dist/mailbox-serve-2UWHEN3M.js.map +7 -0
  229. package/dist/mcp-CYLPUEHC.js +413 -0
  230. package/dist/mcp-CYLPUEHC.js.map +7 -0
  231. package/dist/modeldiag-HENYJ4N7.js +1290 -0
  232. package/dist/modeldiag-HENYJ4N7.js.map +7 -0
  233. package/dist/permissions-FNYLZIL4.js +115 -0
  234. package/dist/permissions-FNYLZIL4.js.map +7 -0
  235. package/dist/picker-key-state.d.ts +7 -0
  236. package/dist/picker-key-state.d.ts.map +1 -0
  237. package/dist/picker-model-picker.d.ts +6 -0
  238. package/dist/picker-model-picker.d.ts.map +1 -0
  239. package/dist/picker-ui.d.ts +17 -0
  240. package/dist/picker-ui.d.ts.map +1 -0
  241. package/dist/picker.d.ts +4 -37
  242. package/dist/picker.d.ts.map +1 -1
  243. package/dist/plugin-usage-OU6X6LM3.js +40 -0
  244. package/dist/plugin-usage-OU6X6LM3.js.map +7 -0
  245. package/dist/plugins-4LJ5IUBI.js +24 -0
  246. package/dist/plugins-4LJ5IUBI.js.map +7 -0
  247. package/dist/pre-launch.d.ts +0 -1
  248. package/dist/pre-launch.d.ts.map +1 -1
  249. package/dist/project-BLQ3ALVL.js +76 -0
  250. package/dist/project-BLQ3ALVL.js.map +7 -0
  251. package/dist/project-manifest-GE25PW4S.js +18 -0
  252. package/dist/project-manifest-GE25PW4S.js.map +7 -0
  253. package/dist/project-picker-BOCWHBXP.js +17 -0
  254. package/dist/project-picker-BOCWHBXP.js.map +7 -0
  255. package/dist/projects-XE76NFNZ.js +38 -0
  256. package/dist/projects-XE76NFNZ.js.map +7 -0
  257. package/dist/provider-helpers.d.ts +22 -6
  258. package/dist/provider-helpers.d.ts.map +1 -1
  259. package/dist/providers-models-GDELBHZK.js +589 -0
  260. package/dist/providers-models-GDELBHZK.js.map +7 -0
  261. package/dist/quick-VIO2BEHS.js +10 -0
  262. package/dist/quick-VIO2BEHS.js.map +7 -0
  263. package/dist/repl-auto-proceed.d.ts +19 -0
  264. package/dist/repl-auto-proceed.d.ts.map +1 -0
  265. package/dist/repl-client-registration.d.ts +7 -0
  266. package/dist/repl-client-registration.d.ts.map +1 -0
  267. package/dist/repl-input.d.ts +11 -0
  268. package/dist/repl-input.d.ts.map +1 -0
  269. package/dist/repl-options.d.ts +54 -0
  270. package/dist/repl-options.d.ts.map +1 -0
  271. package/dist/repl-rendering.d.ts +4 -0
  272. package/dist/repl-rendering.d.ts.map +1 -0
  273. package/dist/repl-suggestions.d.ts +21 -0
  274. package/dist/repl-suggestions.d.ts.map +1 -0
  275. package/dist/repl.d.ts +3 -162
  276. package/dist/repl.d.ts.map +1 -1
  277. package/dist/replay-KCTXNMZQ.js +75 -0
  278. package/dist/replay-KCTXNMZQ.js.map +7 -0
  279. package/dist/rewind-EJMVFVLS.js +185 -0
  280. package/dist/rewind-EJMVFVLS.js.map +7 -0
  281. package/dist/sdd-runtime-JG4EEKL6.js +54 -0
  282. package/dist/sdd-runtime-JG4EEKL6.js.map +7 -0
  283. package/dist/services/sdd/project-context.d.ts +1 -1
  284. package/dist/services/sdd/project-context.d.ts.map +1 -1
  285. package/dist/services/sdd/task-manager.d.ts.map +1 -1
  286. package/dist/services/statusline-config.d.ts +1 -1
  287. package/dist/services/statusline-config.d.ts.map +1 -1
  288. package/dist/session-event-wiring.d.ts +2 -2
  289. package/dist/session-event-wiring.d.ts.map +1 -1
  290. package/dist/sessions-config-NLCMK3BY.js +409 -0
  291. package/dist/sessions-config-NLCMK3BY.js.map +7 -0
  292. package/dist/settings-menu.d.ts +3 -18
  293. package/dist/settings-menu.d.ts.map +1 -1
  294. package/dist/simpleui-dist-JIFGUJO7.js +93 -0
  295. package/dist/simpleui-dist-JIFGUJO7.js.map +7 -0
  296. package/dist/slash-commands/brain.d.ts.map +1 -1
  297. package/dist/slash-commands/clear.d.ts.map +1 -1
  298. package/dist/slash-commands/fallback.d.ts.map +1 -1
  299. package/dist/slash-commands/kanban-agent-helpers.d.ts +18 -0
  300. package/dist/slash-commands/kanban-agent-helpers.d.ts.map +1 -0
  301. package/dist/slash-commands/kanban-format.d.ts +16 -0
  302. package/dist/slash-commands/kanban-format.d.ts.map +1 -0
  303. package/dist/slash-commands/kanban-help.d.ts +2 -0
  304. package/dist/slash-commands/kanban-help.d.ts.map +1 -0
  305. package/dist/slash-commands/kanban.d.ts.map +1 -1
  306. package/dist/slash-commands/mailbox-demo.d.ts.map +1 -1
  307. package/dist/slash-commands/mailbox.d.ts +2 -1
  308. package/dist/slash-commands/mailbox.d.ts.map +1 -1
  309. package/dist/slash-commands/memory-compact.d.ts +5 -0
  310. package/dist/slash-commands/memory-compact.d.ts.map +1 -0
  311. package/dist/slash-commands/memory-flags.d.ts +36 -0
  312. package/dist/slash-commands/memory-flags.d.ts.map +1 -0
  313. package/dist/slash-commands/memory-formatters.d.ts +16 -0
  314. package/dist/slash-commands/memory-formatters.d.ts.map +1 -0
  315. package/dist/slash-commands/memory.d.ts.map +1 -1
  316. package/dist/slash-commands/mouse.d.ts +2 -2
  317. package/dist/slash-commands/review.d.ts.map +1 -1
  318. package/dist/slash-commands/sdd-command-helpers.d.ts +23 -0
  319. package/dist/slash-commands/sdd-command-helpers.d.ts.map +1 -0
  320. package/dist/slash-commands/sdd-format.d.ts +32 -0
  321. package/dist/slash-commands/sdd-format.d.ts.map +1 -0
  322. package/dist/slash-commands/sdd.d.ts.map +1 -1
  323. package/dist/slash-commands/settings.d.ts.map +1 -1
  324. package/dist/subcommands/handlers/chronicle.d.ts.map +1 -1
  325. package/dist/subcommands/handlers/mailbox-serve.d.ts.map +1 -1
  326. package/dist/subcommands/handlers/model-smoke-test.d.ts +51 -0
  327. package/dist/subcommands/handlers/model-smoke-test.d.ts.map +1 -0
  328. package/dist/subcommands/handlers/modeldiag-profiles.d.ts +64 -0
  329. package/dist/subcommands/handlers/modeldiag-profiles.d.ts.map +1 -0
  330. package/dist/subcommands/handlers/modeldiag.d.ts.map +1 -1
  331. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts +3 -0
  332. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts.map +1 -0
  333. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts +3 -0
  334. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts.map +1 -0
  335. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts +36 -0
  336. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts.map +1 -0
  337. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts +18 -0
  338. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts.map +1 -0
  339. package/dist/subcommands/handlers/per-subcommand-help.d.ts +2 -80
  340. package/dist/subcommands/handlers/per-subcommand-help.d.ts.map +1 -1
  341. package/dist/subcommands/handlers/rewind.d.ts.map +1 -1
  342. package/dist/subcommands/index.d.ts +7 -0
  343. package/dist/subcommands/index.d.ts.map +1 -1
  344. package/dist/tools-skills-UNKLOB7M.js +29 -0
  345. package/dist/tools-skills-UNKLOB7M.js.map +7 -0
  346. package/dist/update-YC4TYW2Y.js +16 -0
  347. package/dist/update-YC4TYW2Y.js.map +7 -0
  348. package/dist/update-check-UMYTOH7Z.js +18 -0
  349. package/dist/update-check-UMYTOH7Z.js.map +7 -0
  350. package/dist/version-help-DROHZRW6.js +11 -0
  351. package/dist/version-help-DROHZRW6.js.map +7 -0
  352. package/dist/webui-server/connection-handler.d.ts.map +1 -1
  353. package/dist/webui-server/kanban-host-adapter.d.ts +5 -1
  354. package/dist/webui-server/kanban-host-adapter.d.ts.map +1 -1
  355. package/dist/webui-server/listen-helpers.d.ts +18 -0
  356. package/dist/webui-server/listen-helpers.d.ts.map +1 -0
  357. package/dist/webui-server/node-pty-loader.d.ts +6 -0
  358. package/dist/webui-server/node-pty-loader.d.ts.map +1 -0
  359. package/dist/webui-server-ZF5KVGC5.js +1460 -0
  360. package/dist/webui-server-ZF5KVGC5.js.map +7 -0
  361. package/dist/webui-server-options.d.ts +191 -0
  362. package/dist/webui-server-options.d.ts.map +1 -0
  363. package/dist/webui-server.d.ts +2 -178
  364. package/dist/webui-server.d.ts.map +1 -1
  365. package/dist/wiring/brain-and-orchestration.d.ts.map +1 -1
  366. package/dist/wiring/codebase-index.d.ts.map +1 -1
  367. package/dist/wiring/command-host-state.d.ts +4 -4
  368. package/dist/wiring/dep-watcher-bridge.d.ts +23 -0
  369. package/dist/wiring/dep-watcher-bridge.d.ts.map +1 -0
  370. package/dist/wiring/dep-watcher.d.ts.map +1 -1
  371. package/dist/wiring/hq-telemetry.d.ts +2 -2
  372. package/dist/wiring/lifecycle-plugins.d.ts +4 -3
  373. package/dist/wiring/lifecycle-plugins.d.ts.map +1 -1
  374. package/dist/wiring/mailbox-bridge-bootstrap.d.ts +1 -1
  375. package/dist/wiring/management-tools.d.ts +15 -0
  376. package/dist/wiring/management-tools.d.ts.map +1 -0
  377. package/dist/wiring/pipeline.d.ts +2 -1
  378. package/dist/wiring/pipeline.d.ts.map +1 -1
  379. package/dist/wiring/plugins.d.ts +1 -1
  380. package/dist/wiring/plugins.d.ts.map +1 -1
  381. package/dist/wiring/provider-runtime-setup.d.ts +14 -1
  382. package/dist/wiring/provider-runtime-setup.d.ts.map +1 -1
  383. package/dist/wiring/provider.d.ts.map +1 -1
  384. package/dist/wiring/runtime-controller-deps.d.ts +1 -1
  385. package/dist/wiring/runtime-controller-deps.d.ts.map +1 -1
  386. package/dist/wiring/sage.d.ts.map +1 -1
  387. package/dist/wiring/session-registry.d.ts +38 -0
  388. package/dist/wiring/session-registry.d.ts.map +1 -0
  389. package/dist/wiring/session.d.ts +10 -6
  390. package/dist/wiring/session.d.ts.map +1 -1
  391. package/dist/wiring/tools.d.ts.map +1 -1
  392. package/package.json +22 -22
  393. package/dist/cli-recovery-prompt.d.ts +0 -19
  394. package/dist/cli-recovery-prompt.d.ts.map +0 -1
  395. package/dist/first-run-auth-gate.d.ts +0 -20
  396. package/dist/first-run-auth-gate.d.ts.map +0 -1
  397. package/dist/pre-launch/indexing-question.d.ts +0 -28
  398. package/dist/pre-launch/indexing-question.d.ts.map +0 -1
@@ -0,0 +1,1460 @@
1
+ import {
2
+ createKanbanRunMirror
3
+ } from "./chunk-VCYZ3WZV.js";
4
+ import {
5
+ createHqCommandDispatcher
6
+ } from "./chunk-OP47B3IX.js";
7
+ import {
8
+ startCliHqConnection
9
+ } from "./chunk-WY7KKOUK.js";
10
+ import {
11
+ loadConfigProviders,
12
+ mutateConfigProviders
13
+ } from "./chunk-PJHET45A.js";
14
+ import "./chunk-7OCVIDC7.js";
15
+
16
+ // src/webui-server.ts
17
+ import { findPackageJSON } from "node:module";
18
+ import * as os from "node:os";
19
+ import * as path5 from "node:path";
20
+ import { DefaultSecretScrubber } from "@wrongstack/core/security";
21
+ import { PromptUsageStore, watchProviderConfig } from "@wrongstack/core/storage";
22
+ import { resolveWstackPaths as resolveWstackPaths2, wstackGlobalRoot } from "@wrongstack/core/utils";
23
+ import { TOKENS } from "@wrongstack/core/kernel";
24
+ import { createCompatibilityTrustBoundary } from "@wrongstack/core/security";
25
+ import { SkillInstaller } from "@wrongstack/core/skills";
26
+ import { toErrorMessage } from "@wrongstack/core/utils/error";
27
+ import { makeProviderFromConfig } from "@wrongstack/providers";
28
+ import {
29
+ buildSddWizardDeps,
30
+ buildWebUIAccessUrl,
31
+ createCustomModeStore,
32
+ createEmbeddedMessageRouter,
33
+ createEmbeddedProviderOperations,
34
+ createMailboxRouteHandlers,
35
+ envFlag,
36
+ findFreePort,
37
+ GoalWebSocketHandler,
38
+ resolveAuthToken,
39
+ SddBoardWebSocketHandler,
40
+ SddWizardWebSocketHandler,
41
+ SpecsWebSocketHandler,
42
+ TerminalWebSocketHandler,
43
+ WorktreeWebSocketHandler
44
+ } from "@wrongstack/webui-server";
45
+ import { WebSocket, WebSocketServer } from "ws";
46
+
47
+ // src/webui-server/client-registration.ts
48
+ import { createWebuiClientPresence } from "@wrongstack/webui-server";
49
+ function createWebuiClientRegistration(deps) {
50
+ const control = deps.hqControl;
51
+ return createWebuiClientPresence({
52
+ projectRoot: deps.projectRoot,
53
+ appConfig: deps.appConfig,
54
+ events: deps.events,
55
+ hqSessionId: deps.hqSessionId,
56
+ getSessionId: deps.getSessionId,
57
+ startHqConnection: (options) => startCliHqConnection({
58
+ ...options,
59
+ capabilities: options.capabilities
60
+ }),
61
+ ...control ? {
62
+ createCommandHandler: (mailbox) => createHqCommandDispatcher({
63
+ steerMailbox: mailbox,
64
+ interruptLeader: control.interruptLeader,
65
+ allowRunCommand: control.allowRunCommand,
66
+ sessionTag: deps.getSessionId,
67
+ ...control.spawnAgent ? { spawnAgent: control.spawnAgent } : {},
68
+ ...control.killFleet ? { killFleet: control.killFleet } : {},
69
+ ...control.terminateAgent ? { terminateAgent: control.terminateAgent } : {}
70
+ })
71
+ } : {}
72
+ });
73
+ }
74
+
75
+ // src/webui-server/connection-handler.ts
76
+ import {
77
+ createConnectionLifecycle,
78
+ verifyClient as verifyWsClient
79
+ } from "@wrongstack/webui-server";
80
+ import { buildReplayPayload, decodeProtocolFrame } from "@wrongstack/webui-server/protocol";
81
+ function createConnectionHandler(deps) {
82
+ const clientHandlers = [
83
+ deps.goalHandler,
84
+ deps.specsHandler,
85
+ deps.sddBoardHandler,
86
+ ...deps.sddWizardHandler ? [deps.sddWizardHandler] : [],
87
+ deps.worktreeHandler,
88
+ deps.terminalHandler
89
+ ];
90
+ return createConnectionLifecycle({
91
+ clients: deps.clients,
92
+ pendingConfirms: deps.pendingConfirms,
93
+ // ── Auth trust model ────────────────────────────────────────────────
94
+ // Three layered defenses (see verifyClient in @wrongstack/webui-server/ws-auth):
95
+ // 1. DNS-rebinding guard (Host header must be loopback on loopback bind)
96
+ // 2. Shared-token auth via Cookie (ws_token) or URL query param (?token=)
97
+ // 3. Loopback bootstrap: when requireToken=false (default) AND the server
98
+ // is bound to a loopback interface, browser clients bypass token auth
99
+ // entirely — the Origin header being http://localhost is sufficient.
100
+ //
101
+ // COOKIE PERSISTENCE AFTER TOKEN ROTATION:
102
+ // The HttpOnly ws_token cookie, once set by /ws-auth, survives a process
103
+ // restart. On the next process the expectedToken is a fresh random value,
104
+ // so the old cookie alone would fail the token check. However, on a
105
+ // loopback bind with requireToken=false (default), the loopback-bootstrap
106
+ // path at layer 3 accepts the connection before the cookie is ever
107
+ // compared — the old cookie is harmless because no token is needed.
108
+ //
109
+ // This means a token rotation (e.g. the operator sets a new accessToken
110
+ // in config) does NOT invalidate already-distributed cookies for loopback
111
+ // clients. The mitigating factors:
112
+ // - Loopback bind + requireToken=false already trusts any local process
113
+ // that can reach 127.0.0.1 — a trivial perimeter.
114
+ // - A LAN/0.0.0.0 bind with requireToken=true DOES enforce cookie
115
+ // matching against the new expectedToken on every reconnect.
116
+ // If stronger isolation is needed, set requireToken=true or rebind the
117
+ // server to a non-loopback interface with token enforcement.
118
+ authenticate: (ws, req) => {
119
+ const allowed = verifyWsClient({
120
+ origin: req.headers.origin,
121
+ url: req.url ?? "/",
122
+ hostHeader: req.headers.host,
123
+ remoteAddress: req.socket.remoteAddress,
124
+ cookieHeader: req.headers.cookie,
125
+ wsHost: deps.host,
126
+ expectedToken: deps.wsToken,
127
+ requireToken: deps.requireToken,
128
+ allowedHostnames: deps.publicHostnames,
129
+ allowBrowserUrlToken: Boolean(deps.publicWsUrl)
130
+ });
131
+ if (!allowed) ws.close(4003, "Forbidden");
132
+ return allowed;
133
+ },
134
+ createClient: (ws) => ({ ws, sessionId: deps.currentSessionId() }),
135
+ // Enrich parse-failure / unknown-type logs with per-connection identity
136
+ // so operators can identify which client sent a malformed frame. The
137
+ // `connectionId`/`sessionId` fields are read from the `client` argument
138
+ // directly inside `logRejection`; the CLI's `ConnectedClient` only has
139
+ // `sessionId` (no per-socket `connId`), so the verbose payload carries
140
+ // `sessionId` only. Server-wide identity (`agentId`/`projectRoot`) isn't
141
+ // in scope at this handler and is omitted.
142
+ verboseWsLogging: true,
143
+ registerClient: (ws) => {
144
+ for (const handler of clientHandlers) handler.addClient(ws);
145
+ },
146
+ decode: (raw) => decodeProtocolFrame(raw, "client"),
147
+ dispatch: deps.handleMessage,
148
+ send: deps.send,
149
+ sessionPayload: deps.sessionPayload,
150
+ rateLimitMax: deps.rateLimitMax,
151
+ onClose: (ws) => deps.abortControllers.delete(ws),
152
+ buildInitialPayload: async () => {
153
+ const payload = { ...await deps.buildSessionStartPayload({}, deps.needsSetup) };
154
+ try {
155
+ const replay = await deps.loadReplay?.();
156
+ if (replay) Object.assign(payload, buildReplayPayload(replay));
157
+ } catch {
158
+ console.debug("[WebUI] Failed to load replay");
159
+ }
160
+ try {
161
+ const sessions = await deps.loadAgentSessions?.();
162
+ if (sessions?.length) payload["agentSessions"] = sessions;
163
+ } catch {
164
+ console.debug("[WebUI] Failed to load agent sessions");
165
+ }
166
+ return payload;
167
+ }
168
+ });
169
+ }
170
+
171
+ // src/webui-server/kanban-host-adapter.ts
172
+ import { PhaseGraphBuilder } from "@wrongstack/core/goal";
173
+ import { resolveWstackPaths } from "@wrongstack/core/utils";
174
+ import { exportBoardToTaskGraph } from "@wrongstack/kanban";
175
+ import {
176
+ startSddRunFromGraph
177
+ } from "@wrongstack/webui-server";
178
+ function createCliKanbanHostRoutes(deps) {
179
+ const { opts, send, goalHandler } = deps;
180
+ let isolatedSeq = 0;
181
+ const runIsolatedTurn = opts.sddSubagentFactory ? async (prompt, name) => {
182
+ const result = await opts.sddSubagentFactory({
183
+ id: `sdd-kanban-${name.toLowerCase().replace(/\s+/g, "-")}-${isolatedSeq++}`,
184
+ role: "executor",
185
+ name,
186
+ disabledTools: ["delegate", "write", "edit", "patch", "bash", "exec"],
187
+ allowedCapabilities: ["fs.read", "net.outbound"]
188
+ });
189
+ try {
190
+ const res = await result.agent.run([{ type: "text", text: prompt }]);
191
+ return res.finalText ?? "";
192
+ } finally {
193
+ await result.dispose?.();
194
+ }
195
+ } : void 0;
196
+ return {
197
+ meta: async (ws) => {
198
+ const tools = (opts.agent.ctx.tools ?? []).map((tool) => ({
199
+ name: tool.name,
200
+ description: tool.description ?? ""
201
+ }));
202
+ const skills = opts.skillLoader ? (await opts.skillLoader.list()).map((skill) => ({
203
+ name: skill.name,
204
+ description: skill.description,
205
+ source: skill.source
206
+ })) : [];
207
+ send(ws, {
208
+ type: "kanban.meta",
209
+ payload: {
210
+ success: true,
211
+ data: {
212
+ tools,
213
+ skills,
214
+ fallbackProfiles: opts.appConfig?.fallbackProfiles ?? {},
215
+ sessionProvider: opts.agent.ctx.provider,
216
+ sessionModel: opts.agent.ctx.model
217
+ }
218
+ }
219
+ });
220
+ },
221
+ supervisorStatus: async (ws, msg) => {
222
+ const boardId = msg.payload?.boardId;
223
+ if (!boardId || !deps.kanbanSupervisor) {
224
+ send(ws, {
225
+ type: "kanban.supervisor.status",
226
+ payload: { success: false, error: "Kanban supervisor is unavailable." }
227
+ });
228
+ return;
229
+ }
230
+ const snapshot = deps.kanbanSupervisor.getSnapshot(boardId) ?? (await deps.kanbanSupervisor.auditNow(boardId))[0];
231
+ send(ws, {
232
+ type: "kanban.supervisor.status",
233
+ payload: { success: true, data: snapshot ?? null }
234
+ });
235
+ },
236
+ supervisorAudit: async (ws, msg) => {
237
+ const boardId = msg.payload?.boardId;
238
+ if (!deps.kanbanSupervisor) {
239
+ send(ws, {
240
+ type: "kanban.supervisor.audit",
241
+ payload: { success: false, error: "Kanban supervisor is unavailable." }
242
+ });
243
+ return;
244
+ }
245
+ const snapshots = await deps.kanbanSupervisor.auditNow(boardId);
246
+ send(ws, {
247
+ type: "kanban.supervisor.audit",
248
+ payload: { success: true, data: boardId ? snapshots[0] ?? null : snapshots }
249
+ });
250
+ },
251
+ runStart: async (ws, msg) => {
252
+ const payload = msg.payload ?? {};
253
+ const boardId = payload.boardId;
254
+ const engine = payload.engine === "goal" ? "goal" : payload.engine === "sdd" ? "sdd" : void 0;
255
+ const projectRoot = opts.projectRoot ?? "";
256
+ const failRun = (error) => send(ws, { type: "kanban.run.start", payload: { success: false, error } });
257
+ if (!boardId || !engine) return failRun("boardId and engine required");
258
+ if (!projectRoot) return failRun("No project root");
259
+ try {
260
+ const exported = await exportBoardToTaskGraph(projectRoot, boardId, {
261
+ preserveOriginTaskIds: true
262
+ });
263
+ if (!exported) return failRun(`Board not found: ${boardId}`);
264
+ if (exported.graph.nodes.size === 0) return failRun("Board has no tasks to run");
265
+ if (engine === "goal") {
266
+ deps.kanbanRunMirror?.bindGoalNext(boardId);
267
+ const graph = await PhaseGraphBuilder.fromTaskGraph(exported.graph, {
268
+ title: exported.board.title,
269
+ description: exported.board.description ?? exported.board.title
270
+ });
271
+ const phases = Array.from(graph.phases.values()).map((phase) => ({
272
+ name: phase.name,
273
+ description: phase.description,
274
+ priority: phase.priority,
275
+ estimateHours: phase.estimateHours,
276
+ parallelizable: phase.parallelizable,
277
+ taskTemplates: Array.from(phase.taskGraph.nodes.values()).map((task) => ({
278
+ title: task.title,
279
+ description: task.description,
280
+ type: task.type,
281
+ priority: task.priority,
282
+ estimateHours: task.estimateHours ?? 0,
283
+ ...task.tags ? { tags: task.tags } : {}
284
+ }))
285
+ }));
286
+ await goalHandler.handleMessage(ws, {
287
+ type: "goal.start",
288
+ payload: {
289
+ title: exported.board.title,
290
+ phases,
291
+ autonomous: payload.autonomous ?? false
292
+ }
293
+ });
294
+ send(ws, {
295
+ type: "kanban.run.start",
296
+ payload: { success: true, data: { engine: "goal", boardId } }
297
+ });
298
+ return;
299
+ }
300
+ if (!opts.sddSubagentFactory) {
301
+ return failRun("SDD runs need the multi-agent host, which is not available here.");
302
+ }
303
+ const paths = resolveWstackPaths({ projectRoot });
304
+ const handle = await startSddRunFromGraph(
305
+ exported.graph,
306
+ {
307
+ agent: opts.agent,
308
+ events: opts.events,
309
+ projectRoot,
310
+ subagentFactory: opts.sddSubagentFactory,
311
+ projectSddBoards: paths.projectSddBoards,
312
+ ...opts.brain ? { brain: opts.brain } : {},
313
+ ...runIsolatedTurn ? { runIsolatedTurn } : {}
314
+ },
315
+ { worktrees: true }
316
+ );
317
+ deps.kanbanRunMirror?.bind("sdd", handle.runId, boardId);
318
+ void handle.completion.catch(() => {
319
+ });
320
+ const started = {
321
+ type: "sdd.run.started",
322
+ payload: { runId: handle.runId, graphId: exported.graph.id }
323
+ };
324
+ send(ws, started);
325
+ deps.broadcast?.(started);
326
+ send(ws, {
327
+ type: "kanban.run.start",
328
+ payload: { success: true, data: { engine: "sdd", boardId, runId: handle.runId } }
329
+ });
330
+ } catch (err) {
331
+ failRun(err instanceof Error ? err.message : String(err));
332
+ }
333
+ }
334
+ };
335
+ }
336
+
337
+ // src/webui-server/kanban-supervisor.ts
338
+ import {
339
+ createKanbanSupervisor
340
+ } from "@wrongstack/webui-server";
341
+
342
+ // src/webui-server/lifecycle.ts
343
+ import {
344
+ announceWebuiReady,
345
+ createWebuiShutdown,
346
+ registerWebuiInstance,
347
+ registerWebuiSignalHandlers
348
+ } from "@wrongstack/webui-server";
349
+
350
+ // src/webui-server/logger-shim.ts
351
+ var structuredLine = (level, message) => JSON.stringify({
352
+ level,
353
+ event: "webui.goal",
354
+ message,
355
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
356
+ });
357
+ var consoleLogger = {
358
+ level: "debug",
359
+ error(msg, _ctx) {
360
+ console.error(structuredLine("error", msg));
361
+ },
362
+ warn(msg, _ctx) {
363
+ console.warn(structuredLine("warn", msg));
364
+ },
365
+ info(msg, _ctx) {
366
+ console.log(structuredLine("info", msg));
367
+ },
368
+ debug(msg, _ctx) {
369
+ console.debug(structuredLine("debug", msg));
370
+ },
371
+ trace(msg, _ctx) {
372
+ console.debug(structuredLine("trace", msg));
373
+ },
374
+ child(_bindings) {
375
+ return this;
376
+ }
377
+ };
378
+
379
+ // src/webui-server/prefs-seeding.ts
380
+ import * as fs from "node:fs/promises";
381
+ import * as path from "node:path";
382
+ import { DefaultSecretVault } from "@wrongstack/core/security";
383
+ import {
384
+ PREF_KEYS,
385
+ persistPrefsToConfig,
386
+ prefSnapshot as snapshotPrefs,
387
+ seedContextMeta
388
+ } from "@wrongstack/webui-server";
389
+ async function seedConfigToMeta(opts) {
390
+ let config = opts.appConfig;
391
+ if (!config || Object.keys(config).length === 0) {
392
+ if (!opts.profileConfigPath) return;
393
+ try {
394
+ config = JSON.parse(await fs.readFile(opts.profileConfigPath, "utf8"));
395
+ } catch {
396
+ return;
397
+ }
398
+ }
399
+ seedContextMeta(config, { meta: opts.agent.ctx.meta });
400
+ }
401
+ function createPrefsSeeding(opts) {
402
+ const writeLock = { lock: Promise.resolve() };
403
+ const patchLiveAppConfig = (patch) => {
404
+ if (!opts.appConfig) return;
405
+ opts.appConfig = { ...opts.appConfig, ...patch };
406
+ };
407
+ const persistPrefs = async (payload) => {
408
+ if (Array.isArray(payload["fallbackModels"])) {
409
+ patchLiveAppConfig({ fallbackModels: payload["fallbackModels"] });
410
+ }
411
+ if (payload["fallbackProfiles"] && typeof payload["fallbackProfiles"] === "object" && !Array.isArray(payload["fallbackProfiles"])) {
412
+ patchLiveAppConfig({
413
+ fallbackProfiles: payload["fallbackProfiles"]
414
+ });
415
+ }
416
+ if (Array.isArray(payload["favoriteModels"])) {
417
+ patchLiveAppConfig({ favoriteModels: payload["favoriteModels"] });
418
+ }
419
+ if (typeof payload["favoriteModelsOnly"] === "boolean") {
420
+ patchLiveAppConfig({ favoriteModelsOnly: payload["favoriteModelsOnly"] });
421
+ }
422
+ if (Array.isArray(payload["modelAvailabilitySchedule"])) {
423
+ patchLiveAppConfig({
424
+ modelAvailabilitySchedule: payload["modelAvailabilitySchedule"]
425
+ });
426
+ }
427
+ if (typeof payload["fallbackAuto"] === "boolean") {
428
+ patchLiveAppConfig({ fallbackAuto: payload["fallbackAuto"] });
429
+ }
430
+ if (typeof payload["uiLocale"] === "string") {
431
+ patchLiveAppConfig({ uiLocale: payload["uiLocale"] });
432
+ }
433
+ if (payload["modelMatrix"] && typeof payload["modelMatrix"] === "object" && !Array.isArray(payload["modelMatrix"])) {
434
+ patchLiveAppConfig({ modelMatrix: payload["modelMatrix"] });
435
+ }
436
+ if (!opts.profileConfigPath) return;
437
+ const globalRoot = opts.globalConfigPath ? path.dirname(opts.globalConfigPath) : path.dirname(opts.profileConfigPath);
438
+ const vault = new DefaultSecretVault({ keyFile: path.join(globalRoot, ".key") });
439
+ await persistPrefsToConfig(
440
+ {
441
+ profileConfigPath: opts.profileConfigPath,
442
+ vault,
443
+ logger: {
444
+ warn(message) {
445
+ console.error(
446
+ JSON.stringify({
447
+ level: "warn",
448
+ event: "webui.prefs.persist_failed",
449
+ message,
450
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
451
+ })
452
+ );
453
+ }
454
+ }
455
+ },
456
+ writeLock,
457
+ payload
458
+ );
459
+ };
460
+ return {
461
+ prefSnapshot: () => snapshotPrefs(opts.agent.ctx.meta),
462
+ persistPrefs
463
+ };
464
+ }
465
+
466
+ // src/webui-server/provider-config.ts
467
+ import * as path2 from "node:path";
468
+ import { DefaultSecretVault as DefaultSecretVault2 } from "@wrongstack/core/security";
469
+ function getVault(globalConfigPath) {
470
+ const configDir = path2.dirname(globalConfigPath ?? "");
471
+ const parentDir = path2.dirname(configDir);
472
+ const globalRoot = path2.basename(parentDir) === "profiles" ? path2.dirname(parentDir) : configDir;
473
+ const keyFile = path2.join(globalRoot, ".key");
474
+ return new DefaultSecretVault2({ keyFile });
475
+ }
476
+ async function loadSavedProviders(globalConfigPath) {
477
+ if (!globalConfigPath) return {};
478
+ return loadConfigProviders(globalConfigPath, getVault(globalConfigPath));
479
+ }
480
+ async function saveProviders(globalConfigPath, providers) {
481
+ if (!globalConfigPath) return;
482
+ await mutateConfigProviders(
483
+ globalConfigPath,
484
+ getVault(globalConfigPath),
485
+ (existing) => {
486
+ for (const key of Object.keys(existing)) delete existing[key];
487
+ Object.assign(existing, providers);
488
+ }
489
+ );
490
+ }
491
+ function createProviderConfigStore(globalConfigPath, configProvidersRef) {
492
+ return {
493
+ load: () => configProvidersRef ? Promise.resolve(configProvidersRef()) : loadSavedProviders(globalConfigPath),
494
+ save: (providers) => saveProviders(globalConfigPath, providers)
495
+ };
496
+ }
497
+
498
+ // src/webui-server/session-start-payload.ts
499
+ import * as path3 from "node:path";
500
+ import { DEFAULT_CONTEXT_WINDOW_MODE_ID } from "@wrongstack/core/types";
501
+ import { protocolAdvertisement } from "@wrongstack/webui-server/protocol";
502
+
503
+ // src/webui-server/cost-helpers.ts
504
+ import {
505
+ computeUsageCost,
506
+ getCostRates
507
+ } from "@wrongstack/webui-server";
508
+
509
+ // src/webui-server/session-start-payload.ts
510
+ function createSessionStartPayloadBuilder(deps) {
511
+ return async function buildSessionStartPayload(overrides, needsSetup = false) {
512
+ let maxContext = 0;
513
+ let inputCost = 0;
514
+ let outputCost = 0;
515
+ let cacheReadCost = 0;
516
+ try {
517
+ if (deps.modelsRegistry) {
518
+ const m = await deps.modelsRegistry.getModel(
519
+ deps.agent.ctx.provider.id,
520
+ deps.agent.ctx.model
521
+ );
522
+ const registryMax = m?.capabilities.maxContext;
523
+ maxContext = registryMax ?? deps.agent.ctx.provider.capabilities?.maxContext ?? 0;
524
+ const rates = getCostRates(m);
525
+ inputCost = rates.input;
526
+ outputCost = rates.output;
527
+ cacheReadCost = rates.cacheRead;
528
+ } else {
529
+ maxContext = deps.agent.ctx.provider.capabilities?.maxContext ?? 0;
530
+ }
531
+ } catch {
532
+ }
533
+ const lastInputTokens = typeof deps.agent.ctx.lastRequestTokens === "number" && deps.agent.ctx.lastRequestTokens > 0 ? deps.agent.ctx.lastRequestTokens : 0;
534
+ return {
535
+ sessionId: deps.agent.ctx.session?.id ?? deps.session.id,
536
+ model: deps.agent.ctx.model,
537
+ provider: deps.agent.ctx.provider.id,
538
+ mode: deps.modeId ?? "default",
539
+ projectName: deps.projectRoot ? path3.basename(deps.projectRoot) : void 0,
540
+ // Frontend reads `projectRoot` from session.start (ws-handlers setEnv) —
541
+ // omitting it left the store's projectRoot empty after a project switch.
542
+ projectRoot: deps.projectRoot ?? deps.agent.ctx.projectRoot ?? "",
543
+ cwd: deps.projectRoot ?? deps.agent.ctx.projectRoot ?? "",
544
+ needsSetup,
545
+ // true when provider/model not configured and running in --webui mode
546
+ contextMode: String(
547
+ deps.agent.ctx.meta?.["contextWindowMode"] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID
548
+ ),
549
+ maxContext,
550
+ inputCost,
551
+ outputCost,
552
+ cacheReadCost,
553
+ lastInputTokens,
554
+ providerStatuses: deps.statusTracker?.getAllStatuses() ?? [],
555
+ ...protocolAdvertisement(),
556
+ ...overrides
557
+ };
558
+ };
559
+ }
560
+
561
+ // src/webui-server/setup-events.ts
562
+ import {
563
+ createEternalSubscription,
564
+ setupEvents as setupCanonicalEvents
565
+ } from "@wrongstack/webui-server";
566
+ function createSetupEvents(deps) {
567
+ let fleetConcurrency = 0;
568
+ let fleetConcurrencyMax = 4;
569
+ const emitConcurrency = () => {
570
+ deps.broadcast({
571
+ type: "fleet.concurrency_update",
572
+ payload: deps.sessionPayload({ fleetConcurrency, fleetConcurrencyMax })
573
+ });
574
+ };
575
+ return function setupEvents() {
576
+ for (const unsubscribe of deps.eventUnsubscribers) unsubscribe();
577
+ deps.eventUnsubscribers.length = 0;
578
+ const maxIterations = deps.agent.ctx?.meta?.["maxIterations"];
579
+ const disposeCanonical = setupCanonicalEvents({
580
+ events: deps.events,
581
+ broadcast: (_clients, message) => deps.broadcast(message),
582
+ clients: deps.getClients(),
583
+ config: {
584
+ tools: {
585
+ ...typeof maxIterations === "number" ? { maxIterations } : {}
586
+ }
587
+ },
588
+ context: deps.agent.ctx,
589
+ pendingConfirms: deps.pendingConfirms,
590
+ globalConfigPath: deps.globalConfigPath,
591
+ onFleetBroadcaster: deps.onFleetBroadcaster,
592
+ projection: {
593
+ scrubObject: (value) => deps.secretScrubber.scrubObject(value),
594
+ queueTextDelta: deps.queueTextDelta,
595
+ queueThinkingDelta: deps.queueThinkingDelta,
596
+ queueToolProgress: (payload) => deps.queueToolProgress(payload),
597
+ flushThinkingDelta: deps.flushThinkingDelta,
598
+ flushAllStreamBuffers: deps.flushAllStreamBuffers
599
+ }
600
+ });
601
+ deps.eventUnsubscribers.push(disposeCanonical);
602
+ deps.broadcast({
603
+ type: "subagent.event",
604
+ payload: deps.sessionPayload({
605
+ kind: "leader_updated",
606
+ subagentId: "leader",
607
+ isLeader: true,
608
+ name: "Leader",
609
+ status: "running"
610
+ })
611
+ });
612
+ emitConcurrency();
613
+ deps.eventUnsubscribers.push(
614
+ deps.events.on("concurrency.changed", (event) => {
615
+ fleetConcurrencyMax = Math.max(1, event.n);
616
+ emitConcurrency();
617
+ }),
618
+ deps.events.on("subagent.spawned", () => {
619
+ fleetConcurrency += 1;
620
+ emitConcurrency();
621
+ }),
622
+ deps.events.on("subagent.task_completed", () => {
623
+ fleetConcurrency = Math.max(0, fleetConcurrency - 1);
624
+ emitConcurrency();
625
+ })
626
+ );
627
+ if (deps.subscribeEternalIteration) {
628
+ const subscription = createEternalSubscription(
629
+ deps.subscribeEternalIteration,
630
+ (_clients, message) => deps.broadcast(message),
631
+ deps.getClients
632
+ );
633
+ deps.eventUnsubscribers.push(() => subscription.dispose());
634
+ }
635
+ };
636
+ }
637
+
638
+ // src/webui-server/static-serve.ts
639
+ import {
640
+ ensureDistDir,
641
+ resolveDistDir,
642
+ startStaticServe
643
+ } from "@wrongstack/webui-server";
644
+
645
+ // src/webui-server/stream-coalescer.ts
646
+ import {
647
+ createStreamCoalescer
648
+ } from "@wrongstack/webui-server";
649
+
650
+ // src/webui-server/terminal-log-view.ts
651
+ import { format } from "node:util";
652
+ var DEFAULT_MAX_LINES = 5;
653
+ var DEFAULT_REFRESH_MS = 5e3;
654
+ var CLEAR_VISIBLE_TERMINAL = "\x1B[2J\x1B[H";
655
+ function startBoundedTerminalLogView(options = {}) {
656
+ const isTTY = options.isTTY ?? process.stdout.isTTY === true;
657
+ if (!isTTY) {
658
+ return { enabled: false, redraw: () => {
659
+ }, stop: () => {
660
+ } };
661
+ }
662
+ const maxLines = Math.max(1, Math.trunc(options.maxLines ?? DEFAULT_MAX_LINES));
663
+ const refreshMs = Math.max(100, Math.trunc(options.refreshMs ?? DEFAULT_REFRESH_MS));
664
+ const target = options.consoleTarget ?? console;
665
+ const write = options.write ?? ((chunk) => process.stdout.write(chunk));
666
+ const setIntervalFn = options.setIntervalFn ?? setInterval;
667
+ const clearIntervalFn = options.clearIntervalFn ?? clearInterval;
668
+ const lines = [];
669
+ let stopped = false;
670
+ const originals = {
671
+ log: target.log,
672
+ info: target.info,
673
+ warn: target.warn,
674
+ error: target.error,
675
+ debug: target.debug
676
+ };
677
+ const wrappers = {};
678
+ const remember = (args) => {
679
+ for (const line of format(...args).split(/\r?\n/u)) {
680
+ lines.push(line);
681
+ if (lines.length > maxLines) lines.shift();
682
+ }
683
+ };
684
+ for (const level of Object.keys(originals)) {
685
+ const original = originals[level];
686
+ const wrapper = (...args) => {
687
+ remember(args);
688
+ original.apply(target, args);
689
+ };
690
+ wrappers[level] = wrapper;
691
+ target[level] = wrapper;
692
+ }
693
+ const redraw = () => {
694
+ if (stopped || lines.length === 0) return;
695
+ write(`${CLEAR_VISIBLE_TERMINAL}${lines.join("\n")}
696
+ `);
697
+ };
698
+ const timer = setIntervalFn(redraw, refreshMs);
699
+ timer.unref?.();
700
+ return {
701
+ enabled: true,
702
+ redraw,
703
+ stop: () => {
704
+ if (stopped) return;
705
+ stopped = true;
706
+ clearIntervalFn(timer);
707
+ for (const level of Object.keys(originals)) {
708
+ if (target[level] === wrappers[level]) target[level] = originals[level];
709
+ }
710
+ }
711
+ };
712
+ }
713
+
714
+ // src/webui-server/node-pty-loader.ts
715
+ import { existsSync } from "node:fs";
716
+ import { createRequire } from "node:module";
717
+ import * as path4 from "node:path";
718
+ import { fileURLToPath } from "node:url";
719
+ function createNodePtyLoader(importMetaUrl, logger) {
720
+ const requireFromCli = createRequire(importMetaUrl);
721
+ let cachedNodePty;
722
+ return () => {
723
+ if (cachedNodePty !== void 0) return cachedNodePty;
724
+ try {
725
+ const webuiEntry = requireFromCli.resolve("@wrongstack/webui");
726
+ const webuiDir = webuiEntry.replace(/[\\/]dist.*$/, "");
727
+ const webuiPkgJson = path4.join(webuiDir, "package.json");
728
+ cachedNodePty = createRequire(webuiPkgJson)("node-pty");
729
+ if (cachedNodePty) {
730
+ logger.debug?.(`[terminal] node-pty loaded via webui package (${webuiDir})`);
731
+ return cachedNodePty;
732
+ }
733
+ } catch (err) {
734
+ logger.debug?.(`[terminal] webui-route failed: ${err.message}`);
735
+ }
736
+ try {
737
+ cachedNodePty = requireFromCli("node-pty");
738
+ logger.debug?.("[terminal] node-pty loaded via direct requireFromCli");
739
+ return cachedNodePty;
740
+ } catch (err) {
741
+ logger.debug?.(`[terminal] direct require failed: ${err.message}`);
742
+ }
743
+ try {
744
+ const cliPkgJson = path4.join(path4.dirname(fileURLToPath(importMetaUrl)), "..", "package.json");
745
+ let dir = path4.dirname(cliPkgJson);
746
+ for (let i = 0; i < 6; i++) {
747
+ const candidate = path4.join(dir, "node_modules", "node-pty");
748
+ if (existsSync(candidate)) {
749
+ cachedNodePty = createRequire(candidate)("node-pty");
750
+ if (cachedNodePty) {
751
+ logger.debug?.(`[terminal] node-pty loaded via workspace root (${candidate})`);
752
+ return cachedNodePty;
753
+ }
754
+ }
755
+ const parent = path4.dirname(dir);
756
+ if (parent === dir) break;
757
+ dir = parent;
758
+ }
759
+ } catch (err) {
760
+ logger.debug?.(`[terminal] workspace-root walk failed: ${err.message}`);
761
+ }
762
+ cachedNodePty = null;
763
+ logger.debug?.('[terminal] node-pty resolution failed; terminal panel will report "unavailable"');
764
+ return cachedNodePty;
765
+ };
766
+ }
767
+
768
+ // src/webui-server/listen-helpers.ts
769
+ import * as http from "node:http";
770
+ async function startDeferredHttpListen(args) {
771
+ const { server, host, httpPort, logger } = args;
772
+ await new Promise((resolveListen, rejectListen) => {
773
+ server.listen(httpPort, host, () => resolveListen());
774
+ server.once("error", rejectListen);
775
+ });
776
+ server.on("error", (err) => {
777
+ logger.error("http_server_error", {
778
+ message: err.message,
779
+ port: httpPort
780
+ });
781
+ });
782
+ }
783
+ async function startIpv6LoopbackProxy(args) {
784
+ const { primary, httpPort, logger } = args;
785
+ const v6 = http.createServer();
786
+ v6.on("request", (req, res) => primary.emit("request", req, res));
787
+ v6.on("upgrade", (req, socket, head) => primary.emit("upgrade", req, socket, head));
788
+ const logIpv6Error = (err) => {
789
+ if (err.code === "EAFNOSUPPORT" || err.code === "EADDRNOTAVAIL" || err.code === "EADDRINUSE") {
790
+ logger.warn("ipv6_loopback_unavailable", { code: err.code, port: httpPort });
791
+ return;
792
+ }
793
+ logger.error("http_server_error", { message: err.message, port: httpPort });
794
+ };
795
+ v6.on("error", logIpv6Error);
796
+ const ipv6Listening = await new Promise((resolveListen) => {
797
+ const onListening = () => {
798
+ v6.off("error", onInitialError);
799
+ resolveListen(true);
800
+ };
801
+ const onInitialError = () => {
802
+ v6.off("listening", onListening);
803
+ resolveListen(false);
804
+ };
805
+ v6.once("listening", onListening);
806
+ v6.once("error", onInitialError);
807
+ v6.listen(httpPort, "::1");
808
+ });
809
+ if (!ipv6Listening) return null;
810
+ console.log(`[WebUI] Also listening on http://[::1]:${httpPort}`);
811
+ return v6;
812
+ }
813
+
814
+ // src/webui-server.ts
815
+ async function runWebUI(opts) {
816
+ const trustBoundary = opts.trustBoundary ?? createCompatibilityTrustBoundary({ policyId: "cli-webui-trusted-host-compat-v1" });
817
+ const host = opts.host ?? process.env["WEBUI_HOST"] ?? process.env["WS_HOST"] ?? "127.0.0.1";
818
+ const publicUrl = opts.publicUrl ?? process.env["WEBUI_PUBLIC_URL"];
819
+ const publicWsUrl = opts.publicWsUrl ?? process.env["WEBUI_PUBLIC_WS_URL"];
820
+ const requireToken = opts.requireToken ?? envFlag("WEBUI_REQUIRE_TOKEN");
821
+ const surface = opts.surface ?? "webui";
822
+ const surfaceDefaults = surface === "simpleui" ? { http: 3466 } : { http: 3456 };
823
+ const requestedHttpPort = opts.httpPort ?? opts.port ?? surfaceDefaults.http;
824
+ const strictPort = process.env["WEBUI_STRICT_PORT"] === "1" || process.env["WEBUI_STRICT_PORT"] === "true";
825
+ let httpPort = requestedHttpPort;
826
+ if (!strictPort) {
827
+ httpPort = await findFreePort(host, requestedHttpPort);
828
+ }
829
+ const wsPort = httpPort;
830
+ const globalRoot = opts.globalConfigPath ? path5.dirname(opts.globalConfigPath) : wstackGlobalRoot();
831
+ const profileConfigPath = opts.profileConfigPath ?? opts.globalConfigPath ?? path5.join(globalRoot, "config.json");
832
+ const rateLimitMax = Number.parseInt(process.env["WEBUI_RATE_LIMIT"] ?? "0", 10);
833
+ const clients = /* @__PURE__ */ new Map();
834
+ const pendingConfirms = /* @__PURE__ */ new Map();
835
+ const secretScrubber = new DefaultSecretScrubber();
836
+ let abortController = null;
837
+ const abortControllers = /* @__PURE__ */ new Map();
838
+ const profileDir = path5.dirname(profileConfigPath);
839
+ let customModeStoreP = null;
840
+ const getCustomModeStore = () => {
841
+ customModeStoreP ??= (async () => {
842
+ const store = createCustomModeStore(profileDir);
843
+ await store.load();
844
+ return store;
845
+ })();
846
+ return customModeStoreP;
847
+ };
848
+ const goalStoreDir = opts.projectRoot ? path5.join(opts.projectRoot, ".wrongstack", "goal") : path5.join(os.tmpdir(), ".wrongstack", "goal");
849
+ const kanbanRunMirror = opts.projectRoot ? createKanbanRunMirror({
850
+ projectRoot: opts.projectRoot,
851
+ events: opts.events,
852
+ broadcast,
853
+ log: (m) => consoleLogger.info(m)
854
+ }) : null;
855
+ const kanbanSupervisor = opts.projectRoot ? createKanbanSupervisor({
856
+ projectRoot: opts.projectRoot,
857
+ broadcast,
858
+ ...opts.onKanbanDispatch ? { dispatchTask: opts.onKanbanDispatch } : {},
859
+ log: (message) => consoleLogger.info(message)
860
+ }) : null;
861
+ const goalHandler = new GoalWebSocketHandler(
862
+ opts.agent,
863
+ opts.agent.ctx,
864
+ consoleLogger,
865
+ goalStoreDir,
866
+ opts.events,
867
+ opts.projectRoot,
868
+ kanbanRunMirror ? (graphId, state) => kanbanRunMirror.onGoalState(graphId, state) : void 0
869
+ );
870
+ const worktreeHandler = new WorktreeWebSocketHandler(opts.events, consoleLogger);
871
+ const loadNodePtyViaWebui = createNodePtyLoader(import.meta.url, consoleLogger);
872
+ const terminalHandler = new TerminalWebSocketHandler(
873
+ () => opts.agent.ctx.cwd ?? opts.projectRoot ?? process.cwd(),
874
+ consoleLogger,
875
+ loadNodePtyViaWebui,
876
+ void 0,
877
+ trustBoundary
878
+ );
879
+ const specsPaths = opts.projectRoot ? resolveWstackPaths2({ projectRoot: opts.projectRoot }) : null;
880
+ const specsHandler = new SpecsWebSocketHandler(
881
+ specsPaths?.projectSpecs ?? path5.join(os.tmpdir(), ".wrongstack", "specs"),
882
+ specsPaths?.projectTaskGraphs ?? path5.join(os.tmpdir(), ".wrongstack", "task-graphs")
883
+ );
884
+ const sddBoardHandler = new SddBoardWebSocketHandler(
885
+ specsPaths?.projectSddBoards ?? path5.join(os.tmpdir(), ".wrongstack", "sdd-boards"),
886
+ opts.events,
887
+ specsPaths && opts.projectRoot ? {
888
+ projectRoot: opts.projectRoot,
889
+ paths: {
890
+ projectSpecs: specsPaths.projectSpecs,
891
+ projectTaskGraphs: specsPaths.projectTaskGraphs,
892
+ projectSddSession: specsPaths.projectSddSession,
893
+ projectSddBoards: specsPaths.projectSddBoards
894
+ }
895
+ } : void 0,
896
+ { trustBoundary, logger: consoleLogger }
897
+ );
898
+ const sddWizardHandler = opts.sddSubagentFactory && specsPaths ? new SddWizardWebSocketHandler(
899
+ buildSddWizardDeps({
900
+ agent: opts.agent,
901
+ events: opts.events,
902
+ projectRoot: opts.projectRoot ?? process.cwd(),
903
+ subagentFactory: opts.sddSubagentFactory,
904
+ // Failure supervisor parity with /sdd execute — omit only when
905
+ // the host never bound a BrainArbiter.
906
+ ...opts.brain ? { brain: opts.brain } : {},
907
+ paths: {
908
+ projectSpecs: specsPaths.projectSpecs,
909
+ projectTaskGraphs: specsPaths.projectTaskGraphs,
910
+ projectSddBoards: specsPaths.projectSddBoards,
911
+ projectDir: specsPaths.projectDir,
912
+ projectSddSession: specsPaths.projectSddSession
913
+ }
914
+ })
915
+ ) : null;
916
+ await seedConfigToMeta(opts);
917
+ if (typeof opts.agent.ctx?.meta?.["yolo"] === "boolean") {
918
+ opts.onYoloSwitch?.(opts.agent.ctx.meta["yolo"]);
919
+ }
920
+ const { prefSnapshot, persistPrefs } = createPrefsSeeding(opts);
921
+ const sessionStartedAt = Date.now();
922
+ const buildSessionStartPayload = createSessionStartPayloadBuilder(opts);
923
+ const { register: registerWebuiClient, unregister: unregisterWebuiClient } = createWebuiClientRegistration({
924
+ projectRoot: opts.projectRoot,
925
+ appConfig: opts.appConfig,
926
+ events: opts.events,
927
+ hqSessionId: opts.session.id,
928
+ getSessionId: () => opts.agent.ctx.session?.id ?? opts.session.id,
929
+ // Two-way HQ control for the WebUI client: steer/btw/queue/broadcast
930
+ // land in the project mailbox (the WebUI's agent reads it like any
931
+ // other surface), and abort tears down every in-flight run on this
932
+ // instance. Without this block the WebUI would be HQ-invisible to the
933
+ // Control tab — telemetry only.
934
+ hqControl: {
935
+ interruptLeader: () => {
936
+ let aborted = false;
937
+ if (abortController) {
938
+ abortController.abort();
939
+ abortController = null;
940
+ aborted = true;
941
+ }
942
+ for (const c of abortControllers.values()) {
943
+ c.abort();
944
+ aborted = true;
945
+ }
946
+ abortControllers.clear();
947
+ return aborted;
948
+ },
949
+ allowRunCommand: () => opts.hqAllowExec === true
950
+ }
951
+ });
952
+ registerWebuiClient();
953
+ const wsToken = resolveAuthToken(opts.accessToken);
954
+ const publicHostnames = [publicUrl, publicWsUrl].map((value) => {
955
+ if (!value) return void 0;
956
+ try {
957
+ return new URL(value).hostname;
958
+ } catch {
959
+ return void 0;
960
+ }
961
+ }).filter((value) => Boolean(value));
962
+ const accessUrl = buildWebUIAccessUrl({
963
+ host,
964
+ port: httpPort,
965
+ token: wsToken,
966
+ publicUrl
967
+ });
968
+ let fleetBroadcastCli = null;
969
+ const httpServer = await startStaticServe({
970
+ host,
971
+ httpPort,
972
+ globalRoot,
973
+ distDir: opts.frontendDistDir,
974
+ ensureDistDeps: {
975
+ resolvePackageJson: (id) => {
976
+ const packageJson = findPackageJSON(id, import.meta.url);
977
+ if (!packageJson) throw new Error(`Package not found: ${id}`);
978
+ return packageJson;
979
+ }
980
+ },
981
+ onFleetPing: () => {
982
+ void fleetBroadcastCli?.();
983
+ },
984
+ onTechStackEvent: (event) => broadcast(event),
985
+ // Read through the live agent context so a mid-session model switch or a
986
+ // credential hot-reload takes effect on the next analyze.
987
+ getLlm: () => opts.agent.ctx.provider && opts.agent.ctx.model ? { provider: opts.agent.ctx.provider, model: opts.agent.ctx.model } : void 0,
988
+ projectRoot: opts.projectRoot,
989
+ publicWsUrl,
990
+ apiToken: wsToken,
991
+ requireToken,
992
+ // SimpleUI only: defer listen until after the WebSocketServer is
993
+ // attached, so a WS upgrade request cannot arrive between listen()
994
+ // and the WS handler registration.
995
+ deferListen: surface === "simpleui"
996
+ });
997
+ const wss = httpServer ? new WebSocketServer({ server: httpServer.server, maxPayload: 20 * 1024 * 1024 }) : new WebSocketServer({ port: httpPort, host, maxPayload: 20 * 1024 * 1024 });
998
+ if (httpServer && surface === "simpleui") {
999
+ await startDeferredHttpListen({
1000
+ server: httpServer.server,
1001
+ host,
1002
+ httpPort,
1003
+ logger: consoleLogger
1004
+ });
1005
+ }
1006
+ let ipv6LoopbackServer = null;
1007
+ if (httpServer && host === "127.0.0.1") {
1008
+ ipv6LoopbackServer = await startIpv6LoopbackProxy({
1009
+ primary: httpServer.server,
1010
+ httpPort,
1011
+ logger: consoleLogger
1012
+ });
1013
+ }
1014
+ console.log(`[WebUI] WebSocket server starting on ws://${host}:${httpPort}`);
1015
+ if (httpServer) {
1016
+ announceWebuiReady({
1017
+ surface,
1018
+ server: httpServer.server,
1019
+ host,
1020
+ httpPort,
1021
+ open: !!opts.open,
1022
+ wsToken,
1023
+ publicUrl
1024
+ });
1025
+ } else {
1026
+ console.warn(
1027
+ `[WebUI] Frontend not served (run \`pnpm --filter @wrongstack/webui build\`). WS bridge still active on ws://${host}:${httpPort}.`
1028
+ );
1029
+ }
1030
+ const registryBaseDir = globalRoot;
1031
+ if (opts.projectRoot) {
1032
+ registerWebuiInstance({
1033
+ pid: process.pid,
1034
+ surface,
1035
+ host,
1036
+ httpPort,
1037
+ publicUrl,
1038
+ projectRoot: opts.projectRoot,
1039
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1040
+ registryBaseDir
1041
+ });
1042
+ }
1043
+ const eventUnsubscribers = [];
1044
+ const currentSessionId = () => opts.agent.ctx.session?.id ?? opts.session.id;
1045
+ const sessionPayload = (payload) => {
1046
+ const provided = payload["sessionId"];
1047
+ const sessionId = typeof provided === "string" && provided.length > 0 ? provided : currentSessionId();
1048
+ return { ...payload, sessionId };
1049
+ };
1050
+ const {
1051
+ queueTextDelta,
1052
+ queueThinkingDelta,
1053
+ queueToolProgress,
1054
+ flushThinkingDelta,
1055
+ flushAllStreamBuffers
1056
+ } = createStreamCoalescer({ broadcast, sessionPayload });
1057
+ const setupEvents = createSetupEvents({
1058
+ events: opts.events,
1059
+ agent: opts.agent,
1060
+ subscribeEternalIteration: opts.subscribeEternalIteration,
1061
+ broadcast,
1062
+ sessionPayload,
1063
+ currentSessionId,
1064
+ queueTextDelta,
1065
+ queueThinkingDelta,
1066
+ queueToolProgress,
1067
+ flushThinkingDelta,
1068
+ flushAllStreamBuffers,
1069
+ pendingConfirms,
1070
+ secretScrubber,
1071
+ getClients: () => clients,
1072
+ eventUnsubscribers,
1073
+ globalConfigPath: path5.join(globalRoot, "config.json"),
1074
+ onFleetBroadcaster: (fn) => {
1075
+ fleetBroadcastCli = fn;
1076
+ }
1077
+ });
1078
+ const wsHandlerCtx = {
1079
+ providerStore: createProviderConfigStore(
1080
+ profileConfigPath,
1081
+ // Use the in-memory merged config providers so the WebUI sees the
1082
+ // same provider list the agent uses. Without this, providers stored
1083
+ // only in the project-local config (config.local.json) would be
1084
+ // invisible to the WebUI's saved-providers panel because the store
1085
+ // reads exclusively from the global config file.
1086
+ () => opts.appConfig?.providers ?? {}
1087
+ ),
1088
+ modelsRegistry: opts.modelsRegistry,
1089
+ send,
1090
+ broadcast,
1091
+ log: (m) => console.log(m)
1092
+ };
1093
+ const embeddedProviderOperations = createEmbeddedProviderOperations(wsHandlerCtx);
1094
+ const watchConfigPath = profileConfigPath;
1095
+ let credentialWatcherClose;
1096
+ if (watchConfigPath && process.env["WRONGSTACK_DISABLE_CONFIG_WATCH"] !== "1") {
1097
+ let lastActiveCfg = JSON.stringify(
1098
+ opts.appConfig?.providers?.[opts.agent.ctx.provider.id] ?? null
1099
+ );
1100
+ let lastUiLocale = opts.appConfig?.uiLocale;
1101
+ const watcher = watchProviderConfig(
1102
+ watchConfigPath,
1103
+ // Vault key lives at ~/.wrongstack/.key (derived from globalConfigPath),
1104
+ // not inside the profile directory — resolve via global root to stay correct.
1105
+ getVault(opts.globalConfigPath),
1106
+ (snapshot) => {
1107
+ try {
1108
+ if (opts.appConfig && !Object.isFrozen(opts.appConfig)) {
1109
+ opts.appConfig.providers = snapshot.providers;
1110
+ if (snapshot.uiLocale) opts.appConfig.uiLocale = snapshot.uiLocale;
1111
+ }
1112
+ } catch {
1113
+ }
1114
+ const routingChanged = snapshot.fallbackModels !== void 0 || snapshot.fallbackProfiles !== void 0 || snapshot.favoriteModels !== void 0 || snapshot.favoriteModelsOnly !== void 0 || snapshot.modelMatrix !== void 0 || snapshot.fallbackAuto !== void 0;
1115
+ if (routingChanged) {
1116
+ const configStore = opts.agent.container?.safeResolve?.(TOKENS.ConfigStore);
1117
+ configStore?.update({
1118
+ ...snapshot.fallbackModels !== void 0 ? { fallbackModels: snapshot.fallbackModels } : {},
1119
+ ...snapshot.fallbackProfiles !== void 0 ? { fallbackProfiles: snapshot.fallbackProfiles } : {},
1120
+ ...snapshot.favoriteModels !== void 0 ? { favoriteModels: snapshot.favoriteModels } : {},
1121
+ ...snapshot.favoriteModelsOnly !== void 0 ? { favoriteModelsOnly: snapshot.favoriteModelsOnly } : {},
1122
+ ...snapshot.modelMatrix !== void 0 ? { modelMatrix: snapshot.modelMatrix } : {},
1123
+ ...snapshot.fallbackAuto !== void 0 ? { fallbackAuto: snapshot.fallbackAuto } : {}
1124
+ });
1125
+ }
1126
+ embeddedProviderOperations.broadcastSaved(snapshot.providers);
1127
+ if (snapshot.uiLocale !== lastUiLocale) {
1128
+ lastUiLocale = snapshot.uiLocale;
1129
+ if (snapshot.uiLocale) {
1130
+ opts.agent.ctx.meta["uiLocale"] = snapshot.uiLocale;
1131
+ broadcast({ type: "prefs.updated", payload: { uiLocale: snapshot.uiLocale } });
1132
+ }
1133
+ }
1134
+ const activeId = opts.agent.ctx.provider.id;
1135
+ const newCfgStr = JSON.stringify(snapshot.providers[activeId] ?? null);
1136
+ if (newCfgStr === lastActiveCfg) return;
1137
+ lastActiveCfg = newCfgStr;
1138
+ try {
1139
+ const newCfg = snapshot.providers[activeId] ?? {
1140
+ type: activeId,
1141
+ ...snapshot.apiKey !== void 0 ? { apiKey: snapshot.apiKey } : {},
1142
+ ...snapshot.baseUrl !== void 0 ? { baseUrl: snapshot.baseUrl } : {}
1143
+ };
1144
+ const oldMax = opts.agent.ctx.provider.capabilities?.maxContext;
1145
+ const prov = makeProviderFromConfig(activeId, { ...newCfg, type: activeId });
1146
+ if (oldMax != null && prov.capabilities) prov.capabilities.maxContext = oldMax;
1147
+ opts.agent.ctx.provider = prov;
1148
+ console.log(`[WebUI] Provider credentials reloaded from config.json (${activeId})`);
1149
+ } catch (err) {
1150
+ console.warn(
1151
+ `[WebUI] Credential hot-reload failed for ${activeId}: ${toErrorMessage(err)}`
1152
+ );
1153
+ }
1154
+ },
1155
+ {
1156
+ warn: (m) => console.warn(
1157
+ JSON.stringify({
1158
+ level: "warn",
1159
+ event: "webui.config_watcher",
1160
+ message: m,
1161
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1162
+ })
1163
+ )
1164
+ }
1165
+ );
1166
+ credentialWatcherClose = watcher.close;
1167
+ }
1168
+ const brainCtx = {
1169
+ brainSettings: opts.brainSettings,
1170
+ brainRuntime: opts.brainRuntime,
1171
+ getBrainLog: opts.getBrainLog,
1172
+ // Prefer the host-supplied arbiter; otherwise resolve the one bound
1173
+ // in the agent container (if any). Mirrors the former inline lookup.
1174
+ resolveArbiter: () => opts.brain ?? (opts.agent.container.has(TOKENS.BrainArbiter) ? opts.agent.container.resolve(TOKENS.BrainArbiter) : void 0),
1175
+ getSessionId: currentSessionId,
1176
+ send
1177
+ };
1178
+ const introspectionConfigStore = opts.agent.container?.safeResolve?.(TOKENS.ConfigStore);
1179
+ const introspectionCtx = {
1180
+ agent: opts.agent,
1181
+ modelsRegistry: opts.modelsRegistry,
1182
+ configStore: introspectionConfigStore,
1183
+ getConfig: () => {
1184
+ const cfg = introspectionConfigStore?.get() ?? opts.appConfig;
1185
+ if (!cfg)
1186
+ throw new Error(
1187
+ "Introspection route requires a config but neither ConfigStore nor opts.appConfig is available"
1188
+ );
1189
+ return cfg;
1190
+ },
1191
+ getProjectRoot: () => opts.projectRoot ?? opts.agent.ctx.projectRoot ?? "",
1192
+ getSessionId: currentSessionId,
1193
+ getSessionStartedAt: () => sessionStartedAt,
1194
+ getModeId: () => opts.modeId ?? "default",
1195
+ send
1196
+ };
1197
+ const skillsProjectRoot = opts.projectRoot ?? opts.agent.ctx.projectRoot ?? "";
1198
+ const skillsPaths = skillsProjectRoot ? resolveWstackPaths2({
1199
+ projectRoot: skillsProjectRoot,
1200
+ globalRoot
1201
+ }) : void 0;
1202
+ const skillsCtx = {
1203
+ skillLoader: opts.skillLoader,
1204
+ skillInstaller: opts.skillLoader ? new SkillInstaller({
1205
+ manifestPath: path5.join(skillsPaths?.configDir ?? profileDir, "installed-skills.json"),
1206
+ projectSkillsDir: skillsPaths?.inProjectSkills ?? path5.join(skillsProjectRoot, ".wrongstack", "skills"),
1207
+ globalSkillsDir: skillsPaths?.globalSkills ?? path5.join(profileDir, "skills"),
1208
+ projectHash: skillsPaths?.projectHash ?? "",
1209
+ skillLoader: opts.skillLoader
1210
+ }) : void 0,
1211
+ projectRoot: skillsProjectRoot,
1212
+ projectSkillsDir: skillsPaths?.inProjectSkills,
1213
+ globalSkillsDir: skillsPaths?.globalSkills
1214
+ };
1215
+ const promptsCtx = {
1216
+ promptLoader: opts.promptLoader,
1217
+ promptUsage: new PromptUsageStore(
1218
+ skillsPaths?.promptUsage ?? path5.join(profileDir, "prompt-usage.json")
1219
+ )
1220
+ };
1221
+ const designCtx = {
1222
+ projectRoot: skillsProjectRoot,
1223
+ agentMeta: opts.agent.ctx
1224
+ };
1225
+ const agentConfigCtx = {
1226
+ agent: opts.agent,
1227
+ modeStore: opts.modeStore,
1228
+ loadSavedProviders: () => loadSavedProviders(profileConfigPath),
1229
+ buildSessionStart: (overrides) => buildSessionStartPayload(overrides),
1230
+ modelsRegistry: opts.modelsRegistry,
1231
+ memoryStore: opts.memoryStore,
1232
+ getConfig: () => opts.appConfig,
1233
+ onMaxContextResolved: opts.onModelContextResolved,
1234
+ persistPrefs,
1235
+ send,
1236
+ broadcast,
1237
+ log: (m) => console.log(m)
1238
+ };
1239
+ const prefsCtx = {
1240
+ meta: opts.agent.ctx.meta,
1241
+ snapshot: prefSnapshot,
1242
+ persist: persistPrefs,
1243
+ setYolo: opts.onYoloSwitch,
1244
+ setAutonomy: opts.onAutonomySwitch,
1245
+ pendingConfirms,
1246
+ configStore: opts.agent.container?.safeResolve?.(TOKENS.ConfigStore),
1247
+ send,
1248
+ broadcast
1249
+ };
1250
+ const projectsCtx = {
1251
+ opts,
1252
+ abortControllers,
1253
+ abortLegacyRun: () => {
1254
+ if (abortController) {
1255
+ abortController.abort();
1256
+ abortController = null;
1257
+ }
1258
+ },
1259
+ buildSessionStart: (overrides) => buildSessionStartPayload(overrides),
1260
+ send,
1261
+ broadcast,
1262
+ log: (m) => console.log(m)
1263
+ };
1264
+ const mailboxRoutes = createMailboxRouteHandlers({
1265
+ getProjectRoot: () => opts.projectRoot ?? opts.agent.ctx.projectRoot ?? "",
1266
+ getGlobalRoot: () => opts.globalConfigPath ? path5.dirname(opts.globalConfigPath) : "",
1267
+ events: opts.events
1268
+ });
1269
+ const sessionsCtx = {
1270
+ opts,
1271
+ buildSessionStart: (overrides) => buildSessionStartPayload(overrides),
1272
+ getCustomModeStore,
1273
+ send,
1274
+ broadcast,
1275
+ log: (m) => console.log(m)
1276
+ };
1277
+ const connectionCtx = {
1278
+ agent: opts.agent,
1279
+ abortControllers,
1280
+ pendingConfirms,
1281
+ send,
1282
+ broadcast,
1283
+ log: (m) => console.log(m)
1284
+ };
1285
+ const kanbanHostRoutes = createCliKanbanHostRoutes({
1286
+ opts,
1287
+ send,
1288
+ broadcast,
1289
+ goalHandler,
1290
+ ...kanbanSupervisor ? { kanbanSupervisor } : {},
1291
+ ...kanbanRunMirror ? { kanbanRunMirror } : {}
1292
+ });
1293
+ const handleMessage = createEmbeddedMessageRouter({
1294
+ trustBoundary,
1295
+ opts,
1296
+ logger: consoleLogger,
1297
+ send,
1298
+ sendResult,
1299
+ sessionPayload,
1300
+ currentSessionId,
1301
+ shutdown,
1302
+ providerCtx: wsHandlerCtx,
1303
+ brainCtx,
1304
+ introspectionCtx,
1305
+ skillsCtx,
1306
+ promptsCtx,
1307
+ designCtx,
1308
+ agentConfigCtx,
1309
+ prefsCtx,
1310
+ projectCtx: projectsCtx,
1311
+ mailboxRoutes,
1312
+ sessionCtx: sessionsCtx,
1313
+ conversationCtx: connectionCtx,
1314
+ goalHandler,
1315
+ specsHandler,
1316
+ sddBoardHandler,
1317
+ sddWizardHandler,
1318
+ worktreeHandler,
1319
+ terminalHandler,
1320
+ kanbanHostRoutes,
1321
+ statusTracker: opts.statusTracker
1322
+ });
1323
+ const terminalLogView = startBoundedTerminalLogView();
1324
+ const stopped = new Promise((resolve) => {
1325
+ let listeningAnnounced = false;
1326
+ const announceListening = () => {
1327
+ if (listeningAnnounced) return;
1328
+ listeningAnnounced = true;
1329
+ console.log(`[WebUI] WebSocket server running on ws://${host}:${httpPort}`);
1330
+ try {
1331
+ setupEvents();
1332
+ opts.onListening?.({ httpPort, wsPort, host, url: accessUrl });
1333
+ } catch (err) {
1334
+ consoleLogger.error("setup_events_failed", { message: toErrorMessage(err) });
1335
+ }
1336
+ };
1337
+ wss.on("listening", announceListening);
1338
+ if (httpServer?.server.listening || wss.address()) queueMicrotask(announceListening);
1339
+ wss.on(
1340
+ "connection",
1341
+ createConnectionHandler({
1342
+ host,
1343
+ wsToken,
1344
+ requireToken,
1345
+ publicHostnames,
1346
+ publicWsUrl,
1347
+ clients,
1348
+ currentSessionId,
1349
+ goalHandler,
1350
+ specsHandler,
1351
+ sddBoardHandler,
1352
+ sddWizardHandler,
1353
+ worktreeHandler,
1354
+ terminalHandler,
1355
+ rateLimitMax,
1356
+ send,
1357
+ sessionPayload,
1358
+ handleMessage,
1359
+ abortControllers,
1360
+ pendingConfirms,
1361
+ buildSessionStartPayload,
1362
+ loadReplay: async () => {
1363
+ const activeSession = opts.agent.ctx.session ?? opts.session;
1364
+ await activeSession.flush().catch(() => void 0);
1365
+ if (opts.sessionStore) {
1366
+ const data = await opts.sessionStore.load(activeSession.id);
1367
+ return { messages: data.messages, events: data.events, usage: data.usage };
1368
+ }
1369
+ const usage = opts.agent.ctx.tokenCounter.total();
1370
+ return { messages: opts.agent.ctx.messages, usage };
1371
+ },
1372
+ // Reads the on-disk transcripts when the in-memory ring is cold, which
1373
+ // it always is after a resume — the ring only holds what this process
1374
+ // watched happen.
1375
+ loadAgentSessions: async () => await opts.agentTranscripts?.loadSessionsFromDisk() ?? [],
1376
+ needsSetup: opts.needsSetup ?? false
1377
+ })
1378
+ );
1379
+ wss.on("error", (err) => {
1380
+ console.error(
1381
+ JSON.stringify({
1382
+ level: "error",
1383
+ event: "webui_server.error",
1384
+ message: err instanceof Error ? err.message : String(err),
1385
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1386
+ })
1387
+ );
1388
+ });
1389
+ const signalShutdown = createWebuiShutdown({
1390
+ abortInFlight: () => {
1391
+ if (abortController) {
1392
+ abortController.abort();
1393
+ abortController = null;
1394
+ }
1395
+ for (const c of abortControllers.values()) c.abort();
1396
+ abortControllers.clear();
1397
+ },
1398
+ unsubscribeEvents: () => {
1399
+ flushAllStreamBuffers();
1400
+ for (const unsub of eventUnsubscribers) unsub();
1401
+ },
1402
+ closeClients: () => {
1403
+ for (const [ws] of clients) ws.close();
1404
+ clients.clear();
1405
+ },
1406
+ closeHttpServer: () => {
1407
+ ipv6LoopbackServer?.close();
1408
+ httpServer?.server.close();
1409
+ },
1410
+ wss,
1411
+ pid: process.pid,
1412
+ registryBaseDir,
1413
+ onStopped: () => {
1414
+ terminalLogView.redraw();
1415
+ terminalLogView.stop();
1416
+ resolve();
1417
+ }
1418
+ });
1419
+ registerWebuiSignalHandlers(signalShutdown);
1420
+ });
1421
+ function send(ws, msg) {
1422
+ if (ws.readyState === WebSocket.OPEN) {
1423
+ ws.send(JSON.stringify(msg));
1424
+ }
1425
+ }
1426
+ function shutdown() {
1427
+ console.log("[WebUI] Shutting down...");
1428
+ terminalLogView.redraw();
1429
+ terminalLogView.stop();
1430
+ credentialWatcherClose?.();
1431
+ flushAllStreamBuffers();
1432
+ worktreeHandler.dispose();
1433
+ terminalHandler.dispose();
1434
+ kanbanRunMirror?.dispose();
1435
+ kanbanSupervisor?.dispose();
1436
+ unregisterWebuiClient();
1437
+ ipv6LoopbackServer?.close();
1438
+ httpServer?.server.close();
1439
+ opts.onExit?.();
1440
+ }
1441
+ function broadcast(msg) {
1442
+ const data = JSON.stringify(msg);
1443
+ for (const [ws] of clients) {
1444
+ if (ws.readyState === WebSocket.OPEN) {
1445
+ try {
1446
+ ws.send(data);
1447
+ } catch {
1448
+ }
1449
+ }
1450
+ }
1451
+ }
1452
+ function sendResult(ws, success, message) {
1453
+ send(ws, { type: "key.operation_result", payload: { success, message } });
1454
+ }
1455
+ return stopped.finally(() => terminalLogView.stop());
1456
+ }
1457
+ export {
1458
+ runWebUI
1459
+ };
1460
+ //# sourceMappingURL=webui-server-ZF5KVGC5.js.map