@wrongstack/cli 0.295.1 → 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 (383) hide show
  1. package/data/providers.json +0 -24
  2. package/dist/acp-A5OSIU2P.js +824 -0
  3. package/dist/acp-A5OSIU2P.js.map +7 -0
  4. package/dist/acp-server-agent.d.ts.map +1 -1
  5. package/dist/arg-parser.d.ts.map +1 -1
  6. package/dist/audit-2ZSFGNIF.js +102 -0
  7. package/dist/audit-2ZSFGNIF.js.map +7 -0
  8. package/dist/auth-CJWQJVRH.js +504 -0
  9. package/dist/auth-CJWQJVRH.js.map +7 -0
  10. package/dist/auth-menu/auth-menu-audit.d.ts +0 -4
  11. package/dist/auth-menu/auth-menu-audit.d.ts.map +1 -1
  12. package/dist/bench-7ZDWSNEF.js +278 -0
  13. package/dist/bench-7ZDWSNEF.js.map +7 -0
  14. package/dist/boot/brain-decision-log.d.ts +7 -5
  15. package/dist/boot/brain-decision-log.d.ts.map +1 -1
  16. package/dist/boot/dispatch-webui.d.ts +4 -8
  17. package/dist/boot/dispatch-webui.d.ts.map +1 -1
  18. package/dist/boot/system-prompt-builder.d.ts +3 -0
  19. package/dist/boot/system-prompt-builder.d.ts.map +1 -1
  20. package/dist/boot/tui-coordinator-callbacks.d.ts +45 -0
  21. package/dist/boot/tui-coordinator-callbacks.d.ts.map +1 -0
  22. package/dist/boot/tui-project-switch.d.ts +2 -3
  23. package/dist/boot/tui-project-switch.d.ts.map +1 -1
  24. package/dist/boot/tui-runtime-state.d.ts +5 -6
  25. package/dist/boot/tui-runtime-state.d.ts.map +1 -1
  26. package/dist/boot/tui-session-resume.d.ts.map +1 -1
  27. package/dist/boot/tui-settings-adapter.d.ts +2 -3
  28. package/dist/boot/tui-settings-adapter.d.ts.map +1 -1
  29. package/dist/boot.d.ts.map +1 -1
  30. package/dist/brain-menu/panel-service.d.ts.map +1 -1
  31. package/dist/chimera-review-task.d.ts +6 -0
  32. package/dist/chimera-review-task.d.ts.map +1 -0
  33. package/dist/chimera-reviewer-policy.d.ts +34 -0
  34. package/dist/chimera-reviewer-policy.d.ts.map +1 -0
  35. package/dist/chronicle-QQEQFSSE.js +256 -0
  36. package/dist/chronicle-QQEQFSSE.js.map +7 -0
  37. package/dist/chunk-5N34EWJR.js +418 -0
  38. package/dist/chunk-5N34EWJR.js.map +7 -0
  39. package/dist/chunk-66T43Q4Y.js +90 -0
  40. package/dist/chunk-66T43Q4Y.js.map +7 -0
  41. package/dist/chunk-7OCVIDC7.js +11 -0
  42. package/dist/chunk-7OCVIDC7.js.map +7 -0
  43. package/dist/chunk-ABXK4VVY.js +84 -0
  44. package/dist/chunk-ABXK4VVY.js.map +7 -0
  45. package/dist/chunk-AXVZMEWG.js +306 -0
  46. package/dist/chunk-AXVZMEWG.js.map +7 -0
  47. package/dist/chunk-AZESNNIC.js +216 -0
  48. package/dist/chunk-AZESNNIC.js.map +7 -0
  49. package/dist/chunk-BGFM3PD7.js +41 -0
  50. package/dist/chunk-BGFM3PD7.js.map +7 -0
  51. package/dist/chunk-DPJZQCVP.js +13 -0
  52. package/dist/chunk-DPJZQCVP.js.map +7 -0
  53. package/dist/chunk-F4PEGAJZ.js +176 -0
  54. package/dist/chunk-F4PEGAJZ.js.map +7 -0
  55. package/dist/chunk-IHBYBYGA.js +443 -0
  56. package/dist/chunk-IHBYBYGA.js.map +7 -0
  57. package/dist/chunk-IN4GXGYW.js +425 -0
  58. package/dist/chunk-IN4GXGYW.js.map +7 -0
  59. package/dist/chunk-JBSQ7ONN.js +1023 -0
  60. package/dist/chunk-JBSQ7ONN.js.map +7 -0
  61. package/dist/chunk-JBTFWWKV.js +1325 -0
  62. package/dist/chunk-JBTFWWKV.js.map +7 -0
  63. package/dist/chunk-JUHRI6OV.js +100 -0
  64. package/dist/chunk-JUHRI6OV.js.map +7 -0
  65. package/dist/chunk-OP47B3IX.js +142 -0
  66. package/dist/chunk-OP47B3IX.js.map +7 -0
  67. package/dist/chunk-PJHET45A.js +158 -0
  68. package/dist/chunk-PJHET45A.js.map +7 -0
  69. package/dist/chunk-Q5GTM25S.js +17 -0
  70. package/dist/chunk-Q5GTM25S.js.map +7 -0
  71. package/dist/chunk-QD544J2B.js +19 -0
  72. package/dist/chunk-QD544J2B.js.map +7 -0
  73. package/dist/chunk-QUNHS6O3.js +258 -0
  74. package/dist/chunk-QUNHS6O3.js.map +7 -0
  75. package/dist/chunk-TADVX644.js +480 -0
  76. package/dist/chunk-TADVX644.js.map +7 -0
  77. package/dist/chunk-TGDHN4LM.js +81 -0
  78. package/dist/chunk-TGDHN4LM.js.map +7 -0
  79. package/dist/chunk-TYO2OVAD.js +50 -0
  80. package/dist/chunk-TYO2OVAD.js.map +7 -0
  81. package/dist/chunk-VCYZ3WZV.js +14 -0
  82. package/dist/chunk-VCYZ3WZV.js.map +7 -0
  83. package/dist/chunk-VJUEZZYB.js +29 -0
  84. package/dist/chunk-VJUEZZYB.js.map +7 -0
  85. package/dist/chunk-WHOIR577.js +1 -0
  86. package/dist/chunk-WHOIR577.js.map +7 -0
  87. package/dist/chunk-WY7KKOUK.js +460 -0
  88. package/dist/chunk-WY7KKOUK.js.map +7 -0
  89. package/dist/chunk-X5DQTPXT.js +3059 -0
  90. package/dist/chunk-X5DQTPXT.js.map +7 -0
  91. package/dist/chunk-XJXDOF63.js +28 -0
  92. package/dist/chunk-XJXDOF63.js.map +7 -0
  93. package/dist/chunk-XWEGWYDU.js +560 -0
  94. package/dist/chunk-XWEGWYDU.js.map +7 -0
  95. package/dist/chunk-YWUPHRGB.js +346 -0
  96. package/dist/chunk-YWUPHRGB.js.map +7 -0
  97. package/dist/chunk-Z7YGASQP.js +313 -0
  98. package/dist/chunk-Z7YGASQP.js.map +7 -0
  99. package/dist/cli-entry-main.d.ts +2 -0
  100. package/dist/cli-entry-main.d.ts.map +1 -0
  101. package/dist/cli-entry-point.d.ts +3 -3
  102. package/dist/cli-entry-point.d.ts.map +1 -1
  103. package/dist/cli-main-6AU6E4XZ.js +29126 -0
  104. package/dist/cli-main-6AU6E4XZ.js.map +7 -0
  105. package/dist/cli-main-helpers.d.ts +21 -0
  106. package/dist/cli-main-helpers.d.ts.map +1 -0
  107. package/dist/cli-main.d.ts +25 -1
  108. package/dist/cli-main.d.ts.map +1 -1
  109. package/dist/context-limit.d.ts +48 -0
  110. package/dist/context-limit.d.ts.map +1 -1
  111. package/dist/diag-doctor-OQ3AA63O.js +170 -0
  112. package/dist/diag-doctor-OQ3AA63O.js.map +7 -0
  113. package/dist/execute-deps.d.ts +10 -12
  114. package/dist/execute-deps.d.ts.map +1 -1
  115. package/dist/execution-V26SE52F.js +4656 -0
  116. package/dist/execution-V26SE52F.js.map +7 -0
  117. package/dist/execution-chimera-ask.d.ts +10 -0
  118. package/dist/execution-chimera-ask.d.ts.map +1 -0
  119. package/dist/execution-chimera-cascade.d.ts +15 -0
  120. package/dist/execution-chimera-cascade.d.ts.map +1 -0
  121. package/dist/execution-cleanup.d.ts +23 -0
  122. package/dist/execution-cleanup.d.ts.map +1 -0
  123. package/dist/execution-kanban-dispatch.d.ts +10 -0
  124. package/dist/execution-kanban-dispatch.d.ts.map +1 -0
  125. package/dist/execution-repl-fleet-callbacks.d.ts +11 -0
  126. package/dist/execution-repl-fleet-callbacks.d.ts.map +1 -0
  127. package/dist/execution-storage-observability.d.ts +3 -0
  128. package/dist/execution-storage-observability.d.ts.map +1 -0
  129. package/dist/execution-tui-next-step-callbacks.d.ts +20 -0
  130. package/dist/execution-tui-next-step-callbacks.d.ts.map +1 -0
  131. package/dist/execution.d.ts +2 -139
  132. package/dist/execution.d.ts.map +1 -1
  133. package/dist/export-TPORYVRZ.js +64 -0
  134. package/dist/export-TPORYVRZ.js.map +7 -0
  135. package/dist/fleet/host-acp-runner-cache.d.ts +9 -0
  136. package/dist/fleet/host-acp-runner-cache.d.ts.map +1 -0
  137. package/dist/fleet/host-acp.d.ts +3 -0
  138. package/dist/fleet/host-acp.d.ts.map +1 -0
  139. package/dist/fleet/host-concurrency.d.ts +2 -0
  140. package/dist/fleet/host-concurrency.d.ts.map +1 -0
  141. package/dist/fleet/host-context.d.ts +5 -0
  142. package/dist/fleet/host-context.d.ts.map +1 -0
  143. package/dist/fleet/host-director-builder.d.ts +24 -0
  144. package/dist/fleet/host-director-builder.d.ts.map +1 -0
  145. package/dist/fleet/host-director-event-bridges.d.ts +37 -0
  146. package/dist/fleet/host-director-event-bridges.d.ts.map +1 -0
  147. package/dist/fleet/host-director-services.d.ts +20 -0
  148. package/dist/fleet/host-director-services.d.ts.map +1 -0
  149. package/dist/fleet/host-event-bridge.d.ts +17 -0
  150. package/dist/fleet/host-event-bridge.d.ts.map +1 -0
  151. package/dist/fleet/host-helpers.d.ts +22 -0
  152. package/dist/fleet/host-helpers.d.ts.map +1 -0
  153. package/dist/fleet/host-learning-tracker.d.ts +11 -0
  154. package/dist/fleet/host-learning-tracker.d.ts.map +1 -0
  155. package/dist/fleet/host-learning.d.ts +4 -0
  156. package/dist/fleet/host-learning.d.ts.map +1 -0
  157. package/dist/fleet/host-lifecycle-events.d.ts +4 -0
  158. package/dist/fleet/host-lifecycle-events.d.ts.map +1 -0
  159. package/dist/fleet/host-paths.d.ts +3 -0
  160. package/dist/fleet/host-paths.d.ts.map +1 -0
  161. package/dist/fleet/host-provider.d.ts +22 -0
  162. package/dist/fleet/host-provider.d.ts.map +1 -0
  163. package/dist/fleet/host-session-writer.d.ts +3 -0
  164. package/dist/fleet/host-session-writer.d.ts.map +1 -0
  165. package/dist/fleet/host-shadow-pass.d.ts +21 -0
  166. package/dist/fleet/host-shadow-pass.d.ts.map +1 -0
  167. package/dist/fleet/host-spawn-types.d.ts +25 -0
  168. package/dist/fleet/host-spawn-types.d.ts.map +1 -0
  169. package/dist/fleet/host-status.d.ts +48 -0
  170. package/dist/fleet/host-status.d.ts.map +1 -0
  171. package/dist/fleet/host-subagent-factory.d.ts +16 -0
  172. package/dist/fleet/host-subagent-factory.d.ts.map +1 -0
  173. package/dist/fleet/host-supervisor.d.ts +16 -0
  174. package/dist/fleet/host-supervisor.d.ts.map +1 -0
  175. package/dist/fleet/host-task-result-report.d.ts +11 -0
  176. package/dist/fleet/host-task-result-report.d.ts.map +1 -0
  177. package/dist/fleet/host-types.d.ts +89 -0
  178. package/dist/fleet/host-types.d.ts.map +1 -0
  179. package/dist/fleet/host.d.ts +10 -357
  180. package/dist/fleet/host.d.ts.map +1 -1
  181. package/dist/hq-BECGICEZ.js +547 -0
  182. package/dist/hq-BECGICEZ.js.map +7 -0
  183. package/dist/hq-command-controller.d.ts +2 -2
  184. package/dist/hq-command-controller.d.ts.map +1 -1
  185. package/dist/hq-server/project-root.d.ts +5 -0
  186. package/dist/hq-server/project-root.d.ts.map +1 -0
  187. package/dist/hq-server/routes/auth-handlers.d.ts +32 -0
  188. package/dist/hq-server/routes/auth-handlers.d.ts.map +1 -0
  189. package/dist/hq-server/routes/session-handlers.d.ts +8 -0
  190. package/dist/hq-server/routes/session-handlers.d.ts.map +1 -0
  191. package/dist/hq-server/routes.d.ts +2 -2
  192. package/dist/hq-server/routes.d.ts.map +1 -1
  193. package/dist/hq-server-FJOVOERO.js +39 -0
  194. package/dist/hq-server-FJOVOERO.js.map +7 -0
  195. package/dist/hq-server.d.ts.map +1 -1
  196. package/dist/hq-ttl-U2FAYFAT.js +8 -0
  197. package/dist/hq-ttl-U2FAYFAT.js.map +7 -0
  198. package/dist/hq-tunnel-YZLRONPV.js +111 -0
  199. package/dist/hq-tunnel-YZLRONPV.js.map +7 -0
  200. package/dist/index.d.ts +2 -1
  201. package/dist/index.d.ts.map +1 -1
  202. package/dist/index.js +2503 -53026
  203. package/dist/index.js.map +4 -4
  204. package/dist/init-E2NDDOHI.js +27 -0
  205. package/dist/init-E2NDDOHI.js.map +7 -0
  206. package/dist/kanban-dispatch-route.d.ts +14 -0
  207. package/dist/kanban-dispatch-route.d.ts.map +1 -0
  208. package/dist/kanban-hq-sync.d.ts +2 -0
  209. package/dist/kanban-hq-sync.d.ts.map +1 -1
  210. package/dist/kanban-run-mirror-EKVNGXWW.js +12 -0
  211. package/dist/kanban-run-mirror-EKVNGXWW.js.map +7 -0
  212. package/dist/live-settings-input.d.ts +69 -0
  213. package/dist/live-settings-input.d.ts.map +1 -0
  214. package/dist/mailbox-serve-2UWHEN3M.js +302 -0
  215. package/dist/mailbox-serve-2UWHEN3M.js.map +7 -0
  216. package/dist/mcp-CYLPUEHC.js +413 -0
  217. package/dist/mcp-CYLPUEHC.js.map +7 -0
  218. package/dist/modeldiag-HENYJ4N7.js +1290 -0
  219. package/dist/modeldiag-HENYJ4N7.js.map +7 -0
  220. package/dist/permissions-FNYLZIL4.js +115 -0
  221. package/dist/permissions-FNYLZIL4.js.map +7 -0
  222. package/dist/picker-key-state.d.ts +7 -0
  223. package/dist/picker-key-state.d.ts.map +1 -0
  224. package/dist/picker-model-picker.d.ts +6 -0
  225. package/dist/picker-model-picker.d.ts.map +1 -0
  226. package/dist/picker-ui.d.ts +17 -0
  227. package/dist/picker-ui.d.ts.map +1 -0
  228. package/dist/picker.d.ts +4 -37
  229. package/dist/picker.d.ts.map +1 -1
  230. package/dist/plugin-usage-OU6X6LM3.js +40 -0
  231. package/dist/plugin-usage-OU6X6LM3.js.map +7 -0
  232. package/dist/plugins-4LJ5IUBI.js +24 -0
  233. package/dist/plugins-4LJ5IUBI.js.map +7 -0
  234. package/dist/pre-launch.d.ts +0 -1
  235. package/dist/pre-launch.d.ts.map +1 -1
  236. package/dist/project-BLQ3ALVL.js +76 -0
  237. package/dist/project-BLQ3ALVL.js.map +7 -0
  238. package/dist/project-manifest-GE25PW4S.js +18 -0
  239. package/dist/project-manifest-GE25PW4S.js.map +7 -0
  240. package/dist/project-picker-BOCWHBXP.js +17 -0
  241. package/dist/project-picker-BOCWHBXP.js.map +7 -0
  242. package/dist/projects-XE76NFNZ.js +38 -0
  243. package/dist/projects-XE76NFNZ.js.map +7 -0
  244. package/dist/provider-helpers.d.ts +22 -6
  245. package/dist/provider-helpers.d.ts.map +1 -1
  246. package/dist/providers-models-GDELBHZK.js +589 -0
  247. package/dist/providers-models-GDELBHZK.js.map +7 -0
  248. package/dist/quick-VIO2BEHS.js +10 -0
  249. package/dist/quick-VIO2BEHS.js.map +7 -0
  250. package/dist/repl-auto-proceed.d.ts +19 -0
  251. package/dist/repl-auto-proceed.d.ts.map +1 -0
  252. package/dist/repl-client-registration.d.ts +7 -0
  253. package/dist/repl-client-registration.d.ts.map +1 -0
  254. package/dist/repl-input.d.ts +11 -0
  255. package/dist/repl-input.d.ts.map +1 -0
  256. package/dist/repl-options.d.ts +54 -0
  257. package/dist/repl-options.d.ts.map +1 -0
  258. package/dist/repl-rendering.d.ts +4 -0
  259. package/dist/repl-rendering.d.ts.map +1 -0
  260. package/dist/repl-suggestions.d.ts +21 -0
  261. package/dist/repl-suggestions.d.ts.map +1 -0
  262. package/dist/repl.d.ts +3 -162
  263. package/dist/repl.d.ts.map +1 -1
  264. package/dist/replay-KCTXNMZQ.js +75 -0
  265. package/dist/replay-KCTXNMZQ.js.map +7 -0
  266. package/dist/rewind-EJMVFVLS.js +185 -0
  267. package/dist/rewind-EJMVFVLS.js.map +7 -0
  268. package/dist/sdd-runtime-IKPROVV2.js +54 -0
  269. package/dist/sdd-runtime-IKPROVV2.js.map +7 -0
  270. package/dist/services/sdd/project-context.d.ts +1 -1
  271. package/dist/services/sdd/project-context.d.ts.map +1 -1
  272. package/dist/services/statusline-config.d.ts +1 -1
  273. package/dist/services/statusline-config.d.ts.map +1 -1
  274. package/dist/session-event-wiring.d.ts +2 -2
  275. package/dist/session-event-wiring.d.ts.map +1 -1
  276. package/dist/sessions-config-NLCMK3BY.js +409 -0
  277. package/dist/sessions-config-NLCMK3BY.js.map +7 -0
  278. package/dist/settings-menu.d.ts +3 -18
  279. package/dist/settings-menu.d.ts.map +1 -1
  280. package/dist/simpleui-dist-JIFGUJO7.js +93 -0
  281. package/dist/simpleui-dist-JIFGUJO7.js.map +7 -0
  282. package/dist/slash-commands/brain.d.ts.map +1 -1
  283. package/dist/slash-commands/clear.d.ts.map +1 -1
  284. package/dist/slash-commands/fallback.d.ts.map +1 -1
  285. package/dist/slash-commands/kanban-agent-helpers.d.ts +18 -0
  286. package/dist/slash-commands/kanban-agent-helpers.d.ts.map +1 -0
  287. package/dist/slash-commands/kanban-format.d.ts +16 -0
  288. package/dist/slash-commands/kanban-format.d.ts.map +1 -0
  289. package/dist/slash-commands/kanban-help.d.ts +2 -0
  290. package/dist/slash-commands/kanban-help.d.ts.map +1 -0
  291. package/dist/slash-commands/kanban.d.ts.map +1 -1
  292. package/dist/slash-commands/mailbox-demo.d.ts.map +1 -1
  293. package/dist/slash-commands/mailbox.d.ts +2 -1
  294. package/dist/slash-commands/mailbox.d.ts.map +1 -1
  295. package/dist/slash-commands/memory-compact.d.ts +5 -0
  296. package/dist/slash-commands/memory-compact.d.ts.map +1 -0
  297. package/dist/slash-commands/memory-flags.d.ts +36 -0
  298. package/dist/slash-commands/memory-flags.d.ts.map +1 -0
  299. package/dist/slash-commands/memory-formatters.d.ts +16 -0
  300. package/dist/slash-commands/memory-formatters.d.ts.map +1 -0
  301. package/dist/slash-commands/memory.d.ts.map +1 -1
  302. package/dist/slash-commands/mouse.d.ts +2 -2
  303. package/dist/slash-commands/review.d.ts.map +1 -1
  304. package/dist/slash-commands/sdd-command-helpers.d.ts +23 -0
  305. package/dist/slash-commands/sdd-command-helpers.d.ts.map +1 -0
  306. package/dist/slash-commands/sdd-format.d.ts +32 -0
  307. package/dist/slash-commands/sdd-format.d.ts.map +1 -0
  308. package/dist/slash-commands/sdd.d.ts.map +1 -1
  309. package/dist/subcommands/handlers/chronicle.d.ts.map +1 -1
  310. package/dist/subcommands/handlers/mailbox-serve.d.ts.map +1 -1
  311. package/dist/subcommands/handlers/model-smoke-test.d.ts +51 -0
  312. package/dist/subcommands/handlers/model-smoke-test.d.ts.map +1 -0
  313. package/dist/subcommands/handlers/modeldiag-profiles.d.ts +64 -0
  314. package/dist/subcommands/handlers/modeldiag-profiles.d.ts.map +1 -0
  315. package/dist/subcommands/handlers/modeldiag.d.ts.map +1 -1
  316. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts +3 -0
  317. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts.map +1 -0
  318. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts +3 -0
  319. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts.map +1 -0
  320. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts +36 -0
  321. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts.map +1 -0
  322. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts +18 -0
  323. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts.map +1 -0
  324. package/dist/subcommands/handlers/per-subcommand-help.d.ts +2 -80
  325. package/dist/subcommands/handlers/per-subcommand-help.d.ts.map +1 -1
  326. package/dist/subcommands/handlers/rewind.d.ts.map +1 -1
  327. package/dist/subcommands/index.d.ts +7 -0
  328. package/dist/subcommands/index.d.ts.map +1 -1
  329. package/dist/tools-skills-UNKLOB7M.js +29 -0
  330. package/dist/tools-skills-UNKLOB7M.js.map +7 -0
  331. package/dist/update-YC4TYW2Y.js +16 -0
  332. package/dist/update-YC4TYW2Y.js.map +7 -0
  333. package/dist/update-check-UMYTOH7Z.js +18 -0
  334. package/dist/update-check-UMYTOH7Z.js.map +7 -0
  335. package/dist/version-help-DROHZRW6.js +11 -0
  336. package/dist/version-help-DROHZRW6.js.map +7 -0
  337. package/dist/webui-server/connection-handler.d.ts.map +1 -1
  338. package/dist/webui-server/kanban-host-adapter.d.ts +5 -1
  339. package/dist/webui-server/kanban-host-adapter.d.ts.map +1 -1
  340. package/dist/webui-server/listen-helpers.d.ts +18 -0
  341. package/dist/webui-server/listen-helpers.d.ts.map +1 -0
  342. package/dist/webui-server/node-pty-loader.d.ts +6 -0
  343. package/dist/webui-server/node-pty-loader.d.ts.map +1 -0
  344. package/dist/webui-server-G3TISUIY.js +1459 -0
  345. package/dist/webui-server-G3TISUIY.js.map +7 -0
  346. package/dist/webui-server-options.d.ts +189 -0
  347. package/dist/webui-server-options.d.ts.map +1 -0
  348. package/dist/webui-server.d.ts +2 -178
  349. package/dist/webui-server.d.ts.map +1 -1
  350. package/dist/wiring/brain-and-orchestration.d.ts.map +1 -1
  351. package/dist/wiring/codebase-index.d.ts.map +1 -1
  352. package/dist/wiring/command-host-state.d.ts +4 -4
  353. package/dist/wiring/dep-watcher-bridge.d.ts +23 -0
  354. package/dist/wiring/dep-watcher-bridge.d.ts.map +1 -0
  355. package/dist/wiring/dep-watcher.d.ts.map +1 -1
  356. package/dist/wiring/hq-telemetry.d.ts +2 -2
  357. package/dist/wiring/lifecycle-plugins.d.ts +4 -3
  358. package/dist/wiring/lifecycle-plugins.d.ts.map +1 -1
  359. package/dist/wiring/mailbox-bridge-bootstrap.d.ts +1 -1
  360. package/dist/wiring/management-tools.d.ts +15 -0
  361. package/dist/wiring/management-tools.d.ts.map +1 -0
  362. package/dist/wiring/pipeline.d.ts +2 -1
  363. package/dist/wiring/pipeline.d.ts.map +1 -1
  364. package/dist/wiring/plugins.d.ts +1 -1
  365. package/dist/wiring/plugins.d.ts.map +1 -1
  366. package/dist/wiring/provider-runtime-setup.d.ts +14 -1
  367. package/dist/wiring/provider-runtime-setup.d.ts.map +1 -1
  368. package/dist/wiring/provider.d.ts.map +1 -1
  369. package/dist/wiring/runtime-controller-deps.d.ts +1 -1
  370. package/dist/wiring/runtime-controller-deps.d.ts.map +1 -1
  371. package/dist/wiring/sage.d.ts.map +1 -1
  372. package/dist/wiring/session-registry.d.ts +38 -0
  373. package/dist/wiring/session-registry.d.ts.map +1 -0
  374. package/dist/wiring/session.d.ts +7 -5
  375. package/dist/wiring/session.d.ts.map +1 -1
  376. package/dist/wiring/tools.d.ts.map +1 -1
  377. package/package.json +22 -22
  378. package/dist/cli-recovery-prompt.d.ts +0 -19
  379. package/dist/cli-recovery-prompt.d.ts.map +0 -1
  380. package/dist/first-run-auth-gate.d.ts +0 -20
  381. package/dist/first-run-auth-gate.d.ts.map +0 -1
  382. package/dist/pre-launch/indexing-question.d.ts +0 -28
  383. package/dist/pre-launch/indexing-question.d.ts.map +0 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/hq-command-controller.ts"],
