@wrongstack/cli 0.295.0 → 0.296.2

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 (471) 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 +1 -5
  11. package/dist/auth-menu/auth-menu-audit.d.ts.map +1 -1
  12. package/dist/auth-menu/local.d.ts +1 -1
  13. package/dist/auth-menu/local.d.ts.map +1 -1
  14. package/dist/auth-menu/shared.d.ts +1 -1
  15. package/dist/auth-menu/shared.d.ts.map +1 -1
  16. package/dist/bench-7ZDWSNEF.js +278 -0
  17. package/dist/bench-7ZDWSNEF.js.map +7 -0
  18. package/dist/boot/brain-decision-log.d.ts +7 -5
  19. package/dist/boot/brain-decision-log.d.ts.map +1 -1
  20. package/dist/boot/dispatch-webui.d.ts +4 -8
  21. package/dist/boot/dispatch-webui.d.ts.map +1 -1
  22. package/dist/boot/launch-menu.d.ts +1 -1
  23. package/dist/boot/launch-menu.d.ts.map +1 -1
  24. package/dist/boot/system-prompt-builder.d.ts +4 -1
  25. package/dist/boot/system-prompt-builder.d.ts.map +1 -1
  26. package/dist/boot/tui-coordinator-callbacks.d.ts +45 -0
  27. package/dist/boot/tui-coordinator-callbacks.d.ts.map +1 -0
  28. package/dist/boot/tui-coordinator-setup.d.ts +2 -2
  29. package/dist/boot/tui-coordinator-setup.d.ts.map +1 -1
  30. package/dist/boot/tui-project-picker-callback.d.ts +1 -1
  31. package/dist/boot/tui-project-picker-callback.d.ts.map +1 -1
  32. package/dist/boot/tui-project-switch.d.ts +3 -4
  33. package/dist/boot/tui-project-switch.d.ts.map +1 -1
  34. package/dist/boot/tui-runtime-state.d.ts +5 -6
  35. package/dist/boot/tui-runtime-state.d.ts.map +1 -1
  36. package/dist/boot/tui-session-resume.d.ts.map +1 -1
  37. package/dist/boot/tui-settings-adapter.d.ts +2 -3
  38. package/dist/boot/tui-settings-adapter.d.ts.map +1 -1
  39. package/dist/boot-config.d.ts +2 -2
  40. package/dist/boot-config.d.ts.map +1 -1
  41. package/dist/boot.d.ts +1 -1
  42. package/dist/boot.d.ts.map +1 -1
  43. package/dist/brain-menu/panel-service.d.ts.map +1 -1
  44. package/dist/chimera-review-task.d.ts +6 -0
  45. package/dist/chimera-review-task.d.ts.map +1 -0
  46. package/dist/chimera-reviewer-policy.d.ts +34 -0
  47. package/dist/chimera-reviewer-policy.d.ts.map +1 -0
  48. package/dist/chronicle-QQEQFSSE.js +256 -0
  49. package/dist/chronicle-QQEQFSSE.js.map +7 -0
  50. package/dist/chunk-5N34EWJR.js +418 -0
  51. package/dist/chunk-5N34EWJR.js.map +7 -0
  52. package/dist/chunk-66T43Q4Y.js +90 -0
  53. package/dist/chunk-66T43Q4Y.js.map +7 -0
  54. package/dist/chunk-7OCVIDC7.js +11 -0
  55. package/dist/chunk-7OCVIDC7.js.map +7 -0
  56. package/dist/chunk-ABXK4VVY.js +84 -0
  57. package/dist/chunk-ABXK4VVY.js.map +7 -0
  58. package/dist/chunk-AXVZMEWG.js +306 -0
  59. package/dist/chunk-AXVZMEWG.js.map +7 -0
  60. package/dist/chunk-AZESNNIC.js +216 -0
  61. package/dist/chunk-AZESNNIC.js.map +7 -0
  62. package/dist/chunk-BGFM3PD7.js +41 -0
  63. package/dist/chunk-BGFM3PD7.js.map +7 -0
  64. package/dist/chunk-DPJZQCVP.js +13 -0
  65. package/dist/chunk-DPJZQCVP.js.map +7 -0
  66. package/dist/chunk-F4PEGAJZ.js +176 -0
  67. package/dist/chunk-F4PEGAJZ.js.map +7 -0
  68. package/dist/chunk-IHBYBYGA.js +443 -0
  69. package/dist/chunk-IHBYBYGA.js.map +7 -0
  70. package/dist/chunk-IN4GXGYW.js +425 -0
  71. package/dist/chunk-IN4GXGYW.js.map +7 -0
  72. package/dist/chunk-JBSQ7ONN.js +1023 -0
  73. package/dist/chunk-JBSQ7ONN.js.map +7 -0
  74. package/dist/chunk-JBTFWWKV.js +1325 -0
  75. package/dist/chunk-JBTFWWKV.js.map +7 -0
  76. package/dist/chunk-JUHRI6OV.js +100 -0
  77. package/dist/chunk-JUHRI6OV.js.map +7 -0
  78. package/dist/chunk-OP47B3IX.js +142 -0
  79. package/dist/chunk-OP47B3IX.js.map +7 -0
  80. package/dist/chunk-PJHET45A.js +158 -0
  81. package/dist/chunk-PJHET45A.js.map +7 -0
  82. package/dist/chunk-Q5GTM25S.js +17 -0
  83. package/dist/chunk-Q5GTM25S.js.map +7 -0
  84. package/dist/chunk-QD544J2B.js +19 -0
  85. package/dist/chunk-QD544J2B.js.map +7 -0
  86. package/dist/chunk-QUNHS6O3.js +258 -0
  87. package/dist/chunk-QUNHS6O3.js.map +7 -0
  88. package/dist/chunk-TADVX644.js +480 -0
  89. package/dist/chunk-TADVX644.js.map +7 -0
  90. package/dist/chunk-TGDHN4LM.js +81 -0
  91. package/dist/chunk-TGDHN4LM.js.map +7 -0
  92. package/dist/chunk-TYO2OVAD.js +50 -0
  93. package/dist/chunk-TYO2OVAD.js.map +7 -0
  94. package/dist/chunk-VCYZ3WZV.js +14 -0
  95. package/dist/chunk-VCYZ3WZV.js.map +7 -0
  96. package/dist/chunk-VJUEZZYB.js +29 -0
  97. package/dist/chunk-VJUEZZYB.js.map +7 -0
  98. package/dist/chunk-WHOIR577.js +1 -0
  99. package/dist/chunk-WHOIR577.js.map +7 -0
  100. package/dist/chunk-WY7KKOUK.js +460 -0
  101. package/dist/chunk-WY7KKOUK.js.map +7 -0
  102. package/dist/chunk-X5DQTPXT.js +3059 -0
  103. package/dist/chunk-X5DQTPXT.js.map +7 -0
  104. package/dist/chunk-XJXDOF63.js +28 -0
  105. package/dist/chunk-XJXDOF63.js.map +7 -0
  106. package/dist/chunk-XWEGWYDU.js +560 -0
  107. package/dist/chunk-XWEGWYDU.js.map +7 -0
  108. package/dist/chunk-YWUPHRGB.js +346 -0
  109. package/dist/chunk-YWUPHRGB.js.map +7 -0
  110. package/dist/chunk-Z7YGASQP.js +313 -0
  111. package/dist/chunk-Z7YGASQP.js.map +7 -0
  112. package/dist/cli-entry-main.d.ts +2 -0
  113. package/dist/cli-entry-main.d.ts.map +1 -0
  114. package/dist/cli-entry-point.d.ts +3 -3
  115. package/dist/cli-entry-point.d.ts.map +1 -1
  116. package/dist/cli-eternal-flag.d.ts +2 -2
  117. package/dist/cli-eternal-flag.d.ts.map +1 -1
  118. package/dist/cli-main-6AU6E4XZ.js +29126 -0
  119. package/dist/cli-main-6AU6E4XZ.js.map +7 -0
  120. package/dist/cli-main-helpers.d.ts +21 -0
  121. package/dist/cli-main-helpers.d.ts.map +1 -0
  122. package/dist/cli-main.d.ts +25 -1
  123. package/dist/cli-main.d.ts.map +1 -1
  124. package/dist/context-limit.d.ts +48 -0
  125. package/dist/context-limit.d.ts.map +1 -1
  126. package/dist/diag-doctor-OQ3AA63O.js +170 -0
  127. package/dist/diag-doctor-OQ3AA63O.js.map +7 -0
  128. package/dist/execute-deps.d.ts +10 -12
  129. package/dist/execute-deps.d.ts.map +1 -1
  130. package/dist/execution-V26SE52F.js +4656 -0
  131. package/dist/execution-V26SE52F.js.map +7 -0
  132. package/dist/execution-chimera-ask.d.ts +10 -0
  133. package/dist/execution-chimera-ask.d.ts.map +1 -0
  134. package/dist/execution-chimera-cascade.d.ts +15 -0
  135. package/dist/execution-chimera-cascade.d.ts.map +1 -0
  136. package/dist/execution-cleanup.d.ts +23 -0
  137. package/dist/execution-cleanup.d.ts.map +1 -0
  138. package/dist/execution-kanban-dispatch.d.ts +10 -0
  139. package/dist/execution-kanban-dispatch.d.ts.map +1 -0
  140. package/dist/execution-repl-fleet-callbacks.d.ts +11 -0
  141. package/dist/execution-repl-fleet-callbacks.d.ts.map +1 -0
  142. package/dist/execution-storage-observability.d.ts +3 -0
  143. package/dist/execution-storage-observability.d.ts.map +1 -0
  144. package/dist/execution-tui-next-step-callbacks.d.ts +20 -0
  145. package/dist/execution-tui-next-step-callbacks.d.ts.map +1 -0
  146. package/dist/execution.d.ts +2 -139
  147. package/dist/execution.d.ts.map +1 -1
  148. package/dist/export-TPORYVRZ.js +64 -0
  149. package/dist/export-TPORYVRZ.js.map +7 -0
  150. package/dist/fleet/host-acp-runner-cache.d.ts +9 -0
  151. package/dist/fleet/host-acp-runner-cache.d.ts.map +1 -0
  152. package/dist/fleet/host-acp.d.ts +3 -0
  153. package/dist/fleet/host-acp.d.ts.map +1 -0
  154. package/dist/fleet/host-concurrency.d.ts +2 -0
  155. package/dist/fleet/host-concurrency.d.ts.map +1 -0
  156. package/dist/fleet/host-context.d.ts +5 -0
  157. package/dist/fleet/host-context.d.ts.map +1 -0
  158. package/dist/fleet/host-director-builder.d.ts +24 -0
  159. package/dist/fleet/host-director-builder.d.ts.map +1 -0
  160. package/dist/fleet/host-director-event-bridges.d.ts +37 -0
  161. package/dist/fleet/host-director-event-bridges.d.ts.map +1 -0
  162. package/dist/fleet/host-director-services.d.ts +20 -0
  163. package/dist/fleet/host-director-services.d.ts.map +1 -0
  164. package/dist/fleet/host-event-bridge.d.ts +17 -0
  165. package/dist/fleet/host-event-bridge.d.ts.map +1 -0
  166. package/dist/fleet/host-helpers.d.ts +22 -0
  167. package/dist/fleet/host-helpers.d.ts.map +1 -0
  168. package/dist/fleet/host-learning-tracker.d.ts +11 -0
  169. package/dist/fleet/host-learning-tracker.d.ts.map +1 -0
  170. package/dist/fleet/host-learning.d.ts +4 -0
  171. package/dist/fleet/host-learning.d.ts.map +1 -0
  172. package/dist/fleet/host-lifecycle-events.d.ts +4 -0
  173. package/dist/fleet/host-lifecycle-events.d.ts.map +1 -0
  174. package/dist/fleet/host-paths.d.ts +3 -0
  175. package/dist/fleet/host-paths.d.ts.map +1 -0
  176. package/dist/fleet/host-provider.d.ts +22 -0
  177. package/dist/fleet/host-provider.d.ts.map +1 -0
  178. package/dist/fleet/host-session-writer.d.ts +3 -0
  179. package/dist/fleet/host-session-writer.d.ts.map +1 -0
  180. package/dist/fleet/host-shadow-pass.d.ts +21 -0
  181. package/dist/fleet/host-shadow-pass.d.ts.map +1 -0
  182. package/dist/fleet/host-spawn-types.d.ts +25 -0
  183. package/dist/fleet/host-spawn-types.d.ts.map +1 -0
  184. package/dist/fleet/host-status.d.ts +48 -0
  185. package/dist/fleet/host-status.d.ts.map +1 -0
  186. package/dist/fleet/host-subagent-factory.d.ts +16 -0
  187. package/dist/fleet/host-subagent-factory.d.ts.map +1 -0
  188. package/dist/fleet/host-supervisor.d.ts +16 -0
  189. package/dist/fleet/host-supervisor.d.ts.map +1 -0
  190. package/dist/fleet/host-task-result-report.d.ts +11 -0
  191. package/dist/fleet/host-task-result-report.d.ts.map +1 -0
  192. package/dist/fleet/host-types.d.ts +89 -0
  193. package/dist/fleet/host-types.d.ts.map +1 -0
  194. package/dist/fleet/host.d.ts +10 -357
  195. package/dist/fleet/host.d.ts.map +1 -1
  196. package/dist/fleet/routing.d.ts +1 -1
  197. package/dist/fleet/routing.d.ts.map +1 -1
  198. package/dist/fleet/status-broadcast.d.ts.map +1 -1
  199. package/dist/goal-host.d.ts +2 -2
  200. package/dist/goal-host.d.ts.map +1 -1
  201. package/dist/hq-BECGICEZ.js +547 -0
  202. package/dist/hq-BECGICEZ.js.map +7 -0
  203. package/dist/hq-command-controller.d.ts +2 -2
  204. package/dist/hq-command-controller.d.ts.map +1 -1
  205. package/dist/hq-publisher.d.ts +2 -2
  206. package/dist/hq-publisher.d.ts.map +1 -1
  207. package/dist/hq-server/auth-state.d.ts +1 -1
  208. package/dist/hq-server/auth-state.d.ts.map +1 -1
  209. package/dist/hq-server/project-root.d.ts +5 -0
  210. package/dist/hq-server/project-root.d.ts.map +1 -0
  211. package/dist/hq-server/routes/auth-handlers.d.ts +32 -0
  212. package/dist/hq-server/routes/auth-handlers.d.ts.map +1 -0
  213. package/dist/hq-server/routes/session-handlers.d.ts +8 -0
  214. package/dist/hq-server/routes/session-handlers.d.ts.map +1 -0
  215. package/dist/hq-server/routes/system-handlers.d.ts +16 -0
  216. package/dist/hq-server/routes/system-handlers.d.ts.map +1 -0
  217. package/dist/hq-server/routes.d.ts +6 -6
  218. package/dist/hq-server/routes.d.ts.map +1 -1
  219. package/dist/hq-server/ws.d.ts +1 -1
  220. package/dist/hq-server/ws.d.ts.map +1 -1
  221. package/dist/hq-server-FJOVOERO.js +39 -0
  222. package/dist/hq-server-FJOVOERO.js.map +7 -0
  223. package/dist/hq-server.d.ts.map +1 -1
  224. package/dist/hq-ttl-U2FAYFAT.js +8 -0
  225. package/dist/hq-ttl-U2FAYFAT.js.map +7 -0
  226. package/dist/hq-tunnel-YZLRONPV.js +111 -0
  227. package/dist/hq-tunnel-YZLRONPV.js.map +7 -0
  228. package/dist/index.d.ts +2 -1
  229. package/dist/index.d.ts.map +1 -1
  230. package/dist/index.js +2507 -52632
  231. package/dist/index.js.map +4 -4
  232. package/dist/init-E2NDDOHI.js +27 -0
  233. package/dist/init-E2NDDOHI.js.map +7 -0
  234. package/dist/input-reader.d.ts +1 -1
  235. package/dist/input-reader.d.ts.map +1 -1
  236. package/dist/kanban-dispatch-route.d.ts +14 -0
  237. package/dist/kanban-dispatch-route.d.ts.map +1 -0
  238. package/dist/kanban-hq-sync.d.ts +2 -0
  239. package/dist/kanban-hq-sync.d.ts.map +1 -1
  240. package/dist/kanban-run-mirror-EKVNGXWW.js +12 -0
  241. package/dist/kanban-run-mirror-EKVNGXWW.js.map +7 -0
  242. package/dist/live-settings-input.d.ts +69 -0
  243. package/dist/live-settings-input.d.ts.map +1 -0
  244. package/dist/mailbox-serve-2UWHEN3M.js +302 -0
  245. package/dist/mailbox-serve-2UWHEN3M.js.map +7 -0
  246. package/dist/mcp-CYLPUEHC.js +413 -0
  247. package/dist/mcp-CYLPUEHC.js.map +7 -0
  248. package/dist/mcp-serve.d.ts +1 -1
  249. package/dist/mcp-serve.d.ts.map +1 -1
  250. package/dist/modeldiag-HENYJ4N7.js +1290 -0
  251. package/dist/modeldiag-HENYJ4N7.js.map +7 -0
  252. package/dist/next-task-predictor.d.ts +1 -1
  253. package/dist/next-task-predictor.d.ts.map +1 -1
  254. package/dist/permissions-FNYLZIL4.js +115 -0
  255. package/dist/permissions-FNYLZIL4.js.map +7 -0
  256. package/dist/picker-key-state.d.ts +7 -0
  257. package/dist/picker-key-state.d.ts.map +1 -0
  258. package/dist/picker-model-picker.d.ts +6 -0
  259. package/dist/picker-model-picker.d.ts.map +1 -0
  260. package/dist/picker-ui.d.ts +17 -0
  261. package/dist/picker-ui.d.ts.map +1 -0
  262. package/dist/picker.d.ts +4 -37
  263. package/dist/picker.d.ts.map +1 -1
  264. package/dist/plugin-management.d.ts +1 -1
  265. package/dist/plugin-management.d.ts.map +1 -1
  266. package/dist/plugin-usage-OU6X6LM3.js +40 -0
  267. package/dist/plugin-usage-OU6X6LM3.js.map +7 -0
  268. package/dist/plugins-4LJ5IUBI.js +24 -0
  269. package/dist/plugins-4LJ5IUBI.js.map +7 -0
  270. package/dist/pre-launch.d.ts +0 -1
  271. package/dist/pre-launch.d.ts.map +1 -1
  272. package/dist/project-BLQ3ALVL.js +76 -0
  273. package/dist/project-BLQ3ALVL.js.map +7 -0
  274. package/dist/project-manifest-GE25PW4S.js +18 -0
  275. package/dist/project-manifest-GE25PW4S.js.map +7 -0
  276. package/dist/project-picker-BOCWHBXP.js +17 -0
  277. package/dist/project-picker-BOCWHBXP.js.map +7 -0
  278. package/dist/projects-XE76NFNZ.js +38 -0
  279. package/dist/projects-XE76NFNZ.js.map +7 -0
  280. package/dist/provider-helpers.d.ts +22 -6
  281. package/dist/provider-helpers.d.ts.map +1 -1
  282. package/dist/providers-models-GDELBHZK.js +589 -0
  283. package/dist/providers-models-GDELBHZK.js.map +7 -0
  284. package/dist/quick-VIO2BEHS.js +10 -0
  285. package/dist/quick-VIO2BEHS.js.map +7 -0
  286. package/dist/repl-auto-proceed.d.ts +19 -0
  287. package/dist/repl-auto-proceed.d.ts.map +1 -0
  288. package/dist/repl-client-registration.d.ts +7 -0
  289. package/dist/repl-client-registration.d.ts.map +1 -0
  290. package/dist/repl-input.d.ts +11 -0
  291. package/dist/repl-input.d.ts.map +1 -0
  292. package/dist/repl-options.d.ts +54 -0
  293. package/dist/repl-options.d.ts.map +1 -0
  294. package/dist/repl-rendering.d.ts +4 -0
  295. package/dist/repl-rendering.d.ts.map +1 -0
  296. package/dist/repl-suggestions.d.ts +21 -0
  297. package/dist/repl-suggestions.d.ts.map +1 -0
  298. package/dist/repl.d.ts +3 -162
  299. package/dist/repl.d.ts.map +1 -1
  300. package/dist/replay-KCTXNMZQ.js +75 -0
  301. package/dist/replay-KCTXNMZQ.js.map +7 -0
  302. package/dist/rewind-EJMVFVLS.js +185 -0
  303. package/dist/rewind-EJMVFVLS.js.map +7 -0
  304. package/dist/sdd-runtime-IKPROVV2.js +54 -0
  305. package/dist/sdd-runtime-IKPROVV2.js.map +7 -0
  306. package/dist/services/dispatch-classifier.d.ts +1 -1
  307. package/dist/services/dispatch-classifier.d.ts.map +1 -1
  308. package/dist/services/project-facts.d.ts.map +1 -1
  309. package/dist/services/sdd/project-context.d.ts +1 -1
  310. package/dist/services/sdd/project-context.d.ts.map +1 -1
  311. package/dist/services/sdd/task-manager.d.ts +1 -1
  312. package/dist/services/sdd/task-manager.d.ts.map +1 -1
  313. package/dist/services/statusline-config.d.ts +1 -1
  314. package/dist/services/statusline-config.d.ts.map +1 -1
  315. package/dist/session-event-wiring.d.ts +5 -2
  316. package/dist/session-event-wiring.d.ts.map +1 -1
  317. package/dist/sessions-config-NLCMK3BY.js +409 -0
  318. package/dist/sessions-config-NLCMK3BY.js.map +7 -0
  319. package/dist/settings-menu.d.ts +4 -19
  320. package/dist/settings-menu.d.ts.map +1 -1
  321. package/dist/simpleui-dist-JIFGUJO7.js +93 -0
  322. package/dist/simpleui-dist-JIFGUJO7.js.map +7 -0
  323. package/dist/slash-commands/agent-improve.d.ts +6 -5
  324. package/dist/slash-commands/agent-improve.d.ts.map +1 -1
  325. package/dist/slash-commands/brain.d.ts.map +1 -1
  326. package/dist/slash-commands/btw.d.ts +1 -1
  327. package/dist/slash-commands/btw.d.ts.map +1 -1
  328. package/dist/slash-commands/clear.d.ts +1 -1
  329. package/dist/slash-commands/clear.d.ts.map +1 -1
  330. package/dist/slash-commands/fallback.d.ts.map +1 -1
  331. package/dist/slash-commands/goal-refiner.d.ts +2 -2
  332. package/dist/slash-commands/goal-refiner.d.ts.map +1 -1
  333. package/dist/slash-commands/interrupt.d.ts +1 -1
  334. package/dist/slash-commands/interrupt.d.ts.map +1 -1
  335. package/dist/slash-commands/kanban-agent-helpers.d.ts +18 -0
  336. package/dist/slash-commands/kanban-agent-helpers.d.ts.map +1 -0
  337. package/dist/slash-commands/kanban-format.d.ts +16 -0
  338. package/dist/slash-commands/kanban-format.d.ts.map +1 -0
  339. package/dist/slash-commands/kanban-help.d.ts +2 -0
  340. package/dist/slash-commands/kanban-help.d.ts.map +1 -0
  341. package/dist/slash-commands/kanban.d.ts +1 -1
  342. package/dist/slash-commands/kanban.d.ts.map +1 -1
  343. package/dist/slash-commands/mailbox-demo.d.ts.map +1 -1
  344. package/dist/slash-commands/mailbox.d.ts +3 -2
  345. package/dist/slash-commands/mailbox.d.ts.map +1 -1
  346. package/dist/slash-commands/memory-compact.d.ts +5 -0
  347. package/dist/slash-commands/memory-compact.d.ts.map +1 -0
  348. package/dist/slash-commands/memory-flags.d.ts +36 -0
  349. package/dist/slash-commands/memory-flags.d.ts.map +1 -0
  350. package/dist/slash-commands/memory-formatters.d.ts +16 -0
  351. package/dist/slash-commands/memory-formatters.d.ts.map +1 -0
  352. package/dist/slash-commands/memory.d.ts.map +1 -1
  353. package/dist/slash-commands/mouse.d.ts +2 -2
  354. package/dist/slash-commands/refiner.d.ts +1 -1
  355. package/dist/slash-commands/refiner.d.ts.map +1 -1
  356. package/dist/slash-commands/review.d.ts.map +1 -1
  357. package/dist/slash-commands/sdd-command-helpers.d.ts +23 -0
  358. package/dist/slash-commands/sdd-command-helpers.d.ts.map +1 -0
  359. package/dist/slash-commands/sdd-format.d.ts +32 -0
  360. package/dist/slash-commands/sdd-format.d.ts.map +1 -0
  361. package/dist/slash-commands/sdd.d.ts +1 -1
  362. package/dist/slash-commands/sdd.d.ts.map +1 -1
  363. package/dist/slash-commands/tool.d.ts +1 -1
  364. package/dist/slash-commands/tool.d.ts.map +1 -1
  365. package/dist/slash-commands/working-dir.d.ts +1 -1
  366. package/dist/slash-commands/working-dir.d.ts.map +1 -1
  367. package/dist/subcommands/handlers/chronicle.d.ts.map +1 -1
  368. package/dist/subcommands/handlers/mailbox-serve.d.ts.map +1 -1
  369. package/dist/subcommands/handlers/model-smoke-test.d.ts +51 -0
  370. package/dist/subcommands/handlers/model-smoke-test.d.ts.map +1 -0
  371. package/dist/subcommands/handlers/modeldiag-profiles.d.ts +64 -0
  372. package/dist/subcommands/handlers/modeldiag-profiles.d.ts.map +1 -0
  373. package/dist/subcommands/handlers/modeldiag.d.ts.map +1 -1
  374. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts +3 -0
  375. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts.map +1 -0
  376. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts +3 -0
  377. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts.map +1 -0
  378. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts +36 -0
  379. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts.map +1 -0
  380. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts +18 -0
  381. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts.map +1 -0
  382. package/dist/subcommands/handlers/per-subcommand-help.d.ts +2 -80
  383. package/dist/subcommands/handlers/per-subcommand-help.d.ts.map +1 -1
  384. package/dist/subcommands/handlers/rewind.d.ts.map +1 -1
  385. package/dist/subcommands/index.d.ts +7 -0
  386. package/dist/subcommands/index.d.ts.map +1 -1
  387. package/dist/tools-skills-UNKLOB7M.js +29 -0
  388. package/dist/tools-skills-UNKLOB7M.js.map +7 -0
  389. package/dist/update-YC4TYW2Y.js +16 -0
  390. package/dist/update-YC4TYW2Y.js.map +7 -0
  391. package/dist/update-check-UMYTOH7Z.js +18 -0
  392. package/dist/update-check-UMYTOH7Z.js.map +7 -0
  393. package/dist/version-help-DROHZRW6.js +11 -0
  394. package/dist/version-help-DROHZRW6.js.map +7 -0
  395. package/dist/webui-server/connection-handler.d.ts +2 -1
  396. package/dist/webui-server/connection-handler.d.ts.map +1 -1
  397. package/dist/webui-server/kanban-host-adapter.d.ts +9 -5
  398. package/dist/webui-server/kanban-host-adapter.d.ts.map +1 -1
  399. package/dist/webui-server/listen-helpers.d.ts +18 -0
  400. package/dist/webui-server/listen-helpers.d.ts.map +1 -0
  401. package/dist/webui-server/node-pty-loader.d.ts +6 -0
  402. package/dist/webui-server/node-pty-loader.d.ts.map +1 -0
  403. package/dist/webui-server/prefs-seeding.d.ts.map +1 -1
  404. package/dist/webui-server/terminal-log-view.d.ts +30 -0
  405. package/dist/webui-server/terminal-log-view.d.ts.map +1 -0
  406. package/dist/webui-server-G3TISUIY.js +1459 -0
  407. package/dist/webui-server-G3TISUIY.js.map +7 -0
  408. package/dist/webui-server-options.d.ts +189 -0
  409. package/dist/webui-server-options.d.ts.map +1 -0
  410. package/dist/webui-server.d.ts +2 -178
  411. package/dist/webui-server.d.ts.map +1 -1
  412. package/dist/wiring/brain-and-orchestration.d.ts +2 -2
  413. package/dist/wiring/brain-and-orchestration.d.ts.map +1 -1
  414. package/dist/wiring/codebase-index.d.ts.map +1 -1
  415. package/dist/wiring/command-host-adapters.d.ts +2 -2
  416. package/dist/wiring/command-host-adapters.d.ts.map +1 -1
  417. package/dist/wiring/command-host-state.d.ts +7 -7
  418. package/dist/wiring/command-host-state.d.ts.map +1 -1
  419. package/dist/wiring/dep-watcher-bridge.d.ts +23 -0
  420. package/dist/wiring/dep-watcher-bridge.d.ts.map +1 -0
  421. package/dist/wiring/dep-watcher.d.ts +1 -1
  422. package/dist/wiring/dep-watcher.d.ts.map +1 -1
  423. package/dist/wiring/director-setup.d.ts +4 -4
  424. package/dist/wiring/director-setup.d.ts.map +1 -1
  425. package/dist/wiring/eternal-command-handlers.d.ts +5 -5
  426. package/dist/wiring/eternal-command-handlers.d.ts.map +1 -1
  427. package/dist/wiring/fleet-command-handlers.d.ts +2 -2
  428. package/dist/wiring/fleet-command-handlers.d.ts.map +1 -1
  429. package/dist/wiring/hq-telemetry.d.ts +5 -5
  430. package/dist/wiring/hq-telemetry.d.ts.map +1 -1
  431. package/dist/wiring/lifecycle-plugins.d.ts +9 -8
  432. package/dist/wiring/lifecycle-plugins.d.ts.map +1 -1
  433. package/dist/wiring/mailbox-bridge-bootstrap.d.ts +1 -1
  434. package/dist/wiring/management-tools.d.ts +15 -0
  435. package/dist/wiring/management-tools.d.ts.map +1 -0
  436. package/dist/wiring/pipeline.d.ts +4 -3
  437. package/dist/wiring/pipeline.d.ts.map +1 -1
  438. package/dist/wiring/plugins.d.ts +1 -1
  439. package/dist/wiring/plugins.d.ts.map +1 -1
  440. package/dist/wiring/provider-runtime-setup.d.ts +18 -5
  441. package/dist/wiring/provider-runtime-setup.d.ts.map +1 -1
  442. package/dist/wiring/provider-status.d.ts +3 -3
  443. package/dist/wiring/provider-status.d.ts.map +1 -1
  444. package/dist/wiring/provider-utility-tools.d.ts +4 -4
  445. package/dist/wiring/provider-utility-tools.d.ts.map +1 -1
  446. package/dist/wiring/provider.d.ts.map +1 -1
  447. package/dist/wiring/replay.d.ts +2 -2
  448. package/dist/wiring/replay.d.ts.map +1 -1
  449. package/dist/wiring/runtime-controller-deps.d.ts +4 -4
  450. package/dist/wiring/runtime-controller-deps.d.ts.map +1 -1
  451. package/dist/wiring/runtime-dispatch-state.d.ts +5 -5
  452. package/dist/wiring/runtime-dispatch-state.d.ts.map +1 -1
  453. package/dist/wiring/runtime-picker-deps.d.ts +3 -3
  454. package/dist/wiring/runtime-picker-deps.d.ts.map +1 -1
  455. package/dist/wiring/sage.d.ts.map +1 -1
  456. package/dist/wiring/sdd-handlers.d.ts.map +1 -1
  457. package/dist/wiring/session-command-handlers.d.ts +5 -5
  458. package/dist/wiring/session-command-handlers.d.ts.map +1 -1
  459. package/dist/wiring/session-registry.d.ts +38 -0
  460. package/dist/wiring/session-registry.d.ts.map +1 -0
  461. package/dist/wiring/session.d.ts +7 -5
  462. package/dist/wiring/session.d.ts.map +1 -1
  463. package/dist/wiring/tools.d.ts +2 -2
  464. package/dist/wiring/tools.d.ts.map +1 -1
  465. package/package.json +22 -22
  466. package/dist/cli-recovery-prompt.d.ts +0 -19
  467. package/dist/cli-recovery-prompt.d.ts.map +0 -1
  468. package/dist/first-run-auth-gate.d.ts +0 -20
  469. package/dist/first-run-auth-gate.d.ts.map +0 -1
  470. package/dist/pre-launch/indexing-question.d.ts +0 -28
  471. package/dist/pre-launch/indexing-question.d.ts.map +0 -1
@@ -0,0 +1,4656 @@
1
+ import {
2
+ deriveFsAccessPair,
3
+ filterSafeForProject,
4
+ getSuggestions,
5
+ normalizeTuiThinkingWord,
6
+ resolveActualTarget,
7
+ resolvePersistPath,
8
+ setAutoSuggestions,
9
+ setSuggestions
10
+ } from "./chunk-Z7YGASQP.js";
11
+ import {
12
+ startCliHqConnection
13
+ } from "./chunk-WY7KKOUK.js";
14
+ import "./chunk-WHOIR577.js";
15
+ import {
16
+ advanceToNextTask,
17
+ autoDetectTaskCompletion,
18
+ getActiveSDDContext,
19
+ getActiveSDDPhase,
20
+ getCurrentExecutingContext,
21
+ getTaskListText,
22
+ getTaskProgress,
23
+ renderTaskListWithProgress,
24
+ trySaveImplementationPlan,
25
+ trySaveSpecFromAIOutput,
26
+ trySaveTasksFromAIOutput
27
+ } from "./chunk-IN4GXGYW.js";
28
+ import {
29
+ theme
30
+ } from "./chunk-QD544J2B.js";
31
+ import {
32
+ fmtTok
33
+ } from "./chunk-TYO2OVAD.js";
34
+ import {
35
+ CLI_VERSION
36
+ } from "./chunk-XJXDOF63.js";
37
+ import {
38
+ resolveActiveApiKey
39
+ } from "./chunk-PJHET45A.js";
40
+ import "./chunk-7OCVIDC7.js";
41
+
42
+ // src/execution.ts
43
+ import { randomUUID as randomUUID4 } from "node:crypto";
44
+ import * as path10 from "node:path";
45
+ import { setQueuedMessagesSnapshot as setQueuedMessagesSnapshot2 } from "@wrongstack/core/agent";
46
+ import { isMailboxLeader } from "@wrongstack/core/coordination";
47
+ import {
48
+ CHIMERA_REVIEW_PROMPT
49
+ } from "@wrongstack/core/plugin";
50
+ import { attachTodosCheckpoint as attachTodosCheckpoint2 } from "@wrongstack/core/storage";
51
+ import {
52
+ normalizeTokenSavingTier as normalizeTokenSavingTier2
53
+ } from "@wrongstack/core/types";
54
+ import { mergeCustomModelDefs } from "@wrongstack/core/utils";
55
+ import { capabilitiesFor } from "@wrongstack/providers";
56
+ import { createToolVisionAdapters } from "@wrongstack/runtime/vision";
57
+
58
+ // src/boot/dispatch-singleshot.ts
59
+ import { color, writeOut } from "@wrongstack/core/utils";
60
+
61
+ // src/context-overflow-diagnostic.ts
62
+ import { ERROR_CODES } from "@wrongstack/core/types";
63
+ var CONTEXT_OVERFLOW_RE = /context window|exceeds the context|too many tokens|context.*tokens/i;
64
+ function contextOverflowHint(err) {
65
+ const structured = err.code === ERROR_CODES.PROVIDER_CONTEXT_OVERFLOW || err.code === ERROR_CODES.AGENT_CONTEXT_OVERFLOW;
66
+ const textual = CONTEXT_OVERFLOW_RE.test(`${err.message}
67
+ ${err.describe()}`);
68
+ if (!structured && !textual) return null;
69
+ return [
70
+ "Provider rejected the request as over its effective context window.",
71
+ "If you use a custom baseUrl/proxy, the real limit may be lower than models.dev reports.",
72
+ "Try: /context limit 220k",
73
+ "Then, if needed: /context thresholds 50% 70% 85%",
74
+ "Persistent config: set context.effectiveMaxContext."
75
+ ].join("\n");
76
+ }
77
+
78
+ // src/boot/dispatch-singleshot.ts
79
+ async function runSingleShotDispatch(ctx) {
80
+ const { agent, query, flags, tokenCounter, renderer } = ctx;
81
+ const ctrl = new AbortController();
82
+ const onSigint = () => ctrl.abort();
83
+ process.on("SIGINT", onSigint);
84
+ const startedAt = Date.now();
85
+ const before = tokenCounter.total();
86
+ const costBefore = tokenCounter.estimateCost().total;
87
+ let result;
88
+ try {
89
+ result = await agent.run(query, { signal: ctrl.signal });
90
+ } finally {
91
+ process.off("SIGINT", onSigint);
92
+ const { getProcessRegistry: getProcessRegistry2 } = await import("@wrongstack/tools");
93
+ getProcessRegistry2().killAll({ preserveBackground: true });
94
+ }
95
+ const after = tokenCounter.total();
96
+ const costAfter = tokenCounter.estimateCost().total;
97
+ const usage = {
98
+ input: after.input - before.input,
99
+ output: after.output - before.output,
100
+ iterations: result.iterations,
101
+ cost: costAfter - costBefore,
102
+ elapsedMs: Date.now() - startedAt
103
+ };
104
+ if (flags["output-json"]) {
105
+ const json = JSON.stringify({
106
+ status: result.status,
107
+ finalText: result.finalText ?? null,
108
+ error: result.error ? {
109
+ code: result.error.code,
110
+ subsystem: result.error.subsystem,
111
+ severity: result.error.severity,
112
+ recoverable: result.error.recoverable,
113
+ message: result.error.message,
114
+ context: result.error.context ?? null
115
+ } : null,
116
+ usage
117
+ });
118
+ writeOut(json + "\n");
119
+ return 0;
120
+ }
121
+ let code = 0;
122
+ if (result.status === "failed") {
123
+ code = 1;
124
+ const err = result.error;
125
+ if (err) {
126
+ const tag = err.recoverable ? " (recoverable)" : "";
127
+ renderer.writeError(`Failed [${err.severity}]${tag}: ${err.describe()}`);
128
+ const hint = contextOverflowHint(err);
129
+ if (hint) renderer.writeWarning(hint);
130
+ } else {
131
+ renderer.writeError("Failed.");
132
+ }
133
+ } else if (result.status === "aborted") {
134
+ code = 130;
135
+ renderer.writeWarning("Aborted.");
136
+ } else if (result.status === "max_iterations") {
137
+ code = 1;
138
+ renderer.writeWarning(`Hit max iterations (${result.iterations}).`);
139
+ }
140
+ if (result.finalText) renderer.write("\n" + result.finalText + "\n");
141
+ const r = result;
142
+ renderer.writeDelegateSummaries(r);
143
+ renderer.write(
144
+ "\n" + color.dim(
145
+ `[in: ${fmtTok(usage.input)} out: ${fmtTok(usage.output)} iters: ${usage.iterations} cost: ${usage.cost.toFixed(4)} ${(usage.elapsedMs / 1e3).toFixed(1)}s]`
146
+ ) + "\n"
147
+ );
148
+ return code;
149
+ }
150
+
151
+ // src/boot/dispatch-tui.ts
152
+ async function runTuiDispatch(options) {
153
+ const { runTui } = await import("@wrongstack/tui");
154
+ return runTui(options);
155
+ }
156
+
157
+ // src/boot/dispatch-webui.ts
158
+ import { color as color2 } from "@wrongstack/core/utils";
159
+ async function runWebUIDispatch(ctx) {
160
+ const {
161
+ agent,
162
+ events,
163
+ statusTracker,
164
+ session,
165
+ config,
166
+ flags,
167
+ projectRoot,
168
+ globalConfigPath,
169
+ projectSessionsDir,
170
+ modelsRegistry,
171
+ mcpRegistry,
172
+ brain,
173
+ brainSettings,
174
+ brainRuntime,
175
+ getBrainLog,
176
+ subscribeEternalIteration,
177
+ sessionStore,
178
+ memoryStore,
179
+ skillLoader,
180
+ promptLoader,
181
+ modeStore,
182
+ modeId,
183
+ needsSetup,
184
+ renderer,
185
+ onAutonomy,
186
+ applyLiveSettings,
187
+ onModelContextResolved,
188
+ activateSessionIdentity,
189
+ agentTranscripts,
190
+ sddSubagentFactory,
191
+ onKanbanDispatch
192
+ } = ctx;
193
+ const isSimpleUi = flags["simpleui"] === true;
194
+ agent.disableInteractiveConfirmation();
195
+ renderer.setSilent(true);
196
+ const { runWebUI } = await import("./webui-server-G3TISUIY.js");
197
+ const flagValue = (names) => {
198
+ for (const name of names) {
199
+ if (!Object.hasOwn(flags, name)) continue;
200
+ const value = flags[name];
201
+ if (typeof value === "string" && value.trim() !== "") return value.trim();
202
+ throw new Error(`--${name} requires a value`);
203
+ }
204
+ return void 0;
205
+ };
206
+ const flagBoolean = (names) => {
207
+ for (const name of names) {
208
+ if (!Object.hasOwn(flags, name)) continue;
209
+ const value = flags[name];
210
+ if (value === void 0) continue;
211
+ if (typeof value === "boolean") return value;
212
+ const normalized = value.trim().toLowerCase();
213
+ if (["1", "true", "yes", "on"].includes(normalized)) return true;
214
+ if (["0", "false", "no", "off"].includes(normalized)) return false;
215
+ throw new Error(`--${name} must be a boolean value`);
216
+ }
217
+ return void 0;
218
+ };
219
+ const envFlag = (name) => {
220
+ const value = process.env[name]?.trim().toLowerCase();
221
+ return value === "1" || value === "true" || value === "yes" || value === "on";
222
+ };
223
+ const parsePort = (value, fallback, label) => {
224
+ if (value === void 0) return fallback;
225
+ const parsed = Number.parseInt(value, 10);
226
+ if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) {
227
+ throw new Error(`${label} must be a port between 1 and 65535`);
228
+ }
229
+ return parsed;
230
+ };
231
+ let webuiHost;
232
+ let webuiPort;
233
+ let webuiAccessToken;
234
+ let webuiPublicUrl;
235
+ let webuiPublicWsUrl;
236
+ let webuiRequireToken;
237
+ let frontendDistDir;
238
+ try {
239
+ webuiHost = flagValue(["webui-host", "host"]) ?? process.env["WEBUI_HOST"] ?? process.env["WS_HOST"] ?? "127.0.0.1";
240
+ const defaultPort = isSimpleUi ? 3466 : 3456;
241
+ webuiPort = parsePort(
242
+ flagValue(["webui-port", "http-port", "port", "ws-port"]) ?? process.env["WEBUI_PORT"] ?? process.env["PORT"] ?? process.env["WS_PORT"],
243
+ defaultPort,
244
+ "--port"
245
+ );
246
+ webuiAccessToken = flagValue(["webui-token"]) ?? process.env["WEBUI_TOKEN"] ?? process.env["WEBUI_AUTH_TOKEN"];
247
+ webuiPublicUrl = flagValue(["webui-public-url", "public-url"]) ?? process.env["WEBUI_PUBLIC_URL"];
248
+ webuiPublicWsUrl = flagValue(["webui-public-ws-url", "public-ws-url"]) ?? process.env["WEBUI_PUBLIC_WS_URL"];
249
+ webuiRequireToken = flagBoolean(["webui-require-token", "require-token"]) ?? envFlag("WEBUI_REQUIRE_TOKEN");
250
+ if (isSimpleUi) {
251
+ const { ensureSimpleUiDistDir } = await import("./simpleui-dist-JIFGUJO7.js");
252
+ frontendDistDir = await ensureSimpleUiDistDir();
253
+ }
254
+ } catch (err) {
255
+ renderer.setSilent(false);
256
+ renderer.writeInfo(color2.red(` ${err instanceof Error ? err.message : String(err)}`));
257
+ return 1;
258
+ }
259
+ const webuiPromise = runWebUI({
260
+ agent,
261
+ events,
262
+ statusTracker,
263
+ session,
264
+ surface: isSimpleUi ? "simpleui" : "webui",
265
+ host: webuiHost,
266
+ port: webuiPort,
267
+ frontendDistDir,
268
+ accessToken: webuiAccessToken,
269
+ publicUrl: webuiPublicUrl,
270
+ publicWsUrl: webuiPublicWsUrl,
271
+ requireToken: webuiRequireToken,
272
+ projectRoot,
273
+ appConfig: config,
274
+ open: !!flags.open,
275
+ agentTranscripts,
276
+ hqAllowExec: flagBoolean(["hq-allow-exec"]) ?? false,
277
+ modelsRegistry,
278
+ globalConfigPath,
279
+ profileConfigPath: ctx.profileConfigPath,
280
+ mcpRegistry,
281
+ subscribeEternalIteration,
282
+ sessionStore,
283
+ sessionsDir: projectSessionsDir,
284
+ claimSession: activateSessionIdentity ? async (sessionId) => {
285
+ const previousSessionId = agent.ctx.session?.id ?? session.id;
286
+ await activateSessionIdentity(sessionId);
287
+ return async () => activateSessionIdentity(previousSessionId);
288
+ } : void 0,
289
+ brain,
290
+ brainSettings,
291
+ brainRuntime,
292
+ getBrainLog,
293
+ onSessionSwapped: async (sessionId, target) => {
294
+ if (target && activateSessionIdentity) {
295
+ await activateSessionIdentity(sessionId, target);
296
+ }
297
+ void import("@wrongstack/tools/session-kanban").then(
298
+ ({ hydrateSessionKanban }) => hydrateSessionKanban(agent.ctx)
299
+ );
300
+ },
301
+ onModelContextResolved,
302
+ memoryStore,
303
+ skillLoader,
304
+ promptLoader,
305
+ modeStore,
306
+ modeId,
307
+ needsSetup,
308
+ sddSubagentFactory,
309
+ onKanbanDispatch,
310
+ // Print the "open this" banner only once the server is actually
311
+ // listening, using the RESOLVED port. Requested ports auto-advance past
312
+ // busy ports inside runWebUI, so a banner printed up-front lies whenever
313
+ // the default when it is taken (a second instance, leftover socket).
314
+ onListening: ({ url }) => {
315
+ const surface = isSimpleUi ? "SimpleUI" : "WebUI";
316
+ renderer.writeInfo(color2.green(` \u2726 ${surface} running \u2192 ${color2.bold(url)}`));
317
+ renderer.writeInfo(
318
+ color2.dim(` Press Ctrl+C in this terminal to stop the ${surface} server.
319
+ `)
320
+ );
321
+ },
322
+ // Make autonomy.switch from the browser flip the CLI's real
323
+ // autonomy mode — context.meta alone never reaches the run loop.
324
+ onAutonomySwitch: (mode) => {
325
+ if (mode === "off" || mode === "suggest" || mode === "auto" || mode === "eternal" || mode === "eternal-parallel") {
326
+ onAutonomy?.(mode);
327
+ }
328
+ },
329
+ onYoloSwitch: (enabled) => {
330
+ applyLiveSettings?.({ yolo: enabled });
331
+ }
332
+ });
333
+ const webuiExit = new Promise((resolve3) => {
334
+ webuiPromise.then(() => {
335
+ renderer.setSilent(false);
336
+ renderer.write("\n");
337
+ renderer.writeInfo(
338
+ color2.yellow(` Shutting down ${isSimpleUi ? "SimpleUI" : "WebUI"} server\u2026`)
339
+ );
340
+ resolve3(0);
341
+ }).catch((err) => {
342
+ renderer.setSilent(false);
343
+ console.debug(`[execution] webui error: ${err}`);
344
+ resolve3(1);
345
+ });
346
+ });
347
+ return webuiExit;
348
+ }
349
+
350
+ // src/boot/execution-mode.ts
351
+ function resolveExecutionMode(positional, flags) {
352
+ const prompt = typeof flags["prompt"] === "string" ? flags["prompt"] : "";
353
+ if (positional.length > 0 || prompt.length > 0) return "single-shot";
354
+ if (flags.tui && flags["no-tui"] !== true && !flags.webui) return "tui";
355
+ if (flags.webui) return "webui";
356
+ return "repl";
357
+ }
358
+
359
+ // src/boot/tui-coordinator-callbacks.ts
360
+ function createTuiCoordinatorCallbacks({
361
+ state,
362
+ context,
363
+ coordinatorEvents,
364
+ ensureAutonomousCoordinator
365
+ }) {
366
+ return {
367
+ getAutonomousCoordinator: () => ensureAutonomousCoordinator(),
368
+ subscribeCoordinatorEvents: (fn) => {
369
+ coordinatorEvents.add(fn);
370
+ return () => {
371
+ coordinatorEvents.delete(fn);
372
+ };
373
+ },
374
+ onCoordinatorStart: (goal) => {
375
+ const coordinator = ensureAutonomousCoordinator();
376
+ if (!coordinator) {
377
+ console.error(
378
+ JSON.stringify({
379
+ level: "error",
380
+ event: "coordinator.not_ready",
381
+ message: "no director available",
382
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
383
+ })
384
+ );
385
+ return;
386
+ }
387
+ if (state.coordinatorRun) return;
388
+ state.coordinatorRun = coordinator.run({ goal: goal ?? "Improve the codebase", runUntilComplete: true }).then(() => void 0).catch((err) => {
389
+ console.error(
390
+ JSON.stringify({
391
+ level: "error",
392
+ event: "coordinator.run_failed",
393
+ message: err instanceof Error ? err.message : String(err),
394
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
395
+ })
396
+ );
397
+ }).finally(() => {
398
+ state.coordinatorRun = null;
399
+ });
400
+ },
401
+ onCoordinatorStop: () => {
402
+ state.autonomousCoordinator?.stop();
403
+ },
404
+ onCoordinatorTasks: async () => {
405
+ const coordinator = ensureAutonomousCoordinator();
406
+ if (!coordinator) return null;
407
+ await coordinator.graph.load();
408
+ return coordinator.auction.getPendingTasks().map((task) => ({
409
+ id: task.id,
410
+ title: task.title,
411
+ priority: task.priority,
412
+ tags: task.tags
413
+ }));
414
+ },
415
+ onCoordinatorClaim: async (taskId) => {
416
+ const coordinator = ensureAutonomousCoordinator();
417
+ if (!coordinator) return "No coordinator is active.";
418
+ await coordinator.graph.load();
419
+ const goal = coordinator.graph.get(taskId);
420
+ if (goal?.type !== "goal") {
421
+ return `Task ${taskId.slice(0, 8)} not found in the coordinator graph.`;
422
+ }
423
+ if (goal.status !== "pending") {
424
+ return `Task ${taskId.slice(0, 8)} is ${goal.status}, not claimable.`;
425
+ }
426
+ const ok = await coordinator.auction.claim(
427
+ taskId,
428
+ `terminal@${context.session.id ?? "unknown"}`,
429
+ "Terminal worker"
430
+ );
431
+ if (!ok) {
432
+ return `Task ${taskId.slice(0, 8)} could not be claimed (status changed?).`;
433
+ }
434
+ return { description: goal.description };
435
+ },
436
+ onCoordinatorComplete: async (taskId, result) => {
437
+ const coordinator = ensureAutonomousCoordinator();
438
+ if (!coordinator) return "No coordinator is active.";
439
+ await coordinator.graph.load();
440
+ const goal = coordinator.graph.get(taskId);
441
+ if (goal?.type !== "goal") {
442
+ return `Task ${taskId.slice(0, 8)} not found in the coordinator graph.`;
443
+ }
444
+ if (goal.status !== "in_progress") {
445
+ return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot complete.`;
446
+ }
447
+ await coordinator.reportTaskCompletion(
448
+ taskId,
449
+ result ?? "Terminal worker completed the task"
450
+ );
451
+ return null;
452
+ },
453
+ onCoordinatorFail: async (taskId, error) => {
454
+ const coordinator = ensureAutonomousCoordinator();
455
+ if (!coordinator) return "No coordinator is active.";
456
+ await coordinator.graph.load();
457
+ const goal = coordinator.graph.get(taskId);
458
+ if (goal?.type !== "goal") {
459
+ return `Task ${taskId.slice(0, 8)} not found in the coordinator graph.`;
460
+ }
461
+ if (goal.status !== "in_progress") {
462
+ return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot fail.`;
463
+ }
464
+ await coordinator.reportTaskFailure(taskId, error);
465
+ return null;
466
+ },
467
+ onCoordinatorStatus: async () => {
468
+ const coordinator = ensureAutonomousCoordinator();
469
+ if (!coordinator) return null;
470
+ await coordinator.syncFromGraph();
471
+ const stats = coordinator.getStats();
472
+ return {
473
+ goals: {
474
+ total: stats.goals.total,
475
+ done: stats.goals.done,
476
+ pending: stats.goals.pending,
477
+ failed: stats.goals.failed
478
+ },
479
+ dag: {
480
+ running: stats.dag.running,
481
+ ready: stats.dag.ready,
482
+ done: stats.dag.done,
483
+ failed: stats.dag.failed
484
+ },
485
+ auction: {
486
+ pending: stats.auction.pending,
487
+ inProgress: stats.auction.in_progress
488
+ }
489
+ };
490
+ }
491
+ };
492
+ }
493
+
494
+ // src/boot/tui-coordinator-setup.ts
495
+ import * as path from "node:path";
496
+ import { AutonomousCoordinator } from "@wrongstack/core/coordination";
497
+ function setupAutonomousCoordinator(ctx) {
498
+ const { state, events, context, wpaths, mailbox, director, getDirector, coordinatorController, onCoordinatorStopSetter } = ctx;
499
+ const ensure = () => {
500
+ if (state.autonomousCoordinator) return state.autonomousCoordinator;
501
+ const currentDirector = getDirector?.() ?? director;
502
+ if (!currentDirector) return null;
503
+ const transcript = context.session.transcriptPath;
504
+ const sessionDir = transcript ? path.dirname(transcript) : wpaths.projectDir;
505
+ const llmProvider = {
506
+ decide: async (prompt) => {
507
+ const sysPrompt = [
508
+ {
509
+ type: "text",
510
+ text: 'You are the autonomous brain of a multi-agent coordination system. Pick the best option for the decision described and reply with JSON: {"optionId":"<id>","rationale":"<short why>"}.'
511
+ }
512
+ ];
513
+ const userPrompt = {
514
+ type: "text",
515
+ text: `Decision: ${prompt.question}
516
+
517
+ Context: ${JSON.stringify(prompt.context)}
518
+
519
+ Options:
520
+ ${prompt.options.map((o, i) => ` ${i + 1}. [${o.id}] ${o.label}${o.consequence ? ` \u2014 ${o.consequence}` : ""}`).join("\n")}
521
+
522
+ Risk: ${prompt.risk}
523
+
524
+ Reply with ONLY the JSON object.`
525
+ };
526
+ const resp = await context.provider.complete(
527
+ {
528
+ model: context.model,
529
+ system: sysPrompt,
530
+ messages: [
531
+ {
532
+ role: "user",
533
+ content: [userPrompt]
534
+ }
535
+ ],
536
+ maxTokens: 1024,
537
+ temperature: 0
538
+ },
539
+ { signal: context.signal }
540
+ );
541
+ const text = resp.content.filter((b) => b.type === "text").map((b) => b.text).join("\n").trim();
542
+ const cleaned = text.replace(/^```(?:json)?\s*/i, "").replace(/```$/, "").trim();
543
+ try {
544
+ const parsed = JSON.parse(cleaned);
545
+ const optId = parsed.optionId ?? prompt.options[0]?.id ?? "";
546
+ return { optionId: optId, rationale: parsed.rationale ?? "" };
547
+ } catch {
548
+ return { optionId: prompt.options[0]?.id ?? "", rationale: text };
549
+ }
550
+ }
551
+ };
552
+ state.autonomousCoordinator = new AutonomousCoordinator({
553
+ sessionDir,
554
+ fleet: currentDirector.fleet,
555
+ fleetManager: currentDirector.fleetManager,
556
+ director: currentDirector,
557
+ mailbox,
558
+ selfAgentId: `leader@${context.session.id ?? "unknown"}`,
559
+ selfAgentName: "Leader",
560
+ llmProvider,
561
+ onCoordinatorEvent: (event) => {
562
+ for (const fn of state.coordinatorEvents) fn(event);
563
+ }
564
+ });
565
+ onCoordinatorStopSetter(() => state.autonomousCoordinator?.dispose());
566
+ if (coordinatorController) {
567
+ coordinatorController["onCoordinatorStart"] = (goal) => {
568
+ const coordinator = state.autonomousCoordinator;
569
+ if (!coordinator) return;
570
+ coordinator.run({ goal: goal ?? "Improve the codebase", runUntilComplete: true }).then(() => void 0).catch(
571
+ (err) => console.error(
572
+ JSON.stringify({
573
+ level: "error",
574
+ event: "coordinator.run_failed",
575
+ message: err instanceof Error ? err.message : String(err),
576
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
577
+ })
578
+ )
579
+ );
580
+ };
581
+ coordinatorController["onCoordinatorStop"] = () => state.autonomousCoordinator?.stop();
582
+ coordinatorController["onCoordinatorTasks"] = async () => {
583
+ if (!state.autonomousCoordinator) return null;
584
+ await state.autonomousCoordinator.graph.load();
585
+ return state.autonomousCoordinator.auction.getPendingTasks().map((task) => ({ id: task.id, title: task.title, priority: task.priority, tags: task.tags }));
586
+ };
587
+ coordinatorController["onCoordinatorClaim"] = async (taskId) => {
588
+ if (!state.autonomousCoordinator) return "No coordinator is active.";
589
+ await state.autonomousCoordinator.graph.load();
590
+ const goal = state.autonomousCoordinator.graph.get(taskId);
591
+ if (goal?.type !== "goal") return `Task ${taskId.slice(0, 8)} not found.`;
592
+ if (goal.status !== "pending") return `Task ${taskId.slice(0, 8)} is ${goal.status}, not claimable.`;
593
+ const ok = await state.autonomousCoordinator.auction.claim(
594
+ taskId,
595
+ `terminal@${context.session.id ?? "unknown"}`,
596
+ "Terminal worker"
597
+ );
598
+ if (!ok) return `Task ${taskId.slice(0, 8)} could not be claimed.`;
599
+ return { description: goal.description };
600
+ };
601
+ coordinatorController["onCoordinatorComplete"] = async (taskId, result) => {
602
+ if (!state.autonomousCoordinator) return "No coordinator is active.";
603
+ await state.autonomousCoordinator.graph.load();
604
+ const goal = state.autonomousCoordinator.graph.get(taskId);
605
+ if (goal?.type !== "goal") return `Task ${taskId.slice(0, 8)} not found.`;
606
+ if (goal.status !== "in_progress") return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot complete.`;
607
+ await state.autonomousCoordinator.reportTaskCompletion(taskId, result ?? "Terminal worker completed the task");
608
+ return null;
609
+ };
610
+ coordinatorController["onCoordinatorFail"] = async (taskId, error) => {
611
+ if (!state.autonomousCoordinator) return "No coordinator is active.";
612
+ await state.autonomousCoordinator.graph.load();
613
+ const goal = state.autonomousCoordinator.graph.get(taskId);
614
+ if (goal?.type !== "goal") return `Task ${taskId.slice(0, 8)} not found.`;
615
+ if (goal.status !== "in_progress") return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot fail.`;
616
+ await state.autonomousCoordinator.reportTaskFailure(taskId, error);
617
+ return null;
618
+ };
619
+ coordinatorController["onCoordinatorStatus"] = async () => {
620
+ if (!state.autonomousCoordinator) return null;
621
+ await state.autonomousCoordinator.syncFromGraph();
622
+ const stats = state.autonomousCoordinator.getStats();
623
+ return {
624
+ goals: { total: stats.goals.total, done: stats.goals.done, pending: stats.goals.pending, failed: stats.goals.failed },
625
+ dag: { running: stats.dag.running, ready: stats.dag.ready, done: stats.dag.done, failed: stats.dag.failed },
626
+ auction: { pending: stats.auction.pending, inProgress: stats.auction.in_progress }
627
+ };
628
+ };
629
+ }
630
+ return state.autonomousCoordinator;
631
+ };
632
+ if (director) ensure();
633
+ const offDirectorSpawned = events.onPattern("subagent.spawned", () => {
634
+ if (ensure()) offDirectorSpawned();
635
+ });
636
+ return {
637
+ ensure,
638
+ cleanup: () => offDirectorSpawned()
639
+ };
640
+ }
641
+
642
+ // src/boot/tui-debug-stream.ts
643
+ async function registerDebugStreamCallback(cb) {
644
+ try {
645
+ const { setDebugStreamCallback } = await import("@wrongstack/providers");
646
+ setDebugStreamCallback(cb);
647
+ } catch (err) {
648
+ console.error(
649
+ JSON.stringify({
650
+ level: "error",
651
+ event: "execution.debug_stream_register_failed",
652
+ message: err instanceof Error ? err.message : String(err),
653
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
654
+ })
655
+ );
656
+ }
657
+ }
658
+ async function restoreDebugStreamCallback() {
659
+ try {
660
+ const { setDebugStreamCallback, defaultDebugStreamCallback } = await import("@wrongstack/providers");
661
+ setDebugStreamCallback(defaultDebugStreamCallback);
662
+ } catch (err) {
663
+ console.error(
664
+ JSON.stringify({
665
+ level: "error",
666
+ event: "execution.debug_stream_restore_failed",
667
+ message: err instanceof Error ? err.message : String(err),
668
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
669
+ })
670
+ );
671
+ }
672
+ }
673
+
674
+ // src/boot/tui-goal-wiring.ts
675
+ import { PHASE_EVENT_NAMES } from "@wrongstack/core/goal";
676
+ var GOAL_EVENTS = [
677
+ ...PHASE_EVENT_NAMES,
678
+ // Extra events not in PhaseEventMap (sourced from other subsystems)
679
+ "sdd.board.snapshot",
680
+ "worktree.allocated",
681
+ "worktree.committed",
682
+ "worktree.merged",
683
+ "worktree.conflict",
684
+ "worktree.released",
685
+ "worktree.failed",
686
+ "countdown.tick"
687
+ ];
688
+ function wireGoal(events) {
689
+ const handlers = /* @__PURE__ */ new Map();
690
+ const onUntyped = events.on.bind(events);
691
+ const offUntyped = events.off.bind(events);
692
+ const subscribe = (handler) => {
693
+ const registrations = [];
694
+ for (const ev of GOAL_EVENTS) {
695
+ const h = (p) => handler(ev, p);
696
+ handlers.set(ev, h);
697
+ onUntyped(ev, h);
698
+ registrations.push(() => offUntyped(ev, h));
699
+ }
700
+ return () => {
701
+ for (const unregister of registrations) unregister();
702
+ handlers.clear();
703
+ };
704
+ };
705
+ const cleanup = () => {
706
+ for (const [ev, h] of handlers) {
707
+ offUntyped(ev, h);
708
+ }
709
+ handlers.clear();
710
+ };
711
+ return { subscribe, cleanup };
712
+ }
713
+
714
+ // src/boot/tui-live-sessions.ts
715
+ import * as path2 from "node:path";
716
+ async function getLiveSessions(ctx) {
717
+ const { SessionRegistry } = await import("@wrongstack/core/storage");
718
+ const globalRoot = path2.dirname(ctx.state.wpaths.globalConfig);
719
+ const registry = new SessionRegistry(globalRoot);
720
+ const sessions = await registry.list();
721
+ return sessions.filter((s) => s.status !== "stale").map((s) => ({
722
+ sessionId: s.sessionId,
723
+ projectName: s.projectName,
724
+ projectSlug: s.projectSlug,
725
+ projectRoot: s.projectRoot,
726
+ workingDir: s.workingDir,
727
+ gitBranch: s.gitBranch,
728
+ status: s.status,
729
+ pid: s.pid,
730
+ startedAt: s.startedAt,
731
+ agentCount: s.agentCount,
732
+ agents: s.agents.map((a) => ({
733
+ id: a.id,
734
+ name: a.name,
735
+ status: a.status,
736
+ currentTool: a.currentTool,
737
+ iterations: a.iterations,
738
+ toolCalls: a.toolCalls,
739
+ lastActivityAt: a.lastActivityAt
740
+ }))
741
+ }));
742
+ }
743
+ function onSwitchToSession(ctx, _sessionId, targetRoot, projectName) {
744
+ ctx.state.pendingProjectSwitch = { root: targetRoot, name: projectName };
745
+ }
746
+
747
+ // src/boot/tui-project-picker-callback.ts
748
+ import * as path3 from "node:path";
749
+ import { color as color3 } from "@wrongstack/core/utils";
750
+ async function getProjectPickerItems(ctx) {
751
+ const { buildPickerItems } = await import("./project-picker-BOCWHBXP.js");
752
+ return buildPickerItems({
753
+ globalConfigPath: ctx.state.wpaths.globalConfig,
754
+ currentProjectRoot: ctx.state.projectRoot
755
+ });
756
+ }
757
+ async function onProjectSelect(ctx, slug, kind) {
758
+ const { state, renderer, director, getEternalEngine, getParallelEngine, switchProjectInPlace: switchProjectInPlace2 } = ctx;
759
+ try {
760
+ if (kind === "action") {
761
+ if (slug === "new-session") {
762
+ const name = path3.basename(state.projectRoot) || state.projectRoot;
763
+ const err2 = await switchProjectInPlace2(state.projectRoot, name);
764
+ if (err2) renderer.write(color3.red(`Project switch failed: ${err2}
765
+ `));
766
+ }
767
+ return;
768
+ }
769
+ const { loadManifest, saveManifest } = await import("./project-manifest-GE25PW4S.js");
770
+ const manifest = await loadManifest(state.wpaths.globalConfig);
771
+ const project = manifest.projects.find((p) => p.slug === slug);
772
+ if (!project) return;
773
+ const targetRoot = path3.resolve(project.root);
774
+ if (path3.resolve(state.projectRoot) === targetRoot) return;
775
+ const fleetStatus = director?.status();
776
+ const fleetRunning = fleetStatus?.subagents.filter((a) => a.status === "running").length ?? 0;
777
+ const eternalActive = getEternalEngine?.()?.currentState === "running";
778
+ const parallelActive = getParallelEngine?.()?.currentState === "running";
779
+ const hasActiveAgents = fleetRunning > 0 || eternalActive || parallelActive;
780
+ if (hasActiveAgents) {
781
+ const parts = [
782
+ color3.yellow("\u26A0 Switching project in place; active background work is still tied to the previous project:")
783
+ ];
784
+ if (fleetRunning > 0) parts.push(color3.dim(` \u2022 ${fleetRunning} subagent(s) currently running`));
785
+ if (eternalActive) parts.push(color3.dim(" \u2022 Eternal engine is active"));
786
+ if (parallelActive) parts.push(color3.dim(" \u2022 Parallel engine is active"));
787
+ parts.push("");
788
+ parts.push(color3.dim(` New project: ${project.name}`));
789
+ renderer.write(`
790
+ ${parts.join("\n")}
791
+ `);
792
+ }
793
+ project.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
794
+ await saveManifest(manifest, state.wpaths.globalConfig);
795
+ const err = await switchProjectInPlace2(targetRoot, project.name);
796
+ if (err) renderer.write(color3.red(`Project switch failed: ${err}
797
+ `));
798
+ } catch (err) {
799
+ renderer.write(
800
+ color3.red(
801
+ `Project switch failed: ${err instanceof Error ? err.message : String(err)}
802
+ `
803
+ )
804
+ );
805
+ }
806
+ }
807
+
808
+ // src/boot/tui-project-spawn.ts
809
+ import { spawn } from "node:child_process";
810
+ import { createRequire } from "node:module";
811
+ import * as fs from "node:fs/promises";
812
+ import * as path4 from "node:path";
813
+ import { color as color4 } from "@wrongstack/core/utils";
814
+ async function handleProjectSwitchSpawn(opts) {
815
+ const PROJECT_SWITCH_EXIT_CODE = 42;
816
+ if (opts.code !== PROJECT_SWITCH_EXIT_CODE || !opts.pendingProjectSwitch) {
817
+ return null;
818
+ }
819
+ const { root, name, resumeSessionId } = opts.pendingProjectSwitch;
820
+ process.stdout.write("\x1B[2J\x1B[H");
821
+ let cliPath;
822
+ try {
823
+ const req = createRequire(import.meta.url);
824
+ const pkgPath = req.resolve("@wrongstack/cli/package.json");
825
+ const pkgDir = path4.dirname(pkgPath);
826
+ cliPath = path4.join(pkgDir, "dist", "index.js");
827
+ await fs.access(cliPath);
828
+ } catch {
829
+ cliPath = process.argv[1] ?? "";
830
+ if (!cliPath) {
831
+ console.error(color4.red("Could not locate the CLI entry point.\n"));
832
+ return 1;
833
+ }
834
+ }
835
+ const nodeExe = process.execPath;
836
+ const spawnArgs = [cliPath, "--no-interactive"];
837
+ if (resumeSessionId) spawnArgs.push("--resume", resumeSessionId);
838
+ spawn(nodeExe, spawnArgs, {
839
+ cwd: root,
840
+ stdio: "ignore",
841
+ detached: true
842
+ }).on("error", (err) => {
843
+ console.error(color4.red(`Failed to spawn wstack: ${err.message}`));
844
+ });
845
+ console.log(
846
+ [
847
+ "",
848
+ color4.green(` Switched to ${name}`),
849
+ color4.dim(` Root: ${root}`),
850
+ color4.dim(" (current session stays open \u2014 Ctrl+C to return)"),
851
+ ""
852
+ ].join("\n")
853
+ );
854
+ return 0;
855
+ }
856
+
857
+ // src/boot/tui-project-switch.ts
858
+ import * as fs2 from "node:fs/promises";
859
+ import * as path5 from "node:path";
860
+ import {
861
+ DefaultSystemPromptBuilder,
862
+ setQueuedMessagesSnapshot
863
+ } from "@wrongstack/core/agent";
864
+ import { DefaultSessionStore } from "@wrongstack/core/storage";
865
+ import { resolveWstackPaths, sessionScopedPath } from "@wrongstack/core/utils";
866
+ async function switchProjectInPlace(ctx, targetRoot, displayName) {
867
+ const {
868
+ state,
869
+ context,
870
+ events,
871
+ agent,
872
+ config,
873
+ tokenCounter,
874
+ modeId,
875
+ modeStore,
876
+ memoryStore,
877
+ skillLoader,
878
+ attachTodosCheckpoint: attachTodosCheckpoint3
879
+ } = ctx;
880
+ const resolved = path5.resolve(targetRoot);
881
+ const stat2 = await fs2.stat(resolved).catch(() => null);
882
+ if (!stat2?.isDirectory()) return `Cannot switch: not a directory: ${resolved}`;
883
+ const oldWriter = context.session;
884
+ const oldUsage = tokenCounter.total();
885
+ const oldProjectRoot = state.projectRoot;
886
+ const nextWpaths = resolveWstackPaths({
887
+ projectRoot: resolved,
888
+ globalRoot: state.wpaths.globalRoot
889
+ });
890
+ await fs2.mkdir(nextWpaths.projectSessions, { recursive: true });
891
+ const nextSessionStore = new DefaultSessionStore({
892
+ dir: nextWpaths.projectSessions,
893
+ projectRoot: resolved
894
+ });
895
+ const nextWriter = await nextSessionStore.create({
896
+ id: "",
897
+ title: "",
898
+ model: context.model,
899
+ provider: context.provider.id ?? config.provider
900
+ });
901
+ const previousCwd = process.cwd();
902
+ try {
903
+ process.chdir(resolved);
904
+ process.chdir(previousCwd);
905
+ } catch (err) {
906
+ await nextWriter.close().catch(() => void 0);
907
+ await nextSessionStore.delete(nextWriter.id).catch(() => void 0);
908
+ return `Cannot switch: ${err instanceof Error ? err.message : String(err)}`;
909
+ }
910
+ if (!state.activateSessionIdentity) {
911
+ await nextWriter.close().catch(() => void 0);
912
+ await nextSessionStore.delete(nextWriter.id).catch(() => void 0);
913
+ return "Cannot switch: session ownership registry is unavailable.";
914
+ }
915
+ try {
916
+ await state.activateSessionIdentity(nextWriter.id, {
917
+ projectSlug: nextWpaths.projectSlug,
918
+ projectRoot: resolved,
919
+ projectName: displayName || path5.basename(resolved),
920
+ workingDir: resolved
921
+ });
922
+ } catch (err) {
923
+ await nextWriter.close().catch(() => void 0);
924
+ await nextSessionStore.delete(nextWriter.id).catch(() => void 0);
925
+ return `Cannot switch: ${err instanceof Error ? err.message : String(err)}`;
926
+ }
927
+ await Promise.resolve(state.detachActiveTodosCheckpoint?.()).catch(() => void 0);
928
+ process.chdir(resolved);
929
+ state.projectRoot = resolved;
930
+ state.wpaths = nextWpaths;
931
+ state.activeSessionStore = nextSessionStore;
932
+ context.cwd = resolved;
933
+ context.projectRoot = resolved;
934
+ context.workingDir = resolved;
935
+ context.session = nextWriter;
936
+ context.state.replaceMessages([]);
937
+ context.state.replaceTodos([]);
938
+ context.clearFileTracking();
939
+ context.tokenCounter.reset();
940
+ context.meta["packageTrackerOpts"] = { storageDir: nextWpaths.projectDir, projectRoot: resolved };
941
+ context.state.setMeta(
942
+ "plan.path",
943
+ sessionScopedPath(nextWpaths.projectSessions, nextWriter.id, ".plan.json")
944
+ );
945
+ context.state.setMeta(
946
+ "task.path",
947
+ sessionScopedPath(nextWpaths.projectSessions, nextWriter.id, ".tasks.json")
948
+ );
949
+ try {
950
+ state.detachActiveTodosCheckpoint = attachTodosCheckpoint3(
951
+ context.state,
952
+ sessionScopedPath(nextWpaths.projectSessions, nextWriter.id, ".todos.json"),
953
+ nextWriter.id,
954
+ events,
955
+ context.traceId
956
+ );
957
+ } catch {
958
+ state.detachActiveTodosCheckpoint = void 0;
959
+ }
960
+ setQueuedMessagesSnapshot(context, []);
961
+ try {
962
+ const switchMode = modeId && modeId !== "default" && modeStore ? await modeStore.getMode(modeId) : void 0;
963
+ const switchBuilder = new DefaultSystemPromptBuilder({
964
+ memoryStore: memoryStore ?? void 0,
965
+ // Single injection channel: SAGE turn middleware, not a static section.
966
+ injectMemory: false,
967
+ skillLoader,
968
+ modeStore,
969
+ modeId: modeId ?? "default",
970
+ modePrompt: switchMode?.prompt ?? "",
971
+ instructionPaths: {
972
+ globalDir: nextWpaths.globalInstructions,
973
+ projectDir: nextWpaths.inProjectInstructions,
974
+ systemVariant: config.systemPrompt?.variant
975
+ }
976
+ });
977
+ context.systemPrompt = await switchBuilder.build({
978
+ cwd: resolved,
979
+ projectRoot: resolved,
980
+ tools: agent.tools.list(),
981
+ provider: context.provider.id,
982
+ model: context.model
983
+ });
984
+ } catch (err) {
985
+ console.error(
986
+ JSON.stringify({
987
+ level: "warn",
988
+ event: "execution.project_switch_prompt_rebuild_failed",
989
+ message: err instanceof Error ? err.message : String(err),
990
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
991
+ })
992
+ );
993
+ }
994
+ try {
995
+ await oldWriter.append({ type: "session_end", ts: (/* @__PURE__ */ new Date()).toISOString(), usage: oldUsage });
996
+ await oldWriter.close();
997
+ } catch (err) {
998
+ console.error(
999
+ JSON.stringify({
1000
+ level: "warn",
1001
+ event: "execution.project_switch_old_session_close_failed",
1002
+ message: err instanceof Error ? err.message : String(err),
1003
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1004
+ })
1005
+ );
1006
+ }
1007
+ const emitUntyped = events.emit;
1008
+ emitUntyped("project.switched", { from: oldProjectRoot, to: resolved, name: displayName });
1009
+ return null;
1010
+ }
1011
+
1012
+ // src/boot/tui-sdd-callback.ts
1013
+ async function getSDDContext() {
1014
+ const { getActiveSDDContext: getActiveSDDContext2 } = await import("./sdd-runtime-IKPROVV2.js");
1015
+ return getActiveSDDContext2();
1016
+ }
1017
+ async function onSDDOutput(output) {
1018
+ const {
1019
+ trySaveSpecFromAIOutput: trySaveSpecFromAIOutput2,
1020
+ trySaveImplementationPlan: trySaveImplementationPlan2,
1021
+ trySaveTasksFromAIOutput: trySaveTasksFromAIOutput2,
1022
+ autoDetectTaskCompletion: autoDetectTaskCompletion2,
1023
+ getTaskProgress: getTaskProgress2,
1024
+ getActiveSDDPhase: getActiveSDDPhase2
1025
+ } = await import("./sdd-runtime-IKPROVV2.js");
1026
+ const messages = [];
1027
+ const specSaved = await trySaveSpecFromAIOutput2(output);
1028
+ if (specSaved)
1029
+ messages.push("\u2713 Spec detected and saved! Use /sdd approve to continue.");
1030
+ const planSaved = trySaveImplementationPlan2(output);
1031
+ if (planSaved) messages.push("\u2713 Implementation plan saved!");
1032
+ const tasksSaved = await trySaveTasksFromAIOutput2(output);
1033
+ if (tasksSaved) {
1034
+ const progress = getTaskProgress2();
1035
+ const count = progress?.total ?? 0;
1036
+ messages.push(`\u2713 ${count} tasks detected and saved! Use /sdd approve to execute.`);
1037
+ }
1038
+ const sddPhase = getActiveSDDPhase2();
1039
+ if (sddPhase === "executing") {
1040
+ const autoCompleted = autoDetectTaskCompletion2(output);
1041
+ if (autoCompleted > 0) {
1042
+ const progress = getTaskProgress2();
1043
+ if (progress) {
1044
+ messages.push(
1045
+ `\u2713 ${autoCompleted} task(s) auto-completed! Progress: ${progress.completed}/${progress.total} (${progress.percentComplete}%)`
1046
+ );
1047
+ }
1048
+ }
1049
+ }
1050
+ return messages;
1051
+ }
1052
+
1053
+ // src/boot/tui-session-resume.ts
1054
+ import * as path6 from "node:path";
1055
+ import { attachTodosCheckpoint, loadTodosCheckpoint } from "@wrongstack/core/storage";
1056
+ import { sessionScopedPath as sessionScopedPath2 } from "@wrongstack/core/utils";
1057
+ async function resumeSession(ctx, sessionId) {
1058
+ const { state, agent, tokenCounter, switchProviderAndModel, events } = ctx;
1059
+ if (!state.activeSessionStore) return null;
1060
+ const { replaySessionMessages } = await import("@wrongstack/tui");
1061
+ let canonicalSessionId = sessionId;
1062
+ try {
1063
+ if (state.activeSessionStore.resolveId) {
1064
+ canonicalSessionId = await state.activeSessionStore.resolveId(sessionId);
1065
+ }
1066
+ } catch (err) {
1067
+ console.error(
1068
+ JSON.stringify({
1069
+ level: "error",
1070
+ event: "execution.resume_id_resolve_failed",
1071
+ sessionId,
1072
+ message: err instanceof Error ? err.message : String(err),
1073
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1074
+ })
1075
+ );
1076
+ return null;
1077
+ }
1078
+ try {
1079
+ const { SessionRegistry } = await import("@wrongstack/core/storage");
1080
+ const registry = new SessionRegistry(path6.dirname(state.wpaths.globalConfig));
1081
+ const live = (await registry.list()).find(
1082
+ (s) => s.sessionId === canonicalSessionId && s.status !== "stale" && s.pid !== process.pid
1083
+ );
1084
+ if (live) {
1085
+ throw new Error(
1086
+ `Session is open in another running wstack (pid ${live.pid}) \u2014 it cannot be resumed here while live.`
1087
+ );
1088
+ }
1089
+ } catch (err) {
1090
+ if (err instanceof Error && err.message.startsWith("Session is open")) throw err;
1091
+ }
1092
+ const previousSessionId = agent.ctx.session?.id;
1093
+ let identityClaimed = false;
1094
+ let writerSwapped = false;
1095
+ let openedWriter;
1096
+ try {
1097
+ if (state.activateSessionIdentity) {
1098
+ await state.activateSessionIdentity(canonicalSessionId);
1099
+ identityClaimed = true;
1100
+ }
1101
+ const resumed = await state.activeSessionStore.resume(canonicalSessionId);
1102
+ openedWriter = resumed.writer;
1103
+ const meta = resumed.data.metadata;
1104
+ const entries = replaySessionMessages(
1105
+ resumed.data.messages,
1106
+ resumed.data.events,
1107
+ /* startId */
1108
+ 1
1109
+ );
1110
+ const sessionsDir = state.wpaths.projectSessions;
1111
+ const resumedTodosPath = sessionScopedPath2(sessionsDir, resumed.writer.id, ".todos.json");
1112
+ const restoredTodos = await loadTodosCheckpoint(
1113
+ resumedTodosPath,
1114
+ events,
1115
+ agent.ctx.traceId
1116
+ ).catch(() => null);
1117
+ const oldWriter = agent.ctx.session;
1118
+ const oldMessages = [...agent.ctx.messages];
1119
+ agent.ctx.session = resumed.writer;
1120
+ try {
1121
+ agent.ctx.state.replaceMessages(resumed.data.messages);
1122
+ } catch (err) {
1123
+ agent.ctx.session = oldWriter;
1124
+ agent.ctx.state.replaceMessages(oldMessages);
1125
+ throw err;
1126
+ }
1127
+ writerSwapped = true;
1128
+ await agent.ctx.flushConversationJournal().catch((err) => {
1129
+ console.error(
1130
+ JSON.stringify({
1131
+ level: "error",
1132
+ event: "execution.resume_journal_flush_failed",
1133
+ message: err instanceof Error ? err.message : String(err),
1134
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1135
+ })
1136
+ );
1137
+ });
1138
+ await Promise.resolve(state.detachActiveTodosCheckpoint?.()).catch(() => void 0);
1139
+ agent.ctx.state.setMeta(
1140
+ "plan.path",
1141
+ sessionScopedPath2(sessionsDir, resumed.writer.id, ".plan.json")
1142
+ );
1143
+ agent.ctx.state.setMeta(
1144
+ "task.path",
1145
+ sessionScopedPath2(sessionsDir, resumed.writer.id, ".tasks.json")
1146
+ );
1147
+ agent.ctx.state.replaceTodos(restoredTodos ?? []);
1148
+ try {
1149
+ state.detachActiveTodosCheckpoint = attachTodosCheckpoint(
1150
+ agent.ctx.state,
1151
+ resumedTodosPath,
1152
+ resumed.writer.id,
1153
+ events,
1154
+ agent.ctx.traceId
1155
+ );
1156
+ } catch {
1157
+ state.detachActiveTodosCheckpoint = void 0;
1158
+ }
1159
+ const currentProviderId = agent.ctx.provider.id;
1160
+ const targetProviderId = typeof meta.provider === "string" && meta.provider.length > 0 ? meta.provider : currentProviderId;
1161
+ const targetModel = typeof meta.model === "string" && meta.model.length > 0 ? meta.model : agent.ctx.model;
1162
+ if (switchProviderAndModel && targetProviderId && (targetProviderId !== currentProviderId || targetModel !== agent.ctx.model)) {
1163
+ await Promise.resolve(switchProviderAndModel(targetProviderId, targetModel)).catch(
1164
+ (err) => {
1165
+ console.error(
1166
+ JSON.stringify({
1167
+ level: "error",
1168
+ event: "execution.resume_model_restore_failed",
1169
+ provider: targetProviderId,
1170
+ model: targetModel,
1171
+ message: err instanceof Error ? err.message : String(err),
1172
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1173
+ })
1174
+ );
1175
+ }
1176
+ );
1177
+ } else if (targetModel !== agent.ctx.model) {
1178
+ agent.ctx.model = targetModel;
1179
+ }
1180
+ if (oldWriter && oldWriter !== resumed.writer) {
1181
+ const endedUsage = tokenCounter.total();
1182
+ void (async () => {
1183
+ let appendOk = false;
1184
+ try {
1185
+ await oldWriter.append({
1186
+ type: "session_end",
1187
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1188
+ usage: endedUsage
1189
+ });
1190
+ appendOk = true;
1191
+ } catch (err) {
1192
+ console.error(
1193
+ JSON.stringify({
1194
+ level: "error",
1195
+ event: "execution.session_end_append_failed",
1196
+ message: err instanceof Error ? err.message : String(err),
1197
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1198
+ })
1199
+ );
1200
+ }
1201
+ if (appendOk) {
1202
+ try {
1203
+ await oldWriter.close();
1204
+ } catch (err) {
1205
+ console.error(
1206
+ JSON.stringify({
1207
+ level: "error",
1208
+ event: "execution.session_close_failed",
1209
+ message: err instanceof Error ? err.message : String(err),
1210
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1211
+ })
1212
+ );
1213
+ }
1214
+ }
1215
+ })();
1216
+ }
1217
+ tokenCounter.reset();
1218
+ tokenCounter.account(resumed.data.usage, targetModel, targetProviderId);
1219
+ return {
1220
+ entries,
1221
+ nextId: entries.length + 1,
1222
+ sessionId: resumed.writer.id
1223
+ };
1224
+ } catch (err) {
1225
+ if (identityClaimed && !writerSwapped && previousSessionId) {
1226
+ await state.activateSessionIdentity?.(previousSessionId).catch((rollbackErr) => {
1227
+ console.error(
1228
+ JSON.stringify({
1229
+ level: "error",
1230
+ event: "execution.resume_identity_rollback_failed",
1231
+ sessionId: previousSessionId,
1232
+ message: rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr),
1233
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1234
+ })
1235
+ );
1236
+ });
1237
+ }
1238
+ if (!writerSwapped) {
1239
+ await openedWriter?.close().catch(() => void 0);
1240
+ }
1241
+ console.error(
1242
+ JSON.stringify({
1243
+ level: "error",
1244
+ event: "execution.resume_session_failed",
1245
+ message: err instanceof Error ? err.message : String(err),
1246
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1247
+ })
1248
+ );
1249
+ return null;
1250
+ }
1251
+ }
1252
+
1253
+ // src/boot/tui-settings-adapter.ts
1254
+ import * as fs3 from "node:fs/promises";
1255
+ import * as path7 from "node:path";
1256
+ import { decryptConfigSecrets, encryptConfigSecrets, noOpVault } from "@wrongstack/core/security";
1257
+ import { normalizeTokenSavingTier, resolveFleetChatVerbosity } from "@wrongstack/core/types";
1258
+ import { atomicWrite } from "@wrongstack/core/utils";
1259
+ import { getProcessRegistry } from "@wrongstack/tools";
1260
+ var ANIMATION_STYLES = ["rainbow", "wave", "pulse", "dots", "breathe", "cycle"];
1261
+ function normalizeAnimationStyle(raw) {
1262
+ return typeof raw === "string" && ANIMATION_STYLES.includes(raw) ? raw : "rainbow";
1263
+ }
1264
+ function createSettingsAdapter(ctx) {
1265
+ const { configStore, wpaths, fleetStreamController, applyLiveSettings } = ctx;
1266
+ const deriveFsAccess = deriveFsAccessPair;
1267
+ function getSettings() {
1268
+ const cfg = configStore.get();
1269
+ const autonomy = cfg.autonomy;
1270
+ const rawMode = autonomy?.defaultMode;
1271
+ const mode = rawMode === "suggest" || rawMode === "auto" ? rawMode : "off";
1272
+ const modelRuntime = cfg.modelRuntime;
1273
+ const contextModeRaw = cfg.context?.mode;
1274
+ const contextMode = contextModeRaw === "frugal" || contextModeRaw === "deep" ? contextModeRaw : "balanced";
1275
+ const reasoningEffortRaw = modelRuntime?.reasoning?.effort;
1276
+ const reasoningEffort = reasoningEffortRaw === "none" || reasoningEffortRaw === "minimal" || reasoningEffortRaw === "low" || reasoningEffortRaw === "medium" || reasoningEffortRaw === "high" || reasoningEffortRaw === "xhigh" || reasoningEffortRaw === "max" ? reasoningEffortRaw : "high";
1277
+ const featuresAllow = cfg.features?.allowOutsideProjectRoot;
1278
+ const toolsRestrict = cfg.tools?.restrictToProjectRoot;
1279
+ const resolvedAllow = featuresAllow !== void 0 ? featuresAllow : toolsRestrict !== void 0 ? !toolsRestrict : true;
1280
+ const resolvedRestrict = !resolvedAllow;
1281
+ return {
1282
+ mode,
1283
+ delayMs: autonomy?.autoProceedDelayMs ?? 45e3,
1284
+ titleAnimation: autonomy?.terminalTitleAnimation !== false,
1285
+ yolo: cfg.yolo ?? autonomy?.yolo ?? false,
1286
+ fleetChatVerbosity: resolveFleetChatVerbosity(cfg.autonomy),
1287
+ chime: autonomy?.chime ?? false,
1288
+ confirmExit: autonomy?.confirmExit !== false,
1289
+ nextPrediction: cfg.nextPrediction ?? false,
1290
+ featureMcp: cfg.features?.mcp !== false,
1291
+ featurePlugins: cfg.features?.plugins !== false,
1292
+ featureMemory: cfg.features?.memory !== false,
1293
+ featureSkills: cfg.features?.skills !== false,
1294
+ featureModelsRegistry: cfg.features?.modelsRegistry !== false,
1295
+ // Preserve the 'auto' sentinel for the picker DISPLAY (normalize would
1296
+ // collapse it to 'off', which would then overwrite 'auto' on save);
1297
+ // everything else normalizes to a concrete tier.
1298
+ featureTokenSaving: cfg.features?.tokenSavingMode === "auto" ? "auto" : normalizeTokenSavingTier(cfg.features?.tokenSavingMode),
1299
+ allowOutsideProjectRoot: resolvedAllow,
1300
+ contextAutoCompact: cfg.context?.autoCompact !== false,
1301
+ contextStrategy: cfg.context?.strategy ?? "hybrid",
1302
+ contextMode,
1303
+ maxConcurrent: cfg.maxConcurrent ?? 4,
1304
+ logLevel: cfg.log?.level ?? "info",
1305
+ auditLevel: cfg.session?.auditLevel ?? "standard",
1306
+ indexOnStart: cfg.indexing?.onSessionStart !== false,
1307
+ maxIterations: cfg.tools?.maxIterations ?? 500,
1308
+ restrictFsToRoot: resolvedRestrict,
1309
+ autoProceedMaxIterations: cfg.autonomy?.autoProceedMaxIterations ?? 50,
1310
+ debugStream: cfg.debugStream ?? false,
1311
+ shellBangWarningDontShowAgain: autonomy?.shellBangWarningDontShowAgain === true,
1312
+ statuslineMode: autonomy?.statuslineMode === "no-color" ? "no-color" : autonomy?.statuslineMode === "minimum" ? "minimum" : "detailed",
1313
+ thinkingWord: normalizeTuiThinkingWord(autonomy?.thinkingWord),
1314
+ animationStyle: normalizeAnimationStyle(autonomy?.animationStyle),
1315
+ configScope: cfg.configScope ?? "global",
1316
+ enhanceDelayMs: cfg.autonomy?.enhanceDelayMs ?? 6e4,
1317
+ enhanceEnabled: cfg.autonomy?.enhance ?? true,
1318
+ enhanceLanguage: cfg.autonomy?.enhanceLanguage === "english" ? "english" : "original",
1319
+ midRunSendPicker: cfg.autonomy?.midRunSendPicker ?? true,
1320
+ mouseMode: autonomy?.mouseMode ?? false,
1321
+ autonomyNextPrompt: cfg.autonomy?.autonomyNextPrompt ?? "auto {{suggestion}}",
1322
+ reasoningMode: modelRuntime?.reasoning?.mode === "on" || modelRuntime?.reasoning?.mode === "off" ? modelRuntime.reasoning.mode : "auto",
1323
+ reasoningEffort,
1324
+ reasoningPreserve: modelRuntime?.reasoning?.preserve === true,
1325
+ cacheTtl: modelRuntime?.cache?.ttl === "5m" || modelRuntime?.cache?.ttl === "1h" ? modelRuntime.cache.ttl : "default",
1326
+ breakerEnabled: cfg.circuitBreaker?.enabled === true,
1327
+ breakerAutoKillResetMs: cfg.circuitBreaker?.autoKillResetMs ?? 6e4,
1328
+ showModelReasoning: autonomy?.showModelReasoning ?? true,
1329
+ showAgentSwarmPanel: autonomy?.showAgentSwarmPanel ?? true
1330
+ };
1331
+ }
1332
+ async function saveSettings(s) {
1333
+ try {
1334
+ if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.fleetChatVerbosity !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.shellBangWarningDontShowAgain !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0 || s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0 || s.showModelReasoning !== void 0 || s.showAgentSwarmPanel !== void 0) {
1335
+ const cfg = configStore.get();
1336
+ const activeProfileName = cfg.activeProfile ?? "default";
1337
+ const persistDeps = {
1338
+ configStore,
1339
+ profileConfigPath: wpaths.profileConfig(activeProfileName),
1340
+ inProjectConfigPath: wpaths.inProjectConfig,
1341
+ vault: noOpVault,
1342
+ resolveProfilePath: (name) => wpaths.profileConfig(name)
1343
+ };
1344
+ const targetPath = resolvePersistPath(persistDeps);
1345
+ let raw;
1346
+ try {
1347
+ raw = await fs3.readFile(targetPath, "utf8");
1348
+ } catch (err) {
1349
+ if (err.code !== "ENOENT") {
1350
+ throw new Error(
1351
+ `Failed to read config at ${targetPath}: ${err instanceof Error ? err.message : String(err)}`,
1352
+ { cause: err }
1353
+ );
1354
+ }
1355
+ raw = "{}";
1356
+ }
1357
+ const parsed = JSON.parse(raw);
1358
+ const decrypted = decryptConfigSecrets(parsed, noOpVault);
1359
+ const autonomy = decrypted.autonomy ?? {};
1360
+ if (s.mode !== void 0) autonomy.defaultMode = s.mode;
1361
+ if (s.delayMs !== void 0) autonomy.autoProceedDelayMs = s.delayMs;
1362
+ if (s.titleAnimation !== void 0) autonomy.terminalTitleAnimation = s.titleAnimation;
1363
+ if (s.yolo !== void 0) autonomy.yolo = s.yolo;
1364
+ if (s.fleetChatVerbosity !== void 0) {
1365
+ autonomy.fleetChatVerbosity = s.fleetChatVerbosity;
1366
+ }
1367
+ if (s.chime !== void 0) autonomy.chime = s.chime;
1368
+ if (s.confirmExit !== void 0) autonomy.confirmExit = s.confirmExit;
1369
+ if (s.mouseMode !== void 0) autonomy.mouseMode = s.mouseMode;
1370
+ if (s.enhanceDelayMs !== void 0) autonomy.enhanceDelayMs = s.enhanceDelayMs;
1371
+ if (s.enhanceEnabled !== void 0) autonomy.enhance = s.enhanceEnabled;
1372
+ if (s.enhanceLanguage !== void 0) autonomy.enhanceLanguage = s.enhanceLanguage;
1373
+ if (s.midRunSendPicker !== void 0) autonomy.midRunSendPicker = s.midRunSendPicker;
1374
+ if (s.shellBangWarningDontShowAgain !== void 0)
1375
+ autonomy.shellBangWarningDontShowAgain = s.shellBangWarningDontShowAgain;
1376
+ if (s.statuslineMode !== void 0) autonomy.statuslineMode = s.statuslineMode;
1377
+ if (s.thinkingWord !== void 0)
1378
+ autonomy.thinkingWord = normalizeTuiThinkingWord(s.thinkingWord);
1379
+ if (s.animationStyle !== void 0) autonomy.animationStyle = s.animationStyle;
1380
+ if (s.showModelReasoning !== void 0) autonomy.showModelReasoning = s.showModelReasoning;
1381
+ if (s.showAgentSwarmPanel !== void 0)
1382
+ autonomy.showAgentSwarmPanel = s.showAgentSwarmPanel;
1383
+ if (s.autonomyNextPrompt !== void 0) autonomy.autonomyNextPrompt = s.autonomyNextPrompt;
1384
+ if (s.autoProceedMaxIterations !== void 0)
1385
+ autonomy.autoProceedMaxIterations = s.autoProceedMaxIterations;
1386
+ decrypted.autonomy = autonomy;
1387
+ if (s.nextPrediction !== void 0) decrypted.nextPrediction = s.nextPrediction;
1388
+ if (s.yolo !== void 0) decrypted.yolo = s.yolo;
1389
+ const fsAccess = deriveFsAccess(s);
1390
+ if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || fsAccess !== void 0) {
1391
+ const feats = decrypted.features ?? {};
1392
+ if (s.featureMcp !== void 0) feats.mcp = s.featureMcp;
1393
+ if (s.featurePlugins !== void 0) feats.plugins = s.featurePlugins;
1394
+ if (s.featureMemory !== void 0) feats.memory = s.featureMemory;
1395
+ if (s.featureSkills !== void 0) feats.skills = s.featureSkills;
1396
+ if (s.featureModelsRegistry !== void 0) feats.modelsRegistry = s.featureModelsRegistry;
1397
+ if (s.featureTokenSaving !== void 0) feats.tokenSavingMode = s.featureTokenSaving;
1398
+ if (fsAccess !== void 0)
1399
+ feats.allowOutsideProjectRoot = fsAccess.allowOutsideProjectRoot;
1400
+ decrypted.features = feats;
1401
+ }
1402
+ if (s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0) {
1403
+ const c = decrypted.context ?? {};
1404
+ if (s.contextAutoCompact !== void 0) c.autoCompact = s.contextAutoCompact;
1405
+ if (s.contextStrategy !== void 0) c.strategy = s.contextStrategy;
1406
+ if (s.contextMode !== void 0) c.mode = s.contextMode;
1407
+ decrypted.context = c;
1408
+ }
1409
+ if (s.maxConcurrent !== void 0) decrypted.maxConcurrent = s.maxConcurrent;
1410
+ if (s.logLevel !== void 0) {
1411
+ const log = decrypted.log ?? {};
1412
+ log.level = s.logLevel;
1413
+ decrypted.log = log;
1414
+ }
1415
+ if (s.auditLevel !== void 0) {
1416
+ const sess = decrypted.session ?? {};
1417
+ sess.auditLevel = s.auditLevel;
1418
+ decrypted.session = sess;
1419
+ }
1420
+ if (s.indexOnStart !== void 0) {
1421
+ const idx = decrypted.indexing ?? {};
1422
+ idx.onSessionStart = s.indexOnStart;
1423
+ decrypted.indexing = idx;
1424
+ }
1425
+ if (s.maxIterations !== void 0 || fsAccess !== void 0) {
1426
+ const tools = decrypted.tools ?? {};
1427
+ if (s.maxIterations !== void 0) tools.maxIterations = s.maxIterations;
1428
+ if (fsAccess !== void 0) tools.restrictToProjectRoot = fsAccess.restrictToProjectRoot;
1429
+ decrypted.tools = tools;
1430
+ }
1431
+ if (s.debugStream !== void 0) {
1432
+ decrypted.debugStream = s.debugStream;
1433
+ const { setDebugStreamEnabled } = await import("@wrongstack/providers");
1434
+ setDebugStreamEnabled(s.debugStream);
1435
+ }
1436
+ if (s.configScope !== void 0) decrypted.configScope = s.configScope;
1437
+ if (s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0) {
1438
+ const modelRuntime = decrypted.modelRuntime ?? {};
1439
+ if (s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0) {
1440
+ const reasoning = modelRuntime.reasoning ?? {};
1441
+ if (s.reasoningMode !== void 0) reasoning.mode = s.reasoningMode;
1442
+ if (s.reasoningEffort !== void 0) reasoning.effort = s.reasoningEffort;
1443
+ if (s.reasoningPreserve !== void 0) reasoning.preserve = s.reasoningPreserve;
1444
+ modelRuntime.reasoning = reasoning;
1445
+ }
1446
+ if (s.cacheTtl !== void 0) {
1447
+ const cache = modelRuntime.cache ?? {};
1448
+ if (s.cacheTtl === "default") {
1449
+ delete cache.ttl;
1450
+ } else {
1451
+ cache.ttl = s.cacheTtl;
1452
+ }
1453
+ if (Object.keys(cache).length > 0) modelRuntime.cache = cache;
1454
+ else delete modelRuntime.cache;
1455
+ }
1456
+ decrypted.modelRuntime = modelRuntime;
1457
+ }
1458
+ if (s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0) {
1459
+ const cb = decrypted.circuitBreaker ?? {};
1460
+ if (s.breakerEnabled !== void 0) cb.enabled = s.breakerEnabled;
1461
+ if (s.breakerAutoKillResetMs !== void 0) cb.autoKillResetMs = s.breakerAutoKillResetMs;
1462
+ decrypted.circuitBreaker = cb;
1463
+ }
1464
+ const actualTarget = resolveActualTarget(
1465
+ persistDeps,
1466
+ decrypted,
1467
+ targetPath
1468
+ );
1469
+ const isProjectTarget = actualTarget === wpaths.inProjectConfig;
1470
+ const toWrite = isProjectTarget ? filterSafeForProject(decrypted) : decrypted;
1471
+ const encrypted = encryptConfigSecrets(toWrite, noOpVault);
1472
+ await fs3.mkdir(path7.dirname(actualTarget), { recursive: true });
1473
+ await atomicWrite(actualTarget, JSON.stringify(encrypted, null, 2), { mode: 384 });
1474
+ const currentConfig = configStore.get();
1475
+ const nextModelRuntime = {
1476
+ ...currentConfig.modelRuntime,
1477
+ ...decrypted.modelRuntime ?? {}
1478
+ };
1479
+ if (s.cacheTtl === "default") {
1480
+ delete nextModelRuntime.cache;
1481
+ }
1482
+ configStore.update({
1483
+ ...s.nextPrediction !== void 0 ? { nextPrediction: s.nextPrediction } : {},
1484
+ ...s.yolo !== void 0 ? { yolo: s.yolo } : {},
1485
+ ...s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || fsAccess !== void 0 ? {
1486
+ features: {
1487
+ ...currentConfig.features,
1488
+ ...decrypted.features ?? {}
1489
+ }
1490
+ } : {},
1491
+ ...s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 ? {
1492
+ context: {
1493
+ ...currentConfig.context,
1494
+ ...decrypted.context ?? {}
1495
+ }
1496
+ } : {},
1497
+ ...s.maxConcurrent !== void 0 ? { maxConcurrent: s.maxConcurrent } : {},
1498
+ ...s.logLevel !== void 0 ? {
1499
+ log: {
1500
+ ...currentConfig.log,
1501
+ ...decrypted.log ?? {}
1502
+ }
1503
+ } : {},
1504
+ ...s.auditLevel !== void 0 ? {
1505
+ session: {
1506
+ ...currentConfig.session,
1507
+ ...decrypted.session ?? {}
1508
+ }
1509
+ } : {},
1510
+ ...s.indexOnStart !== void 0 ? {
1511
+ indexing: {
1512
+ ...currentConfig.indexing,
1513
+ ...decrypted.indexing ?? {}
1514
+ }
1515
+ } : {},
1516
+ ...s.maxIterations !== void 0 || fsAccess !== void 0 ? {
1517
+ tools: {
1518
+ ...currentConfig.tools,
1519
+ ...decrypted.tools ?? {}
1520
+ }
1521
+ } : {},
1522
+ ...s.debugStream !== void 0 ? { debugStream: s.debugStream } : {},
1523
+ ...s.configScope !== void 0 ? { configScope: s.configScope } : {},
1524
+ autonomy: {
1525
+ ...currentConfig.autonomy,
1526
+ ...decrypted.autonomy ?? {}
1527
+ },
1528
+ ...s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0 ? {
1529
+ modelRuntime: nextModelRuntime
1530
+ } : {},
1531
+ ...s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0 ? {
1532
+ circuitBreaker: {
1533
+ ...currentConfig.circuitBreaker,
1534
+ ...decrypted.circuitBreaker ?? {}
1535
+ }
1536
+ } : {}
1537
+ });
1538
+ }
1539
+ if (s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0) {
1540
+ getProcessRegistry().setBreakerConfig({
1541
+ ...s.breakerEnabled !== void 0 ? { enabled: s.breakerEnabled } : {},
1542
+ ...s.breakerAutoKillResetMs !== void 0 ? { autoKillResetMs: s.breakerAutoKillResetMs } : {}
1543
+ });
1544
+ }
1545
+ if (s.fleetChatVerbosity !== void 0) {
1546
+ if (fleetStreamController?.setMode) fleetStreamController.setMode(s.fleetChatVerbosity);
1547
+ }
1548
+ applyLiveSettings?.(s);
1549
+ return null;
1550
+ } catch (err) {
1551
+ const message = err instanceof Error ? err.message : String(err);
1552
+ console.debug(
1553
+ JSON.stringify({
1554
+ level: "error",
1555
+ event: "execution.settings_persist_failed",
1556
+ message,
1557
+ errorName: err instanceof Error ? err.name : void 0,
1558
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1559
+ })
1560
+ );
1561
+ return message;
1562
+ }
1563
+ }
1564
+ return { getSettings, saveSettings };
1565
+ }
1566
+
1567
+ // src/brain-menu/panel-service.ts
1568
+ var PERSONA_CYCLE = ["executor", "skeptic", "auditor"];
1569
+ function compactEntry(entry) {
1570
+ return entry.provider ? `${entry.provider}/${entry.model}` : entry.model;
1571
+ }
1572
+ function createBrainPanelHost(deps) {
1573
+ const { brainRuntime } = deps;
1574
+ const apply = async (patch) => {
1575
+ try {
1576
+ const { persisted } = brainRuntime.apply(patch);
1577
+ const result = await persisted;
1578
+ return result.ok ? null : `Applied live but NOT saved: ${result.error ?? "unknown error"}`;
1579
+ } catch (err) {
1580
+ return err instanceof Error ? err.message : String(err);
1581
+ }
1582
+ };
1583
+ const currentPool = () => brainRuntime.getSnapshot().models.map(compactEntry);
1584
+ const currentVoters = () => brainRuntime.getSnapshot().council.voters.map((v) => ({ ...v }));
1585
+ const applyVoters = (voters) => apply({ council: { voters: voters.length > 0 ? voters : null } });
1586
+ return {
1587
+ getSettings() {
1588
+ const snap = brainRuntime.getSnapshot();
1589
+ return {
1590
+ mode: snap.mode,
1591
+ riskLevel: snap.maxAutoRisk,
1592
+ strategy: snap.strategy,
1593
+ decisionTimeoutMs: snap.decisionTimeoutMs,
1594
+ humanTimeoutMs: snap.humanTimeoutMs,
1595
+ pool: snap.models.map(compactEntry),
1596
+ poolResolved: snap.poolLabels,
1597
+ usingSessionModel: snap.usingSessionModel,
1598
+ councilEnabled: snap.council.enabled,
1599
+ councilMinRisk: snap.council.minRisk,
1600
+ voters: snap.council.voters.map((v) => ({
1601
+ label: compactEntry(v),
1602
+ persona: v.persona,
1603
+ veto: v.veto,
1604
+ weight: v.weight
1605
+ })),
1606
+ councilSeats: snap.councilLabels,
1607
+ // The EFFECTIVE judge, not `council.judge`. The configured one is
1608
+ // usually absent, so the panel used to read "auto" and say nothing
1609
+ // about who actually breaks the panel's ties — including when that is
1610
+ // one of the seats that produced the tie.
1611
+ judgeLabel: snap.judgeLabel,
1612
+ judgeConfigured: snap.council.judge !== void 0,
1613
+ judgeIsVoter: snap.judgeIsVoter,
1614
+ ledgerEnabled: snap.ledger.enabled,
1615
+ autoDenyAfterFailures: snap.ledger.autoDenyAfterFailures,
1616
+ terminalPolicy: snap.terminalPolicy,
1617
+ heuristics: {
1618
+ lowRiskAutoAnswer: snap.heuristics.lowRiskAutoAnswer,
1619
+ blockedResolved: snap.heuristics.blockedResolved,
1620
+ deadlockSkip: snap.heuristics.deadlockSkip,
1621
+ retryExhausted: snap.heuristics.retryExhausted,
1622
+ continuePing: snap.heuristics.continuePing,
1623
+ blockedResolvedMarkers: snap.heuristics.blockedResolvedMarkers
1624
+ },
1625
+ llmMaxTokens: snap.llm.maxTokens,
1626
+ llmRejectUncertain: snap.llm.rejectUncertain,
1627
+ llmMinConfidence: snap.llm.minConfidence,
1628
+ llmDenyIsTerminal: snap.llm.denyIsTerminal,
1629
+ cacheEnabled: snap.cache.enabled,
1630
+ cacheTtlMs: snap.cache.ttlMs,
1631
+ cacheMaxEntries: snap.cache.maxEntries,
1632
+ cacheHits: snap.cache.hits,
1633
+ cacheMisses: snap.cache.misses,
1634
+ cacheSize: snap.cache.size,
1635
+ traceEnabled: snap.trace.enabled,
1636
+ traceContent: snap.trace.content,
1637
+ tracePath: snap.trace.path,
1638
+ circuitState: snap.circuit?.state,
1639
+ circuitFailures: snap.circuit?.consecutiveFailures,
1640
+ ruleCount: snap.rules.length,
1641
+ ruleErrors: [...snap.ruleErrors]
1642
+ };
1643
+ },
1644
+ setMode: (mode) => apply({ mode }),
1645
+ setRisk: (level) => apply({ maxAutoRisk: level }),
1646
+ setStrategy: (strategy) => apply({ strategy }),
1647
+ setDecisionTimeout: (ms) => apply({ decisionTimeoutMs: ms ?? null }),
1648
+ setHumanTimeout: (ms) => apply({ humanTimeoutMs: ms ?? null }),
1649
+ addPoolModel: (providerId, model) => apply({ models: [...currentPool(), `${providerId}/${model}`] }),
1650
+ removePoolModel: (index) => {
1651
+ const next = currentPool().filter((_, i) => i !== index);
1652
+ return apply({ models: next.length > 0 ? next : null });
1653
+ },
1654
+ clearPool: () => apply({ models: null }),
1655
+ setCouncilEnabled: (on) => apply({ council: { enabled: on } }),
1656
+ setCouncilMinRisk: (risk) => apply({ council: { minRisk: risk } }),
1657
+ addVoter: (providerId, model) => {
1658
+ const voters = currentVoters();
1659
+ const persona = PERSONA_CYCLE[voters.length % PERSONA_CYCLE.length];
1660
+ return applyVoters([...voters, { provider: providerId, model, persona }]);
1661
+ },
1662
+ removeVoter: (index) => applyVoters(currentVoters().filter((_, i) => i !== index)),
1663
+ cycleVoterPersona: (index) => {
1664
+ const voters = currentVoters();
1665
+ const voter = voters[index];
1666
+ if (!voter) return Promise.resolve("No such voter.");
1667
+ const at = PERSONA_CYCLE.indexOf(voter.persona);
1668
+ voter.persona = PERSONA_CYCLE[(at + 1) % PERSONA_CYCLE.length];
1669
+ return applyVoters(voters);
1670
+ },
1671
+ toggleVoterVeto: (index) => {
1672
+ const voters = currentVoters();
1673
+ const voter = voters[index];
1674
+ if (!voter) return Promise.resolve("No such voter.");
1675
+ voter.veto = !voter.veto;
1676
+ return applyVoters(voters);
1677
+ },
1678
+ setJudge: (providerId, model) => apply({ council: { judge: `${providerId}/${model}` } }),
1679
+ clearJudge: () => apply({ council: { judge: null } }),
1680
+ setLedgerEnabled: (on) => apply({ ledger: { enabled: on } }),
1681
+ setAutoDeny: (count) => apply({ ledger: { autoDenyAfterFailures: count ?? null } }),
1682
+ setTerminalPolicy: (policy) => apply({ terminalPolicy: policy }),
1683
+ // Every sub-block below is MERGED field-by-field by `mergePatch`, so a
1684
+ // single-key patch leaves the operator's other knobs alone.
1685
+ setHeuristic: (key, on) => apply({ heuristics: { [key]: on } }),
1686
+ setLlmMaxTokens: (tokens) => apply({ llm: { maxTokens: tokens } }),
1687
+ setLlmRejectUncertain: (on) => apply({ llm: { rejectUncertain: on } }),
1688
+ setLlmMinConfidence: (value) => apply({ llm: { minConfidence: value } }),
1689
+ setLlmDenyIsTerminal: (mode) => apply({ llm: { denyIsTerminal: mode } }),
1690
+ setCacheEnabled: (on) => apply({ cache: { enabled: on } }),
1691
+ setCacheTtl: (ms) => apply({ cache: { ttlMs: ms } }),
1692
+ setCacheMaxEntries: (count) => apply({ cache: { maxEntries: count } }),
1693
+ setTraceEnabled: (on) => apply({ trace: { enabled: on } }),
1694
+ setTraceContent: (content) => apply({ trace: { content } })
1695
+ };
1696
+ }
1697
+
1698
+ // src/chimera-review-task.ts
1699
+ import { parseReviewSeverity } from "@wrongstack/core/plugin";
1700
+ function truncateAtCodePointBoundary(text, maxCodeUnits) {
1701
+ if (text.length <= maxCodeUnits) return text;
1702
+ let result = "";
1703
+ for (const ch of text) {
1704
+ if (result.length + ch.length > maxCodeUnits) break;
1705
+ result += ch;
1706
+ }
1707
+ return result;
1708
+ }
1709
+ function isChimeraAllClearReview(text) {
1710
+ const severities = parseReviewSeverity(text);
1711
+ if (severities.critical > 0 || severities.high > 0 || severities.medium > 0) {
1712
+ return false;
1713
+ }
1714
+ const normalized = text.trim().toLowerCase();
1715
+ return normalized.startsWith("## \u{1F982} chimera review \u2014 all clear") || normalized.includes("chimera review: all clear");
1716
+ }
1717
+ function buildChimeraReviewTaskDescription(p) {
1718
+ const lines = [];
1719
+ lines.push(`Review the following ${p.files.length} file(s) changed in this session at ${p.cwd}.`);
1720
+ lines.push("");
1721
+ for (const f of p.files) {
1722
+ lines.push(`## [${f.status.toUpperCase()}] ${f.path}`);
1723
+ if (f.diff) {
1724
+ lines.push("");
1725
+ lines.push("```diff");
1726
+ lines.push(f.diff);
1727
+ lines.push("```");
1728
+ } else if (f.status === "added") {
1729
+ lines.push("");
1730
+ lines.push("(New file \u2014 full content provided)");
1731
+ }
1732
+ lines.push("");
1733
+ }
1734
+ if (p.allChangedFiles && p.allChangedFiles.length > p.files.length) {
1735
+ const reviewedPaths = new Set(p.files.map((f) => f.path));
1736
+ const siblings = p.allChangedFiles.filter((s) => !reviewedPaths.has(s.path)).map((s) => ` ${s.path} (${s.status})`);
1737
+ if (siblings.length > 0) {
1738
+ lines.push("---");
1739
+ lines.push("");
1740
+ lines.push(
1741
+ `**Also changed this session (${siblings.length} files \u2014 for context, NOT in your review scope):**`
1742
+ );
1743
+ lines.push(siblings.slice(0, 30).join("\n"));
1744
+ lines.push("");
1745
+ }
1746
+ }
1747
+ if (p.recentCommits && p.recentCommits.length > 0) {
1748
+ lines.push("---");
1749
+ lines.push("");
1750
+ lines.push("**Recent commits (newest first):**");
1751
+ for (const c of p.recentCommits) lines.push(` ${c}`);
1752
+ lines.push("");
1753
+ }
1754
+ if (p.activeTodos && p.activeTodos.length > 0) {
1755
+ lines.push("---");
1756
+ lines.push("");
1757
+ lines.push(`**Active task items (${p.activeTodos.length}):**`);
1758
+ for (const t of p.activeTodos) {
1759
+ lines.push(` [${t.status}] ${t.content}`);
1760
+ }
1761
+ lines.push("");
1762
+ }
1763
+ if (p.kanbanCard) {
1764
+ lines.push("---");
1765
+ lines.push("");
1766
+ lines.push(`**Kanban card: ${p.kanbanCard.title}**`);
1767
+ if (p.kanbanCard.description) {
1768
+ lines.push(` ${p.kanbanCard.description.slice(0, 500)}`);
1769
+ }
1770
+ if (p.kanbanCard.successCriteria && p.kanbanCard.successCriteria.length > 0) {
1771
+ lines.push(" **Success criteria:**");
1772
+ for (const sc of p.kanbanCard.successCriteria) lines.push(` - ${sc}`);
1773
+ }
1774
+ lines.push("");
1775
+ }
1776
+ if (p.fileProvenance && p.fileProvenance.length > 0) {
1777
+ lines.push("---");
1778
+ lines.push("");
1779
+ lines.push("**File provenance (Chronicle):**");
1780
+ for (const fp of p.fileProvenance) {
1781
+ const parts = [];
1782
+ if (fp.agentId) parts.push(`agent: ${fp.agentId}`);
1783
+ if (fp.taskId) parts.push(`task: ${fp.taskId}`);
1784
+ if (fp.eventType) parts.push(fp.eventType);
1785
+ if (fp.observedAt) parts.push(fp.observedAt);
1786
+ lines.push(` ${fp.path} \u2014 ${parts.join(", ")}`);
1787
+ }
1788
+ lines.push("");
1789
+ }
1790
+ lines.push("---");
1791
+ lines.push("");
1792
+ lines.push("Read each file using the read tool. For modified files, focus on the");
1793
+ lines.push("diff above \u2014 do not re-review unchanged pre-existing code.");
1794
+ lines.push("Check for bugs, type issues, security problems, and produce a");
1795
+ lines.push("structured review report.");
1796
+ return lines.join("\n");
1797
+ }
1798
+ function buildChimeraCascadeTaskDescription(agentKind, p) {
1799
+ const fileList = p.bundle.files.map((f) => `- ${f.path}`).join("\n");
1800
+ const reportSlice = truncateAtCodePointBoundary(p.reviewText, 12e3);
1801
+ const severityLine = `Critical: ${p.severities.critical}, High: ${p.severities.high}, Medium: ${p.severities.medium}`;
1802
+ if (agentKind === "security-scanner") {
1803
+ return [
1804
+ `You are a security cascade agent. A Chimera code review flagged security-relevant findings.`,
1805
+ ``,
1806
+ `Repository: ${p.bundle.cwd}`,
1807
+ `Severity summary: ${severityLine}`,
1808
+ ``,
1809
+ `--- Review report ---`,
1810
+ reportSlice,
1811
+ ``,
1812
+ `--- Changed files ---`,
1813
+ fileList,
1814
+ ``,
1815
+ `Investigate the security findings above. Read the flagged files, confirm or refute`,
1816
+ `each finding, and **apply fixes** for confirmed vulnerabilities using the edit tool.`,
1817
+ `Use severity (Critical/High/Medium), file:line citations, and remediation steps.`,
1818
+ `After fixing, run the project's typecheck and linter to verify. If a finding is a`,
1819
+ `false positive, say so and do not modify the file.`
1820
+ ].join("\n");
1821
+ }
1822
+ return [
1823
+ `You are a bug-hunter cascade agent. A Chimera code review flagged correctness defects.`,
1824
+ ``,
1825
+ `Repository: ${p.bundle.cwd}`,
1826
+ `Severity summary: ${severityLine}`,
1827
+ ``,
1828
+ `--- Review report ---`,
1829
+ reportSlice,
1830
+ ``,
1831
+ `--- Changed files ---`,
1832
+ fileList,
1833
+ ``,
1834
+ `Hunt for the bugs flagged above. Read the affected files, trace each finding to its`,
1835
+ `root cause, and **apply minimal fixes** for confirmed bugs using the edit tool.`,
1836
+ `Use severity (Critical/High/Medium), file:line citations. After fixing, run the`,
1837
+ `project's typecheck and linter to verify. If a finding is a false positive, say so`,
1838
+ `and do not modify the file.`
1839
+ ].join("\n");
1840
+ }
1841
+
1842
+ // src/chimera-reviewer-policy.ts
1843
+ import {
1844
+ buildReviewerModelPool,
1845
+ selectRoundRobinReviewerAssignment
1846
+ } from "@wrongstack/core/plugin";
1847
+ function resolveReviewerFallbackModels(reviewFallbackModels, sessionRef) {
1848
+ const base = reviewFallbackModels && reviewFallbackModels.length > 0 ? [...reviewFallbackModels] : [];
1849
+ if (sessionRef && !base.includes(sessionRef)) {
1850
+ base.push(sessionRef);
1851
+ }
1852
+ return base;
1853
+ }
1854
+ var reviewerRoundRobinCursor = 0;
1855
+ function __resetReviewerRoundRobinCursor(value = 0) {
1856
+ reviewerRoundRobinCursor = value;
1857
+ }
1858
+ function assignReviewerModelsRoundRobin(provider, model, fallbackModels) {
1859
+ const pool = buildReviewerModelPool(provider, model, fallbackModels);
1860
+ if (pool.length <= 1) {
1861
+ return {
1862
+ provider,
1863
+ model,
1864
+ fallbackModels: [...fallbackModels]
1865
+ };
1866
+ }
1867
+ const assignment = selectRoundRobinReviewerAssignment(
1868
+ pool,
1869
+ reviewerRoundRobinCursor,
1870
+ provider,
1871
+ model
1872
+ );
1873
+ reviewerRoundRobinCursor = assignment.nextCursor;
1874
+ return {
1875
+ provider: assignment.provider,
1876
+ model: assignment.model,
1877
+ fallbackModels: assignment.fallbackModels
1878
+ };
1879
+ }
1880
+ var CHIMERA_REVIEW_READ_ONLY_TOOLS = Object.freeze([
1881
+ "read",
1882
+ "grep",
1883
+ "glob",
1884
+ "tree",
1885
+ "codebase-search",
1886
+ "codebase-stats"
1887
+ ]);
1888
+ function applyChimeraReviewerReadOnlyPolicy(config) {
1889
+ return {
1890
+ ...config,
1891
+ // A security boundary, not an additive default: discard any inherited
1892
+ // mutation tools/capabilities so Chimera reviewers cannot repair files.
1893
+ tools: [...CHIMERA_REVIEW_READ_ONLY_TOOLS],
1894
+ allowedCapabilities: ["fs.read"],
1895
+ worktree: "off"
1896
+ };
1897
+ }
1898
+
1899
+ // src/execution-cleanup.ts
1900
+ async function finalizeExecutionCleanup(input) {
1901
+ const {
1902
+ offStorageObservability,
1903
+ fleetStatusLine,
1904
+ onCoordinatorStop,
1905
+ stats,
1906
+ renderer,
1907
+ detachTodosCheckpoint,
1908
+ mcpRegistry,
1909
+ agent,
1910
+ session,
1911
+ tokenCounter,
1912
+ events,
1913
+ getPendingChimeraWork,
1914
+ director,
1915
+ reader
1916
+ } = input;
1917
+ offStorageObservability();
1918
+ fleetStatusLine?.stop();
1919
+ onCoordinatorStop?.();
1920
+ try {
1921
+ stats.render(renderer);
1922
+ } catch (_err) {
1923
+ }
1924
+ await Promise.resolve(detachTodosCheckpoint?.()).catch(() => void 0);
1925
+ await mcpRegistry.stopAll().catch((err) => {
1926
+ console.warn(
1927
+ JSON.stringify({
1928
+ level: "warn",
1929
+ event: "shutdown.mcp_stop_failed",
1930
+ message: `MCP registry stopAll failed: ${err instanceof Error ? err.message : String(err)}`,
1931
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1932
+ })
1933
+ );
1934
+ });
1935
+ const activeSession = agent.ctx.session ?? session;
1936
+ const pending = activeSession.pendingToolUses;
1937
+ await activeSession.append({
1938
+ type: "session_end",
1939
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1940
+ usage: tokenCounter.total(),
1941
+ pendingToolUses: pending.length > 0 ? pending : void 0
1942
+ }).catch((err) => {
1943
+ console.warn(
1944
+ JSON.stringify({
1945
+ level: "warn",
1946
+ event: "shutdown.session_end_append_failed",
1947
+ message: `session_end append failed: ${err instanceof Error ? err.message : String(err)}`,
1948
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1949
+ })
1950
+ );
1951
+ });
1952
+ events.emit("session.ended", {
1953
+ id: activeSession.id,
1954
+ sessionId: activeSession.id,
1955
+ usage: tokenCounter.total()
1956
+ });
1957
+ if (getPendingChimeraWork) {
1958
+ const chimeraWork = getPendingChimeraWork();
1959
+ if (chimeraWork) {
1960
+ await chimeraWork.catch((err) => {
1961
+ console.warn(
1962
+ JSON.stringify({
1963
+ level: "warn",
1964
+ event: "shutdown.chimera_work_failed",
1965
+ message: `Pending chimera work failed: ${err instanceof Error ? err.message : String(err)}`,
1966
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1967
+ })
1968
+ );
1969
+ });
1970
+ }
1971
+ }
1972
+ if (director) {
1973
+ try {
1974
+ await director.terminateAll();
1975
+ } catch (termErr) {
1976
+ console.warn(
1977
+ JSON.stringify({
1978
+ level: "warn",
1979
+ event: "shutdown.director_terminate_all_failed",
1980
+ message: termErr instanceof Error ? termErr.message : String(termErr),
1981
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1982
+ })
1983
+ );
1984
+ }
1985
+ }
1986
+ await activeSession.close().catch((err) => {
1987
+ console.warn(
1988
+ JSON.stringify({
1989
+ level: "warn",
1990
+ event: "shutdown.session_close_failed",
1991
+ message: `Session close failed: ${err instanceof Error ? err.message : String(err)}`,
1992
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1993
+ })
1994
+ );
1995
+ });
1996
+ await reader.close().catch((err) => {
1997
+ console.warn(
1998
+ JSON.stringify({
1999
+ level: "warn",
2000
+ event: "shutdown.reader_close_failed",
2001
+ message: `Input reader close failed: ${err instanceof Error ? err.message : String(err)}`,
2002
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2003
+ })
2004
+ );
2005
+ });
2006
+ }
2007
+
2008
+ // src/execution-kanban-dispatch.ts
2009
+ import { randomUUID } from "node:crypto";
2010
+ import { WIDE_SUBAGENT_CAPABILITIES } from "@wrongstack/core/security";
2011
+
2012
+ // src/kanban-dispatch-route.ts
2013
+ import {
2014
+ fallbackProfileChain,
2015
+ parseModelRef
2016
+ } from "@wrongstack/core/agent";
2017
+ function resolveKanbanDispatchRoute(config, spawnOpts) {
2018
+ let provider = spawnOpts?.provider;
2019
+ let model = spawnOpts?.model;
2020
+ let fallbackModels = spawnOpts?.fallbackModels;
2021
+ if (spawnOpts?.fallbackProfile) {
2022
+ const chain = fallbackProfileChain(config, spawnOpts.fallbackProfile);
2023
+ const primary = chain[0] ? parseModelRef(chain[0]) : void 0;
2024
+ if (primary?.model) {
2025
+ provider = primary.provider ?? config.provider;
2026
+ model = primary.model;
2027
+ fallbackModels = spawnOpts.fallbackModels ?? chain.slice(1);
2028
+ }
2029
+ }
2030
+ return { provider, model, fallbackModels };
2031
+ }
2032
+
2033
+ // src/execution-kanban-dispatch.ts
2034
+ function createKanbanDispatchHandler({
2035
+ config,
2036
+ events,
2037
+ skillLoader,
2038
+ sddSubagentFactory
2039
+ }) {
2040
+ if (!sddSubagentFactory) return {};
2041
+ const onKanbanDispatch = async (description, spawnOpts) => {
2042
+ const subagentId = `kanban-${randomUUID().slice(0, 8)}`;
2043
+ const taskId = randomUUID();
2044
+ const name = spawnOpts?.name ?? "kanban-agent";
2045
+ const {
2046
+ provider: resolvedProvider,
2047
+ model: resolvedModel,
2048
+ fallbackModels: resolvedFallbackModels
2049
+ } = resolveKanbanDispatchRoute(config, spawnOpts);
2050
+ let agentDescription = description;
2051
+ if (spawnOpts?.skills?.length && skillLoader) {
2052
+ const loaded = await Promise.all(
2053
+ spawnOpts.skills.map(async (skillName) => {
2054
+ const manifest = await skillLoader.find(skillName);
2055
+ if (!manifest) throw new Error(`Kanban skill not found: ${skillName}`);
2056
+ const body = await skillLoader.readBody(skillName);
2057
+ return `## Required skill: ${skillName}
2058
+
2059
+ ${body}`;
2060
+ })
2061
+ );
2062
+ agentDescription = `${description}
2063
+
2064
+ # Required agentic skill instructions
2065
+
2066
+ ${loaded.join("\n\n")}`;
2067
+ }
2068
+ void (async () => {
2069
+ const built = await sddSubagentFactory({
2070
+ id: subagentId,
2071
+ name,
2072
+ role: "kanban-agent",
2073
+ prompt: agentDescription,
2074
+ allowedCapabilities: spawnOpts?.allowedCapabilities ?? WIDE_SUBAGENT_CAPABILITIES,
2075
+ ...resolvedProvider ? { provider: resolvedProvider } : {},
2076
+ ...resolvedModel ? { model: resolvedModel } : {},
2077
+ ...resolvedFallbackModels ? { fallbackModels: resolvedFallbackModels } : {},
2078
+ ...spawnOpts?.tools ? { tools: spawnOpts.tools } : {}
2079
+ });
2080
+ try {
2081
+ const result = await built.agent.run(agentDescription);
2082
+ await spawnOpts?.onDone?.({
2083
+ status: result.status === "done" ? "completed" : "failed",
2084
+ result: result.finalText,
2085
+ ..."error" in result && result.error?.message ? { error: result.error.message } : {}
2086
+ });
2087
+ } catch (err) {
2088
+ await spawnOpts?.onDone?.({
2089
+ status: "failed",
2090
+ error: err instanceof Error ? err.message : String(err)
2091
+ });
2092
+ throw err;
2093
+ } finally {
2094
+ await built.dispose?.();
2095
+ }
2096
+ })().catch((err) => {
2097
+ events.emit("error", {
2098
+ err: err instanceof Error ? err : new Error(String(err)),
2099
+ phase: "kanban.dispatch"
2100
+ });
2101
+ });
2102
+ const tags = [];
2103
+ if (resolvedProvider) tags.push(resolvedProvider);
2104
+ if (resolvedModel) tags.push(resolvedModel);
2105
+ if (resolvedFallbackModels?.length) {
2106
+ tags.push(`fallback=${resolvedFallbackModels.join(",")}`);
2107
+ }
2108
+ if (spawnOpts?.fallbackProfile) tags.push(`profile=${spawnOpts.fallbackProfile}`);
2109
+ if (spawnOpts?.skills?.length) tags.push(`skills=${spawnOpts.skills.join(",")}`);
2110
+ if (spawnOpts?.name) tags.push(`"${spawnOpts.name}"`);
2111
+ const tag = tags.length > 0 ? ` (${tags.join(" / ")})` : "";
2112
+ return `Spawned subagent ${subagentId}${tag} for task ${taskId}.`;
2113
+ };
2114
+ return { onKanbanDispatch };
2115
+ }
2116
+
2117
+ // src/execution-repl-fleet-callbacks.ts
2118
+ function createReplFleetCallbacks({
2119
+ director,
2120
+ getDirector
2121
+ }) {
2122
+ const resolveDirector = () => getDirector?.() ?? director;
2123
+ return {
2124
+ onInterruptFleet: () => {
2125
+ const dir = resolveDirector();
2126
+ if (!dir) return 0;
2127
+ let killed = 0;
2128
+ for (const sa of dir.status().subagents) {
2129
+ if (sa.status === "running" || sa.status === "idle") {
2130
+ try {
2131
+ void dir.remove(sa.id);
2132
+ killed++;
2133
+ } catch {
2134
+ }
2135
+ }
2136
+ }
2137
+ return killed;
2138
+ },
2139
+ onAgentIterationComplete: (tokens) => {
2140
+ const dir = resolveDirector();
2141
+ dir?.setLeaderContextPressure(tokens);
2142
+ }
2143
+ };
2144
+ }
2145
+
2146
+ // src/fleet-statusline.ts
2147
+ import { color as color5 } from "@wrongstack/core/utils";
2148
+ import { onResize } from "@wrongstack/core/utils";
2149
+ function fmtElapsed(ms) {
2150
+ const s = Math.floor(ms / 1e3);
2151
+ if (s < 60) return `${s}s`;
2152
+ const m = Math.floor(s / 60);
2153
+ const rem = s % 60;
2154
+ if (m < 60) return `${m}m${rem.toString().padStart(2, "0")}s`;
2155
+ const h = Math.floor(m / 60);
2156
+ return `${h}h${(m % 60).toString().padStart(2, "0")}m`;
2157
+ }
2158
+ function renderFleetLine(states, now, columns, version) {
2159
+ const all = [...states.values()];
2160
+ if (all.length === 0) return "";
2161
+ const running = all.filter((a) => a.status === "running");
2162
+ const done = all.filter((a) => a.status === "done").length;
2163
+ const failed = all.filter((a) => a.status === "failed").length;
2164
+ const versionChip = version ? `${color5.bold("WS")}${color5.dim(` v${version}`)} ${color5.dim("\u2502")} ` : "";
2165
+ const counts = versionChip + `${color5.cyan("\u27F3 fleet")} ${color5.yellow(`\u25B6${running.length}`)} ${color5.green(`\u2713${done}`)}` + (failed > 0 ? ` ${color5.red(`\u2717${failed}`)}` : "");
2166
+ const shown = running.sort((a, b) => a.startedAt - b.startedAt).slice(0, 4).map((a) => {
2167
+ const elapsed = fmtElapsed(Math.max(0, now - a.startedAt));
2168
+ const tool = a.lastTool ? ` ${color5.dim(a.lastTool)}` : "";
2169
+ const ext = a.extensions && a.extensions > 0 ? ` ${color5.yellow(`\u26A1${a.extensions}`)}` : "";
2170
+ return `${color5.bold(a.name)} ${color5.yellow("\u25B6")} ${color5.dim(elapsed)} ${color5.dim(`L${a.iterations}`)} ${color5.dim(`${a.toolCalls}t`)}${tool}${ext}`;
2171
+ });
2172
+ let line = shown.length > 0 ? `${counts} ${color5.dim("\u2502")} ${shown.join(color5.dim(" \xB7 "))}` : counts;
2173
+ const max = Math.max(20, columns - 1);
2174
+ const visible = line.replace(/\x1b\[[0-9;]*m/g, "");
2175
+ if (visible.length > max) {
2176
+ let count = 0;
2177
+ const out = [];
2178
+ let i = 0;
2179
+ while (i < line.length && count < max - 1) {
2180
+ if (line[i] === "\x1B") {
2181
+ const end = line.indexOf("m", i);
2182
+ if (end !== -1) {
2183
+ out.push(line.slice(i, end + 1));
2184
+ i = end + 1;
2185
+ continue;
2186
+ }
2187
+ }
2188
+ if (line[i] !== void 0) out.push(line[i]);
2189
+ count++;
2190
+ i++;
2191
+ }
2192
+ line = out.join("") + "\u2026";
2193
+ }
2194
+ return line;
2195
+ }
2196
+ var FleetStatusLine = class {
2197
+ events;
2198
+ out;
2199
+ throttleMs;
2200
+ now;
2201
+ version;
2202
+ states = /* @__PURE__ */ new Map();
2203
+ unsubs = [];
2204
+ active = false;
2205
+ rows = 0;
2206
+ repaintTimer = null;
2207
+ tickTimer = null;
2208
+ resizeCleanup = null;
2209
+ lastPaint = 0;
2210
+ onResize = () => {
2211
+ if (this.active) {
2212
+ this.rows = this.out.rows ?? 24;
2213
+ this.out.write(`\x1B[1;${this.rows - 1}r`);
2214
+ this.paint(true);
2215
+ }
2216
+ };
2217
+ constructor(opts) {
2218
+ this.events = opts.events;
2219
+ this.out = opts.out ?? process.stdout;
2220
+ this.throttleMs = opts.throttleMs ?? 150;
2221
+ this.now = opts.now ?? Date.now;
2222
+ this.version = opts.version;
2223
+ }
2224
+ /** Subscribe to host fleet events. No terminal output until a subagent spawns. */
2225
+ start() {
2226
+ const ensure = (id, name) => {
2227
+ let s = this.states.get(id);
2228
+ if (!s) {
2229
+ s = {
2230
+ id,
2231
+ name: name ?? id,
2232
+ status: "running",
2233
+ iterations: 0,
2234
+ toolCalls: 0,
2235
+ startedAt: this.now()
2236
+ };
2237
+ this.states.set(id, s);
2238
+ } else if (name && s.name === s.id) {
2239
+ s.name = name;
2240
+ }
2241
+ return s;
2242
+ };
2243
+ this.unsubs.push(
2244
+ this.events.on("subagent.spawned", (e) => {
2245
+ ensure(e.subagentId, e.name);
2246
+ this.activate();
2247
+ this.schedulePaint();
2248
+ }),
2249
+ this.events.on("subagent.task_started", (e) => {
2250
+ const s = ensure(e.subagentId);
2251
+ s.status = "running";
2252
+ this.activate();
2253
+ this.schedulePaint();
2254
+ }),
2255
+ this.events.on("subagent.tool_executed", (e) => {
2256
+ const s = ensure(e.subagentId);
2257
+ s.toolCalls++;
2258
+ s.lastTool = e.name;
2259
+ this.activate();
2260
+ this.schedulePaint();
2261
+ }),
2262
+ this.events.on("subagent.iteration_summary", (e) => {
2263
+ const s = ensure(e.subagentId);
2264
+ s.iterations = e.iteration;
2265
+ if (typeof e.toolCalls === "number") s.toolCalls = e.toolCalls;
2266
+ if (e.currentTool) s.lastTool = e.currentTool;
2267
+ this.schedulePaint();
2268
+ }),
2269
+ this.events.on("subagent.budget_extended", (e) => {
2270
+ const s = ensure(e.subagentId);
2271
+ s.extensions = e.totalExtensions;
2272
+ this.activate();
2273
+ this.schedulePaint();
2274
+ }),
2275
+ this.events.on("subagent.task_completed", (e) => {
2276
+ const s = ensure(e.subagentId);
2277
+ s.status = e.status === "success" ? "done" : "failed";
2278
+ s.iterations = e.iterations;
2279
+ s.toolCalls = e.toolCalls;
2280
+ s.endedAt = this.now();
2281
+ this.schedulePaint();
2282
+ if (![...this.states.values()].some((a) => a.status === "running")) {
2283
+ setTimeout(() => {
2284
+ if (![...this.states.values()].some((a) => a.status === "running")) {
2285
+ this.deactivate();
2286
+ }
2287
+ }, 800);
2288
+ }
2289
+ })
2290
+ );
2291
+ }
2292
+ /** Unsubscribe and restore the terminal. Idempotent. */
2293
+ stop() {
2294
+ for (const u of this.unsubs.splice(0)) u();
2295
+ this.deactivate();
2296
+ }
2297
+ isTty() {
2298
+ return !!this.out.isTTY;
2299
+ }
2300
+ activate() {
2301
+ if (this.active || !this.isTty()) return;
2302
+ this.active = true;
2303
+ this.rows = this.out.rows ?? 24;
2304
+ this.out.write("\n");
2305
+ this.out.write(`\x1B[1;${this.rows - 1}r`);
2306
+ this.out.write(`\x1B[${this.rows - 1};1H`);
2307
+ this.resizeCleanup = onResize(() => this.onResize(), this.out);
2308
+ this.tickTimer = setInterval(() => this.paint(true), 1e3);
2309
+ if (this.tickTimer.unref) this.tickTimer.unref();
2310
+ this.paint(true);
2311
+ }
2312
+ deactivate() {
2313
+ if (!this.active) return;
2314
+ this.active = false;
2315
+ if (this.tickTimer) {
2316
+ clearInterval(this.tickTimer);
2317
+ this.tickTimer = null;
2318
+ }
2319
+ if (this.repaintTimer) {
2320
+ clearTimeout(this.repaintTimer);
2321
+ this.repaintTimer = null;
2322
+ }
2323
+ this.resizeCleanup?.();
2324
+ this.resizeCleanup = null;
2325
+ if (this.isTty()) {
2326
+ this.out.write("\x1B7");
2327
+ this.out.write(`\x1B[${this.rows};1H`);
2328
+ this.out.write("\x1B[2K");
2329
+ this.out.write("\x1B8");
2330
+ this.out.write("\x1B[r");
2331
+ }
2332
+ }
2333
+ schedulePaint() {
2334
+ if (!this.active) return;
2335
+ const since = this.now() - this.lastPaint;
2336
+ if (since >= this.throttleMs) {
2337
+ this.paint(false);
2338
+ return;
2339
+ }
2340
+ if (this.repaintTimer) return;
2341
+ this.repaintTimer = setTimeout(() => {
2342
+ this.repaintTimer = null;
2343
+ this.paint(false);
2344
+ }, this.throttleMs - since);
2345
+ if (this.repaintTimer.unref) this.repaintTimer.unref();
2346
+ }
2347
+ paint(force) {
2348
+ if (!this.active || !this.isTty()) return;
2349
+ if (!force) this.lastPaint = this.now();
2350
+ else this.lastPaint = this.now();
2351
+ const line = renderFleetLine(this.states, this.now(), this.out.columns ?? 80, this.version);
2352
+ this.out.write("\x1B7");
2353
+ this.out.write(`\x1B[${this.rows};1H`);
2354
+ this.out.write("\x1B[2K");
2355
+ this.out.write(line);
2356
+ this.out.write("\x1B8");
2357
+ }
2358
+ };
2359
+
2360
+ // src/execution-chimera-ask.ts
2361
+ import { createHash } from "node:crypto";
2362
+ async function waitForChimeraAskApproval(opts) {
2363
+ const rawPoll = opts.meta["chimeraPollIntervalMs"] ?? 2e3;
2364
+ const pollIntervalMs = Number.isFinite(rawPoll) ? Math.max(0, rawPoll) : 2e3;
2365
+ const abortSignal = opts.meta["chimeraAbortSignal"];
2366
+ const askStartTime = Date.now();
2367
+ let leaderApproved = false;
2368
+ let repliesFound = false;
2369
+ let nonLeaderReplyCount = 0;
2370
+ let pollDone = false;
2371
+ const pollNext = () => {
2372
+ if (pollDone) return Promise.resolve();
2373
+ const elapsed = Date.now() - askStartTime;
2374
+ const remaining = opts.askTimeoutMs - elapsed;
2375
+ if (remaining <= 0 || abortSignal?.aborted) {
2376
+ pollDone = true;
2377
+ return Promise.resolve();
2378
+ }
2379
+ return new Promise((r) => setTimeout(r, Math.min(pollIntervalMs, remaining))).then(
2380
+ () => pollForReply()
2381
+ );
2382
+ };
2383
+ const pollForReply = async () => {
2384
+ if (pollDone) return;
2385
+ const replies = await opts.mailbox.query({ replyTo: opts.messageId, limit: 5 });
2386
+ if (replies.length > 0) {
2387
+ repliesFound = true;
2388
+ const firstReply = replies[0];
2389
+ if (!firstReply) return pollNext();
2390
+ const replyFromBase = (firstReply.from ?? "").split("@")[0];
2391
+ if (replyFromBase !== "leader" || firstReply.audience === "leaders") {
2392
+ nonLeaderReplyCount++;
2393
+ if (nonLeaderReplyCount >= 5) {
2394
+ console.warn(
2395
+ JSON.stringify({
2396
+ level: "warn",
2397
+ event: "execution.chimera_ask_non_leader_threshold",
2398
+ message: `${nonLeaderReplyCount} non-leader replies seen on chimera ask \u2014 stopping poll`,
2399
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2400
+ })
2401
+ );
2402
+ pollDone = true;
2403
+ return;
2404
+ }
2405
+ console.warn(
2406
+ JSON.stringify({
2407
+ level: nonLeaderReplyCount <= 1 ? "warn" : "debug",
2408
+ event: "execution.chimera_ask_non_leader_reply",
2409
+ message: `Ignoring non-leader reply #${nonLeaderReplyCount} from ${firstReply.from}`,
2410
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2411
+ })
2412
+ );
2413
+ return pollNext();
2414
+ }
2415
+ await opts.mailbox.ack({
2416
+ messageId: firstReply.id,
2417
+ readerId: "chimera-review",
2418
+ read: true,
2419
+ completed: true
2420
+ }).catch((_ackErr) => {
2421
+ console.warn(
2422
+ JSON.stringify({
2423
+ level: "warn",
2424
+ event: "execution.chimera_ask_ack_failed",
2425
+ message: _ackErr instanceof Error ? _ackErr.message : String(_ackErr),
2426
+ replyMessageId: firstReply.id,
2427
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2428
+ })
2429
+ );
2430
+ });
2431
+ const body = firstReply.body.toLowerCase();
2432
+ if (body.trim().length === 0) {
2433
+ pollDone = true;
2434
+ return;
2435
+ }
2436
+ leaderApproved = /^\s*(?:y(?:es)?|sure|ok(?:ay)?|go ahead|proceed|approve|fix it|please do|do it|yep|yeah)\b/.test(
2437
+ body
2438
+ ) || /^\s*👍/.test(body);
2439
+ if (leaderApproved) {
2440
+ pollDone = true;
2441
+ return;
2442
+ }
2443
+ if (/^\s*(no|don'?t|stop|skip|ignore|cancel|reject|decline)\b/.test(body)) {
2444
+ pollDone = true;
2445
+ return;
2446
+ }
2447
+ leaderApproved = /\b(?:y(?:es)?|sure|approve|proceed|go ahead)\b/i.test(body);
2448
+ if (leaderApproved) {
2449
+ pollDone = true;
2450
+ return;
2451
+ }
2452
+ const hash = createHash("sha256").update(body).digest("hex").slice(0, 12);
2453
+ console.warn(
2454
+ JSON.stringify({
2455
+ level: "debug",
2456
+ event: "execution.chimera_ask_reply_unmatched",
2457
+ replyBodyHash: hash,
2458
+ replyBodyLength: body.length,
2459
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2460
+ })
2461
+ );
2462
+ }
2463
+ return pollNext();
2464
+ };
2465
+ await pollForReply();
2466
+ if (!leaderApproved) {
2467
+ await recordChimeraAskFallback(opts.session, opts.askTimeoutMs, repliesFound);
2468
+ }
2469
+ return leaderApproved;
2470
+ }
2471
+ async function recordChimeraAskFallback(session, askTimeoutMs, repliesFound) {
2472
+ console.warn(
2473
+ JSON.stringify({
2474
+ level: "warn",
2475
+ event: repliesFound ? "execution.chimera_ask_rejected" : "execution.chimera_ask_timeout",
2476
+ message: repliesFound ? "Leader replied to ask but did not approve" : "Ask timeout expired, falling back to off mode (no auto-fix)",
2477
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2478
+ })
2479
+ );
2480
+ await session.append({
2481
+ type: "llm_response",
2482
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2483
+ content: [
2484
+ {
2485
+ type: "text",
2486
+ text: `\u{1F982} Chimera auto-fix request sent to leader \u2014 no approval received within ${askTimeoutMs / 1e3}s timeout. Falling back to manual review mode. Set autoFix via \`/chimera autoFix auto\` to auto-approve future reviews.`
2487
+ }
2488
+ ],
2489
+ stopReason: "end_turn",
2490
+ usage: { input: 0, output: 0 }
2491
+ }).catch((_appendErr) => {
2492
+ console.warn(
2493
+ JSON.stringify({
2494
+ level: "warn",
2495
+ event: "execution.chimera_timeout_append_failed",
2496
+ message: _appendErr instanceof Error ? _appendErr.message : String(_appendErr),
2497
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2498
+ })
2499
+ );
2500
+ });
2501
+ }
2502
+
2503
+ // src/execution-chimera-cascade.ts
2504
+ import { randomUUID as randomUUID2 } from "node:crypto";
2505
+ import * as fsp from "node:fs/promises";
2506
+ import * as path8 from "node:path";
2507
+ import { emitReviewIfChanged } from "@wrongstack/core/plugin";
2508
+ function installChimeraCascadeHandler({
2509
+ events,
2510
+ director,
2511
+ session,
2512
+ getPendingWork,
2513
+ setPendingWork
2514
+ }) {
2515
+ events.onPattern("chimera.cascade_needed", (_event, payload) => {
2516
+ const p = payload;
2517
+ const dir = director;
2518
+ if (!dir) return;
2519
+ if (p.agents.length === 0) return;
2520
+ const previousWork = getPendingWork();
2521
+ const pendingWork = (async () => {
2522
+ try {
2523
+ await previousWork;
2524
+ } catch {
2525
+ }
2526
+ for (const agentKind of p.agents) {
2527
+ try {
2528
+ const taskDesc = buildChimeraCascadeTaskDescription(agentKind, p);
2529
+ const role = agentKind === "security-scanner" ? "security-scanner" : "bug-hunter";
2530
+ const cfg = {
2531
+ name: `chimera-cascade-${agentKind}`,
2532
+ role,
2533
+ maxIterations: 40,
2534
+ maxToolCalls: 200,
2535
+ timeoutMs: 6e5
2536
+ };
2537
+ const subagentId = await dir.spawn(cfg);
2538
+ try {
2539
+ const taskId = randomUUID2();
2540
+ await dir.assign({ id: taskId, description: taskDesc, subagentId });
2541
+ const results = await dir.awaitTasks([taskId]);
2542
+ const result = results[0];
2543
+ if (result?.status === "success") {
2544
+ const resultText = typeof result.result === "string" ? result.result : JSON.stringify(result.result);
2545
+ await session.append({
2546
+ type: "llm_response",
2547
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2548
+ content: [
2549
+ {
2550
+ type: "text",
2551
+ text: `\u{1F982} Chimera cascade (${agentKind}) \u2014 ${resultText}`
2552
+ }
2553
+ ],
2554
+ stopReason: "end_turn",
2555
+ usage: { input: 0, output: 0 }
2556
+ });
2557
+ } else {
2558
+ await session.append({
2559
+ type: "error",
2560
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2561
+ message: `\u{1F982} Chimera cascade (${agentKind}) ${result?.status ?? "unknown"}: ${result?.error?.message ?? "no result"}`,
2562
+ phase: "agent"
2563
+ });
2564
+ }
2565
+ } finally {
2566
+ try {
2567
+ await dir.terminate(subagentId);
2568
+ } catch {
2569
+ }
2570
+ }
2571
+ } catch (err) {
2572
+ await session.append({
2573
+ type: "error",
2574
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2575
+ message: `\u{1F982} Chimera cascade (${agentKind}) failed: ${err instanceof Error ? err.message : String(err)}`,
2576
+ phase: "agent"
2577
+ });
2578
+ }
2579
+ }
2580
+ await maybeReReviewCascade({ events, session, bundle: p.bundle });
2581
+ })();
2582
+ setPendingWork(pendingWork);
2583
+ });
2584
+ }
2585
+ async function maybeReReviewCascade({
2586
+ events,
2587
+ session,
2588
+ bundle
2589
+ }) {
2590
+ const maxDepth = bundle.maxCascadeDepth ?? 0;
2591
+ const currentDepth = bundle.cascadeDepth ?? 0;
2592
+ if (maxDepth > 0 && currentDepth < maxDepth) {
2593
+ try {
2594
+ const reReadFiles = [];
2595
+ for (const f of bundle.files) {
2596
+ try {
2597
+ const absPath = path8.join(bundle.cwd, f.path);
2598
+ const content = await fsp.readFile(absPath, "utf8");
2599
+ reReadFiles.push({ path: f.path, status: "modified", content });
2600
+ } catch {
2601
+ }
2602
+ }
2603
+ if (reReadFiles.length > 0) {
2604
+ const reReviewBundle = {
2605
+ ...bundle,
2606
+ files: reReadFiles,
2607
+ cascadeDepth: currentDepth + 1
2608
+ };
2609
+ await session.append({
2610
+ type: "llm_response",
2611
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2612
+ content: [
2613
+ {
2614
+ type: "text",
2615
+ text: `\u{1F982} Chimera cascade re-review (depth ${currentDepth + 1}/${maxDepth}) \u2014 re-reviewing ${reReadFiles.length} file(s) after fixes`
2616
+ }
2617
+ ],
2618
+ stopReason: "end_turn",
2619
+ usage: { input: 0, output: 0 }
2620
+ });
2621
+ const emitted = emitReviewIfChanged(
2622
+ { events, emitCustom: events.emitCustom.bind(events) },
2623
+ reReviewBundle
2624
+ );
2625
+ if (!emitted) {
2626
+ await session.append({
2627
+ type: "llm_response",
2628
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2629
+ content: [
2630
+ {
2631
+ type: "text",
2632
+ text: `\u{1F982} Chimera cascade re-review skipped \u2014 content unchanged since previous review (depth ${currentDepth + 1}/${maxDepth})`
2633
+ }
2634
+ ],
2635
+ stopReason: "end_turn",
2636
+ usage: { input: 0, output: 0 }
2637
+ });
2638
+ }
2639
+ }
2640
+ } catch (err) {
2641
+ await session.append({
2642
+ type: "error",
2643
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2644
+ message: `\u{1F982} Chimera cascade re-review failed: ${err instanceof Error ? err.message : String(err)}`,
2645
+ phase: "agent"
2646
+ });
2647
+ }
2648
+ } else if (maxDepth > 0 && currentDepth >= maxDepth) {
2649
+ await session.append({
2650
+ type: "llm_response",
2651
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2652
+ content: [
2653
+ {
2654
+ type: "text",
2655
+ text: `\u{1F982} Chimera cascade stopped at depth limit (${currentDepth}/${maxDepth}) \u2014 manual review recommended if issues persist`
2656
+ }
2657
+ ],
2658
+ stopReason: "end_turn",
2659
+ usage: { input: 0, output: 0 }
2660
+ });
2661
+ }
2662
+ }
2663
+
2664
+ // src/execution-storage-observability.ts
2665
+ function installStorageObservability(events, rootTraceId) {
2666
+ const storageLog = (event, payload) => {
2667
+ const traceId = payload.traceId ?? rootTraceId;
2668
+ console.warn(
2669
+ JSON.stringify({
2670
+ level: "info",
2671
+ event,
2672
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2673
+ traceId,
2674
+ ...payload
2675
+ })
2676
+ );
2677
+ };
2678
+ const onStorageRead = (...args) => storageLog("storage.read", args[0]);
2679
+ const onStorageWrite = (...args) => storageLog("storage.write", args[0]);
2680
+ const onStorageError = (...args) => storageLog("storage.error", args[0]);
2681
+ const offStorageRead = events.on("storage.read", onStorageRead);
2682
+ const offStorageWrite = events.on("storage.write", onStorageWrite);
2683
+ const offStorageError = events.on("storage.error", onStorageError);
2684
+ return () => {
2685
+ offStorageRead();
2686
+ offStorageWrite();
2687
+ offStorageError();
2688
+ };
2689
+ }
2690
+
2691
+ // src/next-task-predictor.ts
2692
+ import { readBundledInstructionText } from "@wrongstack/core/utils";
2693
+ var SYSTEM_PROMPT = readBundledInstructionText("cli/next-task-predictor.md");
2694
+ var MAX_REQUEST_CHARS = 1200;
2695
+ var MAX_SUMMARY_CHARS = 1200;
2696
+ function clamp(text, n) {
2697
+ const t = text.trim();
2698
+ return t.length <= n ? t : `${t.slice(0, n)}\u2026`;
2699
+ }
2700
+ function buildPredictionPrompt(input) {
2701
+ const parts = [];
2702
+ parts.push(`The user asked:
2703
+ ${clamp(input.userRequest, MAX_REQUEST_CHARS) || "(no text)"}`);
2704
+ if (input.assistantSummary.trim()) {
2705
+ parts.push(
2706
+ `The assistant just finished and reported:
2707
+ ${clamp(input.assistantSummary, MAX_SUMMARY_CHARS)}`
2708
+ );
2709
+ }
2710
+ const pending = input.todos.filter((t) => t.status !== "completed");
2711
+ if (pending.length > 0) {
2712
+ const list = pending.slice(0, 8).map((t) => `- [${t.status}] ${t.content}`).join("\n");
2713
+ parts.push(`Open todo items:
2714
+ ${list}`);
2715
+ }
2716
+ parts.push(
2717
+ "Predict the 1-3 most likely exact prompt messages the user could submit back to the agent through the TUI or WebUI. Each must ask the agent to perform the work, never assign a manual chore to the user."
2718
+ );
2719
+ return parts.join("\n\n");
2720
+ }
2721
+ function parsePredictions(raw, max = 3) {
2722
+ const text = raw.trim();
2723
+ if (!text) return [];
2724
+ if (/^none\b/i.test(text) || /no further steps/i.test(text)) return [];
2725
+ const out = [];
2726
+ for (const lineRaw of text.split("\n")) {
2727
+ const line = lineRaw.trim();
2728
+ if (!line) continue;
2729
+ const stripped = line.replace(/^\s*(?:\d+[.)]|[-*•])\s+/, "").trim();
2730
+ const candidate = stripped || line;
2731
+ if (/^none$/i.test(candidate)) continue;
2732
+ if (candidate) out.push(candidate);
2733
+ if (out.length >= max) break;
2734
+ }
2735
+ return out;
2736
+ }
2737
+ function extractText(content) {
2738
+ if (Array.isArray(content)) {
2739
+ return content[0]?.text ?? "";
2740
+ }
2741
+ if (content && typeof content === "object") {
2742
+ return content.text ?? "";
2743
+ }
2744
+ return typeof content === "string" ? content : "";
2745
+ }
2746
+ async function predictNextTasks(input, opts) {
2747
+ const max = opts.maxPredictions ?? 3;
2748
+ const internal = new AbortController();
2749
+ const timeout = setTimeout(() => internal.abort(), 12e3);
2750
+ const onParentAbort = () => internal.abort();
2751
+ if (opts.signal) {
2752
+ if (opts.signal.aborted) internal.abort();
2753
+ else opts.signal.addEventListener("abort", onParentAbort, { once: true });
2754
+ }
2755
+ try {
2756
+ const resp = await opts.provider.complete(
2757
+ {
2758
+ model: opts.model,
2759
+ system: [{ type: "text", text: SYSTEM_PROMPT }],
2760
+ messages: [
2761
+ { role: "user", content: [{ type: "text", text: buildPredictionPrompt(input) }] }
2762
+ ],
2763
+ maxTokens: 160,
2764
+ temperature: 0.3
2765
+ },
2766
+ { signal: internal.signal }
2767
+ );
2768
+ return parsePredictions(extractText(resp.content), max);
2769
+ } catch {
2770
+ return [];
2771
+ } finally {
2772
+ clearTimeout(timeout);
2773
+ if (opts.signal) opts.signal.removeEventListener("abort", onParentAbort);
2774
+ }
2775
+ }
2776
+
2777
+ // src/repl.ts
2778
+ import { toErrorMessage } from "@wrongstack/core/utils";
2779
+ import { color as color9, estimateRequestTokensCalibrated as estimateRequestTokensCalibrated2, expectDefined, hasOpenTodos as hasOpenTodos2 } from "@wrongstack/core/utils";
2780
+ import { detectContinueIntent, InputBuilder, resolveContinuation } from "@wrongstack/core/agent";
2781
+ import { goalFilePath, loadGoal, summarizeUsage } from "@wrongstack/core/goal";
2782
+ import { readClipboardImage, routeImagesForModel } from "@wrongstack/runtime";
2783
+
2784
+ // src/repl-suggestions.ts
2785
+ import { hasOpenTodos } from "@wrongstack/core/utils";
2786
+ import { parseNextSteps } from "@wrongstack/tools/next-steps";
2787
+ function parseSuggestionsFromOutput(finalText, todos) {
2788
+ if (hasOpenTodos(todos)) {
2789
+ setAutoSuggestions([]);
2790
+ return null;
2791
+ }
2792
+ const { texts, autoTexts } = parseNextSteps(finalText, false);
2793
+ if (autoTexts.length > 0) {
2794
+ setAutoSuggestions(autoTexts);
2795
+ }
2796
+ return texts.length > 0 ? texts : null;
2797
+ }
2798
+
2799
+ // src/repl-auto-proceed.ts
2800
+ import { color as color6, estimateRequestTokensCalibrated } from "@wrongstack/core/utils";
2801
+ import { GROUNDED_NO_PROGRESS_STEER } from "@wrongstack/tools/auto-proceed-loop-guard";
2802
+ async function runAutoProceed(opts, suggestion, delayMs, ctrl, loopGuard, grounded = false) {
2803
+ const truncated = suggestion.length > 80 ? `${suggestion.slice(0, 77)}\u2026` : suggestion;
2804
+ console.log(
2805
+ JSON.stringify({
2806
+ level: "info",
2807
+ event: "auto_proceed_started",
2808
+ suggestion: truncated,
2809
+ delayMs
2810
+ })
2811
+ );
2812
+ try {
2813
+ const proceed = await autoProceedCooldown(opts, delayMs, suggestion, ctrl.signal);
2814
+ if (!proceed) {
2815
+ console.log(
2816
+ JSON.stringify({
2817
+ level: "info",
2818
+ event: "auto_proceed_cancelled",
2819
+ suggestion: truncated
2820
+ })
2821
+ );
2822
+ return false;
2823
+ }
2824
+ if ((opts.getAutonomy?.() ?? "off") !== "auto") {
2825
+ console.log(
2826
+ JSON.stringify({
2827
+ level: "info",
2828
+ event: "auto_proceed_cancelled",
2829
+ suggestion: truncated,
2830
+ reason: "autonomy_not_auto"
2831
+ })
2832
+ );
2833
+ return false;
2834
+ }
2835
+ const repetition = grounded ? loopGuard.recordGrounded(suggestion) : loopGuard.record(suggestion);
2836
+ if (repetition.shouldHalt) {
2837
+ setSuggestions([]);
2838
+ setAutoSuggestions([]);
2839
+ opts.onSuggestionsParsed?.(null);
2840
+ opts.renderer.writeWarning(
2841
+ `Auto-proceed halted: the same prompt was fed ${repetition.runLength} times in a row. Autonomy mode is still on, but no automatic next step will run until you provide input. Type anything to continue (resets the guard). Last seen prompt: "${suggestion.length > 100 ? `${suggestion.slice(0, 97)}\u2026` : suggestion}"`
2842
+ );
2843
+ return false;
2844
+ }
2845
+ const steered = "action" in repetition && repetition.action === "steer";
2846
+ if (steered) {
2847
+ opts.renderer.writeWarning(
2848
+ "Todo board unchanged since the last automatic turn \u2014 steering the agent to update the board before continuing."
2849
+ );
2850
+ }
2851
+ const runBlocks = [
2852
+ {
2853
+ type: "text",
2854
+ text: steered ? `${suggestion}
2855
+
2856
+ ${GROUNDED_NO_PROGRESS_STEER}` : suggestion
2857
+ }
2858
+ ];
2859
+ const runResult = await opts.agent.run(runBlocks, { signal: ctrl.signal });
2860
+ console.log(
2861
+ JSON.stringify({
2862
+ level: "info",
2863
+ event: "auto_proceed_completed",
2864
+ suggestion: truncated,
2865
+ status: runResult.status,
2866
+ iterations: runResult.iterations
2867
+ })
2868
+ );
2869
+ opts.onAgentIterationComplete?.(
2870
+ estimateRequestTokensCalibrated(
2871
+ opts.agent.ctx.messages,
2872
+ opts.agent.ctx.systemPrompt,
2873
+ opts.agent.ctx.tools ?? []
2874
+ ).total
2875
+ );
2876
+ if (runResult.status === "done" && opts.onSuggestionsParsed) {
2877
+ const parsed = runResult.finalText ? parseSuggestionsFromOutput(runResult.finalText, opts.agent.ctx.todos) : null;
2878
+ opts.onSuggestionsParsed(parsed);
2879
+ }
2880
+ return true;
2881
+ } finally {
2882
+ }
2883
+ }
2884
+ async function autoProceedCooldown(opts, delayMs, suggestion, signal) {
2885
+ if (delayMs <= 0) return true;
2886
+ const truncated = suggestion.length > 100 ? `${suggestion.slice(0, 97)}\u2026` : suggestion;
2887
+ const sec = Math.ceil(delayMs / 1e3);
2888
+ opts.renderer.write(`
2889
+ ${color6.cyan("\u23F3 Auto")} ${color6.dim("(Ctrl+C to cancel)")}
2890
+ `);
2891
+ opts.renderer.write(`${color6.dim(" \u25B8")} ${color6.dim(truncated)}
2892
+ `);
2893
+ void runContextCompaction(opts, signal);
2894
+ const start = Date.now();
2895
+ let interval;
2896
+ let lastTickedSecond = sec + 1;
2897
+ let onAbort;
2898
+ return new Promise((resolve3) => {
2899
+ onAbort = () => resolve3(false);
2900
+ signal.addEventListener("abort", onAbort, { once: true });
2901
+ interval = setInterval(() => {
2902
+ if (signal.aborted) {
2903
+ resolve3(false);
2904
+ return;
2905
+ }
2906
+ const elapsed = Date.now() - start;
2907
+ const remaining = Math.max(0, Math.ceil((delayMs - elapsed) / 1e3));
2908
+ if (remaining <= 0) {
2909
+ opts.renderer.write(color6.dim(` \u21B3 ${truncated}
2910
+ `));
2911
+ resolve3(true);
2912
+ return;
2913
+ }
2914
+ if (opts.onCountdownTick && remaining !== lastTickedSecond) {
2915
+ lastTickedSecond = remaining;
2916
+ try {
2917
+ const shouldAbort = opts.onCountdownTick(remaining);
2918
+ if (shouldAbort === true) {
2919
+ opts.renderer.write(
2920
+ color6.yellow(" \u21B3 Countdown cancelled \u2014 switching to manual mode\n")
2921
+ );
2922
+ resolve3(false);
2923
+ return;
2924
+ }
2925
+ } catch {
2926
+ }
2927
+ }
2928
+ if (remaining % 5 === 0 || remaining === sec) {
2929
+ opts.renderer.write(color6.dim(` \u23F3 ${remaining}s\u2026
2930
+ `));
2931
+ }
2932
+ }, 1e3);
2933
+ }).finally(() => {
2934
+ if (interval) clearInterval(interval);
2935
+ if (onAbort) signal.removeEventListener("abort", onAbort);
2936
+ try {
2937
+ opts.onCountdownTick?.(0);
2938
+ } catch {
2939
+ }
2940
+ });
2941
+ }
2942
+ async function runContextCompaction(opts, _signal) {
2943
+ try {
2944
+ const ctx = opts.agent.ctx;
2945
+ if (!ctx?.compactor) return;
2946
+ if ((ctx.messages?.length ?? 0) < 50) return;
2947
+ await ctx.compactor.compact(ctx, { aggressive: false });
2948
+ } catch {
2949
+ }
2950
+ }
2951
+
2952
+ // src/repl-input.ts
2953
+ import { color as color7 } from "@wrongstack/core/utils";
2954
+ async function readPossiblyMultiline(opts) {
2955
+ const firstPrompt = theme.primary("\u203A ");
2956
+ const contPrompt = color7.dim("\xB7 ");
2957
+ const first = await opts.reader.readLine(firstPrompt);
2958
+ if (first.trim() === '"""') {
2959
+ const parts = [];
2960
+ try {
2961
+ for (; ; ) {
2962
+ const next = await opts.reader.readLine(contPrompt);
2963
+ if (next.trim() === '"""') break;
2964
+ parts.push(next);
2965
+ }
2966
+ } catch {
2967
+ return parts.join("\n");
2968
+ }
2969
+ return parts.join("\n");
2970
+ }
2971
+ let buf = first;
2972
+ while (buf.endsWith("\\")) {
2973
+ buf = buf.slice(0, -1);
2974
+ const cont = await opts.reader.readLine(contPrompt);
2975
+ buf += "\n" + cont;
2976
+ }
2977
+ return buf;
2978
+ }
2979
+
2980
+ // src/repl-rendering.ts
2981
+ import { color as color8 } from "@wrongstack/core/utils";
2982
+ var FILLED = "\u2588";
2983
+ var EMPTY = "\u2591";
2984
+ function renderContextChip(used, max) {
2985
+ const ratio = Math.max(0, Math.min(1, used / max));
2986
+ const pct = Math.round(ratio * 100);
2987
+ const bar = renderProgress(ratio, 6);
2988
+ return `${bar} ${pct}% (${fmtTok(used)}/${fmtTok(max)})`;
2989
+ }
2990
+ function renderProgress(ratio, width) {
2991
+ const clamped = Math.max(0, Math.min(1, ratio));
2992
+ const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
2993
+ const capped = Math.min(width, filled);
2994
+ return FILLED.repeat(capped) + EMPTY.repeat(width - capped);
2995
+ }
2996
+ function printBanner(renderer, projectName) {
2997
+ const lines = [
2998
+ theme.primary(theme.bold("WrongStack")) + color8.dim(` v${CLI_VERSION}`),
2999
+ color8.dim("Built on the wrong stack. Shipped anyway.")
3000
+ ];
3001
+ if (projectName && projectName.length > 0) {
3002
+ lines.push(color8.dim("Project: ") + theme.bold(projectName));
3003
+ }
3004
+ lines.push(color8.dim("Type /help for commands, /exit or q to quit."), "");
3005
+ renderer.write(`${lines.join("\n")}
3006
+ `);
3007
+ }
3008
+
3009
+ // src/repl-client-registration.ts
3010
+ import * as crypto from "node:crypto";
3011
+ import * as path9 from "node:path";
3012
+ import {
3013
+ getSharedProjectMailbox,
3014
+ resolveProjectDir
3015
+ } from "@wrongstack/core/coordination";
3016
+ import { wstackGlobalRoot } from "@wrongstack/core/utils";
3017
+ function registerReplClient(opts) {
3018
+ const replProjectRoot = opts.projectRoot ?? process.cwd();
3019
+ const projectDir = resolveProjectDir(replProjectRoot, wstackGlobalRoot());
3020
+ const clientId = `repl@${crypto.randomUUID().slice(0, 8)}`;
3021
+ const hqConnection = startCliHqConnection({
3022
+ clientKind: "repl",
3023
+ projectRoot: replProjectRoot,
3024
+ projectName: path9.basename(replProjectRoot),
3025
+ appConfig: opts.appConfig,
3026
+ capabilities: ["telemetry.publish", "mailbox.summary"]
3027
+ });
3028
+ const clientMailbox = getSharedProjectMailbox(
3029
+ projectDir,
3030
+ void 0,
3031
+ () => hqConnection.getPublisher()
3032
+ );
3033
+ let clientHeartbeat;
3034
+ clientMailbox.registerClient({
3035
+ clientId,
3036
+ sessionId: opts.getSessionId?.() ?? replProjectRoot,
3037
+ name: `REPL [${path9.basename(replProjectRoot)}]`,
3038
+ source: "repl",
3039
+ pid: process.pid
3040
+ }).then(() => {
3041
+ clientHeartbeat = setInterval(() => {
3042
+ clientMailbox.clientHeartbeat({ clientId, sessionId: opts.getSessionId?.() ?? replProjectRoot }).catch(() => {
3043
+ });
3044
+ }, 15e3);
3045
+ }).catch(() => {
3046
+ });
3047
+ return {
3048
+ clientId,
3049
+ close() {
3050
+ if (clientHeartbeat) clearInterval(clientHeartbeat);
3051
+ clientMailbox.deregisterClient(clientId).catch(() => void 0);
3052
+ hqConnection.stop();
3053
+ }
3054
+ };
3055
+ }
3056
+
3057
+ // src/repl.ts
3058
+ import { createAutoProceedLoopGuard } from "@wrongstack/tools/auto-proceed-loop-guard";
3059
+ var DEFAULT_MAX_CONSECUTIVE_AUTO_PROCEED = 50;
3060
+ async function runRepl(opts) {
3061
+ if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
3062
+ await renderGoalBanner(opts);
3063
+ let activeCtrl;
3064
+ let interrupts = 0;
3065
+ if (opts.interruptController) {
3066
+ opts.interruptController.abortLeader = () => {
3067
+ if (activeCtrl) {
3068
+ activeCtrl.abort();
3069
+ return true;
3070
+ }
3071
+ return false;
3072
+ };
3073
+ }
3074
+ let autoIterCount = 0;
3075
+ let autoCapWarned = false;
3076
+ const autoProceedLoopGuard = createAutoProceedLoopGuard();
3077
+ let exiting = false;
3078
+ const onSigint = () => {
3079
+ interrupts++;
3080
+ if (interrupts >= 3) {
3081
+ process.exit(130);
3082
+ }
3083
+ if (interrupts >= 2) {
3084
+ opts.renderer.writeWarning("Exiting.");
3085
+ exiting = true;
3086
+ activeCtrl?.abort();
3087
+ const hardExit = setTimeout(() => process.exit(130), 2e3);
3088
+ hardExit.unref?.();
3089
+ return;
3090
+ }
3091
+ if (opts.getAutonomy?.() === "eternal" || opts.getAutonomy?.() === "eternal-parallel") {
3092
+ opts.getEternalEngine?.()?.stop();
3093
+ opts.getParallelEngine?.()?.stop();
3094
+ opts.onAutonomy?.("off");
3095
+ opts.renderer.writeWarning("Engine stop requested. Press Ctrl+C again to exit.");
3096
+ interrupts = 0;
3097
+ return;
3098
+ }
3099
+ const sddRun = opts.getSddRun?.();
3100
+ if (sddRun?.isRunning()) {
3101
+ sddRun.stop();
3102
+ opts.renderer.writeWarning("SDD run stop requested. Press Ctrl+C again to exit.");
3103
+ interrupts = 0;
3104
+ return;
3105
+ }
3106
+ if (activeCtrl) {
3107
+ activeCtrl.abort();
3108
+ const killed = opts.onInterruptFleet?.() ?? 0;
3109
+ opts.renderer.writeWarning(
3110
+ killed > 0 ? `Iteration cancelled \xB7 stopped ${killed} subagent${killed === 1 ? "" : "s"}. Press Ctrl+C again to exit.` : "Iteration cancelled. Press Ctrl+C again to exit."
3111
+ );
3112
+ } else {
3113
+ opts.renderer.writeWarning("Press Ctrl+C again to exit.");
3114
+ }
3115
+ };
3116
+ process.on("SIGINT", onSigint);
3117
+ const replClientRegistration = registerReplClient(opts);
3118
+ const builder = new InputBuilder({ store: opts.attachments });
3119
+ try {
3120
+ for (; ; ) {
3121
+ if (exiting) break;
3122
+ if (opts.getAutonomy?.() === "eternal") {
3123
+ const engine = opts.getEternalEngine?.();
3124
+ if (!engine) {
3125
+ opts.renderer.writeWarning("Eternal mode set but no engine wired \u2014 falling back to off.");
3126
+ } else {
3127
+ const beforeGoal = await loadGoalSafe(opts);
3128
+ const beforeIter = beforeGoal?.iterations ?? 0;
3129
+ opts.renderer.write(color9.dim(`
3130
+ \u21B3 [eternal #${beforeIter + 1}] running iteration\u2026
3131
+ `));
3132
+ interrupts = 0;
3133
+ try {
3134
+ const ok = await engine.runOneIteration();
3135
+ const afterGoal = await loadGoalSafe(opts);
3136
+ const last = afterGoal?.journal[afterGoal.journal.length - 1];
3137
+ if (!ok && !last) {
3138
+ opts.renderer.write(color9.dim(" \u21B3 [eternal] iteration produced no progress.\n"));
3139
+ } else if (last) {
3140
+ const mark = last.status === "success" ? color9.green("\u2713") : last.status === "failure" ? color9.red("\u2717") : color9.amber("\u2298");
3141
+ const tail = last.note ? color9.dim(` \u2014 ${last.note.slice(0, 80)}`) : "";
3142
+ opts.renderer.write(
3143
+ ` ${mark} ${color9.dim(`#${last.iteration}`)} ${color9.dim(`[${last.source}]`)} ${last.task}${tail}
3144
+ `
3145
+ );
3146
+ }
3147
+ if (engine.currentState === "stopped") {
3148
+ const goal = await loadGoalSafe(opts);
3149
+ if (goal?.goalState === "completed") {
3150
+ const u = goal.journal.length > 0 ? summarizeUsage(goal) : null;
3151
+ const costLine = u && u.iterationsWithUsage > 0 ? color9.dim(
3152
+ ` \u2014 ${u.totalCostUsd.toFixed(4)} \xB7 ${u.totalInputTokens} in / ${u.totalOutputTokens} out \xB7 ${goal.iterations} iterations`
3153
+ ) : goal.iterations > 0 ? color9.dim(` \u2014 ${goal.iterations} iterations`) : "";
3154
+ opts.renderer.write(
3155
+ color9.green(`
3156
+ \u{1F3AF} Goal completed!${costLine}
3157
+
3158
+ `) + color9.dim(" Goal cleared. Use /goal set <mission> to create a new goal.\n")
3159
+ );
3160
+ if (opts.projectRoot) {
3161
+ try {
3162
+ const { unlink } = await import("node:fs/promises");
3163
+ await unlink(goalFilePath(opts.projectRoot));
3164
+ } catch {
3165
+ }
3166
+ }
3167
+ }
3168
+ opts.onAutonomy?.("auto");
3169
+ continue;
3170
+ }
3171
+ } catch (err) {
3172
+ opts.renderer.writeError(
3173
+ `[eternal] ${toErrorMessage(err)}`
3174
+ );
3175
+ }
3176
+ await new Promise((resolve3) => setTimeout(resolve3, 250));
3177
+ continue;
3178
+ }
3179
+ } else if (opts.getAutonomy?.() === "eternal-parallel") {
3180
+ const engine = opts.getParallelEngine?.();
3181
+ if (!engine) {
3182
+ opts.renderer.writeWarning(
3183
+ "Parallel mode set but no engine wired \u2014 falling back to off."
3184
+ );
3185
+ } else {
3186
+ const beforeGoal = await loadGoalSafe(opts);
3187
+ const beforeIter = beforeGoal?.iterations ?? 0;
3188
+ const coord = engine.getCoordinator();
3189
+ if (coord) {
3190
+ const stats = coord.getStats();
3191
+ opts.renderer.write(
3192
+ color9.dim(
3193
+ ` \u250C\u2500 Fleet: ${stats.running} running, ${stats.idle} idle, ${stats.pending} pending, ${stats.completed} done`
3194
+ ) + "\n"
3195
+ );
3196
+ }
3197
+ opts.renderer.write(
3198
+ color9.magenta(` \u21B3 [parallel #${beforeIter + 1}] launching fan-out\u2026
3199
+ `)
3200
+ );
3201
+ interrupts = 0;
3202
+ try {
3203
+ await engine.runOneIteration();
3204
+ const afterGoal = await loadGoalSafe(opts);
3205
+ const last = afterGoal?.journal[afterGoal.journal.length - 1];
3206
+ if (coord) {
3207
+ const stats = coord.getStats();
3208
+ opts.renderer.write(
3209
+ color9.dim(
3210
+ ` \u2514\u2500 Fleet: ${stats.running} running, ${stats.idle} idle, ${stats.completed} done
3211
+ `
3212
+ )
3213
+ );
3214
+ }
3215
+ if (last) {
3216
+ const mark = last.status === "success" ? color9.green("\u2713") : last.status === "failure" ? color9.red("\u2717") : color9.amber("\u2298");
3217
+ const tail = last.note ? color9.dim(` \u2014 ${last.note.slice(0, 80)}`) : "";
3218
+ opts.renderer.write(
3219
+ ` ${mark} ${color9.dim(`#${last.iteration}`)} ${color9.dim(`[${last.source}]`)} ${last.task}${tail}
3220
+ `
3221
+ );
3222
+ }
3223
+ if (engine.currentState === "stopped") {
3224
+ const goal = await loadGoalSafe(opts);
3225
+ if (goal?.goalState === "completed") {
3226
+ const u = goal.journal.length > 0 ? summarizeUsage(goal) : null;
3227
+ const costLine = u && u.iterationsWithUsage > 0 ? color9.dim(
3228
+ ` \u2014 ${u.totalCostUsd.toFixed(4)} \xB7 ${u.totalInputTokens} in / ${u.totalOutputTokens} out \xB7 ${goal.iterations} iterations`
3229
+ ) : goal.iterations > 0 ? color9.dim(` \u2014 ${goal.iterations} iterations`) : "";
3230
+ opts.renderer.write(
3231
+ color9.green(`
3232
+ \u{1F3AF} Goal completed!${costLine}
3233
+
3234
+ `) + color9.dim(" Goal cleared. Use /goal set <mission> to create a new goal.\n")
3235
+ );
3236
+ if (opts.projectRoot) {
3237
+ try {
3238
+ const { unlink } = await import("node:fs/promises");
3239
+ await unlink(goalFilePath(opts.projectRoot));
3240
+ } catch {
3241
+ }
3242
+ }
3243
+ }
3244
+ opts.onAutonomy?.("auto");
3245
+ continue;
3246
+ }
3247
+ } catch (err) {
3248
+ opts.renderer.writeError(
3249
+ `[parallel] ${toErrorMessage(err)}`
3250
+ );
3251
+ }
3252
+ await new Promise((resolve3) => setTimeout(resolve3, 250));
3253
+ continue;
3254
+ }
3255
+ }
3256
+ {
3257
+ const mode = opts.getAutonomy?.() ?? "off";
3258
+ const suggestions = opts.getSuggestions?.() ?? [];
3259
+ if (mode === "suggest" && suggestions.length > 0) {
3260
+ const lines = suggestions.map((s, i) => ` ${color9.bold(`${i + 1}.`)} ${color9.dim(s)}`);
3261
+ opts.renderer.write(
3262
+ `
3263
+ ${color9.cyan(" \u{1F4A1} Suggested next steps")} ${color9.dim("(use /next 1, /next 2, or /next 1 2 3)")}
3264
+ ${lines.join("\n")}
3265
+
3266
+ `
3267
+ );
3268
+ }
3269
+ if (mode === "auto") {
3270
+ let top;
3271
+ let groundedTodo = false;
3272
+ if (suggestions.length > 0) {
3273
+ const isYolo = opts.getYolo?.() ?? false;
3274
+ const autoSuggestions = opts.getAutoSuggestions?.() ?? [];
3275
+ const useAutoSuggestions = isYolo && autoSuggestions.length > 0;
3276
+ top = useAutoSuggestions ? autoSuggestions[0] ?? "" : suggestions[0] ?? "";
3277
+ } else {
3278
+ const todos = opts.agent.ctx.todos ?? [];
3279
+ const resolved = resolveContinuation({ todos, suggestions: [] });
3280
+ top = resolved.source === "todo" ? resolved.text : "";
3281
+ groundedTodo = top !== "";
3282
+ }
3283
+ if (!top) {
3284
+ } else {
3285
+ const maxAuto = opts.autoProceedMaxIterations ?? DEFAULT_MAX_CONSECUTIVE_AUTO_PROCEED;
3286
+ if (maxAuto > 0 && autoIterCount >= maxAuto) {
3287
+ if (!autoCapWarned) {
3288
+ autoCapWarned = true;
3289
+ opts.renderer.writeWarning(
3290
+ `Auto-proceed paused after ${maxAuto} consecutive automatic turns \u2014 enter input to continue (resets the counter). Autonomy stays on.`
3291
+ );
3292
+ }
3293
+ } else {
3294
+ const delay = opts.autoProceedDelayMs ?? 1e3;
3295
+ const ctrl = new AbortController();
3296
+ activeCtrl = ctrl;
3297
+ try {
3298
+ const isYolo = opts.getYolo?.() ?? false;
3299
+ const autoSuggestions = opts.getAutoSuggestions?.() ?? [];
3300
+ const useAutoSuggestions = isYolo && autoSuggestions.length > 0;
3301
+ const promptToFeed = useAutoSuggestions && opts.autonomyNextPrompt ? opts.autonomyNextPrompt.replace("{{suggestion}}", top) : top;
3302
+ const submitted = await runAutoProceed(
3303
+ opts,
3304
+ promptToFeed,
3305
+ delay,
3306
+ ctrl,
3307
+ autoProceedLoopGuard,
3308
+ groundedTodo
3309
+ );
3310
+ if (submitted) {
3311
+ autoIterCount++;
3312
+ continue;
3313
+ }
3314
+ } finally {
3315
+ activeCtrl = void 0;
3316
+ }
3317
+ }
3318
+ }
3319
+ }
3320
+ }
3321
+ let raw;
3322
+ try {
3323
+ raw = await readPossiblyMultiline(opts);
3324
+ } catch {
3325
+ break;
3326
+ }
3327
+ const trimmed = raw.trim();
3328
+ if (!trimmed) {
3329
+ interrupts = 0;
3330
+ continue;
3331
+ }
3332
+ interrupts = 0;
3333
+ autoIterCount = 0;
3334
+ autoCapWarned = false;
3335
+ autoProceedLoopGuard.reset();
3336
+ if (trimmed === "q") {
3337
+ opts.renderer.write(color9.dim(" Goodbye!\n"));
3338
+ break;
3339
+ }
3340
+ if (trimmed === "wd" || trimmed.startsWith("cd ")) {
3341
+ const args = trimmed.startsWith("cd ") ? trimmed.slice(3).trim() : "";
3342
+ try {
3343
+ const res = await opts.slashRegistry.dispatch(`/working_dir ${args}`, opts.agent.ctx);
3344
+ if (res?.message) opts.renderer.write(`${res.message}
3345
+ `);
3346
+ } catch (err) {
3347
+ opts.renderer.writeError(toErrorMessage(err));
3348
+ }
3349
+ continue;
3350
+ }
3351
+ if (trimmed === "/image" || trimmed === "/paste-image" || raw === "\x1Bv") {
3352
+ await pasteClipboardImage(builder, opts);
3353
+ continue;
3354
+ }
3355
+ if (trimmed.startsWith("/")) {
3356
+ try {
3357
+ const res = await opts.slashRegistry.dispatch(trimmed, opts.agent.ctx);
3358
+ if (res?.message) opts.renderer.write(`${res.message}
3359
+ `);
3360
+ if (res?.exit) break;
3361
+ if (res?.runText) {
3362
+ const runBlocks = [{ type: "text", text: res.runText }];
3363
+ const runCtrl2 = new AbortController();
3364
+ activeCtrl = runCtrl2;
3365
+ try {
3366
+ const runResult = await opts.agent.run(runBlocks, { signal: runCtrl2.signal });
3367
+ opts.onAgentIterationComplete?.(
3368
+ estimateRequestTokensCalibrated2(
3369
+ opts.agent.ctx.messages,
3370
+ opts.agent.ctx.systemPrompt,
3371
+ opts.agent.ctx.tools ?? []
3372
+ ).total
3373
+ );
3374
+ if (runResult.status === "done" && runResult.finalText) {
3375
+ const specSaved = await trySaveSpecFromAIOutput(runResult.finalText);
3376
+ if (specSaved) {
3377
+ opts.renderer.write(
3378
+ `
3379
+ ${color9.cyan(" \u2713 Spec detected and saved! Use /sdd approve to continue.")}
3380
+ `
3381
+ );
3382
+ }
3383
+ const planSaved = trySaveImplementationPlan(runResult.finalText);
3384
+ if (planSaved) {
3385
+ opts.renderer.write(`
3386
+ ${color9.cyan(" \u2713 Implementation plan saved!")}
3387
+ `);
3388
+ }
3389
+ const tasksSaved = await trySaveTasksFromAIOutput(runResult.finalText);
3390
+ if (tasksSaved) {
3391
+ const progress = getTaskProgress();
3392
+ const count = progress?.total ?? 0;
3393
+ opts.renderer.write(
3394
+ `
3395
+ ${color9.cyan(` \u2713 ${count} tasks detected and saved! Use /sdd approve to execute.`)}
3396
+ `
3397
+ );
3398
+ }
3399
+ const sddPhase2 = getActiveSDDPhase();
3400
+ if (sddPhase2 === "executing") {
3401
+ const autoCompleted = autoDetectTaskCompletion(runResult.finalText);
3402
+ if (autoCompleted > 0) {
3403
+ const progress = getTaskProgress();
3404
+ if (progress) {
3405
+ opts.renderer.write(
3406
+ `
3407
+ ${color9.cyan(` \u2713 ${autoCompleted} task(s) auto-completed! Progress: ${progress.completed}/${progress.total} (${progress.percentComplete}%)`)}
3408
+ `
3409
+ );
3410
+ const taskList2 = renderTaskListWithProgress();
3411
+ if (taskList2) {
3412
+ opts.renderer.write(`
3413
+ ${color9.dim(taskList2)}
3414
+ `);
3415
+ }
3416
+ }
3417
+ } else {
3418
+ const taskList2 = renderTaskListWithProgress();
3419
+ if (taskList2) {
3420
+ opts.renderer.write(`
3421
+ ${color9.dim(taskList2)}
3422
+ `);
3423
+ }
3424
+ }
3425
+ }
3426
+ if (opts.onSuggestionsParsed) {
3427
+ const parsed = parseSuggestionsFromOutput(
3428
+ runResult.finalText,
3429
+ opts.agent.ctx.todos
3430
+ );
3431
+ opts.onSuggestionsParsed(parsed);
3432
+ }
3433
+ }
3434
+ } catch (_runErr) {
3435
+ opts.renderer.writeWarning("AI auto-trigger failed. You can continue manually.");
3436
+ }
3437
+ }
3438
+ } catch (err) {
3439
+ opts.renderer.writeError(toErrorMessage(err));
3440
+ }
3441
+ continue;
3442
+ }
3443
+ if (detectContinueIntent(trimmed)) {
3444
+ const resolved = resolveContinuation({
3445
+ todos: opts.agent.ctx.todos,
3446
+ suggestions: getSuggestions()
3447
+ });
3448
+ if (resolved.source === "open") {
3449
+ opts.renderer.write(
3450
+ ` ${color9.amber("\u26A0")} ${color9.bold("'continue' has no anchor")} ${color9.dim("\u2014 no pending todo or suggestion.")}
3451
+ ` + color9.dim(" If you proceed, I'll choose the next step from context; that can drift.\n")
3452
+ );
3453
+ const ans = (await opts.reader.readLine(color9.dim(" Proceed anyway? [Y/n \xB7 e = type your own] "))).trim().toLowerCase();
3454
+ if (ans === "n" || ans === "no") {
3455
+ opts.renderer.write(color9.dim(" Cancelled \u2014 nothing sent.\n"));
3456
+ continue;
3457
+ }
3458
+ if (ans === "e" || ans === "edit") {
3459
+ opts.renderer.write(color9.dim(" Okay \u2014 type what to continue with.\n"));
3460
+ continue;
3461
+ }
3462
+ } else {
3463
+ opts.renderer.write(color9.dim(` ${resolved.label}
3464
+ `));
3465
+ }
3466
+ builder.appendText(resolved.text);
3467
+ } else {
3468
+ const ph = await builder.appendPaste(raw);
3469
+ if (ph) {
3470
+ const lineCount = raw.split("\n").length;
3471
+ opts.renderer.write(color9.dim(` \u21B3 ${ph} (${lineCount} lines)
3472
+ `));
3473
+ }
3474
+ }
3475
+ const blocks = await builder.submit();
3476
+ const sddContext = getActiveSDDContext();
3477
+ const taskList = getTaskListText();
3478
+ const taskProgress = getTaskProgress();
3479
+ const sddPhase = getActiveSDDPhase();
3480
+ let sddPrefix = "";
3481
+ if (sddContext) {
3482
+ sddPrefix = `[SDD SESSION ACTIVE]
3483
+ ${sddContext}`;
3484
+ if (sddPhase === "executing") {
3485
+ const currentCtx = getCurrentExecutingContext();
3486
+ if (currentCtx) {
3487
+ sddPrefix += `
3488
+
3489
+ ${currentCtx}`;
3490
+ }
3491
+ }
3492
+ if (taskList) {
3493
+ sddPrefix += `
3494
+
3495
+ **Current Task List:**
3496
+ ${taskList}`;
3497
+ }
3498
+ if (taskProgress && taskProgress.total > 0) {
3499
+ sddPrefix += `
3500
+ **Progress:** ${taskProgress.completed}/${taskProgress.total} (${taskProgress.percentComplete}%)`;
3501
+ }
3502
+ if (sddPhase === "executing" && taskProgress && taskProgress.percentComplete === 100) {
3503
+ sddPrefix += "\n\n**All tasks completed! Provide a summary of everything implemented.**";
3504
+ }
3505
+ sddPrefix += "\n\n---\nUser message:\n";
3506
+ }
3507
+ const effectiveBlocks = sddPrefix ? [{ type: "text", text: sddPrefix }, ...blocks] : blocks;
3508
+ const runCtrl = new AbortController();
3509
+ activeCtrl = runCtrl;
3510
+ try {
3511
+ const startedAt = Date.now();
3512
+ const before = opts.tokenCounter?.total();
3513
+ const costBefore = opts.tokenCounter?.estimateCost().total ?? 0;
3514
+ const routed = effectiveBlocks.some((block) => block.type === "image") ? await routeImagesForModel(effectiveBlocks, {
3515
+ supportsVision: opts.supportsVision ? await opts.supportsVision() : opts.agent.ctx.provider.capabilities.vision,
3516
+ adapters: opts.visionAdapters ?? [],
3517
+ ctx: opts.agent.ctx,
3518
+ signal: runCtrl.signal,
3519
+ providerId: opts.agent.ctx.provider.id,
3520
+ model: opts.agent.ctx.model
3521
+ }) : { blocks: effectiveBlocks, route: "none", convertedImages: 0 };
3522
+ if (routed.route === "adapter") {
3523
+ opts.renderer.write(
3524
+ color9.dim(
3525
+ ` \u21B3 image analyzed via ${routed.adapterName ?? "vision adapter"} (${routed.convertedImages} image${routed.convertedImages === 1 ? "" : "s"})
3526
+ `
3527
+ )
3528
+ );
3529
+ }
3530
+ const result = await opts.agent.run(routed.blocks, { signal: runCtrl.signal });
3531
+ opts.onAgentIterationComplete?.(
3532
+ estimateRequestTokensCalibrated2(
3533
+ opts.agent.ctx.messages,
3534
+ opts.agent.ctx.systemPrompt,
3535
+ opts.agent.ctx.tools ?? []
3536
+ ).total
3537
+ );
3538
+ if (result.status === "aborted") {
3539
+ opts.renderer.writeWarning("Aborted.");
3540
+ } else if (result.status === "failed") {
3541
+ const err = result.error;
3542
+ if (err) {
3543
+ const tag = err.recoverable ? " (recoverable)" : "";
3544
+ opts.renderer.writeError(`Failed [${err.severity}]${tag}: ${err.describe()}`);
3545
+ const hint = contextOverflowHint(err);
3546
+ if (hint) opts.renderer.writeWarning(hint);
3547
+ } else {
3548
+ opts.renderer.writeError("Failed.");
3549
+ }
3550
+ } else if (result.status === "max_iterations") {
3551
+ opts.renderer.writeWarning(`Hit max iterations (${result.iterations}).`);
3552
+ }
3553
+ if (result.status === "done" && result.finalText && sddContext) {
3554
+ const specSaved = await trySaveSpecFromAIOutput(result.finalText);
3555
+ if (specSaved) {
3556
+ opts.renderer.write(
3557
+ `
3558
+ ${color9.cyan(" \u2713 Spec detected and saved! Use /sdd approve to continue.")}
3559
+ `
3560
+ );
3561
+ }
3562
+ const planSaved = trySaveImplementationPlan(result.finalText);
3563
+ if (planSaved) {
3564
+ opts.renderer.write(`
3565
+ ${color9.cyan(" \u2713 Implementation plan saved!")}
3566
+ `);
3567
+ }
3568
+ const tasksSaved = await trySaveTasksFromAIOutput(result.finalText);
3569
+ if (tasksSaved) {
3570
+ const progress = getTaskProgress();
3571
+ const count = progress?.total ?? 0;
3572
+ opts.renderer.write(
3573
+ `
3574
+ ${color9.cyan(` \u2713 ${count} tasks detected and saved! Use /sdd approve to execute.`)}
3575
+ `
3576
+ );
3577
+ }
3578
+ const phase = getActiveSDDPhase();
3579
+ if (phase === "executing") {
3580
+ const autoCompleted = autoDetectTaskCompletion(result.finalText);
3581
+ if (autoCompleted > 0) {
3582
+ const progress = getTaskProgress();
3583
+ if (progress) {
3584
+ opts.renderer.write(
3585
+ `
3586
+ ${color9.cyan(` \u2713 ${autoCompleted} task(s) auto-completed! Progress: ${progress.completed}/${progress.total} (${progress.percentComplete}%)`)}
3587
+ `
3588
+ );
3589
+ if (progress.percentComplete === 100) {
3590
+ opts.renderer.write(
3591
+ `
3592
+ ${color9.green(" \u{1F389} All tasks completed! Use /sdd cancel to end the session.")}
3593
+ `
3594
+ );
3595
+ }
3596
+ }
3597
+ advanceToNextTask();
3598
+ const taskList2 = renderTaskListWithProgress();
3599
+ if (taskList2) {
3600
+ opts.renderer.write(`
3601
+ ${color9.dim(taskList2)}
3602
+ `);
3603
+ }
3604
+ } else {
3605
+ const taskList2 = renderTaskListWithProgress();
3606
+ if (taskList2) {
3607
+ opts.renderer.write(`
3608
+ ${color9.dim(taskList2)}
3609
+ `);
3610
+ }
3611
+ }
3612
+ }
3613
+ }
3614
+ if (result.status === "done" && result.finalText && opts.onSuggestionsParsed) {
3615
+ const parsed = parseSuggestionsFromOutput(result.finalText, opts.agent.ctx.todos);
3616
+ opts.onSuggestionsParsed(parsed);
3617
+ }
3618
+ if (opts.tokenCounter && before) {
3619
+ const after = opts.tokenCounter.total();
3620
+ const costAfter = opts.tokenCounter.estimateCost().total;
3621
+ const effectiveMaxContext = opts.getEffectiveMaxContext?.() ?? opts.effectiveMaxContext;
3622
+ const ctxChip = effectiveMaxContext && effectiveMaxContext > 0 ? ` ctx: ${renderContextChip(after.input, effectiveMaxContext)}` : "";
3623
+ opts.renderer.write(
3624
+ `
3625
+ ${color9.dim(
3626
+ `[in: ${fmtTok(after.input - before.input)} out: ${fmtTok(after.output - before.output)} iters: ${result.iterations} cost: ${(costAfter - costBefore).toFixed(4)} ${((Date.now() - startedAt) / 1e3).toFixed(1)}s]${ctxChip}`
3627
+ )}
3628
+ `
3629
+ );
3630
+ }
3631
+ if (result.status === "done" && opts.getAutonomy) {
3632
+ const autonomy = opts.getAutonomy();
3633
+ if (autonomy === "suggest" && !hasOpenTodos2(opts.agent.ctx.todos)) {
3634
+ const suggestPrompt = 'Based on what you just did, suggest 3 exact prompt messages that can be submitted back to you through the TUI or WebUI. Each prompt must ask the agent to perform work; never assign a manual chore to the user. If you include suggestions, wrap them in a balanced <nextsteps>...</nextsteps> block, with one numbered prompt per line and no explanation. If there is nothing meaningful left, say "No further steps needed."';
3635
+ const suggestBlocks = [{ type: "text", text: suggestPrompt }];
3636
+ const suggestCtrl = new AbortController();
3637
+ activeCtrl = suggestCtrl;
3638
+ try {
3639
+ const suggestResult = await opts.agent.run(suggestBlocks, {
3640
+ signal: suggestCtrl.signal
3641
+ });
3642
+ opts.onAgentIterationComplete?.(
3643
+ estimateRequestTokensCalibrated2(
3644
+ opts.agent.ctx.messages,
3645
+ opts.agent.ctx.systemPrompt,
3646
+ opts.agent.ctx.tools ?? []
3647
+ ).total
3648
+ );
3649
+ if (suggestResult.status === "done" && suggestResult.finalText) {
3650
+ opts.renderer.write(
3651
+ `
3652
+ ${color9.cyan(" Suggested next steps:")}
3653
+ ${suggestResult.finalText}
3654
+ `
3655
+ );
3656
+ if (opts.onSuggestionsParsed) {
3657
+ const parsed = parseSuggestionsFromOutput(
3658
+ suggestResult.finalText,
3659
+ opts.agent.ctx.todos
3660
+ );
3661
+ opts.onSuggestionsParsed(parsed);
3662
+ }
3663
+ }
3664
+ } catch {
3665
+ } finally {
3666
+ activeCtrl = void 0;
3667
+ }
3668
+ }
3669
+ }
3670
+ if (result.status === "done" && opts.getNextPredict?.() && !hasOpenTodos2(opts.agent.ctx.todos)) {
3671
+ const autonomy = opts.getAutonomy?.() ?? "off";
3672
+ if (autonomy === "off") {
3673
+ const predictCtrl = new AbortController();
3674
+ activeCtrl = predictCtrl;
3675
+ try {
3676
+ const predictions = await predictNextTasks(
3677
+ {
3678
+ userRequest: trimmed,
3679
+ assistantSummary: result.finalText ?? "",
3680
+ todos: opts.agent.ctx.todos
3681
+ },
3682
+ {
3683
+ provider: opts.agent.ctx.provider,
3684
+ model: opts.agent.ctx.model,
3685
+ signal: predictCtrl.signal
3686
+ }
3687
+ );
3688
+ if (predictions.length > 0) {
3689
+ const lines = predictions.map((p, i) => ` ${i + 1}. ${p}`).join("\n");
3690
+ opts.renderer.write(`
3691
+ ${color9.dim(" \u21B3 likely next:")}
3692
+ ${color9.dim(lines)}
3693
+ `);
3694
+ }
3695
+ } catch {
3696
+ } finally {
3697
+ activeCtrl = void 0;
3698
+ }
3699
+ }
3700
+ }
3701
+ } catch (err) {
3702
+ opts.renderer.writeError(toErrorMessage(err));
3703
+ } finally {
3704
+ activeCtrl = void 0;
3705
+ }
3706
+ }
3707
+ return 0;
3708
+ } finally {
3709
+ process.off("SIGINT", onSigint);
3710
+ await opts.reader.close().catch(() => {
3711
+ });
3712
+ replClientRegistration.close();
3713
+ opts.onDestroy?.();
3714
+ }
3715
+ }
3716
+ async function pasteClipboardImage(builder, opts) {
3717
+ try {
3718
+ const img = await readClipboardImage();
3719
+ if (!img) {
3720
+ opts.renderer.write(color9.dim(" no image on clipboard\n"));
3721
+ return;
3722
+ }
3723
+ const placeholder = await builder.appendImage(img.base64, img.mediaType);
3724
+ const kb = (img.bytes / 1024).toFixed(0);
3725
+ opts.renderer.write(color9.dim(` \u21B3 ${placeholder} (PNG ${kb}KB)
3726
+ `));
3727
+ } catch (err) {
3728
+ opts.renderer.writeError(
3729
+ `Clipboard image error: ${toErrorMessage(err)}`
3730
+ );
3731
+ }
3732
+ }
3733
+ async function loadGoalSafe(opts) {
3734
+ if (!opts.projectRoot) return null;
3735
+ try {
3736
+ return await loadGoal(goalFilePath(opts.projectRoot));
3737
+ } catch {
3738
+ return null;
3739
+ }
3740
+ }
3741
+ async function renderGoalBanner(opts) {
3742
+ const goal = await loadGoalSafe(opts);
3743
+ if (!goal) return;
3744
+ const summary = goal.goal.length > 80 ? `${goal.goal.slice(0, 77)}\u2026` : goal.goal;
3745
+ const stateColor = goal.goalState === "active" ? color9.green : goal.goalState === "paused" ? color9.amber : goal.goalState === "completed" ? color9.green : goal.goalState === "abandoned" ? color9.dim : color9.dim;
3746
+ opts.renderer.write(
3747
+ color9.dim("Goal: ") + stateColor(summary) + color9.dim(` [${goal.goalState}] (iter ${goal.iterations})`) + "\n"
3748
+ );
3749
+ if (goal.journal.length > 0) {
3750
+ const lastEntry = expectDefined(goal.journal[goal.journal.length - 1]);
3751
+ const statusIcon = lastEntry.status === "success" ? "\u2713" : lastEntry.status === "failure" ? "\u2717" : lastEntry.status === "aborted" ? "\u2298" : lastEntry.status === "skipped" ? "\u229D" : "\xB7";
3752
+ opts.renderer.write(
3753
+ color9.dim(` Last: ${statusIcon} ${lastEntry.task} (${lastEntry.status})`) + "\n"
3754
+ );
3755
+ }
3756
+ if (goal.engineState === "running") {
3757
+ opts.renderer.write(
3758
+ color9.amber(" \u21BA Eternal engine was running when last session ended.") + "\n"
3759
+ );
3760
+ try {
3761
+ const answer = (await opts.reader.readLine(color9.dim(" Resume eternal mode? [y/N] "))).trim().toLowerCase();
3762
+ if (answer === "y" || answer === "yes") {
3763
+ try {
3764
+ await opts.slashRegistry.dispatch("/autonomy eternal", opts.agent.ctx);
3765
+ } catch (err) {
3766
+ opts.renderer.writeError(
3767
+ `Auto-resume failed: ${toErrorMessage(err)}`
3768
+ );
3769
+ }
3770
+ } else {
3771
+ opts.renderer.write(
3772
+ color9.dim(" Not resuming. Use `/autonomy eternal` later to continue.") + "\n"
3773
+ );
3774
+ }
3775
+ } catch {
3776
+ opts.renderer.write(color9.dim(" Use `/autonomy eternal` to resume.") + "\n");
3777
+ }
3778
+ } else if (goal.goalState === "paused") {
3779
+ opts.renderer.write(color9.amber(" \u23F8 Goal is paused. Use `/goal resume` to continue.") + "\n");
3780
+ } else if (goal.goalState === "completed") {
3781
+ opts.renderer.write(
3782
+ color9.green(" \u2713 Goal completed! Use `/goal clear` to set a new goal.") + "\n"
3783
+ );
3784
+ } else if (goal.goalState === "abandoned") {
3785
+ opts.renderer.write(color9.dim(" Use `/goal clear` to set a new goal.") + "\n");
3786
+ }
3787
+ opts.renderer.write("\n");
3788
+ }
3789
+
3790
+ // src/execution-tui-next-step-callbacks.ts
3791
+ function createTuiNextStepCallbacks(input) {
3792
+ const { context, getNextPredict, getAutonomy, getSuggestions: getSuggestions2 } = input;
3793
+ return {
3794
+ async predictNext(request) {
3795
+ if (!getNextPredict?.()) return [];
3796
+ if ((getAutonomy?.() ?? "off") !== "off") return [];
3797
+ return predictNextTasks(
3798
+ { ...request, todos: context.todos ?? [] },
3799
+ {
3800
+ provider: context.provider,
3801
+ model: context.model
3802
+ }
3803
+ );
3804
+ },
3805
+ onSuggestionsParsed(finalText) {
3806
+ const parsed = parseSuggestionsFromOutput(finalText, context.todos);
3807
+ setSuggestions(parsed ?? []);
3808
+ },
3809
+ getSuggestions: () => getSuggestions2?.() ?? [],
3810
+ setSuggestions
3811
+ };
3812
+ }
3813
+
3814
+ // src/execution.ts
3815
+ async function execute(deps) {
3816
+ const {
3817
+ core: {
3818
+ agent,
3819
+ events,
3820
+ config,
3821
+ configStore,
3822
+ wpaths: initialWpaths,
3823
+ projectRoot: initialProjectRoot,
3824
+ flags,
3825
+ positional,
3826
+ slashRegistry,
3827
+ tokenCounter,
3828
+ activateSessionIdentity,
3829
+ updateInfo: initialUpdateInfo
3830
+ },
3831
+ session: {
3832
+ session,
3833
+ context,
3834
+ attachments,
3835
+ queueStore,
3836
+ mcpRegistry,
3837
+ mailbox,
3838
+ sessionStore,
3839
+ memoryStore,
3840
+ modeStore,
3841
+ detachTodosCheckpoint,
3842
+ restoredMessages,
3843
+ restoredToolCalls,
3844
+ restoredEvents,
3845
+ needsSetup
3846
+ },
3847
+ provider: {
3848
+ modelsRegistry,
3849
+ savedProviderCfg,
3850
+ resolvedProvider,
3851
+ statusTracker,
3852
+ getPickableProviders,
3853
+ switchProviderAndModel,
3854
+ onModelContextResolved,
3855
+ sddSubagentFactory
3856
+ },
3857
+ ui: {
3858
+ renderer,
3859
+ reader,
3860
+ secretInputController,
3861
+ stats,
3862
+ effectiveMaxContext,
3863
+ getEffectiveMaxContext,
3864
+ skillLoader,
3865
+ promptLoader,
3866
+ modeId
3867
+ },
3868
+ fleet: {
3869
+ director,
3870
+ getDirector,
3871
+ coordinatorController,
3872
+ fleetRoster,
3873
+ fleetStreamController,
3874
+ agentsMonitorController,
3875
+ agentTranscripts,
3876
+ authHost,
3877
+ onPanelOpen
3878
+ },
3879
+ controllers: {
3880
+ interruptController,
3881
+ enhanceController,
3882
+ getEnhancerReasoning,
3883
+ buildEnhancerProvider,
3884
+ getEnhanceFallbackRef,
3885
+ getConfiguredRefinerRef,
3886
+ statuslineHiddenItems,
3887
+ setStatuslineHiddenItems,
3888
+ saveStatuslineHiddenItems,
3889
+ getYolo,
3890
+ onYolo,
3891
+ getAutonomy,
3892
+ onAutonomy,
3893
+ getNextPredict,
3894
+ applyLiveSettings,
3895
+ onCountdownTick
3896
+ },
3897
+ picker: {
3898
+ getPluginItems,
3899
+ onPluginToggle,
3900
+ getMcpServers,
3901
+ onMcpToggle,
3902
+ onMcpRestart,
3903
+ getToolsItems,
3904
+ onToolToggle,
3905
+ getBrainData,
3906
+ onBrainRiskLevel,
3907
+ getBrainLog,
3908
+ brain,
3909
+ brainSettings,
3910
+ brainRuntime,
3911
+ getShadowData,
3912
+ onShadowStart,
3913
+ onShadowStop
3914
+ } = {},
3915
+ lifecycles: {
3916
+ getSuggestions: getSuggestions2,
3917
+ getAutoSuggestions,
3918
+ onSuggestionsParsed,
3919
+ autonomyNextPrompt,
3920
+ autoProceedDelayMs,
3921
+ autoProceedMaxIterations,
3922
+ onValidateAutoProceed,
3923
+ getEternalEngine,
3924
+ getParallelEngine,
3925
+ getSddRun,
3926
+ onSddLifecycle,
3927
+ subscribeEternalIteration,
3928
+ subscribeEternalStage,
3929
+ onDestroy,
3930
+ onCoordinatorStop
3931
+ } = {}
3932
+ } = deps;
3933
+ let onCoordinatorStopImpl = onCoordinatorStop;
3934
+ const wpaths = initialWpaths;
3935
+ const projectRoot = initialProjectRoot;
3936
+ const activeSessionStore = sessionStore;
3937
+ const detachActiveTodosCheckpoint = detachTodosCheckpoint;
3938
+ const profileName = config.activeProfile ?? "default";
3939
+ const bootUpdateInfo = initialUpdateInfo;
3940
+ const offStorageObservability = installStorageObservability(events, context.traceId);
3941
+ let pendingChimeraWork;
3942
+ events.onPattern("chimera.review_needed", (_event, payload) => {
3943
+ const p = payload;
3944
+ const dir = director;
3945
+ if (!dir) {
3946
+ return;
3947
+ }
3948
+ if (p.files.length === 0) return;
3949
+ pendingChimeraWork = (async () => {
3950
+ let subagentId;
3951
+ try {
3952
+ const taskDesc = buildChimeraReviewTaskDescription(p);
3953
+ const tProvider = config.provider?.trim() || void 0;
3954
+ const tModel = config.model?.trim() || void 0;
3955
+ const rawProvider = p.reviewFallbackModels ? p.config.provider?.trim() || void 0 : tProvider;
3956
+ const rawModel = p.reviewFallbackModels ? p.config.model?.trim() || void 0 : tModel;
3957
+ const baseProvider = rawProvider || tProvider || config.provider;
3958
+ const baseModel = rawModel || tModel || config.model;
3959
+ const baseFallbacks = p.reviewFallbackModels ? [...p.reviewFallbackModels] : resolveReviewerFallbackModels(void 0);
3960
+ const assigned = assignReviewerModelsRoundRobin(baseProvider, baseModel, baseFallbacks);
3961
+ const cfg = applyChimeraReviewerReadOnlyPolicy({
3962
+ name: "chimera-review",
3963
+ role: "reviewer",
3964
+ systemPromptOverride: CHIMERA_REVIEW_PROMPT,
3965
+ maxIterations: 50,
3966
+ maxToolCalls: 250,
3967
+ timeoutMs: 9e5,
3968
+ provider: assigned.provider,
3969
+ model: assigned.model,
3970
+ fallbackModels: assigned.fallbackModels
3971
+ });
3972
+ subagentId = await dir.spawn(cfg);
3973
+ const taskId = randomUUID4();
3974
+ await dir.assign({
3975
+ id: taskId,
3976
+ description: taskDesc,
3977
+ subagentId
3978
+ });
3979
+ const results = await dir.awaitTasks([taskId]);
3980
+ const result = results[0];
3981
+ if (result?.status !== "success") {
3982
+ try {
3983
+ await session.append({
3984
+ type: "error",
3985
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
3986
+ message: `\u{1F982} Chimera review subagent ${result?.status ?? "unknown"}: ${result?.error?.message ?? "no result"}`,
3987
+ phase: "agent"
3988
+ });
3989
+ } catch (err) {
3990
+ console.error(
3991
+ JSON.stringify({
3992
+ level: "error",
3993
+ event: "execution.chimera_append_failed",
3994
+ message: err instanceof Error ? err.message : String(err),
3995
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
3996
+ })
3997
+ );
3998
+ }
3999
+ events.emitCustom("chimera.review_complete", {
4000
+ bundle: p,
4001
+ reviewText: "",
4002
+ status: result?.status ?? "unknown",
4003
+ cwd: p.cwd,
4004
+ sessionId: session.id
4005
+ });
4006
+ return;
4007
+ }
4008
+ const reviewText = typeof result.result === "string" ? result.result.trim() : JSON.stringify(result.result);
4009
+ events.emitCustom("chimera.review_complete", {
4010
+ bundle: p,
4011
+ reviewText,
4012
+ status: "success",
4013
+ cwd: p.cwd,
4014
+ sessionId: session.id
4015
+ });
4016
+ if (reviewText) {
4017
+ await session.append({
4018
+ type: "llm_response",
4019
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4020
+ content: [{ type: "text", text: reviewText }],
4021
+ stopReason: "end_turn",
4022
+ usage: { input: 0, output: 0 }
4023
+ });
4024
+ const autoFix = agent.ctx.meta["chimeraAutoFix"] ?? p.config.autoFix ?? "off";
4025
+ const reviewHasFindings = !isChimeraAllClearReview(reviewText);
4026
+ const isAskMode = autoFix === "ask" && reviewHasFindings;
4027
+ const mailboxType = isAskMode ? "ask" : "result";
4028
+ const subject = isAskMode ? `\u{1F982} Chimera review \u2014 ${p.files.length} file(s) changed. Shall I fix the findings?` : `\u{1F982} Chimera review \u2014 ${p.files.length} file(s) changed`;
4029
+ let leaderApproved = false;
4030
+ let spawnedFix = false;
4031
+ let askMailMsgId;
4032
+ let leaderOnline = false;
4033
+ if (isAskMode) {
4034
+ try {
4035
+ const onlineAgents = await mailbox.getOnlineAgents();
4036
+ leaderOnline = onlineAgents.some(
4037
+ (a) => a.online && isMailboxLeader(a.agentId, a.role)
4038
+ );
4039
+ } catch (leaderCheckErr) {
4040
+ console.warn(
4041
+ JSON.stringify({
4042
+ level: "warn",
4043
+ event: "execution.chimera_leader_check_failed",
4044
+ message: leaderCheckErr instanceof Error ? leaderCheckErr.message : String(leaderCheckErr),
4045
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4046
+ })
4047
+ );
4048
+ }
4049
+ if (!leaderOnline) {
4050
+ console.warn(
4051
+ JSON.stringify({
4052
+ level: "warn",
4053
+ event: "execution.chimera_mailbox_leader_offline",
4054
+ message: `Leader not online \u2014 mailbox ${mailboxType} from chimera-review to leader will be delivered when leader reconnects`,
4055
+ fileCount: p.files.length,
4056
+ autoFix,
4057
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4058
+ })
4059
+ );
4060
+ }
4061
+ } else {
4062
+ leaderOnline = true;
4063
+ console.debug(
4064
+ JSON.stringify({
4065
+ level: "debug",
4066
+ event: "execution.chimera_auto_no_presence_check",
4067
+ message: "Result mode: leader presence not checked \u2014 mailbox message delivered regardless",
4068
+ fileCount: p.files.length,
4069
+ autoFix,
4070
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4071
+ })
4072
+ );
4073
+ }
4074
+ try {
4075
+ const askTimeoutRaw = agent.ctx.meta["chimeraAskTimeoutMs"] ?? 3e4;
4076
+ const ASK_TIMEOUT_MS = Number.isFinite(askTimeoutRaw) ? Math.max(0, askTimeoutRaw) : 3e4;
4077
+ const directive = isAskMode ? `LEADER ACTION REQUIRED: The Chimera review below found issues. Reply with "yes" to auto-fix, or "no" to skip (${ASK_TIMEOUT_MS / 1e3}s timeout).` : reviewHasFindings ? "LEADER ACTION REQUIRED: The Chimera review below found issues. Read the report and fix any Critical or High findings automatically using the edit tool. Verify with typecheck and linter." : "Chimera review completed with no findings. Read the report summary below; no fix action is requested.";
4078
+ const reviewBody = reviewText.length > 7500 ? truncateAtCodePointBoundary(reviewText, 7500) + "\n\n\u2026(truncated, full report in session transcript)" : reviewText;
4079
+ const body = `${directive}
4080
+
4081
+ ${reviewBody}`;
4082
+ const mailMsg = await mailbox.send({
4083
+ from: "chimera-review",
4084
+ to: "leader",
4085
+ type: mailboxType,
4086
+ audience: "leaders",
4087
+ subject,
4088
+ body,
4089
+ priority: "normal"
4090
+ });
4091
+ if (!mailMsg?.id) throw new Error("mailbox.send returned no message id");
4092
+ askMailMsgId = mailMsg.id;
4093
+ if (isAskMode) {
4094
+ leaderApproved = await waitForChimeraAskApproval({
4095
+ mailbox,
4096
+ messageId: askMailMsgId,
4097
+ meta: agent.ctx.meta,
4098
+ session: agent.ctx.session ?? session,
4099
+ askTimeoutMs: ASK_TIMEOUT_MS
4100
+ });
4101
+ }
4102
+ } catch (mailErr) {
4103
+ const errMsg = mailErr instanceof Error ? mailErr.message : String(mailErr);
4104
+ console.error(
4105
+ JSON.stringify({
4106
+ level: "error",
4107
+ event: "execution.chimera_mailbox_failed",
4108
+ message: errMsg,
4109
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4110
+ })
4111
+ );
4112
+ await session.append({
4113
+ type: "error",
4114
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4115
+ message: `\u{1F982} Chimera auto-fix skipped \u2014 mailbox unreachable: ${errMsg}. Falling back to manual review mode.`,
4116
+ phase: "agent"
4117
+ });
4118
+ }
4119
+ events.emitCustom("chimera.mailbox_delivered", {
4120
+ subject,
4121
+ autoFixMode: autoFix,
4122
+ fileCount: p.files.length,
4123
+ reviewLength: reviewText.length
4124
+ });
4125
+ if (!leaderOnline) {
4126
+ try {
4127
+ await mailbox.send({
4128
+ from: "chimera-review",
4129
+ to: "leader",
4130
+ type: "note",
4131
+ audience: "leaders",
4132
+ subject: `\u23F0 Chimera review pending \u2014 ${p.files.length} file(s) checked`,
4133
+ body: `The leader was offline when a chimera review completed. A full review result with "LEADER ACTION REQUIRED" directive is waiting in this mailbox from chimera-review. Open it, read the findings, and fix any Critical or High issues.`,
4134
+ priority: "high"
4135
+ });
4136
+ } catch (wakeErr) {
4137
+ console.warn(
4138
+ JSON.stringify({
4139
+ level: "warn",
4140
+ event: "execution.chimera_wakeup_companion_failed",
4141
+ message: wakeErr instanceof Error ? wakeErr.message : String(wakeErr),
4142
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4143
+ })
4144
+ );
4145
+ }
4146
+ }
4147
+ const shouldSpawnFix = !spawnedFix && reviewHasFindings && (autoFix === "auto" || isAskMode && leaderApproved) && reviewText.length > 0;
4148
+ if (shouldSpawnFix) {
4149
+ spawnedFix = true;
4150
+ const fixTaskDesc = [
4151
+ `You are a fix agent. Apply the fixes requested in this review report.`,
4152
+ ``,
4153
+ `Repository: ${p.cwd}`,
4154
+ ``,
4155
+ `--- Review report ---`,
4156
+ truncateAtCodePointBoundary(reviewText, 12e3),
4157
+ ``,
4158
+ `--- Changed files ---`,
4159
+ p.files.map((f) => `- ${f.path}`).join("\n"),
4160
+ ``,
4161
+ `Read each file, understand the issue, apply fixes using the edit tool.`,
4162
+ `After fixing, run the project's typecheck and linter to verify.`,
4163
+ `Do NOT remove or reorder existing code unless the bug requires it.`
4164
+ ].join("\n");
4165
+ try {
4166
+ const fixCfg = {
4167
+ name: "chimera-fix",
4168
+ role: "fixer",
4169
+ maxIterations: 60,
4170
+ maxToolCalls: 350,
4171
+ timeoutMs: 12e5
4172
+ };
4173
+ const fixSubagentId = await dir.spawn(fixCfg);
4174
+ try {
4175
+ const fixTaskId = randomUUID4();
4176
+ await dir.assign({
4177
+ id: fixTaskId,
4178
+ description: fixTaskDesc,
4179
+ subagentId: fixSubagentId
4180
+ });
4181
+ const fixResults = await dir.awaitTasks([fixTaskId]);
4182
+ const fixResult = fixResults[0];
4183
+ if (fixResult?.status === "success") {
4184
+ await session.append({
4185
+ type: "llm_response",
4186
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4187
+ content: [
4188
+ { type: "text", text: `Chimera fix subagent completed: ${fixResult.result}` }
4189
+ ],
4190
+ stopReason: "end_turn",
4191
+ usage: { input: 0, output: 0 }
4192
+ });
4193
+ } else {
4194
+ await session.append({
4195
+ type: "error",
4196
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4197
+ message: `Chimera fix subagent ${fixResult?.status ?? "unknown"}: ${fixResult?.error?.message ?? "no result"}`,
4198
+ phase: "agent"
4199
+ });
4200
+ }
4201
+ } finally {
4202
+ try {
4203
+ await dir.terminate(fixSubagentId);
4204
+ } catch {
4205
+ }
4206
+ }
4207
+ } catch (fixErr) {
4208
+ await session.append({
4209
+ type: "error",
4210
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4211
+ message: `\u{1F982} Chimera auto-fix failed: ${fixErr instanceof Error ? fixErr.message : String(fixErr)}`,
4212
+ phase: "agent"
4213
+ });
4214
+ }
4215
+ }
4216
+ }
4217
+ } catch (err) {
4218
+ try {
4219
+ await session.append({
4220
+ type: "error",
4221
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4222
+ message: `\u{1F982} Chimera review failed: ${err instanceof Error ? err.message : String(err)}`,
4223
+ phase: "agent"
4224
+ });
4225
+ } catch (appendErr) {
4226
+ console.error(
4227
+ JSON.stringify({
4228
+ level: "error",
4229
+ event: "execution.chimera_review_append_failed",
4230
+ message: appendErr instanceof Error ? appendErr.message : String(appendErr),
4231
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4232
+ })
4233
+ );
4234
+ }
4235
+ } finally {
4236
+ if (subagentId) {
4237
+ try {
4238
+ await dir.terminate(subagentId);
4239
+ } catch {
4240
+ }
4241
+ }
4242
+ }
4243
+ })();
4244
+ });
4245
+ installChimeraCascadeHandler({
4246
+ events,
4247
+ director,
4248
+ session,
4249
+ getPendingWork: () => pendingChimeraWork,
4250
+ setPendingWork: (work) => {
4251
+ pendingChimeraWork = work;
4252
+ }
4253
+ });
4254
+ let code = 0;
4255
+ let fleetStatusLine = null;
4256
+ try {
4257
+ const visionAdapters = () => createToolVisionAdapters(agent.tools);
4258
+ const supportsVision = async () => {
4259
+ try {
4260
+ const providerConfig = config.providers?.[context.provider.id];
4261
+ const mergedModels = mergeCustomModelDefs(providerConfig?.customModels, config.models);
4262
+ const caps = await capabilitiesFor(
4263
+ modelsRegistry,
4264
+ context.provider.id,
4265
+ context.model,
4266
+ mergedModels
4267
+ );
4268
+ return caps.vision;
4269
+ } catch {
4270
+ return context.provider.capabilities.vision;
4271
+ }
4272
+ };
4273
+ const promptFlag = typeof flags["prompt"] === "string" ? flags["prompt"] : void 0;
4274
+ if (promptFlag) {
4275
+ positional.unshift(promptFlag);
4276
+ }
4277
+ const goalFlag = typeof flags["goal"] === "string" ? flags["goal"] : void 0;
4278
+ const askFlag = typeof flags["ask"] === "string" ? flags["ask"] : void 0;
4279
+ if ((goalFlag || askFlag) && positional.length === 0 && !promptFlag) {
4280
+ flags.tui = true;
4281
+ }
4282
+ const executionMode = resolveExecutionMode(positional, flags);
4283
+ const enteringTui = executionMode === "tui";
4284
+ if (!enteringTui) {
4285
+ fleetStatusLine = new FleetStatusLine({ events, version: CLI_VERSION });
4286
+ fleetStatusLine.start();
4287
+ }
4288
+ if (executionMode === "single-shot") {
4289
+ code = await runSingleShotDispatch({
4290
+ agent,
4291
+ query: positional.join(" "),
4292
+ flags,
4293
+ tokenCounter,
4294
+ renderer
4295
+ });
4296
+ } else if (executionMode === "tui") {
4297
+ agent.disableInteractiveConfirmation();
4298
+ const state = {
4299
+ projectRoot,
4300
+ wpaths,
4301
+ activeSessionStore,
4302
+ activateSessionIdentity,
4303
+ detachActiveTodosCheckpoint,
4304
+ pendingProjectSwitch: null,
4305
+ autonomousCoordinator: null,
4306
+ coordinatorRun: null,
4307
+ coordinatorEvents: /* @__PURE__ */ new Set()
4308
+ };
4309
+ const banneredFamily = savedProviderCfg?.family ?? resolvedProvider?.family;
4310
+ const banneredKey = (savedProviderCfg ? resolveActiveApiKey(savedProviderCfg) : void 0) ?? config.apiKey ?? (resolvedProvider?.envVars ?? savedProviderCfg?.envVars ?? []).map((v) => process.env[v]).find((v) => !!v);
4311
+ const banneredKeyTail = banneredKey && banneredKey.length >= 3 ? banneredKey.slice(-3) : void 0;
4312
+ const goalWiring = wireGoal(events);
4313
+ const subscribeGoal = goalWiring.subscribe;
4314
+ const coordinatorEvents = /* @__PURE__ */ new Set();
4315
+ state.coordinatorEvents = coordinatorEvents;
4316
+ const autonomousCoordinationEnabled = config.features.autonomousCoordination !== false;
4317
+ const coordinatorSetup = autonomousCoordinationEnabled ? setupAutonomousCoordinator({
4318
+ state,
4319
+ events,
4320
+ context,
4321
+ wpaths,
4322
+ mailbox,
4323
+ director,
4324
+ getDirector,
4325
+ coordinatorController,
4326
+ onCoordinatorStopSetter: (fn) => {
4327
+ onCoordinatorStopImpl = fn ?? void 0;
4328
+ }
4329
+ }) : {
4330
+ ensure: () => null,
4331
+ cleanup: () => void 0
4332
+ };
4333
+ const ensureAutonomousCoordinator = coordinatorSetup.ensure;
4334
+ const offDirectorSpawned = coordinatorSetup.cleanup;
4335
+ const switchCtx = {
4336
+ state,
4337
+ context,
4338
+ events,
4339
+ agent,
4340
+ config,
4341
+ tokenCounter,
4342
+ modeId,
4343
+ modeStore,
4344
+ memoryStore,
4345
+ skillLoader,
4346
+ attachTodosCheckpoint: attachTodosCheckpoint2
4347
+ };
4348
+ const switchProjectInPlace2 = async (targetRoot, displayName) => {
4349
+ return switchProjectInPlace(switchCtx, targetRoot, displayName);
4350
+ };
4351
+ const pickerCtx = {
4352
+ state,
4353
+ renderer,
4354
+ director,
4355
+ getEternalEngine,
4356
+ getParallelEngine,
4357
+ switchCtx,
4358
+ switchProjectInPlace: switchProjectInPlace2
4359
+ };
4360
+ renderer.setTuiActive(true);
4361
+ try {
4362
+ code = await runTuiDispatch({
4363
+ agent,
4364
+ events,
4365
+ slashRegistry,
4366
+ secretInputController,
4367
+ attachments,
4368
+ tokenCounter,
4369
+ visionAdapters,
4370
+ supportsVision,
4371
+ model: context.model,
4372
+ banner: !flags["no-banner"],
4373
+ queueStore,
4374
+ onQueueChange: (items) => {
4375
+ setQueuedMessagesSnapshot2(context, items);
4376
+ },
4377
+ mouse: flags.mouse ? true : void 0,
4378
+ yolo: !!config.yolo,
4379
+ getYolo,
4380
+ onYolo,
4381
+ getAutonomy,
4382
+ ...createTuiNextStepCallbacks({
4383
+ context,
4384
+ getNextPredict,
4385
+ getAutonomy,
4386
+ getSuggestions: getSuggestions2
4387
+ }),
4388
+ getEternalEngine,
4389
+ getSddRun,
4390
+ onSddLifecycle,
4391
+ subscribeEternalIteration,
4392
+ subscribeEternalStage,
4393
+ subscribeGoal,
4394
+ appVersion: CLI_VERSION,
4395
+ latestVersion: bootUpdateInfo?.latest,
4396
+ updateAvailable: bootUpdateInfo?.outdated,
4397
+ provider: config.provider,
4398
+ family: banneredFamily,
4399
+ keyTail: banneredKeyTail,
4400
+ profile: profileName,
4401
+ profileConfigPath: (() => {
4402
+ const abs = wpaths.profileConfig(profileName);
4403
+ const home = wpaths.homeDir;
4404
+ return home && abs.startsWith(home) ? `~${abs.slice(home.length)}` : abs;
4405
+ })(),
4406
+ getPickableProviders,
4407
+ switchProviderAndModel,
4408
+ switchAutonomy: (mode) => {
4409
+ onAutonomy?.(mode);
4410
+ return null;
4411
+ },
4412
+ ...createSettingsAdapter({
4413
+ configStore,
4414
+ wpaths,
4415
+ fleetStreamController,
4416
+ applyLiveSettings
4417
+ }),
4418
+ effectiveMaxContext,
4419
+ titleAnimation: config.autonomy?.["terminalTitleAnimation"] ?? true,
4420
+ chime: config.autonomy?.["chime"] ?? false,
4421
+ confirmExit: config.autonomy?.["confirmExit"] ?? true,
4422
+ director,
4423
+ getDirector,
4424
+ fleetRoster,
4425
+ ...createTuiCoordinatorCallbacks({
4426
+ state,
4427
+ context,
4428
+ coordinatorEvents,
4429
+ ensureAutonomousCoordinator
4430
+ }),
4431
+ onClearHistory: (dispatch) => {
4432
+ dispatch({ type: "clearHistory", model: context.model, provider: context.provider.id });
4433
+ dispatch({ type: "resetContextChip" });
4434
+ dispatch({ type: "streamReset" });
4435
+ dispatch({ type: "toolStreamClear" });
4436
+ },
4437
+ fleetStreamController,
4438
+ interruptController,
4439
+ enhanceController,
4440
+ getEnhancerReasoning,
4441
+ buildEnhancerProvider,
4442
+ getEnhanceFallbackRef,
4443
+ getConfiguredRefinerRef,
4444
+ statuslineHiddenItems,
4445
+ setStatuslineHiddenItems,
4446
+ saveStatuslineHiddenItems,
4447
+ getPluginItems,
4448
+ onPluginToggle,
4449
+ getMcpServers,
4450
+ onMcpToggle,
4451
+ onMcpRestart,
4452
+ getToolsItems,
4453
+ onToolToggle,
4454
+ getBrainData,
4455
+ onBrainRiskLevel,
4456
+ brainPanelHost: brainRuntime ? createBrainPanelHost({ brainRuntime }) : void 0,
4457
+ getShadowData,
4458
+ onShadowStart,
4459
+ onShadowStop,
4460
+ authHost,
4461
+ agentsMonitorController,
4462
+ agentTranscripts,
4463
+ getLiveSessions: () => getLiveSessions({ state }),
4464
+ onSwitchToSession: (_sessionId, targetRoot, projectName) => onSwitchToSession({ state }, _sessionId, targetRoot, projectName),
4465
+ initialGoal: goalFlag,
4466
+ initialAsk: askFlag,
4467
+ projectRoot,
4468
+ appConfig: config,
4469
+ hqTelemetryOwnedExternally: true,
4470
+ getSessionId: () => agent.ctx.session?.id ?? session.id,
4471
+ getSDDContext: () => getSDDContext(),
4472
+ onSDDOutput: (output) => onSDDOutput(output),
4473
+ modeLabel: modeId,
4474
+ getModeLabel: () => {
4475
+ const metaMode = context.meta?.["mode"];
4476
+ return typeof metaMode === "string" ? metaMode : modeId ?? "default";
4477
+ },
4478
+ getModes: modeStore ? async () => {
4479
+ const [modes, active] = await Promise.all([
4480
+ modeStore.listModes(),
4481
+ modeStore.getActiveMode()
4482
+ ]);
4483
+ return { modes, activeId: active?.id ?? null };
4484
+ } : void 0,
4485
+ switchMode: modeStore ? async (id) => {
4486
+ const prev = await modeStore.getActiveMode();
4487
+ await modeStore.setActiveMode(id);
4488
+ const active = await modeStore.getActiveMode();
4489
+ const from = prev?.id ?? "default";
4490
+ if (agent.ctx.session && from !== id) {
4491
+ void agent.ctx.session.append({ type: "mode_changed", ts: (/* @__PURE__ */ new Date()).toISOString(), from, to: id }).catch(() => {
4492
+ });
4493
+ }
4494
+ return active?.name ?? null;
4495
+ } : void 0,
4496
+ registerDebugStreamCallback,
4497
+ restoreDebugStreamCallback,
4498
+ restoredMessages,
4499
+ restoredToolCalls,
4500
+ restoredEvents,
4501
+ listSessions: async (limit = 20) => {
4502
+ if (!activeSessionStore) return [];
4503
+ const summaries = await activeSessionStore.list(limit);
4504
+ const currentId = agent.ctx.session?.id ?? session.id;
4505
+ return summaries.map((s) => ({
4506
+ id: s.id,
4507
+ title: s.title ?? "",
4508
+ name: s.name,
4509
+ lastUserMessage: s.lastUserMessage,
4510
+ messageCount: s.messageCount,
4511
+ lastActivityAt: s.lastActivityAt,
4512
+ startedAt: s.startedAt ?? "",
4513
+ endedAt: s.endedAt,
4514
+ tokenTotal: s.tokenTotal ?? 0,
4515
+ iterationCount: s.iterationCount ?? 0,
4516
+ toolCallCount: s.toolCallCount ?? 0,
4517
+ toolErrorCount: s.toolErrorCount ?? 0,
4518
+ outcome: s.outcome,
4519
+ isCurrent: s.id === currentId
4520
+ }));
4521
+ },
4522
+ onResumeSession: (sessionId) => resumeSession(
4523
+ { state, agent, tokenCounter, switchProviderAndModel, events },
4524
+ sessionId
4525
+ ),
4526
+ getProjectPickerItems: () => getProjectPickerItems(pickerCtx),
4527
+ onProjectSelect: (slug, kind) => onProjectSelect(pickerCtx, slug, kind),
4528
+ initialAgentsMonitorOpen: !!flags.quick,
4529
+ tokenSavingMode: normalizeTokenSavingTier2(config.features.tokenSavingMode),
4530
+ toolCount: agent.tools.list().length,
4531
+ onPanelOpen,
4532
+ memoryStore
4533
+ });
4534
+ const spawnResult = await handleProjectSwitchSpawn({
4535
+ code,
4536
+ pendingProjectSwitch: state.pendingProjectSwitch
4537
+ });
4538
+ if (spawnResult !== null) return spawnResult;
4539
+ } finally {
4540
+ renderer.setTuiActive(false);
4541
+ offDirectorSpawned();
4542
+ }
4543
+ } else if (executionMode === "webui") {
4544
+ code = await runWebUIDispatch({
4545
+ agent,
4546
+ events,
4547
+ session,
4548
+ config,
4549
+ flags,
4550
+ projectRoot,
4551
+ globalConfigPath: wpaths.globalConfig,
4552
+ profileConfigPath: wpaths.profileConfig(profileName),
4553
+ projectSessionsDir: wpaths.projectSessions,
4554
+ modelsRegistry,
4555
+ mcpRegistry,
4556
+ brain,
4557
+ brainSettings,
4558
+ brainRuntime,
4559
+ getBrainLog,
4560
+ subscribeEternalIteration,
4561
+ sessionStore: activeSessionStore,
4562
+ memoryStore,
4563
+ skillLoader,
4564
+ promptLoader,
4565
+ modeStore,
4566
+ modeId,
4567
+ needsSetup,
4568
+ renderer,
4569
+ onAutonomy,
4570
+ applyLiveSettings,
4571
+ activateSessionIdentity,
4572
+ agentTranscripts,
4573
+ onModelContextResolved,
4574
+ sddSubagentFactory,
4575
+ statusTracker,
4576
+ ...createKanbanDispatchHandler({ config, events, skillLoader, sddSubagentFactory })
4577
+ });
4578
+ } else {
4579
+ const headlessKanbanMirror = projectRoot ? (await import("./kanban-run-mirror-EKVNGXWW.js")).createKanbanRunMirror({
4580
+ projectRoot,
4581
+ events,
4582
+ broadcast: () => {
4583
+ },
4584
+ log: (m) => console.log(m)
4585
+ }) : null;
4586
+ try {
4587
+ code = await runRepl({
4588
+ agent,
4589
+ renderer,
4590
+ reader,
4591
+ slashRegistry,
4592
+ tokenCounter,
4593
+ visionAdapters,
4594
+ supportsVision,
4595
+ attachments,
4596
+ effectiveMaxContext,
4597
+ getEffectiveMaxContext,
4598
+ projectName: path10.basename(projectRoot) || void 0,
4599
+ projectRoot,
4600
+ appConfig: config,
4601
+ getSessionId: () => agent.ctx.session?.id ?? session.id,
4602
+ getAutonomy,
4603
+ onAutonomy,
4604
+ getNextPredict,
4605
+ onSuggestionsParsed,
4606
+ getSuggestions: getSuggestions2,
4607
+ getAutoSuggestions,
4608
+ getYolo,
4609
+ autonomyNextPrompt,
4610
+ autoProceedDelayMs,
4611
+ onValidateAutoProceed,
4612
+ autoProceedMaxIterations,
4613
+ getEternalEngine,
4614
+ getParallelEngine,
4615
+ getSddRun,
4616
+ skillLoader,
4617
+ agentsMonitorController,
4618
+ fleetStreamController,
4619
+ interruptController,
4620
+ ...createReplFleetCallbacks({ director, getDirector }),
4621
+ onCountdownTick,
4622
+ onDestroy
4623
+ });
4624
+ } finally {
4625
+ headlessKanbanMirror?.dispose();
4626
+ }
4627
+ }
4628
+ } finally {
4629
+ await finalizeExecutionCleanup({
4630
+ offStorageObservability,
4631
+ fleetStatusLine,
4632
+ onCoordinatorStop: onCoordinatorStopImpl,
4633
+ stats,
4634
+ renderer,
4635
+ detachTodosCheckpoint,
4636
+ mcpRegistry,
4637
+ agent,
4638
+ session,
4639
+ tokenCounter,
4640
+ events,
4641
+ getPendingChimeraWork: () => pendingChimeraWork,
4642
+ director,
4643
+ reader
4644
+ });
4645
+ }
4646
+ return code;
4647
+ }
4648
+ export {
4649
+ CHIMERA_REVIEW_READ_ONLY_TOOLS,
4650
+ __resetReviewerRoundRobinCursor,
4651
+ applyChimeraReviewerReadOnlyPolicy,
4652
+ assignReviewerModelsRoundRobin,
4653
+ execute,
4654
+ resolveReviewerFallbackModels
4655
+ };
4656
+ //# sourceMappingURL=execution-V26SE52F.js.map