4
+ "sourcesContent": ["/**\n * HQ command controller \u2014 the client-side dispatch surface for Phase 4 of the\n * HQ command center. A mutable holder (mirroring the established\n * `interruptController` pattern in cli-main.ts) that the `onCommand` handler\n * on the HQ publisher reads lazily, because several of its targets\n * (`director`, the rebound `interruptLeader`) are not yet defined at HQ-connect\n * time.\n *\n * The five command types route through the agent's own decision loop or the\n * project mailbox, so they inherit existing guardrails. `run-command` (raw\n * shell) is deliberately NOT wired here \u2014 it requires a separately-audited\n * escalation policy (operator flag + per-token `control.execute` + allowlist)\n * and is left as a stub that rejects until that policy exists.\n *\n * @module hq-command-controller\n */\nimport type { HqPublisherCommandResult } from '@wrongstack/core/hq';\nimport type { RemoteMailbox } from '@wrongstack/core/coordination';\nimport type { HqCommand } from '@wrongstack/core/hq';\n\n/**\n * Mutable holder for the command dispatch targets. Each field is populated\n * lazily as the corresponding subsystem comes online (director on\n * `onDirectorReady`, interruptLeader rebound by the REPL/TUI, \u2026). The\n * `onCommand` handler reads these at dispatch time, not at construction.\n */\nexport interface HqCommandController {\n /** Project mailbox used to deliver steer/broadcast messages. */\n steerMailbox?: RemoteMailbox | undefined;\n /** Abort the session leader's running Agent.run(). Returns true if a run was aborted. */\n interruptLeader: () => boolean;\n /** Terminate a specific subagent by id. Returns true if terminated. */\n terminateAgent?: (subagentId: string) => boolean | Promise<boolean>;\n /** Stop the entire fleet (all running/idle subagents). Returns kill count. */\n killFleet?: () => number | Promise<number>;\n /** Spawn a subagent of the given role. Returns the new subagentId. */\n spawnAgent?: (role: string, task?: string, maxIterations?: number) => Promise<string>;\n /** Derive the session-unique mailbox tag for addressing (e.g. `leader@<tag>`). */\n sessionTag: () => string;\n /** Whether raw shell execution is explicitly opted-in by the operator. */\n allowRunCommand: () => boolean;\n}\n\n/**\n * Build the `onCommand` handler for an HQ publisher. The handler validates\n * the command, dispatches through the controller, and returns an ack result\n * (or throws to produce a `failed` ack \u2014 the publisher's `handleCommandBatch`\n * wraps it). Best-effort: a dispatch failure never breaks the host.\n */\nexport function createHqCommandDispatcher(\n controller: HqCommandController,\n): (command: { commandId: string; type: string; payload: unknown }) => Promise<HqPublisherCommandResult> {\n return async (command) => {\n const cmd = command as { commandId: string; type: string; payload: Record<string, unknown> };\n try {\n const result = await dispatch(controller, cmd.commandId, cmd.type as HqCommand['type'], cmd.payload);\n return result;\n } catch (err) {\n return {\n commandId: command.commandId,\n status: 'failed',\n message: err instanceof Error ? err.message : String(err),\n };\n }\n };\n}\n\nasync function dispatch(\n controller: HqCommandController,\n commandId: string,\n type: HqCommand['type'],\n payload: Record<string, unknown>,\n): Promise<HqPublisherCommandResult> {\n switch (type) {\n case 'steer': {\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const to = typeof payload['to'] === 'string' ? payload['to'] : 'leader';\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ steer';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to, type: 'steer', subject, body, priority });\n return { commandId, status: 'accepted', message: `steered ${to}` };\n }\n\n case 'btw': {\n // Non-urgent FYI. Same targeting as steer, but delivered as a `btw`\n // mailbox message so the receiving agent absorbs it as context instead\n // of treating it as a course-correction. Lands in the mailbox file\n // regardless of whether a loop is currently running.\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const to = typeof payload['to'] === 'string' ? payload['to'] : 'leader';\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ note';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to, type: 'btw', subject, body, priority });\n return { commandId, status: 'accepted', message: `noted ${to}` };\n }\n\n case 'queue': {\n // Queue a prompt/note for the target. Delivered as a plain `note` the\n // agent picks up before its next step \u2014 used when the prompt should\n // wait its turn rather than steer the current operation. Like steer/btw,\n // this only writes to the mailbox; no live loop is required.\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const to = typeof payload['to'] === 'string' ? payload['to'] : 'leader';\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ prompt';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to, type: 'note', subject, body, priority });\n return { commandId, status: 'accepted', message: `queued for ${to}` };\n }\n\n case 'broadcast': {\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ broadcast';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to: 'all', type: 'broadcast', subject, body, priority });\n return { commandId, status: 'accepted', message: 'broadcast sent' };\n }\n\n case 'abort': {\n const target = typeof payload['target'] === 'string' ? payload['target'] : 'leader';\n if (target === 'leader') {\n const aborted = controller.interruptLeader();\n return {\n commandId,\n status: aborted ? 'completed' : 'accepted',\n message: aborted ? 'leader aborted' : 'no active leader run',\n };\n }\n if (target === 'fleet') {\n const killed = (await controller.killFleet?.()) ?? 0;\n return {\n commandId,\n status: 'completed',\n message: `fleet stopped (${killed} agents)`,\n };\n }\n // Specific subagent id.\n const terminated = (await controller.terminateAgent?.(target)) ?? false;\n return {\n commandId,\n status: terminated ? 'completed' : 'rejected',\n message: terminated ? `agent ${target} terminated` : `agent ${target} not found`,\n };\n }\n\n case 'spawn': {\n const role = typeof payload['role'] === 'string' ? payload['role'] : '';\n const task = typeof payload['task'] === 'string' ? payload['task'] : undefined;\n const maxIterations = typeof payload['maxIterations'] === 'number' ? payload['maxIterations'] : undefined;\n if (controller.spawnAgent === undefined) {\n return { commandId, status: 'rejected', message: 'no director active' };\n }\n const subagentId = await controller.spawnAgent(role, task, maxIterations);\n return { commandId, status: 'completed', message: `spawned ${subagentId}` };\n }\n\n case 'run-command': {\n // RCE gate: require explicit operator opt-in. Without it, reject every\n // run-command so a stolen client token can never gain shell access.\n if (!controller.allowRunCommand()) {\n return {\n commandId,\n status: 'rejected',\n message: 'run-command requires operator opt-in (--hq-allow-exec)',\n };\n }\n // Even with opt-in, we do NOT exec shell directly \u2014 we route through the\n // agent as a steer so the agent's own permission policy still applies.\n // A full direct-exec path is deferred until a separately-audited\n // escalation policy + allowlist exists.\n const mailbox = controller.steerMailbox;\n const command = typeof payload['command'] === 'string' ? payload['command'] : '';\n if (mailbox !== undefined && command.length > 0) {\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({\n from,\n to: 'leader',\n type: 'steer',\n subject: 'Run command (HQ)',\n body: `Run the following shell command:\\n\\n\\`\\`\\`\\n${command}\\n\\`\\`\\``,\n priority: 'high',\n });\n return { commandId, status: 'accepted', message: 'run-command routed to leader as steer' };\n }\n return { commandId, status: 'rejected', message: 'cannot route run-command (no mailbox)' };\n }\n\n default:\n return { commandId, status: 'rejected', message: `unknown command type: ${type}` };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,158 @@
1
+
2
+ // src/provider-config-utils.ts
3
+ import { expectDefined } from "@wrongstack/core/utils";
4
+ import { FsError } from "@wrongstack/core/types";
5
+ import * as fs from "node:fs/promises";
6
+ import { atomicWrite, color } from "@wrongstack/core/utils";
7
+ import { decryptConfigSecrets, encryptConfigSecrets } from "@wrongstack/core/security";
8
+ function normalizeKeys(cfg) {
9
+ if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
10
+ return cfg.apiKeys.map((k) => ({ ...k }));
11
+ }
12
+ if (typeof cfg.apiKey === "string" && cfg.apiKey.length > 0) {
13
+ return [{ label: "default", apiKey: cfg.apiKey, createdAt: "" }];
14
+ }
15
+ return [];
16
+ }
17
+ function writeKeysBack(cfg, keys) {
18
+ if (keys.length === 0) {
19
+ delete cfg.apiKeys;
20
+ delete cfg.apiKey;
21
+ delete cfg.activeKey;
22
+ return;
23
+ }
24
+ cfg.apiKeys = keys;
25
+ const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);
26
+ delete cfg.apiKey;
27
+ if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {
28
+ cfg.activeKey = active.label;
29
+ }
30
+ }
31
+ function resolveActiveApiKey(cfg) {
32
+ if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
33
+ const active = cfg.activeKey ? cfg.apiKeys.find((k) => k.label === cfg.activeKey) : void 0;
34
+ return (active ?? cfg.apiKeys[0])?.apiKey;
35
+ }
36
+ return cfg.apiKey && cfg.apiKey.length > 0 ? cfg.apiKey : void 0;
37
+ }
38
+ function isLoopbackBaseUrl(baseUrl) {
39
+ if (!baseUrl) return false;
40
+ try {
41
+ let host = new URL(baseUrl).hostname.toLowerCase();
42
+ host = host.replace(/^\[|\]$/g, "");
43
+ return host === "localhost" || host === "::1" || host === "0.0.0.0" || /^127\./.test(host);
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ function providerCanRunWithoutSavedKey(cfg) {
49
+ return isLoopbackBaseUrl(cfg.baseUrl) && (!cfg.envVars || cfg.envVars.length === 0);
50
+ }
51
+ function hasUsableSavedProvider(cfg) {
52
+ return resolveActiveApiKey(cfg) !== void 0 || providerCanRunWithoutSavedKey(cfg);
53
+ }
54
+ function clearStaleProviderDefaults(config) {
55
+ const providerId = typeof config["provider"] === "string" ? config["provider"] : void 0;
56
+ if (!providerId) return;
57
+ const providers = config["providers"];
58
+ const provider = providers?.[providerId];
59
+ if (!provider || !hasUsableSavedProvider(provider)) {
60
+ delete config["provider"];
61
+ delete config["model"];
62
+ return;
63
+ }
64
+ const modelId = typeof config["model"] === "string" ? config["model"] : void 0;
65
+ if (modelId && Array.isArray(provider.models) && provider.models.length > 0 && !provider.models.includes(modelId)) {
66
+ delete config["model"];
67
+ }
68
+ }
69
+ function activeLabel(cfg, keys) {
70
+ if (cfg.activeKey && keys.some((k) => k.label === cfg.activeKey)) return cfg.activeKey;
71
+ return keys[0]?.label;
72
+ }
73
+ function maskedKey(key) {
74
+ if (!key) return color.dim("\u2014");
75
+ if (key.length <= 8) return color.dim("\u2022".repeat(key.length));
76
+ const head = key.slice(0, 4);
77
+ const tail = key.slice(-4);
78
+ return `${color.dim(head + "\u2026")}${tail}`;
79
+ }
80
+ function nowIso() {
81
+ return (/* @__PURE__ */ new Date()).toISOString();
82
+ }
83
+ async function loadConfigProviders(configPath, vault, opts) {
84
+ const warn = opts?.warn;
85
+ const targetPath = opts?.profileConfigPath ?? configPath;
86
+ let raw;
87
+ try {
88
+ raw = await fs.readFile(targetPath, "utf8");
89
+ } catch (err) {
90
+ if (err.code !== "ENOENT") {
91
+ warn?.(`Could not read ${targetPath}: ${err.message}. Treating as empty.`);
92
+ }
93
+ return {};
94
+ }
95
+ let parsed;
96
+ try {
97
+ parsed = JSON.parse(raw);
98
+ } catch (err) {
99
+ warn?.(`Config at ${targetPath} is not valid JSON: ${err.message}`);
100
+ return {};
101
+ }
102
+ const decrypted = decryptConfigSecrets(parsed, vault);
103
+ return decrypted.providers ?? {};
104
+ }
105
+ async function mutateConfigProviders(configPath, vault, mutator, profileConfigPath) {
106
+ const targetPath = profileConfigPath ?? configPath;
107
+ let raw;
108
+ let fileExists = true;
109
+ try {
110
+ raw = await fs.readFile(targetPath, "utf8");
111
+ } catch (err) {
112
+ if (err.code !== "ENOENT") {
113
+ throw new FsError({
114
+ message: `Refusing to mutate ${configPath}: ${err.message}`,
115
+ code: "FS_READ_FAILED",
116
+ path: targetPath,
117
+ context: { operation: "mutateConfigProviders", phase: "read" },
118
+ cause: err
119
+ });
120
+ }
121
+ fileExists = false;
122
+ raw = "{}";
123
+ }
124
+ let parsed;
125
+ try {
126
+ parsed = JSON.parse(raw);
127
+ } catch (err) {
128
+ if (fileExists) {
129
+ throw new FsError({
130
+ message: `Refusing to overwrite corrupt config at ${targetPath} (${err.message}). Fix or move the file aside before retrying.`,
131
+ code: "FS_READ_FAILED",
132
+ path: targetPath,
133
+ context: { operation: "mutateConfigProviders", phase: "parse" },
134
+ cause: err
135
+ });
136
+ }
137
+ parsed = {};
138
+ }
139
+ const decrypted = decryptConfigSecrets(parsed, vault);
140
+ const providers = decrypted.providers ?? {};
141
+ mutator(providers);
142
+ decrypted.providers = providers;
143
+ clearStaleProviderDefaults(decrypted);
144
+ const encrypted = encryptConfigSecrets(decrypted, vault);
145
+ await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
146
+ }
147
+
148
+ export {
149
+ normalizeKeys,
150
+ writeKeysBack,
151
+ resolveActiveApiKey,
152
+ activeLabel,
153
+ maskedKey,
154
+ nowIso,
155
+ loadConfigProviders,
156
+ mutateConfigProviders
157
+ };
158
+ //# sourceMappingURL=chunk-PJHET45A.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/provider-config-utils.ts"],
4
+ "sourcesContent": ["import { expectDefined } from '@wrongstack/core/utils';\nimport { FsError } from '@wrongstack/core/types';\n\nexport { expectDefined };\n\n/**\n * Pure helpers for ProviderConfig shape normalisation, key masking, and\n * timestamp generation \u2014 plus config file I/O (load/mutate providers).\n * Shared between auth-menu.ts, webui-server.ts, and any future code that\n * touches the config `providers` map.\n */\nimport * as fs from 'node:fs/promises';\nimport type { ProviderApiKey, ProviderConfig, SecretVault } from '@wrongstack/core/types';\nimport { atomicWrite, color } from '@wrongstack/core/utils';\nimport { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';\n/**\n * Normalize a ProviderConfig to the canonical `apiKeys[]` form.\n * Migrates the legacy single-key `apiKey` field on the fly so every\n * consumer sees a uniform shape. Does NOT mutate the input.\n */\nexport function normalizeKeys(cfg: ProviderConfig): ProviderApiKey[] {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n return cfg.apiKeys.map((k) => ({ ...k }));\n }\n if (typeof cfg.apiKey === 'string' && cfg.apiKey.length > 0) {\n return [{ label: 'default', apiKey: cfg.apiKey, createdAt: '' }];\n }\n return [];\n}\n\n/**\n * Write a normalized key list back into a ProviderConfig. Does NOT mirror\n * the plaintext key to the legacy `apiKey` field \u2014 that would leak the\n * secret on any accidental JSON.stringify of the config. Consumers that\n * need the real key must call {@link resolveActiveApiKey}.\n */\nexport function writeKeysBack(cfg: ProviderConfig, keys: ProviderApiKey[]): void {\n if (keys.length === 0) {\n delete cfg.apiKeys;\n delete cfg.apiKey;\n delete cfg.activeKey;\n return;\n }\n cfg.apiKeys = keys;\n const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);\n // Do NOT mirror plaintext to cfg.apiKey \u2014 the legacy field is cleared so\n // that accidental serialization (logging, error messages, WS payloads)\n // cannot leak the active key. Use resolveActiveApiKey() to read the real key.\n delete cfg.apiKey;\n if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {\n cfg.activeKey = active.label;\n }\n}\n\n/**\n * Extract the active (decrypted) API key from a ProviderConfig.\n *\n * Resolution order:\n * 1. `apiKeys[]` \u2014 pick the entry matching `activeKey`, or the first one\n * 2. Legacy `apiKey` field \u2014 only for configs not yet migrated to multi-key\n *\n * This is the **preferred** way to read the API key. Never read `cfg.apiKey`\n * directly in new code \u2014 after {@link writeKeysBack} it is cleared, and even\n * when present on a freshly-loaded config it may contain a masked value.\n */\nexport function resolveActiveApiKey(cfg: ProviderConfig): string | undefined {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n const active = cfg.activeKey\n ? cfg.apiKeys.find((k) => k.label === cfg.activeKey)\n : undefined;\n return (active ?? cfg.apiKeys[0])?.apiKey;\n }\n return cfg.apiKey && cfg.apiKey.length > 0 ? cfg.apiKey : undefined;\n}\n\nfunction isLoopbackBaseUrl(baseUrl: string | undefined): boolean {\n if (!baseUrl) return false;\n try {\n let host = new URL(baseUrl).hostname.toLowerCase();\n host = host.replace(/^\\[|\\]$/g, '');\n return host === 'localhost' || host === '::1' || host === '0.0.0.0' || /^127\\./.test(host);\n } catch {\n return false;\n }\n}\n\nfunction providerCanRunWithoutSavedKey(cfg: ProviderConfig): boolean {\n return isLoopbackBaseUrl(cfg.baseUrl) && (!cfg.envVars || cfg.envVars.length === 0);\n}\n\nfunction hasUsableSavedProvider(cfg: ProviderConfig): boolean {\n return resolveActiveApiKey(cfg) !== undefined || providerCanRunWithoutSavedKey(cfg);\n}\n\n/**\n * Clear top-level provider/model defaults when provider mutations make them\n * stale. This prevents a removed provider, deleted final key, or edited model\n * allowlist from being accepted on the next boot and crashing provider setup.\n */\nexport function clearStaleProviderDefaults(config: Record<string, unknown>): void {\n const providerId = typeof config['provider'] === 'string' ? config['provider'] : undefined;\n if (!providerId) return;\n const providers = config['providers'] as Record<string, ProviderConfig> | undefined;\n const provider = providers?.[providerId];\n if (!provider || !hasUsableSavedProvider(provider)) {\n delete config['provider'];\n delete config['model'];\n return;\n }\n const modelId = typeof config['model'] === 'string' ? config['model'] : undefined;\n if (modelId && Array.isArray(provider.models) && provider.models.length > 0 && !provider.models.includes(modelId)) {\n delete config['model'];\n }\n}\n\n/**\n * Return the label of the active key, or the first key's label if no\n * active is pinned. Returns `undefined` when there are no keys at all.\n */\nexport function activeLabel(cfg: ProviderConfig, keys: ProviderApiKey[]): string | undefined {\n if (cfg.activeKey && keys.some((k) => k.label === cfg.activeKey)) return cfg.activeKey;\n return keys[0]?.label;\n}\n\n/** Mask an API key for display: show first 4 + last 4 chars. */\nexport function maskedKey(key: string): string {\n if (!key) return color.dim('\u2014');\n if (key.length <= 8) return color.dim('\u2022'.repeat(key.length));\n const head = key.slice(0, 4);\n const tail = key.slice(-4);\n return `${color.dim(head + '\u2026')}${tail}`;\n}\n\n/** ISO-8601 timestamp for key `createdAt` fields. */\nexport function nowIso(): string {\n return new Date().toISOString();\n}\n\n/* ------------------------------------------------------------------ */\n/* Config file I/O \u2014 load / mutate `providers` atomically */\n/* ------------------------------------------------------------------ */\n\n/**\n * Read the on-disk config file and return its `providers` map, fully\n * decrypted. Returns `{}` on ENOENT or corrupt JSON (surfacing the error\n * via the optional `warn` callback when provided).\n */\nexport async function loadConfigProviders(\n configPath: string,\n vault: SecretVault,\n opts?: { warn?: (msg: string) => void; profileConfigPath?: string },\n): Promise<Record<string, ProviderConfig>> {\n const warn = opts?.warn;\n const targetPath = opts?.profileConfigPath ?? configPath;\n let raw: string;\n try {\n raw = await fs.readFile(targetPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n warn?.(`Could not read ${targetPath}: ${(err as Error).message}. Treating as empty.`);\n }\n return {};\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n warn?.(`Config at ${targetPath} is not valid JSON: ${(err as Error).message}`);\n return {};\n }\n const decrypted = decryptConfigSecrets(parsed, vault);\n return (decrypted as { providers?: Record<string, ProviderConfig> }).providers ?? {};\n}\n\n/**\n * Load \u2192 mutate \u2192 encrypt \u2192 atomic-write. Operates on the FULL config file\n * so non-provider keys are preserved. Refuses to overwrite a corrupt-but-\n * existing config (the user may still have salvageable data).\n */\nexport async function mutateConfigProviders(\n configPath: string,\n vault: SecretVault,\n mutator: (providers: Record<string, ProviderConfig>) => void,\n profileConfigPath?: string,\n): Promise<void> {\n const targetPath = profileConfigPath ?? configPath;\n let raw: string;\n let fileExists = true;\n try {\n raw = await fs.readFile(targetPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new FsError({\n message: `Refusing to mutate ${configPath}: ${(err as Error).message}`,\n code: 'FS_READ_FAILED',\n path: targetPath,\n context: { operation: 'mutateConfigProviders', phase: 'read' },\n cause: err,\n });\n }\n fileExists = false;\n raw = '{}';\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n if (fileExists) {\n throw new FsError({\n message:\n `Refusing to overwrite corrupt config at ${targetPath} ` +\n `(${(err as Error).message}). Fix or move the file aside before retrying.`,\n code: 'FS_READ_FAILED',\n path: targetPath,\n context: { operation: 'mutateConfigProviders', phase: 'parse' },\n cause: err,\n });\n }\n parsed = {};\n }\n const decrypted = decryptConfigSecrets(parsed, vault) as Record<string, unknown>;\n const providers = (decrypted.providers as Record<string, ProviderConfig>) ?? {};\n mutator(providers);\n decrypted.providers = providers;\n clearStaleProviderDefaults(decrypted);\n const encrypted = encryptConfigSecrets(decrypted, vault);\n await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n}\n"],
5
+ "mappings": ";;;AAAA,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AAUxB,YAAY,QAAQ;AAEpB,SAAS,aAAa,aAAa;AACnC,SAAS,sBAAsB,4BAA4B;AAMpD,SAAS,cAAc,KAAuC;AACnE,MAAI,MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,SAAS,GAAG;AACxD,WAAO,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AAAA,EAC1C;AACA,MAAI,OAAO,IAAI,WAAW,YAAY,IAAI,OAAO,SAAS,GAAG;AAC3D,WAAO,CAAC,EAAE,OAAO,WAAW,QAAQ,IAAI,QAAQ,WAAW,GAAG,CAAC;AAAA,EACjE;AACA,SAAO,CAAC;AACV;AAQO,SAAS,cAAc,KAAqB,MAA8B;AAC/E,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,IAAI;AACX,WAAO,IAAI;AACX,WAAO,IAAI;AACX;AAAA,EACF;AACA,MAAI,UAAU;AACd,QAAM,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,SAAS,KAAK,cAAc,KAAK,CAAC,CAAC;AAInF,SAAO,IAAI;AACX,MAAI,CAAC,IAAI,aAAa,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,SAAS,GAAG;AAClE,QAAI,YAAY,OAAO;AAAA,EACzB;AACF;AAaO,SAAS,oBAAoB,KAAyC;AAC3E,MAAI,MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,SAAS,GAAG;AACxD,UAAM,SAAS,IAAI,YACf,IAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,SAAS,IACjD;AACJ,YAAQ,UAAU,IAAI,QAAQ,CAAC,IAAI;AAAA,EACrC;AACA,SAAO,IAAI,UAAU,IAAI,OAAO,SAAS,IAAI,IAAI,SAAS;AAC5D;AAEA,SAAS,kBAAkB,SAAsC;AAC/D,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,QAAI,OAAO,IAAI,IAAI,OAAO,EAAE,SAAS,YAAY;AACjD,WAAO,KAAK,QAAQ,YAAY,EAAE;AAClC,WAAO,SAAS,eAAe,SAAS,SAAS,SAAS,aAAa,SAAS,KAAK,IAAI;AAAA,EAC3F,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,8BAA8B,KAA8B;AACnE,SAAO,kBAAkB,IAAI,OAAO,MAAM,CAAC,IAAI,WAAW,IAAI,QAAQ,WAAW;AACnF;AAEA,SAAS,uBAAuB,KAA8B;AAC5D,SAAO,oBAAoB,GAAG,MAAM,UAAa,8BAA8B,GAAG;AACpF;AAOO,SAAS,2BAA2B,QAAuC;AAChF,QAAM,aAAa,OAAO,OAAO,UAAU,MAAM,WAAW,OAAO,UAAU,IAAI;AACjF,MAAI,CAAC,WAAY;AACjB,QAAM,YAAY,OAAO,WAAW;AACpC,QAAM,WAAW,YAAY,UAAU;AACvC,MAAI,CAAC,YAAY,CAAC,uBAAuB,QAAQ,GAAG;AAClD,WAAO,OAAO,UAAU;AACxB,WAAO,OAAO,OAAO;AACrB;AAAA,EACF;AACA,QAAM,UAAU,OAAO,OAAO,OAAO,MAAM,WAAW,OAAO,OAAO,IAAI;AACxE,MAAI,WAAW,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,OAAO,SAAS,KAAK,CAAC,SAAS,OAAO,SAAS,OAAO,GAAG;AACjH,WAAO,OAAO,OAAO;AAAA,EACvB;AACF;AAMO,SAAS,YAAY,KAAqB,MAA4C;AAC3F,MAAI,IAAI,aAAa,KAAK,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,SAAS,EAAG,QAAO,IAAI;AAC7E,SAAO,KAAK,CAAC,GAAG;AAClB;AAGO,SAAS,UAAU,KAAqB;AAC7C,MAAI,CAAC,IAAK,QAAO,MAAM,IAAI,QAAG;AAC9B,MAAI,IAAI,UAAU,EAAG,QAAO,MAAM,IAAI,SAAI,OAAO,IAAI,MAAM,CAAC;AAC5D,QAAM,OAAO,IAAI,MAAM,GAAG,CAAC;AAC3B,QAAM,OAAO,IAAI,MAAM,EAAE;AACzB,SAAO,GAAG,MAAM,IAAI,OAAO,QAAG,CAAC,GAAG,IAAI;AACxC;AAGO,SAAS,SAAiB;AAC/B,UAAO,oBAAI,KAAK,GAAE,YAAY;AAChC;AAWA,eAAsB,oBACpB,YACA,OACA,MACyC;AACzC,QAAM,OAAO,MAAM;AACnB,QAAM,aAAa,MAAM,qBAAqB;AAC9C,MAAI;AACJ,MAAI;AACF,UAAM,MAAS,YAAS,YAAY,MAAM;AAAA,EAC5C,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,UAAU;AACpD,aAAO,kBAAkB,UAAU,KAAM,IAAc,OAAO,sBAAsB;AAAA,IACtF;AACA,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,KAAK;AACZ,WAAO,aAAa,UAAU,uBAAwB,IAAc,OAAO,EAAE;AAC7E,WAAO,CAAC;AAAA,EACV;AACA,QAAM,YAAY,qBAAqB,QAAQ,KAAK;AACpD,SAAQ,UAA6D,aAAa,CAAC;AACrF;AAOA,eAAsB,sBACpB,YACA,OACA,SACA,mBACe;AACf,QAAM,aAAa,qBAAqB;AACxC,MAAI;AACJ,MAAI,aAAa;AACjB,MAAI;AACF,UAAM,MAAS,YAAS,YAAY,MAAM;AAAA,EAC5C,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,UAAU;AACpD,YAAM,IAAI,QAAQ;AAAA,QAChB,SAAS,sBAAsB,UAAU,KAAM,IAAc,OAAO;AAAA,QACpE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,yBAAyB,OAAO,OAAO;AAAA,QAC7D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,iBAAa;AACb,UAAM;AAAA,EACR;AACA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,KAAK;AACZ,QAAI,YAAY;AACd,YAAM,IAAI,QAAQ;AAAA,QAChB,SACE,2CAA2C,UAAU,KAChD,IAAc,OAAO;AAAA,QAC5B,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,yBAAyB,OAAO,QAAQ;AAAA,QAC9D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,aAAS,CAAC;AAAA,EACZ;AACA,QAAM,YAAY,qBAAqB,QAAQ,KAAK;AACpD,QAAM,YAAa,UAAU,aAAgD,CAAC;AAC9E,UAAQ,SAAS;AACjB,YAAU,YAAY;AACtB,6BAA2B,SAAS;AACpC,QAAM,YAAY,qBAAqB,WAAW,KAAK;AACvD,QAAM,YAAY,YAAY,KAAK,UAAU,WAAW,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AACnF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+
2
+ // src/hq-server/audit-actor.ts
3
+ import * as os from "node:os";
4
+ function resolveAuditActor() {
5
+ const user = (process.env.USERNAME ?? process.env.USER ?? "").toString();
6
+ try {
7
+ const host = os.hostname();
8
+ return user ? `${user}@${host}` : `cli@${host}`;
9
+ } catch {
10
+ return user ? `${user}@unknown` : "cli";
11
+ }
12
+ }
13
+
14
+ export {
15
+ resolveAuditActor
16
+ };
17
+ //# sourceMappingURL=chunk-Q5GTM25S.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/hq-server/audit-actor.ts"],
4
+ "sourcesContent": ["import * as os from 'node:os';\n\n/** Build the non-secret actor label used by HQ authentication audit entries. */\nexport function resolveAuditActor(): string {\n const user = (process.env.USERNAME ?? process.env.USER ?? '').toString();\n try {\n const host = os.hostname();\n return user ? `${user}@${host}` : `cli@${host}`;\n } catch {\n return user ? `${user}@unknown` : 'cli';\n }\n}\n"],
5
+ "mappings": ";;;AAAA,YAAY,QAAQ;AAGb,SAAS,oBAA4B;AAC1C,QAAM,QAAQ,QAAQ,IAAI,YAAY,QAAQ,IAAI,QAAQ,IAAI,SAAS;AACvE,MAAI;AACF,UAAM,OAAU,YAAS;AACzB,WAAO,OAAO,GAAG,IAAI,IAAI,IAAI,KAAK,OAAO,IAAI;AAAA,EAC/C,QAAQ;AACN,WAAO,OAAO,GAAG,IAAI,aAAa;AAAA,EACpC;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,19 @@
1
+
2
+ // src/theme.ts
3
+ import { color } from "@wrongstack/core/utils";
4
+ var theme = {
5
+ primary: color.amber,
6
+ accent: color.pink,
7
+ muted: color.dim,
8
+ success: color.green,
9
+ warn: color.yellow,
10
+ error: color.red,
11
+ info: color.cyan,
12
+ bold: color.bold,
13
+ underline: color.underline
14
+ };
15
+
16
+ export {
17
+ theme
18
+ };
19
+ //# sourceMappingURL=chunk-QD544J2B.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/theme.ts"],
4
+ "sourcesContent": ["import { color } from '@wrongstack/core/utils';\n\nexport const theme = {\n primary: color.amber,\n accent: color.pink,\n muted: color.dim,\n success: color.green,\n warn: color.yellow,\n error: color.red,\n info: color.cyan,\n bold: color.bold,\n underline: color.underline,\n};\n"],
5
+ "mappings": ";;;AAAA,SAAS,aAAa;AAEf,IAAM,QAAQ;AAAA,EACnB,SAAS,MAAM;AAAA,EACf,QAAQ,MAAM;AAAA,EACd,OAAO,MAAM;AAAA,EACb,SAAS,MAAM;AAAA,EACf,MAAM,MAAM;AAAA,EACZ,OAAO,MAAM;AAAA,EACb,MAAM,MAAM;AAAA,EACZ,MAAM,MAAM;AAAA,EACZ,WAAW,MAAM;AACnB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,258 @@
1
+ import {
2
+ PLUGIN_AUDIT_ENTRIES
3
+ } from "./chunk-XWEGWYDU.js";
4
+ import {
5
+ patchConfig
6
+ } from "./chunk-TYO2OVAD.js";
7
+
8
+ // src/wiring/plugins.ts
9
+ import { join } from "node:path";
10
+ import { loadPlugins, resolvePluginConfig } from "@wrongstack/core/plugin";
11
+ import { OFFICIAL_PLUGIN_FACTORIES } from "@wrongstack/plugins/factories";
12
+
13
+ // src/plugin-api-factory.ts
14
+ import { DefaultPluginAPI } from "@wrongstack/core/plugin";
15
+ function createApi(ownerName, base) {
16
+ return new DefaultPluginAPI({ ownerName, ...base });
17
+ }
18
+
19
+ // src/wiring/plugins.ts
20
+ var DEPRECATED_PLUGIN_NAMES = {
21
+ "web-search": "use the built-in `search` and `fetch` tools",
22
+ "json-path": "use the built-in `json` tool with action: query | validate | transform | merge"
23
+ };
24
+ var deprecatedWarningsEmitted = /* @__PURE__ */ new Set();
25
+ var BUILTIN_PLUGIN_CONFIG_ALIASES = {
26
+ lsp: "@wrongstack/plug-lsp",
27
+ "@wrongstack/telegram": "telegram"
28
+ };
29
+ var BUILTIN_PLUGIN_CONFIG_NAMES = /* @__PURE__ */ new Set([
30
+ ...PLUGIN_AUDIT_ENTRIES.map((entry) => entry.name),
31
+ ...PLUGIN_AUDIT_ENTRIES.map((entry) => `@wrongstack/plugins/${entry.name}`),
32
+ ...Object.keys(BUILTIN_PLUGIN_CONFIG_ALIASES)
33
+ ]);
34
+ function _resetDeprecatedWarningsForTests() {
35
+ deprecatedWarningsEmitted.clear();
36
+ }
37
+ function warnIfDeprecatedPluginName(name, log) {
38
+ const replacement = DEPRECATED_PLUGIN_NAMES[name];
39
+ if (!replacement) return false;
40
+ if (deprecatedWarningsEmitted.has(name)) return true;
41
+ deprecatedWarningsEmitted.add(name);
42
+ log.warn(`[setupPlugins] plugin "${name}" is deprecated and no longer loaded \u2014 ${replacement}`);
43
+ return true;
44
+ }
45
+ function pluginNameFromSpec(spec) {
46
+ if (spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("file:")) {
47
+ return null;
48
+ }
49
+ const parts = spec.split("/");
50
+ const last = parts[parts.length - 1];
51
+ if (!last) return null;
52
+ return last.split("?")[0] ?? null;
53
+ }
54
+ function builtinPluginNameFromSpec(spec) {
55
+ if (BUILTIN_PLUGIN_CONFIG_ALIASES[spec]) return BUILTIN_PLUGIN_CONFIG_ALIASES[spec];
56
+ const bareName = pluginNameFromSpec(spec);
57
+ if (BUILTIN_PLUGIN_CONFIG_NAMES.has(spec)) return bareName ?? spec;
58
+ if (bareName && BUILTIN_PLUGIN_CONFIG_NAMES.has(bareName)) return bareName;
59
+ return null;
60
+ }
61
+ var BUILTIN_PLUGIN_FACTORIES = [
62
+ async () => {
63
+ const { createPromptsPlugin } = await import("@wrongstack/core/plugin");
64
+ return createPromptsPlugin();
65
+ },
66
+ async () => {
67
+ const { createSyncPlugin } = await import("@wrongstack/core/plugin");
68
+ return createSyncPlugin();
69
+ },
70
+ async () => {
71
+ const { createChimeraPlugin } = await import("@wrongstack/core/plugin");
72
+ return createChimeraPlugin();
73
+ },
74
+ async () => {
75
+ const { createAutoReviewPlugin } = await import("@wrongstack/core/plugin");
76
+ return createAutoReviewPlugin();
77
+ },
78
+ async () => {
79
+ const { createSkillsPlugin } = await import("@wrongstack/core/plugin");
80
+ return createSkillsPlugin();
81
+ },
82
+ // ── Workspace plugins (@wrongstack/plugins subpath exports) ──────────
83
+ ...OFFICIAL_PLUGIN_FACTORIES,
84
+ // ── LSP plugin ──────────────────────────────────────────────────────
85
+ async () => (await import("@wrongstack/plug-lsp")).default,
86
+ // ── Telegram plugin ─────────────────────────────────────────────────
87
+ async () => (await import("@wrongstack/telegram")).default
88
+ ];
89
+ async function setupPlugins(params) {
90
+ const {
91
+ config,
92
+ container,
93
+ events,
94
+ toolRegistry,
95
+ providerRegistry,
96
+ slashCommandRegistry,
97
+ mcpRegistry,
98
+ log,
99
+ agent,
100
+ sessionWriter,
101
+ metricsSink,
102
+ metricsStatus,
103
+ modelsRegistry,
104
+ mailbox,
105
+ healthRegistry,
106
+ skillLoader,
107
+ promptLoader,
108
+ configStore,
109
+ vault,
110
+ pipelines,
111
+ paths,
112
+ hookRegistry
113
+ } = params;
114
+ const builtinPlugins = [];
115
+ const disabledBuiltins = new Set(
116
+ (config.plugins ?? []).filter(
117
+ (p) => typeof p === "object" && p.enabled === false
118
+ ).flatMap((p) => {
119
+ const builtinName = builtinPluginNameFromSpec(p.name);
120
+ return builtinName && builtinName !== p.name ? [p.name, builtinName] : [p.name];
121
+ })
122
+ );
123
+ if (paths && config.features?.plugins !== false) {
124
+ for (const factory of BUILTIN_PLUGIN_FACTORIES) {
125
+ try {
126
+ const plugin = await factory();
127
+ if (!plugin) continue;
128
+ const auditEntry = PLUGIN_AUDIT_ENTRIES.find((entry) => entry.name === plugin.name);
129
+ const explicitlyEnabled = (config.plugins ?? []).some((entry) => {
130
+ const spec = typeof entry === "string" ? entry : entry.name;
131
+ if (typeof entry === "object" && entry.enabled === false) return false;
132
+ return (builtinPluginNameFromSpec(spec) ?? spec) === plugin.name;
133
+ });
134
+ if (auditEntry?.defaultState === "inactive" && !explicitlyEnabled) {
135
+ continue;
136
+ }
137
+ if (disabledBuiltins.has(plugin.name)) {
138
+ log.info(`[setupPlugins] built-in plugin "${plugin.name}" disabled by config`);
139
+ continue;
140
+ }
141
+ if (warnIfDeprecatedPluginName(plugin.name, log)) continue;
142
+ builtinPlugins.push(plugin);
143
+ } catch (err) {
144
+ log.warn("[setupPlugins] builtin plugin failed to load:", err);
145
+ }
146
+ }
147
+ }
148
+ const userPlugins = [];
149
+ if (config.features?.plugins !== false) {
150
+ for (const p of config.plugins ?? []) {
151
+ if (typeof p === "object" && p.enabled === false) continue;
152
+ const spec = typeof p === "string" ? p : p.name;
153
+ const bareName = pluginNameFromSpec(spec);
154
+ if (bareName && warnIfDeprecatedPluginName(bareName, log)) {
155
+ continue;
156
+ }
157
+ if (builtinPluginNameFromSpec(spec)) {
158
+ continue;
159
+ }
160
+ try {
161
+ const mod = await import(spec);
162
+ if (mod.default) userPlugins.push(mod.default);
163
+ } catch (err) {
164
+ log.warn(`Plugin "${spec}" failed to load`, err);
165
+ }
166
+ }
167
+ }
168
+ const allPlugins = [...builtinPlugins, ...userPlugins];
169
+ if (allPlugins.length === 0) return;
170
+ const pluginOptions = buildPluginOptions(config, allPlugins);
171
+ if (paths?.projectDir) {
172
+ if (pluginOptions["todo-tracker"] === void 0) {
173
+ pluginOptions["todo-tracker"] = {};
174
+ }
175
+ const todoTrackerOpts = pluginOptions["todo-tracker"];
176
+ if (typeof todoTrackerOpts["filePath"] !== "string" || todoTrackerOpts["filePath"] === "") {
177
+ todoTrackerOpts["filePath"] = join(paths.projectDir, "todo-tracker.json");
178
+ }
179
+ const contextPinsOpts = pluginOptions["context-pins"] ?? {};
180
+ pluginOptions["context-pins"] = contextPinsOpts;
181
+ if (typeof contextPinsOpts["filePath"] !== "string" || contextPinsOpts["filePath"] === "") {
182
+ contextPinsOpts["filePath"] = join(paths.projectDir, "context-pins.json");
183
+ }
184
+ }
185
+ const pluginConfig = patchConfig(config, {
186
+ extensions: pluginOptions,
187
+ paths,
188
+ configStore,
189
+ vault,
190
+ metricsSink,
191
+ metricsStatus,
192
+ healthRegistry,
193
+ skillLoader,
194
+ promptLoader
195
+ });
196
+ const pluginHost = await loadPlugins(allPlugins, {
197
+ log,
198
+ pluginOptions,
199
+ apiFactory: (plugin) => createApi(plugin.name, {
200
+ // First-party plugins come from BUILTIN_PLUGIN_FACTORIES — trust them
201
+ // ("official") so they can claim bare slash command names (/prompts,
202
+ // /sync) and override built-ins. User plugins stay namespaced.
203
+ official: builtinPlugins.includes(plugin),
204
+ container,
205
+ events,
206
+ pipelines,
207
+ toolRegistry,
208
+ providerRegistry,
209
+ slashCommandRegistry,
210
+ mcpRegistry,
211
+ config: pluginConfig,
212
+ log,
213
+ extensions: agent.extensions,
214
+ hookRegistry,
215
+ modelsRegistry,
216
+ mailbox,
217
+ notifier: params.notifier,
218
+ llm: params.llm,
219
+ sessionWriter: {
220
+ transcriptPath: sessionWriter.transcriptPath,
221
+ append: (e) => sessionWriter.append(e)
222
+ },
223
+ metricsSink,
224
+ configStore
225
+ })
226
+ });
227
+ log.info(
228
+ `[setupPlugins] loaded ${builtinPlugins.length} built-in, ${userPlugins.length} user plugin(s)`
229
+ );
230
+ return pluginHost;
231
+ }
232
+ function buildPluginOptions(config, plugins) {
233
+ const options = {};
234
+ for (const [name, value] of Object.entries(config.extensions ?? {})) {
235
+ options[name] = { ...value };
236
+ }
237
+ for (const plugin of plugins) {
238
+ const resolved = resolvePluginConfig({
239
+ name: plugin.name,
240
+ aliases: plugin.configAliases,
241
+ config
242
+ });
243
+ if (resolved.configured) options[plugin.name] = resolved.options;
244
+ }
245
+ return options;
246
+ }
247
+
248
+ export {
249
+ DEPRECATED_PLUGIN_NAMES,
250
+ BUILTIN_PLUGIN_CONFIG_NAMES,
251
+ _resetDeprecatedWarningsForTests,
252
+ warnIfDeprecatedPluginName,
253
+ pluginNameFromSpec,
254
+ builtinPluginNameFromSpec,
255
+ BUILTIN_PLUGIN_FACTORIES,
256
+ setupPlugins
257
+ };
258
+ //# sourceMappingURL=chunk-QUNHS6O3.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/wiring/plugins.ts", "../src/plugin-api-factory.ts"],
4
+ "sourcesContent": ["import { join } from 'node:path';\nimport type { AgentPipelines } from '@wrongstack/core/agent';\nimport type { Config, HealthRegistry, Logger, MetricsRuntimeStatus, MetricsSinkView, ModelsRegistry, Plugin, PromptLoader, SkillLoader } from '@wrongstack/core/types';\nimport type { ExtensionRegistry } from '@wrongstack/core/extension';\nimport type { PluginHostHandle } from '@wrongstack/core/plugin';\nimport type { ConfigStore, SessionWriter } from '@wrongstack/core/types';\nimport type { Container, EventBus } from '@wrongstack/core/kernel';\nimport type { ProviderRegistry, SlashCommandRegistry, ToolRegistry } from '@wrongstack/core/registry';\nimport { loadPlugins, resolvePluginConfig } from '@wrongstack/core/plugin';\nimport type { MCPRegistry } from '@wrongstack/mcp';\nimport { OFFICIAL_PLUGIN_FACTORIES } from '@wrongstack/plugins/factories';\nimport createApi from '../plugin-api-factory.js';\nimport { PLUGIN_AUDIT_ENTRIES } from '../plugin-management.js';\nimport { patchConfig } from '../utils.js';\n\n// ---------------------------------------------------------------------------\n// Deprecated plugin names \u2014 built-ins that have been merged into core\n// tools and no longer ship as separate plugins. We no longer auto-import\n// these factories, and if a user references one of these names in their\n// `config.plugins` we warn once and skip. Removal is split into two\n// phases:\n// 1. Remove the factory from BUILTIN_PLUGIN_FACTORIES (today).\n// 2. Drop the source files + subpath exports + tests from\n// @wrongstack/plugins in a follow-up commit.\n// Keeping the source files temporarily (phase 2) means user configs\n// that hard-code `@wrongstack/plugins/web-search` as a string spec\n// still resolve at runtime \u2014 the loader receives a no-op stub plugin\n// instead of an import error. Once the user removes the entry from\n// their config, the source can be safely deleted.\n// ---------------------------------------------------------------------------\nexport const DEPRECATED_PLUGIN_NAMES: Record<string, string> = {\n 'web-search': 'use the built-in `search` and `fetch` tools',\n 'json-path': 'use the built-in `json` tool with action: query | validate | transform | merge',\n};\n\n// Per-process dedupe so we don't spam the log if a user lists the\n// same deprecated name across multiple config entries (object form\n// + string form, etc.). Cleared on process restart by design \u2014\n// startup noise is fine, mid-session noise is not.\nconst deprecatedWarningsEmitted = new Set<string>();\n\nconst BUILTIN_PLUGIN_CONFIG_ALIASES: Record<string, string> = {\n lsp: '@wrongstack/plug-lsp',\n '@wrongstack/telegram': 'telegram',\n};\n\nexport const BUILTIN_PLUGIN_CONFIG_NAMES = new Set<string>([\n ...PLUGIN_AUDIT_ENTRIES.map((entry) => entry.name),\n ...PLUGIN_AUDIT_ENTRIES.map((entry) => `@wrongstack/plugins/${entry.name}`),\n ...Object.keys(BUILTIN_PLUGIN_CONFIG_ALIASES),\n]);\n\n/** Test helper: reset the dedupe set between test cases. */\nexport function _resetDeprecatedWarningsForTests(): void {\n deprecatedWarningsEmitted.clear();\n}\n\n/**\n * If `name` is in `DEPRECATED_PLUGIN_NAMES`, log a one-shot `warn`\n * describing the migration target and return true (caller should\n * skip the plugin). If the name is deprecated but already warned\n * about, return true WITHOUT logging again \u2014 the caller still needs\n * to know to skip the plugin. For unknown names, return false.\n */\nexport function warnIfDeprecatedPluginName(name: string, log: Logger): boolean {\n const replacement = DEPRECATED_PLUGIN_NAMES[name];\n if (!replacement) return false;\n if (deprecatedWarningsEmitted.has(name)) return true;\n deprecatedWarningsEmitted.add(name);\n log.warn(`[setupPlugins] plugin \"${name}\" is deprecated and no longer loaded \u2014 ${replacement}`);\n return true;\n}\n\n/**\n * Normalize a plugin spec (either a short name like `'web-search'` or a\n * fully-qualified import path like `'@wrongstack/plugins/web-search'`)\n * to its bare plugin name. Used to look the spec up in\n * `DEPRECATED_PLUGIN_NAMES` regardless of how the user spelled it.\n *\n * Returns null if the spec is not a string we can normalize (e.g.\n * relative paths, file URLs).\n */\nexport function pluginNameFromSpec(spec: string): string | null {\n if (spec.startsWith('.') || spec.startsWith('/') || spec.startsWith('file:')) {\n return null;\n }\n // `@scope/name/sub` \u2192 'name'; `@scope/name` \u2192 'name'; `name/sub` \u2192 'name'.\n const parts = spec.split('/');\n const last = parts[parts.length - 1];\n if (!last) return null;\n return last.split('?')[0] ?? null;\n}\n\nexport function builtinPluginNameFromSpec(spec: string): string | null {\n if (BUILTIN_PLUGIN_CONFIG_ALIASES[spec]) return BUILTIN_PLUGIN_CONFIG_ALIASES[spec];\n const bareName = pluginNameFromSpec(spec);\n if (BUILTIN_PLUGIN_CONFIG_NAMES.has(spec)) return bareName ?? spec;\n if (bareName && BUILTIN_PLUGIN_CONFIG_NAMES.has(bareName)) return bareName;\n return null;\n}\n\nexport interface PluginsWiringDeps {\n config: Config;\n container: Container;\n events: EventBus;\n pipelines: AgentPipelines;\n toolRegistry: ToolRegistry;\n providerRegistry: ProviderRegistry;\n slashCommandRegistry: SlashCommandRegistry;\n mcpRegistry: MCPRegistry;\n log: Logger;\n agent: { extensions?: ExtensionRegistry | undefined };\n /** Lifecycle hook registry \u2014 injected so plugins can register in-process hooks. */\n hookRegistry?: import('@wrongstack/core/hooks').HookRegistry | undefined;\n sessionWriter: SessionWriter;\n metricsSink?: MetricsSinkView | undefined;\n metricsStatus?: MetricsRuntimeStatus | undefined;\n /**\n * Models registry (models.dev-backed catalog of providers, models, and\n * per-token pricing). Forwarded to plugins that need model metadata\n * (cost-tracker, billing reports). Optional \u2014 minimal hosts may omit.\n */\n modelsRegistry?: ModelsRegistry | undefined;\n /**\n * Project-level mailbox (server-backed). Forwarded to plugins that\n * publish to other agents (todo-listener, session-recap). Optional \u2014\n * minimal hosts (tests, the LSP server) may omit.\n */\n mailbox?: import('@wrongstack/core/coordination').Mailbox | undefined;\n /**\n * Notification router \u2014 instantiated as a `NotifierImpl` by the host.\n * Plugins that deliver one-way notifications (Telegram, Slack, webhook)\n * register their `NotificationChannel` with this notifier during setup().\n * Optional \u2014 minimal hosts may omit.\n */\n notifier?: import('@wrongstack/core/notifications').Notifier | undefined;\n /**\n * LLM wiring for `api.llm` \u2014 the host session's live provider, its\n * default model, and a factory for named-provider overrides. Optional \u2014\n * minimal hosts omit it and plugins see `api.llm === undefined`.\n */\n llm?:\n | {\n provider: import('@wrongstack/core/types').Provider;\n model: string;\n getProvider?: (() => import('@wrongstack/core/types').Provider) | undefined;\n getModel?: (() => string) | undefined;\n createProvider?:\n | ((name: string, model?: string) => import('@wrongstack/core/types').Provider)\n | undefined;\n }\n | undefined;\n /** Health registry \u2014 injected so the observability built-in can run /health. */\n healthRegistry?: HealthRegistry | undefined;\n /** Skill loader \u2014 injected so the skills built-in can list/read skills. */\n skillLoader?: SkillLoader | undefined;\n /** Prompt loader \u2014 injected so the prompts built-in can list/search/save prompts. */\n promptLoader?: PromptLoader | undefined;\n configStore: ConfigStore;\n /** Secret vault \u2014 injected so sync plugin can encrypt the GitHub token. */\n vault?: { encrypt(plaintext: string): string; decrypt?(value: string): string };\n /** Resolved WstackPaths \u2014 injected so built-in plugins can init stores. */\n paths?: {\n globalRoot: string;\n globalConfig: string;\n globalSkills: string;\n globalPrompts: string;\n globalMemory: string;\n historyFile: string;\n syncConfig: string;\n /** ~/.wrongstack/profiles/<activeProfile> \u2014 used by sync plugin for its state path. */\n configDir: string;\n /**\n * Per-project root (`~/.wrongstack/projects/<slug>/`). Plugins that\n * need project-scoped state (todo-tracker, etc.) should put their\n * files here so they follow the same lifecycle as goals/SDD\n * boards/tasks.\n */\n projectDir?: string;\n /** Per-project goal.json path. Useful as a sibling anchor. */\n projectGoal?: string;\n };\n}\n\n/**\n * Built-in plugins loaded automatically for every WrongStack session.\n * Lazy (dynamic import) so they don't bloat consumers who never use them.\n *\n * Disable a built-in by adding `{ name: 'wstack-prompts', enabled: false }`\n * to config.plugins.\n *\n * Override for tests by mocking this module's `BUILTIN_PLUGIN_FACTORIES`.\n */\nexport const BUILTIN_PLUGIN_FACTORIES: (() => Promise<Plugin>)[] = [\n async () => {\n const { createPromptsPlugin } = await import('@wrongstack/core/plugin');\n return createPromptsPlugin();\n },\n async () => {\n const { createSyncPlugin } = await import('@wrongstack/core/plugin');\n return createSyncPlugin();\n },\n async () => {\n const { createChimeraPlugin } = await import('@wrongstack/core/plugin');\n return createChimeraPlugin();\n },\n async () => {\n const { createAutoReviewPlugin } = await import('@wrongstack/core/plugin');\n return createAutoReviewPlugin();\n },\n async () => {\n const { createSkillsPlugin } = await import('@wrongstack/core/plugin');\n return createSkillsPlugin();\n },\n // \u2500\u2500 Workspace plugins (@wrongstack/plugins subpath exports) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n ...OFFICIAL_PLUGIN_FACTORIES,\n // \u2500\u2500 LSP plugin \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async () => (await import('@wrongstack/plug-lsp')).default,\n // \u2500\u2500 Telegram plugin \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async () => (await import('@wrongstack/telegram')).default,\n];\n\nexport async function setupPlugins(\n params: PluginsWiringDeps,\n): Promise<PluginHostHandle | undefined> {\n const {\n config,\n container,\n events,\n toolRegistry,\n providerRegistry,\n slashCommandRegistry,\n mcpRegistry,\n log,\n agent,\n sessionWriter,\n metricsSink,\n metricsStatus,\n modelsRegistry,\n mailbox,\n healthRegistry,\n skillLoader,\n promptLoader,\n configStore,\n vault,\n pipelines,\n paths,\n hookRegistry,\n } = params;\n\n // \u2500\u2500 1. Load built-in plugins (prompts, sync, git, \u2026) only when paths are\n // available \u2014 they need WstackPaths to initialise their stores.\n //\n // Built-ins are ENABLED BY DEFAULT. A user can opt a specific one out by\n // adding `{ name: 'wstack-git', enabled: false }` to `config.plugins`\n // (or disable all plugins with `config.features.plugins === false`).\n const builtinPlugins: Plugin[] = [];\n const disabledBuiltins = new Set(\n (config.plugins ?? [])\n .filter(\n (p): p is { name: string; enabled?: boolean | undefined } =>\n typeof p === 'object' && p.enabled === false,\n )\n .flatMap((p) => {\n const builtinName = builtinPluginNameFromSpec(p.name);\n return builtinName && builtinName !== p.name ? [p.name, builtinName] : [p.name];\n }),\n );\n if (paths && config.features?.plugins !== false) {\n for (const factory of BUILTIN_PLUGIN_FACTORIES) {\n try {\n const plugin = await factory();\n if (!plugin) continue;\n const auditEntry = PLUGIN_AUDIT_ENTRIES.find((entry) => entry.name === plugin.name);\n const explicitlyEnabled = (config.plugins ?? []).some((entry) => {\n const spec = typeof entry === 'string' ? entry : entry.name;\n if (typeof entry === 'object' && entry.enabled === false) return false;\n return (builtinPluginNameFromSpec(spec) ?? spec) === plugin.name;\n });\n if (auditEntry?.defaultState === 'inactive' && !explicitlyEnabled) {\n continue;\n }\n if (disabledBuiltins.has(plugin.name)) {\n log.info(`[setupPlugins] built-in plugin \"${plugin.name}\" disabled by config`);\n continue;\n }\n // Defensive: if a future PR leaves a deprecated factory in\n // BUILTIN_PLUGIN_FACTORIES, the loader-level deprecation policy\n // still skips it (and warns once per name). Today this branch\n // is unreachable because we removed those factories \u2014 but the\n // check stays so a sloppy re-add doesn't silently re-enable a\n // retired plugin.\n if (warnIfDeprecatedPluginName(plugin.name, log)) continue;\n builtinPlugins.push(plugin);\n } catch (err) {\n log.warn('[setupPlugins] builtin plugin failed to load:', err);\n }\n }\n }\n\n // \u2500\u2500 2. Load user plugins from config.plugins \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const userPlugins: Plugin[] = [];\n if (config.features?.plugins !== false) {\n for (const p of config.plugins ?? []) {\n if (typeof p === 'object' && p.enabled === false) continue;\n const spec = typeof p === 'string' ? p : p.name;\n // Deprecation policy: if the spec resolves to a deprecated plugin\n // name (either as `'web-search'` or `'@wrongstack/plugins/web-search'`),\n // warn once and skip the dynamic import. Today this means\n // web-search/json-path stub plugins silently load \u2014 after the\n // source files are deleted (phase 2), this branch becomes the\n // only line of defense.\n const bareName = pluginNameFromSpec(spec);\n if (bareName && warnIfDeprecatedPluginName(bareName, log)) {\n continue;\n }\n if (builtinPluginNameFromSpec(spec)) {\n continue;\n }\n try {\n const mod = (await import(spec)) as { default?: Plugin | undefined };\n if (mod.default) userPlugins.push(mod.default);\n } catch (err) {\n log.warn(`Plugin \"${spec}\" failed to load`, err);\n }\n }\n }\n\n // \u2500\u2500 3. Merge: builtins first (they set up infrastructure), then user plugins\n const allPlugins = [...builtinPlugins, ...userPlugins];\n if (allPlugins.length === 0) return;\n\n const pluginOptions = buildPluginOptions(config, allPlugins);\n\n // Workspace plugins that persist project-scoped state read ONLY their own\n // namespaced `config.extensions[name]` options \u2014 they never see the\n // top-level `paths` injected below. Bridge that gap for todo-tracker by\n // seeding a default `filePath` derived from `paths.projectDir` when the\n // user hasn't set one explicitly. This mirrors how goals/SDD boards/tasks\n // live under `~/.wrongstack/projects/<slug>/` and follows the intent\n // documented on `PluginsWiringDeps.paths.projectDir`.\n if (paths?.projectDir) {\n if (pluginOptions['todo-tracker'] === undefined) {\n pluginOptions['todo-tracker'] = {};\n }\n const todoTrackerOpts = pluginOptions['todo-tracker'];\n if (typeof todoTrackerOpts['filePath'] !== 'string' || todoTrackerOpts['filePath'] === '') {\n todoTrackerOpts['filePath'] = join(paths.projectDir, 'todo-tracker.json');\n }\n // context-pins persists pinned facts the same way \u2014 project-scoped,\n // next to goals/SDD boards/todo-tracker.\n const contextPinsOpts = pluginOptions['context-pins'] ?? {};\n pluginOptions['context-pins'] = contextPinsOpts;\n if (typeof contextPinsOpts['filePath'] !== 'string' || contextPinsOpts['filePath'] === '') {\n contextPinsOpts['filePath'] = join(paths.projectDir, 'context-pins.json');\n }\n }\n\n // Built-in plugins read their host dependencies off the TOP LEVEL of the\n // config object they receive (e.g. prompts/sync use `config.paths` /\n // `config.configStore`, observability uses `config.metricsSink` /\n // `config.healthRegistry`). Inject them here so each can wire up its store or\n // view without a circular import. User plugins never see these \u2014 they only\n // read their own namespaced `config.extensions[name]` options.\n const pluginConfig = patchConfig(config, {\n extensions: pluginOptions,\n paths,\n configStore,\n vault,\n metricsSink,\n metricsStatus,\n healthRegistry,\n skillLoader,\n promptLoader,\n } as Partial<Config>);\n\n const pluginHost = await loadPlugins(allPlugins, {\n log,\n pluginOptions,\n apiFactory: (plugin) =>\n createApi(plugin.name, {\n // First-party plugins come from BUILTIN_PLUGIN_FACTORIES \u2014 trust them\n // (\"official\") so they can claim bare slash command names (/prompts,\n // /sync) and override built-ins. User plugins stay namespaced.\n official: builtinPlugins.includes(plugin),\n container,\n events,\n pipelines: pipelines as never as Parameters<typeof createApi>[1]['pipelines'],\n toolRegistry,\n providerRegistry,\n slashCommandRegistry,\n mcpRegistry,\n config: pluginConfig,\n log,\n extensions: agent.extensions,\n hookRegistry,\n modelsRegistry,\n mailbox,\n notifier: params.notifier,\n llm: params.llm,\n sessionWriter: {\n transcriptPath: sessionWriter.transcriptPath,\n append: (e: Record<string, unknown> & { type: string; ts: string }) =>\n sessionWriter.append(e as Parameters<typeof sessionWriter.append>[0]),\n },\n metricsSink,\n configStore,\n }),\n });\n\n log.info(\n `[setupPlugins] loaded ${builtinPlugins.length} built-in, ${userPlugins.length} user plugin(s)`,\n );\n return pluginHost;\n}\n\nfunction buildPluginOptions(\n config: Config,\n plugins: readonly Plugin[],\n): Record<string, Record<string, unknown>> {\n const options: Record<string, Record<string, unknown>> = {};\n for (const [name, value] of Object.entries(config.extensions ?? {})) {\n options[name] = { ...value };\n }\n for (const plugin of plugins) {\n const resolved = resolvePluginConfig({\n name: plugin.name,\n aliases: plugin.configAliases,\n config,\n });\n if (resolved.configured) options[plugin.name] = resolved.options;\n }\n return options;\n}\n", "import { DefaultPluginAPI, type PluginAPI, type PluginAPIInit } from '@wrongstack/core/plugin';\n\nexport default function createApi(\n ownerName: string,\n base: Omit<PluginAPIInit, 'ownerName'>,\n): PluginAPI {\n return new DefaultPluginAPI({ ownerName, ...base });\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }