@wrongstack/cli 0.296.4 → 0.298.0

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 (523) hide show
  1. package/dist/{acp-A5OSIU2P.js → acp-S4LZQB66.js} +91 -23
  2. package/dist/{auth-CJWQJVRH.js → auth-NLLGEYQR.js} +3 -3
  3. package/dist/boot/dispatch-webui.d.ts +7 -0
  4. package/dist/boot/governance-evidence-candidate.d.ts +3 -0
  5. package/dist/boot/governance-shadow-bridge.d.ts +19 -0
  6. package/dist/boot/governance-trace-context.d.ts +64 -0
  7. package/dist/boot/launch-banner.d.ts +22 -0
  8. package/dist/boot/tui-session-resume.d.ts +10 -1
  9. package/dist/chimera-leader-wake.d.ts +57 -0
  10. package/dist/chimera-reviewer-policy.d.ts +89 -1
  11. package/dist/chimera-subagent-ladder.d.ts +72 -0
  12. package/dist/{chunk-AZESNNIC.js → chunk-4HH3YGG4.js} +3 -3
  13. package/dist/{chunk-IHBYBYGA.js → chunk-A6Q5KGLV.js} +51 -18
  14. package/dist/{chunk-ABXK4VVY.js → chunk-ARWGQUB3.js} +2 -1
  15. package/dist/{chunk-OI7GWJDS.js → chunk-C5GH4YBL.js} +1389 -184
  16. package/dist/{chunk-TADVX644.js → chunk-GO3TJICK.js} +11 -2
  17. package/dist/{chunk-JBTFWWKV.js → chunk-I2BM6FK6.js} +9 -4
  18. package/dist/{chunk-AXVZMEWG.js → chunk-I5MEUFDI.js} +2 -2
  19. package/dist/{chunk-WY7KKOUK.js → chunk-JW75HY4F.js} +31 -10
  20. package/dist/chunk-U3SS4NRH.js +10 -0
  21. package/dist/{chunk-Z7YGASQP.js → chunk-V3XH6XBJ.js} +30 -26
  22. package/dist/{chunk-BQCAJ7FI.js → chunk-XTIXVJXP.js} +16 -3
  23. package/dist/{cli-main-TOAWVJDY.js → cli-main-TJEU4OUY.js} +25912 -25134
  24. package/dist/cli-main-helpers.d.ts +42 -2
  25. package/dist/{execution-O7I5DYE6.js → execution-INOV5P7N.js} +1264 -650
  26. package/dist/execution-chimera-cascade.d.ts +7 -1
  27. package/dist/execution-chimera-review.d.ts +35 -0
  28. package/dist/fleet/host-types.d.ts +6 -1
  29. package/dist/fleet-statusline.d.ts +1 -0
  30. package/dist/goal-host.d.ts +1 -1
  31. package/dist/governance-V2Z42RBE.js +65 -0
  32. package/dist/governance-hq-telemetry.d.ts +17 -0
  33. package/dist/{hq-JUYKUNJX.js → hq-WO6CLUSI.js} +2 -2
  34. package/dist/hq-publisher.d.ts +3 -2
  35. package/dist/hq-server/auth.d.ts +33 -2
  36. package/dist/hq-server/login-attempt-store.d.ts +73 -0
  37. package/dist/hq-server/routes/auth-handlers.d.ts +73 -5
  38. package/dist/hq-server/routes.d.ts +5 -5
  39. package/dist/hq-server/types.d.ts +44 -2
  40. package/dist/hq-server/utils.d.ts +51 -6
  41. package/dist/hq-server/ws.d.ts +61 -2
  42. package/dist/{hq-server-6AQ3BXZA.js → hq-server-6TSAORAC.js} +2 -2
  43. package/dist/hq-server.d.ts +10 -0
  44. package/dist/index.js +337 -42
  45. package/dist/kanban-hq-sync.d.ts +13 -1
  46. package/dist/live-settings-input.d.ts +10 -1
  47. package/dist/{mailbox-serve-2UWHEN3M.js → mailbox-serve-DBOOOOWZ.js} +50 -8
  48. package/dist/{sdd-runtime-JG4EEKL6.js → sdd-runtime-AIJCJGWC.js} +2 -2
  49. package/dist/services/sdd/state.d.ts +3 -3
  50. package/dist/settings-menu.d.ts +1 -1
  51. package/dist/slash-commands/command-context.d.ts +2 -0
  52. package/dist/slash-commands/fallback.d.ts +2 -0
  53. package/dist/slash-commands/goal-refiner.d.ts +1 -1
  54. package/dist/slash-commands/goal.d.ts +1 -1
  55. package/dist/subcommands/handlers/acp-connection-gate.d.ts +20 -0
  56. package/dist/subcommands/handlers/governance.d.ts +8 -0
  57. package/dist/{update-YC4TYW2Y.js → update-MV6TUACD.js} +3 -3
  58. package/dist/utils/win32-cmd.d.ts +9 -6
  59. package/dist/{version-help-DROHZRW6.js → version-help-ASKQYXDJ.js} +2 -2
  60. package/dist/webui-server/kanban-host-adapter.d.ts +1 -1
  61. package/dist/webui-server/session-start-payload.d.ts +4 -0
  62. package/dist/{webui-server-ZF5KVGC5.js → webui-server-PCLSXX6L.js} +164 -134
  63. package/dist/webui-server-options.d.ts +7 -0
  64. package/dist/wiring/brain-and-orchestration.d.ts +2 -0
  65. package/dist/wiring/hq-telemetry.d.ts +4 -3
  66. package/dist/wiring/lifecycle-plugins.d.ts +5 -8
  67. package/dist/wiring/metrics.d.ts +1 -1
  68. package/dist/wiring/provider-runtime-setup.d.ts +2 -2
  69. package/package.json +23 -22
  70. package/dist/acp-A5OSIU2P.js.map +0 -7
  71. package/dist/acp-registry-cache.d.ts.map +0 -1
  72. package/dist/acp-server-agent.d.ts.map +0 -1
  73. package/dist/arg-parser.d.ts.map +0 -1
  74. package/dist/audit-2ZSFGNIF.js.map +0 -7
  75. package/dist/auth-CJWQJVRH.js.map +0 -7
  76. package/dist/auth-menu/add-provider.d.ts.map +0 -1
  77. package/dist/auth-menu/anthropic-oauth.d.ts.map +0 -1
  78. package/dist/auth-menu/auth-menu-audit.d.ts.map +0 -1
  79. package/dist/auth-menu/direct.d.ts.map +0 -1
  80. package/dist/auth-menu/github-copilot-oauth.d.ts.map +0 -1
  81. package/dist/auth-menu/helpers.d.ts.map +0 -1
  82. package/dist/auth-menu/index.d.ts.map +0 -1
  83. package/dist/auth-menu/local-presets.d.ts.map +0 -1
  84. package/dist/auth-menu/local.d.ts.map +0 -1
  85. package/dist/auth-menu/loopback-server.d.ts.map +0 -1
  86. package/dist/auth-menu/oauth-menu.d.ts.map +0 -1
  87. package/dist/auth-menu/openai-codex-oauth.d.ts.map +0 -1
  88. package/dist/auth-menu/panel-service.d.ts.map +0 -1
  89. package/dist/auth-menu/provider-menu.d.ts.map +0 -1
  90. package/dist/auth-menu/shared.d.ts.map +0 -1
  91. package/dist/auth-menu/top-menu.d.ts.map +0 -1
  92. package/dist/auth-menu/types.d.ts.map +0 -1
  93. package/dist/auth-menu.d.ts.map +0 -1
  94. package/dist/bench-7ZDWSNEF.js.map +0 -7
  95. package/dist/boot/auto-discover-providers.d.ts.map +0 -1
  96. package/dist/boot/brain-decision-log.d.ts.map +0 -1
  97. package/dist/boot/config-backup-recovery.d.ts.map +0 -1
  98. package/dist/boot/container-wiring.d.ts.map +0 -1
  99. package/dist/boot/dispatch-singleshot.d.ts.map +0 -1
  100. package/dist/boot/dispatch-tui.d.ts.map +0 -1
  101. package/dist/boot/dispatch-webui.d.ts.map +0 -1
  102. package/dist/boot/event-wiring.d.ts.map +0 -1
  103. package/dist/boot/execution-mode.d.ts.map +0 -1
  104. package/dist/boot/launch-menu.d.ts.map +0 -1
  105. package/dist/boot/short-circuit-desktop.d.ts.map +0 -1
  106. package/dist/boot/short-circuit-flags.d.ts.map +0 -1
  107. package/dist/boot/short-circuit-hq.d.ts.map +0 -1
  108. package/dist/boot/simpleui-full-auto.d.ts.map +0 -1
  109. package/dist/boot/system-prompt-builder.d.ts.map +0 -1
  110. package/dist/boot/system-prompt.d.ts.map +0 -1
  111. package/dist/boot/tool-registry.d.ts.map +0 -1
  112. package/dist/boot/tui-coordinator-callbacks.d.ts.map +0 -1
  113. package/dist/boot/tui-coordinator-setup.d.ts.map +0 -1
  114. package/dist/boot/tui-debug-stream.d.ts.map +0 -1
  115. package/dist/boot/tui-goal-wiring.d.ts.map +0 -1
  116. package/dist/boot/tui-live-sessions.d.ts.map +0 -1
  117. package/dist/boot/tui-project-picker-callback.d.ts.map +0 -1
  118. package/dist/boot/tui-project-spawn.d.ts.map +0 -1
  119. package/dist/boot/tui-project-switch.d.ts.map +0 -1
  120. package/dist/boot/tui-runtime-state.d.ts.map +0 -1
  121. package/dist/boot/tui-sdd-callback.d.ts.map +0 -1
  122. package/dist/boot/tui-session-resume.d.ts.map +0 -1
  123. package/dist/boot/tui-settings-adapter.d.ts.map +0 -1
  124. package/dist/boot-config.d.ts.map +0 -1
  125. package/dist/boot.d.ts.map +0 -1
  126. package/dist/brain-menu/panel-service.d.ts.map +0 -1
  127. package/dist/chimera-review-task.d.ts.map +0 -1
  128. package/dist/chimera-reviewer-policy.d.ts.map +0 -1
  129. package/dist/chronicle-QQEQFSSE.js.map +0 -7
  130. package/dist/chunk-5N34EWJR.js.map +0 -7
  131. package/dist/chunk-66T43Q4Y.js.map +0 -7
  132. package/dist/chunk-7OCVIDC7.js.map +0 -7
  133. package/dist/chunk-ABXK4VVY.js.map +0 -7
  134. package/dist/chunk-AXVZMEWG.js.map +0 -7
  135. package/dist/chunk-AZESNNIC.js.map +0 -7
  136. package/dist/chunk-BGFM3PD7.js.map +0 -7
  137. package/dist/chunk-BQCAJ7FI.js.map +0 -7
  138. package/dist/chunk-DPJZQCVP.js.map +0 -7
  139. package/dist/chunk-F4PEGAJZ.js.map +0 -7
  140. package/dist/chunk-IHBYBYGA.js.map +0 -7
  141. package/dist/chunk-JBSQ7ONN.js.map +0 -7
  142. package/dist/chunk-JBTFWWKV.js.map +0 -7
  143. package/dist/chunk-JUHRI6OV.js.map +0 -7
  144. package/dist/chunk-OI7GWJDS.js.map +0 -7
  145. package/dist/chunk-OP47B3IX.js.map +0 -7
  146. package/dist/chunk-PJHET45A.js.map +0 -7
  147. package/dist/chunk-Q5GTM25S.js.map +0 -7
  148. package/dist/chunk-QD544J2B.js.map +0 -7
  149. package/dist/chunk-QUNHS6O3.js.map +0 -7
  150. package/dist/chunk-TADVX644.js.map +0 -7
  151. package/dist/chunk-TGDHN4LM.js.map +0 -7
  152. package/dist/chunk-TYO2OVAD.js.map +0 -7
  153. package/dist/chunk-VCYZ3WZV.js.map +0 -7
  154. package/dist/chunk-VJUEZZYB.js +0 -29
  155. package/dist/chunk-VJUEZZYB.js.map +0 -7
  156. package/dist/chunk-WHOIR577.js.map +0 -7
  157. package/dist/chunk-WY7KKOUK.js.map +0 -7
  158. package/dist/chunk-XJXDOF63.js.map +0 -7
  159. package/dist/chunk-XWEGWYDU.js.map +0 -7
  160. package/dist/chunk-YWUPHRGB.js.map +0 -7
  161. package/dist/chunk-Z7YGASQP.js.map +0 -7
  162. package/dist/cli-bundled-prompts.d.ts.map +0 -1
  163. package/dist/cli-bundled-skills.d.ts.map +0 -1
  164. package/dist/cli-context.d.ts.map +0 -1
  165. package/dist/cli-entry-main.d.ts.map +0 -1
  166. package/dist/cli-entry-point.d.ts.map +0 -1
  167. package/dist/cli-eternal-flag.d.ts.map +0 -1
  168. package/dist/cli-main-TOAWVJDY.js.map +0 -7
  169. package/dist/cli-main-helpers.d.ts.map +0 -1
  170. package/dist/cli-main.d.ts.map +0 -1
  171. package/dist/cli-update-notice.d.ts.map +0 -1
  172. package/dist/config-doctor.d.ts.map +0 -1
  173. package/dist/config-history.d.ts.map +0 -1
  174. package/dist/context-limit.d.ts.map +0 -1
  175. package/dist/context-overflow-diagnostic.d.ts.map +0 -1
  176. package/dist/diag-doctor-OQ3AA63O.js.map +0 -7
  177. package/dist/diff-renderer.d.ts.map +0 -1
  178. package/dist/execute-deps.d.ts.map +0 -1
  179. package/dist/execution-O7I5DYE6.js.map +0 -7
  180. package/dist/execution-chimera-ask.d.ts.map +0 -1
  181. package/dist/execution-chimera-cascade.d.ts.map +0 -1
  182. package/dist/execution-cleanup.d.ts.map +0 -1
  183. package/dist/execution-kanban-dispatch.d.ts.map +0 -1
  184. package/dist/execution-repl-fleet-callbacks.d.ts.map +0 -1
  185. package/dist/execution-storage-observability.d.ts.map +0 -1
  186. package/dist/execution-tui-next-step-callbacks.d.ts.map +0 -1
  187. package/dist/execution.d.ts.map +0 -1
  188. package/dist/export-TPORYVRZ.js.map +0 -7
  189. package/dist/fleet/host-acp-runner-cache.d.ts.map +0 -1
  190. package/dist/fleet/host-acp.d.ts.map +0 -1
  191. package/dist/fleet/host-concurrency.d.ts.map +0 -1
  192. package/dist/fleet/host-context.d.ts.map +0 -1
  193. package/dist/fleet/host-director-builder.d.ts.map +0 -1
  194. package/dist/fleet/host-director-event-bridges.d.ts.map +0 -1
  195. package/dist/fleet/host-director-services.d.ts.map +0 -1
  196. package/dist/fleet/host-event-bridge.d.ts.map +0 -1
  197. package/dist/fleet/host-helpers.d.ts.map +0 -1
  198. package/dist/fleet/host-learning-tracker.d.ts.map +0 -1
  199. package/dist/fleet/host-learning.d.ts.map +0 -1
  200. package/dist/fleet/host-lifecycle-events.d.ts.map +0 -1
  201. package/dist/fleet/host-paths.d.ts.map +0 -1
  202. package/dist/fleet/host-provider.d.ts.map +0 -1
  203. package/dist/fleet/host-session-writer.d.ts.map +0 -1
  204. package/dist/fleet/host-shadow-pass.d.ts.map +0 -1
  205. package/dist/fleet/host-spawn-types.d.ts.map +0 -1
  206. package/dist/fleet/host-status.d.ts.map +0 -1
  207. package/dist/fleet/host-subagent-factory.d.ts.map +0 -1
  208. package/dist/fleet/host-supervisor.d.ts.map +0 -1
  209. package/dist/fleet/host-task-result-report.d.ts.map +0 -1
  210. package/dist/fleet/host-types.d.ts.map +0 -1
  211. package/dist/fleet/host.d.ts.map +0 -1
  212. package/dist/fleet/routing.d.ts.map +0 -1
  213. package/dist/fleet/status-broadcast.d.ts.map +0 -1
  214. package/dist/fleet/supervisor-registry.d.ts.map +0 -1
  215. package/dist/fleet-statusline.d.ts.map +0 -1
  216. package/dist/goal-host.d.ts.map +0 -1
  217. package/dist/hooks-wiring.d.ts.map +0 -1
  218. package/dist/hq-JUYKUNJX.js.map +0 -7
  219. package/dist/hq-command-controller.d.ts.map +0 -1
  220. package/dist/hq-publisher.d.ts.map +0 -1
  221. package/dist/hq-recovery-html.d.ts.map +0 -1
  222. package/dist/hq-server/audit-actor.d.ts.map +0 -1
  223. package/dist/hq-server/auth-state.d.ts.map +0 -1
  224. package/dist/hq-server/auth.d.ts.map +0 -1
  225. package/dist/hq-server/preflight.d.ts.map +0 -1
  226. package/dist/hq-server/project-root.d.ts.map +0 -1
  227. package/dist/hq-server/routes/auth-handlers.d.ts.map +0 -1
  228. package/dist/hq-server/routes/session-handlers.d.ts.map +0 -1
  229. package/dist/hq-server/routes/system-handlers.d.ts.map +0 -1
  230. package/dist/hq-server/routes.d.ts.map +0 -1
  231. package/dist/hq-server/snapshot.d.ts.map +0 -1
  232. package/dist/hq-server/startup.d.ts.map +0 -1
  233. package/dist/hq-server/trust-boundary.d.ts.map +0 -1
  234. package/dist/hq-server/types.d.ts.map +0 -1
  235. package/dist/hq-server/utils.d.ts.map +0 -1
  236. package/dist/hq-server/ws.d.ts.map +0 -1
  237. package/dist/hq-server-6AQ3BXZA.js.map +0 -7
  238. package/dist/hq-server.d.ts.map +0 -1
  239. package/dist/hq-static-serve.d.ts.map +0 -1
  240. package/dist/hq-ttl-U2FAYFAT.js.map +0 -7
  241. package/dist/hq-tunnel-RFKGC4HI.js.map +0 -7
  242. package/dist/hq-tunnel.d.ts.map +0 -1
  243. package/dist/index.d.ts.map +0 -1
  244. package/dist/index.js.map +0 -7
  245. package/dist/init-E2NDDOHI.js.map +0 -7
  246. package/dist/input-reader.d.ts.map +0 -1
  247. package/dist/kanban-dispatch-route.d.ts.map +0 -1
  248. package/dist/kanban-hq-sync.d.ts.map +0 -1
  249. package/dist/kanban-run-mirror-EKVNGXWW.js.map +0 -7
  250. package/dist/launch-hints.d.ts.map +0 -1
  251. package/dist/live-settings-input.d.ts.map +0 -1
  252. package/dist/mailbox-bridge-bootstrap.d.ts.map +0 -1
  253. package/dist/mailbox-serve-2UWHEN3M.js.map +0 -7
  254. package/dist/mcp-CYLPUEHC.js.map +0 -7
  255. package/dist/mcp-serve.d.ts.map +0 -1
  256. package/dist/modeldiag-HENYJ4N7.js.map +0 -7
  257. package/dist/multi-agent.d.ts.map +0 -1
  258. package/dist/next-task-predictor.d.ts.map +0 -1
  259. package/dist/permission-prompt.d.ts.map +0 -1
  260. package/dist/permissions-FNYLZIL4.js.map +0 -7
  261. package/dist/picker-key-state.d.ts.map +0 -1
  262. package/dist/picker-model-picker.d.ts.map +0 -1
  263. package/dist/picker-ui.d.ts.map +0 -1
  264. package/dist/picker.d.ts.map +0 -1
  265. package/dist/plugin-api-factory.d.ts.map +0 -1
  266. package/dist/plugin-management.d.ts.map +0 -1
  267. package/dist/plugin-usage-OU6X6LM3.js.map +0 -7
  268. package/dist/plugins-4LJ5IUBI.js.map +0 -7
  269. package/dist/pre-launch/launch-prompts.d.ts.map +0 -1
  270. package/dist/pre-launch/project-check.d.ts.map +0 -1
  271. package/dist/pre-launch.d.ts.map +0 -1
  272. package/dist/preflight.d.ts.map +0 -1
  273. package/dist/profile-config-path.d.ts.map +0 -1
  274. package/dist/project-BLQ3ALVL.js.map +0 -7
  275. package/dist/project-manifest-GE25PW4S.js.map +0 -7
  276. package/dist/project-picker-BOCWHBXP.js.map +0 -7
  277. package/dist/project-picker.d.ts.map +0 -1
  278. package/dist/projects-XE76NFNZ.js.map +0 -7
  279. package/dist/provider-config-utils.d.ts.map +0 -1
  280. package/dist/provider-helpers.d.ts.map +0 -1
  281. package/dist/provider-id.d.ts.map +0 -1
  282. package/dist/providers-models-GDELBHZK.js.map +0 -7
  283. package/dist/quick-VIO2BEHS.js.map +0 -7
  284. package/dist/renderer.d.ts.map +0 -1
  285. package/dist/repl-auto-proceed.d.ts.map +0 -1
  286. package/dist/repl-client-registration.d.ts.map +0 -1
  287. package/dist/repl-input.d.ts.map +0 -1
  288. package/dist/repl-options.d.ts.map +0 -1
  289. package/dist/repl-rendering.d.ts.map +0 -1
  290. package/dist/repl-suggestions.d.ts.map +0 -1
  291. package/dist/repl.d.ts.map +0 -1
  292. package/dist/replay-KCTXNMZQ.js.map +0 -7
  293. package/dist/rewind-EJMVFVLS.js.map +0 -7
  294. package/dist/sdd-runtime-JG4EEKL6.js.map +0 -7
  295. package/dist/services/autonomy-mode.d.ts.map +0 -1
  296. package/dist/services/commit-message.d.ts.map +0 -1
  297. package/dist/services/dispatch-classifier.d.ts.map +0 -1
  298. package/dist/services/mcp-management.d.ts.map +0 -1
  299. package/dist/services/project-facts.d.ts.map +0 -1
  300. package/dist/services/project-manifest.d.ts.map +0 -1
  301. package/dist/services/sdd/project-context.d.ts.map +0 -1
  302. package/dist/services/sdd/spec-detection.d.ts.map +0 -1
  303. package/dist/services/sdd/state.d.ts.map +0 -1
  304. package/dist/services/sdd/task-manager.d.ts.map +0 -1
  305. package/dist/services/sdd-runtime.d.ts.map +0 -1
  306. package/dist/services/statusline-config.d.ts.map +0 -1
  307. package/dist/services/suggestion-store.d.ts.map +0 -1
  308. package/dist/session-event-wiring.d.ts.map +0 -1
  309. package/dist/session-stats.d.ts.map +0 -1
  310. package/dist/sessions-config-NLCMK3BY.js.map +0 -7
  311. package/dist/settings-menu.d.ts.map +0 -1
  312. package/dist/shutdown-cleanup.d.ts.map +0 -1
  313. package/dist/simpleui-dist-JIFGUJO7.js.map +0 -7
  314. package/dist/simpleui-dist.d.ts.map +0 -1
  315. package/dist/slash-commands/acp.d.ts.map +0 -1
  316. package/dist/slash-commands/agent-improve.d.ts.map +0 -1
  317. package/dist/slash-commands/agents.d.ts.map +0 -1
  318. package/dist/slash-commands/audit.d.ts.map +0 -1
  319. package/dist/slash-commands/auth.d.ts.map +0 -1
  320. package/dist/slash-commands/autonomy.d.ts.map +0 -1
  321. package/dist/slash-commands/brain.d.ts.map +0 -1
  322. package/dist/slash-commands/btw.d.ts.map +0 -1
  323. package/dist/slash-commands/clear.d.ts.map +0 -1
  324. package/dist/slash-commands/codebase-reindex.d.ts.map +0 -1
  325. package/dist/slash-commands/collab.d.ts.map +0 -1
  326. package/dist/slash-commands/command-context.d.ts.map +0 -1
  327. package/dist/slash-commands/commit-llm.d.ts.map +0 -1
  328. package/dist/slash-commands/compact.d.ts.map +0 -1
  329. package/dist/slash-commands/context.d.ts.map +0 -1
  330. package/dist/slash-commands/coordinator.d.ts.map +0 -1
  331. package/dist/slash-commands/delegate.d.ts.map +0 -1
  332. package/dist/slash-commands/design.d.ts.map +0 -1
  333. package/dist/slash-commands/dev.d.ts.map +0 -1
  334. package/dist/slash-commands/diag-stats.d.ts.map +0 -1
  335. package/dist/slash-commands/dispatch-llm.d.ts.map +0 -1
  336. package/dist/slash-commands/doctor.d.ts.map +0 -1
  337. package/dist/slash-commands/enhance.d.ts.map +0 -1
  338. package/dist/slash-commands/ensemble.d.ts.map +0 -1
  339. package/dist/slash-commands/f-keys.d.ts.map +0 -1
  340. package/dist/slash-commands/fallback.d.ts.map +0 -1
  341. package/dist/slash-commands/fix-classifier.d.ts.map +0 -1
  342. package/dist/slash-commands/fix.d.ts.map +0 -1
  343. package/dist/slash-commands/fleet.d.ts.map +0 -1
  344. package/dist/slash-commands/git.d.ts.map +0 -1
  345. package/dist/slash-commands/gitid.d.ts.map +0 -1
  346. package/dist/slash-commands/goal-refiner.d.ts.map +0 -1
  347. package/dist/slash-commands/goal.d.ts.map +0 -1
  348. package/dist/slash-commands/health.d.ts.map +0 -1
  349. package/dist/slash-commands/help.d.ts.map +0 -1
  350. package/dist/slash-commands/helpers.d.ts.map +0 -1
  351. package/dist/slash-commands/hq.d.ts.map +0 -1
  352. package/dist/slash-commands/index.d.ts.map +0 -1
  353. package/dist/slash-commands/init.d.ts.map +0 -1
  354. package/dist/slash-commands/interrupt.d.ts.map +0 -1
  355. package/dist/slash-commands/kanban-agent-helpers.d.ts.map +0 -1
  356. package/dist/slash-commands/kanban-format.d.ts.map +0 -1
  357. package/dist/slash-commands/kanban-help.d.ts.map +0 -1
  358. package/dist/slash-commands/kanban.d.ts.map +0 -1
  359. package/dist/slash-commands/mailbox-demo.d.ts.map +0 -1
  360. package/dist/slash-commands/mailbox-serve.d.ts.map +0 -1
  361. package/dist/slash-commands/mailbox.d.ts.map +0 -1
  362. package/dist/slash-commands/mcp-utils.d.ts.map +0 -1
  363. package/dist/slash-commands/mcp.d.ts.map +0 -1
  364. package/dist/slash-commands/memory-compact.d.ts.map +0 -1
  365. package/dist/slash-commands/memory-flags.d.ts.map +0 -1
  366. package/dist/slash-commands/memory-formatters.d.ts.map +0 -1
  367. package/dist/slash-commands/memory.d.ts.map +0 -1
  368. package/dist/slash-commands/metrics.d.ts.map +0 -1
  369. package/dist/slash-commands/mode.d.ts.map +0 -1
  370. package/dist/slash-commands/modelcaps.d.ts.map +0 -1
  371. package/dist/slash-commands/models.d.ts.map +0 -1
  372. package/dist/slash-commands/mouse.d.ts.map +0 -1
  373. package/dist/slash-commands/next.d.ts.map +0 -1
  374. package/dist/slash-commands/plan.d.ts.map +0 -1
  375. package/dist/slash-commands/plugin.d.ts.map +0 -1
  376. package/dist/slash-commands/profile.d.ts.map +0 -1
  377. package/dist/slash-commands/project-utils.d.ts.map +0 -1
  378. package/dist/slash-commands/project.d.ts.map +0 -1
  379. package/dist/slash-commands/provider-status.d.ts.map +0 -1
  380. package/dist/slash-commands/prune.d.ts.map +0 -1
  381. package/dist/slash-commands/refiner.d.ts.map +0 -1
  382. package/dist/slash-commands/review.d.ts.map +0 -1
  383. package/dist/slash-commands/sdd/rendering.d.ts.map +0 -1
  384. package/dist/slash-commands/sdd-command-helpers.d.ts.map +0 -1
  385. package/dist/slash-commands/sdd-format.d.ts.map +0 -1
  386. package/dist/slash-commands/sdd.d.ts.map +0 -1
  387. package/dist/slash-commands/security.d.ts.map +0 -1
  388. package/dist/slash-commands/session.d.ts.map +0 -1
  389. package/dist/slash-commands/setmodel.d.ts.map +0 -1
  390. package/dist/slash-commands/settings.d.ts.map +0 -1
  391. package/dist/slash-commands/shadow.d.ts.map +0 -1
  392. package/dist/slash-commands/slash-deep-help.d.ts.map +0 -1
  393. package/dist/slash-commands/spawn-agents.d.ts.map +0 -1
  394. package/dist/slash-commands/statusline.d.ts.map +0 -1
  395. package/dist/slash-commands/suggest.d.ts.map +0 -1
  396. package/dist/slash-commands/suggestion-store.d.ts.map +0 -1
  397. package/dist/slash-commands/supervisor.d.ts.map +0 -1
  398. package/dist/slash-commands/surfaces.d.ts.map +0 -1
  399. package/dist/slash-commands/tasks.d.ts.map +0 -1
  400. package/dist/slash-commands/techstack.d.ts.map +0 -1
  401. package/dist/slash-commands/telegram-pairing.d.ts.map +0 -1
  402. package/dist/slash-commands/telegram-settings.d.ts.map +0 -1
  403. package/dist/slash-commands/telegram-setup.d.ts.map +0 -1
  404. package/dist/slash-commands/todos.d.ts.map +0 -1
  405. package/dist/slash-commands/tool.d.ts.map +0 -1
  406. package/dist/slash-commands/tools.d.ts.map +0 -1
  407. package/dist/slash-commands/tuneup.d.ts.map +0 -1
  408. package/dist/slash-commands/working-dir.d.ts.map +0 -1
  409. package/dist/slash-commands/worktree.d.ts.map +0 -1
  410. package/dist/slash-commands/yolo.d.ts.map +0 -1
  411. package/dist/spinner.d.ts.map +0 -1
  412. package/dist/subcommands/contracts.d.ts.map +0 -1
  413. package/dist/subcommands/handlers/acp.d.ts.map +0 -1
  414. package/dist/subcommands/handlers/audit.d.ts.map +0 -1
  415. package/dist/subcommands/handlers/auth-local-help.d.ts.map +0 -1
  416. package/dist/subcommands/handlers/auth.d.ts.map +0 -1
  417. package/dist/subcommands/handlers/bench-run-help.d.ts.map +0 -1
  418. package/dist/subcommands/handlers/bench.d.ts.map +0 -1
  419. package/dist/subcommands/handlers/chronicle.d.ts.map +0 -1
  420. package/dist/subcommands/handlers/config-history.d.ts.map +0 -1
  421. package/dist/subcommands/handlers/diag-doctor.d.ts.map +0 -1
  422. package/dist/subcommands/handlers/export.d.ts.map +0 -1
  423. package/dist/subcommands/handlers/helpers.d.ts.map +0 -1
  424. package/dist/subcommands/handlers/hq.d.ts.map +0 -1
  425. package/dist/subcommands/handlers/init.d.ts.map +0 -1
  426. package/dist/subcommands/handlers/mailbox-serve.d.ts.map +0 -1
  427. package/dist/subcommands/handlers/mcp.d.ts.map +0 -1
  428. package/dist/subcommands/handlers/model-smoke-test.d.ts.map +0 -1
  429. package/dist/subcommands/handlers/modeldiag-profiles.d.ts.map +0 -1
  430. package/dist/subcommands/handlers/modeldiag.d.ts.map +0 -1
  431. package/dist/subcommands/handlers/models-add-help.d.ts.map +0 -1
  432. package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts.map +0 -1
  433. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts.map +0 -1
  434. package/dist/subcommands/handlers/per-subcommand-help-table.d.ts.map +0 -1
  435. package/dist/subcommands/handlers/per-subcommand-help-types.d.ts.map +0 -1
  436. package/dist/subcommands/handlers/per-subcommand-help.d.ts.map +0 -1
  437. package/dist/subcommands/handlers/permissions.d.ts.map +0 -1
  438. package/dist/subcommands/handlers/plugin-usage.d.ts.map +0 -1
  439. package/dist/subcommands/handlers/project.d.ts.map +0 -1
  440. package/dist/subcommands/handlers/projects.d.ts.map +0 -1
  441. package/dist/subcommands/handlers/providers-models.d.ts.map +0 -1
  442. package/dist/subcommands/handlers/quick.d.ts.map +0 -1
  443. package/dist/subcommands/handlers/replay.d.ts.map +0 -1
  444. package/dist/subcommands/handlers/rewind.d.ts.map +0 -1
  445. package/dist/subcommands/handlers/sessions-config.d.ts.map +0 -1
  446. package/dist/subcommands/handlers/sessions-fleet.d.ts.map +0 -1
  447. package/dist/subcommands/handlers/tools-skills.d.ts.map +0 -1
  448. package/dist/subcommands/handlers/update.d.ts.map +0 -1
  449. package/dist/subcommands/handlers/version-help.d.ts.map +0 -1
  450. package/dist/subcommands/index.d.ts.map +0 -1
  451. package/dist/theme.d.ts.map +0 -1
  452. package/dist/tools-skills-UNKLOB7M.js.map +0 -7
  453. package/dist/tui-thinking-word.d.ts.map +0 -1
  454. package/dist/tuneup.d.ts.map +0 -1
  455. package/dist/update-YC4TYW2Y.js.map +0 -7
  456. package/dist/update-check-UMYTOH7Z.js.map +0 -7
  457. package/dist/update-check.d.ts.map +0 -1
  458. package/dist/utils/delay-format.d.ts.map +0 -1
  459. package/dist/utils/hq-ttl.d.ts.map +0 -1
  460. package/dist/utils/win32-cmd.d.ts.map +0 -1
  461. package/dist/utils.d.ts.map +0 -1
  462. package/dist/version-help-DROHZRW6.js.map +0 -7
  463. package/dist/version.d.ts.map +0 -1
  464. package/dist/webui-server/client-registration.d.ts.map +0 -1
  465. package/dist/webui-server/connection-handler.d.ts.map +0 -1
  466. package/dist/webui-server/context-breakdown.d.ts.map +0 -1
  467. package/dist/webui-server/contracts.d.ts.map +0 -1
  468. package/dist/webui-server/cost-helpers.d.ts.map +0 -1
  469. package/dist/webui-server/kanban-host-adapter.d.ts.map +0 -1
  470. package/dist/webui-server/kanban-run-mirror.d.ts.map +0 -1
  471. package/dist/webui-server/kanban-supervisor.d.ts.map +0 -1
  472. package/dist/webui-server/lifecycle.d.ts.map +0 -1
  473. package/dist/webui-server/listen-helpers.d.ts.map +0 -1
  474. package/dist/webui-server/logger-shim.d.ts.map +0 -1
  475. package/dist/webui-server/node-pty-loader.d.ts.map +0 -1
  476. package/dist/webui-server/prefs-seeding.d.ts.map +0 -1
  477. package/dist/webui-server/privileged-actions.d.ts.map +0 -1
  478. package/dist/webui-server/provider-config.d.ts.map +0 -1
  479. package/dist/webui-server/session-start-payload.d.ts.map +0 -1
  480. package/dist/webui-server/setup-events.d.ts.map +0 -1
  481. package/dist/webui-server/static-serve.d.ts.map +0 -1
  482. package/dist/webui-server/stream-coalescer.d.ts.map +0 -1
  483. package/dist/webui-server/terminal-log-view.d.ts.map +0 -1
  484. package/dist/webui-server-ZF5KVGC5.js.map +0 -7
  485. package/dist/webui-server-options.d.ts.map +0 -1
  486. package/dist/webui-server.d.ts.map +0 -1
  487. package/dist/wiring/brain-and-orchestration.d.ts.map +0 -1
  488. package/dist/wiring/codebase-index.d.ts.map +0 -1
  489. package/dist/wiring/command-host-adapters.d.ts.map +0 -1
  490. package/dist/wiring/command-host-state.d.ts.map +0 -1
  491. package/dist/wiring/controllers.d.ts.map +0 -1
  492. package/dist/wiring/dep-watcher-bridge.d.ts.map +0 -1
  493. package/dist/wiring/dep-watcher.d.ts.map +0 -1
  494. package/dist/wiring/design-studio.d.ts.map +0 -1
  495. package/dist/wiring/director-setup.d.ts.map +0 -1
  496. package/dist/wiring/eternal-command-handlers.d.ts.map +0 -1
  497. package/dist/wiring/fleet-command-handlers.d.ts.map +0 -1
  498. package/dist/wiring/hq-telemetry.d.ts.map +0 -1
  499. package/dist/wiring/lifecycle-plugins.d.ts.map +0 -1
  500. package/dist/wiring/mailbox-bridge-bootstrap.d.ts.map +0 -1
  501. package/dist/wiring/management-tools.d.ts.map +0 -1
  502. package/dist/wiring/metrics.d.ts.map +0 -1
  503. package/dist/wiring/pipeline.d.ts.map +0 -1
  504. package/dist/wiring/plugins.d.ts.map +0 -1
  505. package/dist/wiring/provider-runtime-setup.d.ts.map +0 -1
  506. package/dist/wiring/provider-runtime.d.ts.map +0 -1
  507. package/dist/wiring/provider-status.d.ts.map +0 -1
  508. package/dist/wiring/provider-utility-tools.d.ts.map +0 -1
  509. package/dist/wiring/provider.d.ts.map +0 -1
  510. package/dist/wiring/replay.d.ts.map +0 -1
  511. package/dist/wiring/runtime-controller-deps.d.ts.map +0 -1
  512. package/dist/wiring/runtime-dispatch-state.d.ts.map +0 -1
  513. package/dist/wiring/runtime-lifecycle-deps.d.ts.map +0 -1
  514. package/dist/wiring/runtime-picker-deps.d.ts.map +0 -1
  515. package/dist/wiring/sage.d.ts.map +0 -1
  516. package/dist/wiring/sdd-handlers.d.ts.map +0 -1
  517. package/dist/wiring/security-command.d.ts.map +0 -1
  518. package/dist/wiring/session-command-handlers.d.ts.map +0 -1
  519. package/dist/wiring/session-registry.d.ts.map +0 -1
  520. package/dist/wiring/session.d.ts.map +0 -1
  521. package/dist/wiring/slash-commands.d.ts.map +0 -1
  522. package/dist/wiring/to-execute-deps.d.ts.map +0 -1
  523. package/dist/wiring/tools.d.ts.map +0 -1
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/arg-parser.ts", "../src/auth-menu/local-presets.ts", "../src/picker.ts", "../src/picker-key-state.ts", "../src/picker-model-picker.ts", "../src/picker-ui.ts"],
4
- "sourcesContent": ["/**\n * Unified CLI argument parsing. Three parsers that were previously\n * spread across index.ts, subcommands/index.ts, and slash-commands/index.ts.\n */\n\n/** Flags that are boolean-only (no value expected after them). */\nexport const BOOLEAN_FLAGS = new Set([\n 'yolo',\n 'no-yolo',\n 'yolo-destructive',\n 'confirm-destructive',\n 'force-all-yolo',\n 'verbose',\n 'trace',\n 'help',\n 'version',\n 'yes',\n 'no-banner',\n 'no-features',\n 'tui',\n 'no-tui',\n // Legacy no-ops: every surface now starts fresh unless an explicit\n // `--resume <id>` is supplied. Keep parsing these as booleans so old\n // launch scripts do not accidentally consume the next positional token.\n 'no-recovery',\n 'recover',\n 'output-json',\n 'prompt',\n 'metrics',\n 'webui',\n 'simpleui',\n 'full-auto',\n 'desktop',\n 'open',\n 'webui-require-token',\n 'require-token',\n 'no-check',\n 'no-models-refresh',\n // (removed: 'director' and 'no-director' \u2014 Director Mode is always on)\n 'no-autonomy',\n 'no-hints',\n 'hints',\n 'no-menu',\n 'no-hooks',\n 'skip',\n 'skip-index',\n 'mouse',\n 'no-interactive',\n 'token-saving-mode',\n 'system-lite',\n 'system-pro',\n 'hq',\n 'hq-allow-exec',\n 'tunnel',\n // Opt-in to a non-loopback HQ bind with no token/password configured.\n 'insecure-open',\n 'strict-port',\n 'client',\n // `wstack update` booleans. Keeping these here prevents parseArgs from\n // consuming a following positional token as an accidental flag value.\n 'check-only',\n 'allow-scripts',\n 'lifecycle-scripts',\n 'npm',\n 'pnpm',\n 'yarn',\n 'bun',\n // `wstack acp` booleans. Without these, parseArgs treats the value after\n // `--fs`/`--echo` as the flag's value and eats a following positional\n // (e.g. the agent list in `acp bench --fs gemini-cli,codex-cli`).\n 'echo',\n 'fs',\n // `wstack modeldiag test` booleans. Keep a following positional token from\n // being consumed as the value of one of these switches.\n 'all-models',\n 'plan',\n 'json',\n]);\n\n// ------------------------------------------------------------------ main args\n\nexport interface ParsedArgs {\n flags: Record<string, string | boolean>;\n positional: string[];\n}\n\n/** Parse top-level `wstack` CLI args. */\nexport function parseArgs(argv: string[]): ParsedArgs {\n const flags: Record<string, string | boolean> = {};\n const positional: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (!a) continue;\n if (a === '--') {\n positional.push(...argv.slice(i + 1));\n break;\n }\n if (a.startsWith('--')) {\n const eq = a.indexOf('=');\n if (eq !== -1) {\n flags[a.slice(2, eq)] = a.slice(eq + 1);\n continue;\n }\n const name = a.slice(2);\n if (BOOLEAN_FLAGS.has(name)) {\n flags[name] = true;\n continue;\n }\n if (i + 1 < argv.length && !(argv[i + 1] ?? '').startsWith('-')) {\n flags[name] = argv[++i] ?? '';\n } else {\n flags[name] = true;\n }\n } else if (a.startsWith('-') && a.length === 2) {\n const short = a.slice(1);\n const expand: Record<string, string> = { v: 'verbose', y: 'yes' };\n flags[expand[short] ?? short] = true;\n } else {\n positional.push(a);\n }\n }\n normalizeSurfaceAliases(flags, positional);\n return { flags, positional };\n}\n\n/**\n * Keep the user-facing launch shapes equivalent:\n * wstack --webui == wstack webui\n * wstack --simpleui == wstack simpleui\n * wstack --desktop == wstack desktop\n * wstack --hq == wstack hq / wstack hq serve\n *\n * HQ token management remains a real subcommand (`wstack hq token ...`), so\n * only the bare and explicit serve forms are normalized here.\n */\nfunction normalizeSurfaceAliases(\n flags: Record<string, string | boolean>,\n positional: string[],\n): void {\n // SimpleUI deliberately reuses the WebUI backend/runtime path. Keep its own\n // flag so dispatch can select the independent frontend build, while also\n // setting `webui` so every existing non-interactive surface guard applies.\n if (flags['simpleui']) flags['webui'] = true;\n\n const first = positional[0];\n if (first === 'simpleui') {\n flags['simpleui'] = true;\n flags['webui'] = true;\n positional.splice(0, 1);\n return;\n }\n if (first === 'webui' || first === 'desktop') {\n flags[first] = true;\n positional.splice(0, 1);\n return;\n }\n if (first === 'hq' && (positional.length === 1 || positional[1] === 'serve')) {\n flags['hq'] = true;\n positional.splice(0, positional[1] === 'serve' ? 2 : 1);\n }\n}\n\n// --------------------------------------------------------------- auth flags\n\nexport interface AuthFlags {\n positional: string[];\n label?: string | undefined;\n family?: import('@wrongstack/core/types').WireFamily | undefined;\n baseUrl?: string | undefined;\n envVars?: string[] | undefined;\n}\n\n/** Parse `wstack auth <provider> [--label ...] [--family ...] [...]` flags. */\nexport function parseAuthFlags(args: string[]): AuthFlags {\n const out: AuthFlags = { positional: [] };\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a === '--label') {\n const v = args[++i];\n if (v) out.label = v;\n } else if (a === '--family') {\n const v = args[++i];\n if (v) out.family = v as AuthFlags['family'];\n } else if (a === '--base-url') {\n const v = args[++i];\n if (v) out.baseUrl = v;\n } else if (a === '--env') {\n const v = args[++i];\n if (v)\n out.envVars = v\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n } else if (a && !a.startsWith('--')) {\n out.positional.push(a);\n }\n }\n return out;\n}\n\n// -------------------------------------------------------------- spawn flags\n\nexport interface SpawnFlags {\n description: string;\n opts: {\n provider?: string | undefined;\n model?: string | undefined;\n tools?: string[] | undefined;\n name?: string | undefined;\n };\n}\n\n/**\n * Parse `/spawn` flags from the args head. Supported:\n * --provider=<id> / -p <id> override the subagent's provider id\n * --model=<id> / -m <id> override the subagent's model\n * --name=<label> / -n <label> display name\n * --tools=a,b,c restrict the subagent's tool slice\n *\n * Anything after the last flag is the task description.\n */\nexport function parseSpawnFlags(input: string): SpawnFlags {\n const opts: SpawnFlags['opts'] = {};\n let rest = input;\n const consume = (re: RegExp): RegExpMatchArray | null => {\n const m = rest.match(re);\n if (m) {\n rest = rest.slice(m[0].length).replace(/^\\s+/, '');\n return m;\n }\n return null;\n };\n while (rest.length > 0) {\n let m: RegExpMatchArray | null;\n m = consume(/^--provider=(\\S+)\\s*/);\n if (m) opts.provider = m[1];\n else {\n m = consume(/^--model=(\\S+)\\s*/);\n if (m) opts.model = m[1];\n else {\n m = consume(/^--name=(\"([^\"]+)\"|(\\S+))\\s*/);\n if (m) opts.name = m[2] ?? m[3];\n else {\n m = consume(/^--tools=(\\S+)\\s*/);\n if (m)\n opts.tools = m[1]\n ?.split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n else {\n m = consume(/^-p\\s+(\\S+)\\s*/);\n if (m) opts.provider = m[1];\n else {\n m = consume(/^-m\\s+(\\S+)\\s*/);\n if (m) opts.model = m[1];\n else {\n m = consume(/^-n\\s+(\"([^\"]+)\"|(\\S+))\\s*/);\n if (m) opts.name = m[2] ?? m[3];\n else break;\n }\n }\n }\n }\n }\n }\n }\n return { description: rest.trim(), opts };\n}\n", "import { projectLocalProviderPresets } from '@wrongstack/providers/definitions';\n\nexport type { LocalProviderPresetProjection as LocalLlmPresetEntry } from '@wrongstack/providers/definitions';\nexport const LOCAL_LLM_PRESETS = projectLocalProviderPresets();\n", "import os from 'node:os';\nimport type { Config, ModelsRegistry, ResolvedProvider } from '@wrongstack/core/types';\nimport { color, expectDefined, setOutputLineGuard, setRawMode, stripAnsi, writeOut } from '@wrongstack/core/utils';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport { LOCAL_LLM_PRESETS } from './auth-menu/local-presets.js';\nimport { appendHistory, backupCurrent } from './config-history.js';\nimport type { ReadlineInputReader } from './input-reader.js';\nimport { applyPickerKey, type ProviderPickerState } from './picker-key-state.js';\nimport {\n LIVE_PICKER_MAX_VISIBLE,\n runLiveModelPicker,\n} from './picker-model-picker.js';\nimport {\n boxBottom,\n boxDivider,\n boxRow,\n boxTop,\n codexPickerPreamble,\n keyHints,\n padVisible,\n theme,\n} from './picker-ui.js';\nimport { hasApiKey, isKeylessLocalProvider, visibleModelIds } from './provider-helpers.js';\nimport type { TerminalRenderer } from './renderer.js';\n\nexport { applyPickerKey, type ProviderPickerState } from './picker-key-state.js';\nexport { filterModels, LIVE_PICKER_MAX_VISIBLE, renderLiveModelList } from './picker-model-picker.js';\nexport { codexPickerPreamble } from './picker-ui.js';\n\n/**\n * Filter providers by a free-text query: case-insensitive substring match\n * against the provider id OR display name. An empty/whitespace query returns\n * all providers (as a copy). Input order is preserved. Powers the live\n * type-to-filter provider picker.\n */\n/**\n * Append synthetic entries for the built-in local-server presets\n * (OmniRoute / Ollama / vLLM / LM Studio) that aren't already present in\n * the merged list. These are keyless loopback gateways, so they pass the\n * `isKeylessLocalProvider` filter and become immediately selectable even\n * on a fresh install with no config and no catalog entry \u2014 mirroring the\n * `wstack auth local` shortcut. An entry is skipped when an id-match\n * already exists (catalog or saved config), so a user's customized\n * provider always wins over the preset default. Mutates and returns\n * `merged` for call-site convenience. Pure aside from the push.\n */\nexport function appendLocalPresetProviders(merged: ResolvedProvider[]): ResolvedProvider[] {\n const existing = new Set(merged.map((p) => p.id));\n for (const preset of LOCAL_LLM_PRESETS) {\n if (existing.has(preset.id)) continue;\n merged.push({\n id: preset.id,\n name: preset.label,\n family: 'openai-compatible',\n apiBase: preset.defaultBaseUrl,\n // No env vars \u2192 with a loopback apiBase this reads as a keyless\n // local gateway, so the picker offers it without a key.\n envVars: [],\n // No catalog models yet; OmniRoute/LM Studio/etc. auto-discover at\n // boot or the user picks `m` to set a list. An empty list still\n // lets the provider be chosen \u2014 pickModel surfaces the \"no models\n // listed\" hint and the user can type an id directly.\n models: [],\n });\n }\n return merged;\n}\n\nexport function filterProviders(query: string, providers: ResolvedProvider[]): ResolvedProvider[] {\n const q = query.trim().toLowerCase();\n if (!q) return [...providers];\n return providers.filter(\n (p) => p.id.toLowerCase().includes(q) || p.name.toLowerCase().includes(q),\n );\n}\n\n/** Preferred family display order; remaining families follow in insertion order. */\nconst PROVIDER_FAMILY_PREFERRED_ORDER = [\n 'anthropic',\n 'anthropic-oauth',\n 'openai',\n 'openai-codex',\n 'github-copilot',\n 'google',\n 'openai-compatible',\n];\n\n/**\n * Order providers for display: grouped by wire family in preferred order, then\n * alphabetical by id within each family. Pure. Shared by the live render and\n * the raw-stdin loop so the selection index and the rendered cursor always\n * refer to the same provider.\n */\nfunction orderProvidersForDisplay(filtered: ResolvedProvider[]): ResolvedProvider[] {\n const families = new Map<string, ResolvedProvider[]>();\n for (const p of filtered) {\n const arr = families.get(p.family) ?? [];\n arr.push(p);\n families.set(p.family, arr);\n }\n const order = [\n ...PROVIDER_FAMILY_PREFERRED_ORDER.filter((f) => families.has(f)),\n ...[...families.keys()].filter((f) => !PROVIDER_FAMILY_PREFERRED_ORDER.includes(f)),\n ];\n const flat: ResolvedProvider[] = [];\n for (const fam of order) {\n const arr = (families.get(fam) ?? [])\n .slice()\n .sort((a, b) => a.id.toLowerCase().localeCompare(b.id.toLowerCase()));\n flat.push(...arr);\n }\n return flat;\n}\n\n/**\n * Render the live type-to-filter provider view as one string: the query line,\n * providers grouped by wire family (preferred order, alphabetical within each\n * family), the selected provider marked with \u25B6, and a key hint. Capped to\n * LIVE_PICKER_MAX_VISIBLE rows so a frame always fits the viewport (the raw\n * loop redraws by moving the cursor up and clearing). Pure.\n */\nexport function renderLiveProviderList(\n query: string,\n filtered: ResolvedProvider[],\n selectedIdx: number,\n savedSet?: Set<string>,\n): string {\n const ordered = orderProvidersForDisplay(filtered);\n const scrollOffset = Math.max(0, selectedIdx - LIVE_PICKER_MAX_VISIBLE + 1);\n const visible = ordered.slice(scrollOffset, scrollOffset + LIVE_PICKER_MAX_VISIBLE);\n\n const lines: string[] = [];\n lines.push(boxTop('Select a provider'));\n // Search field. `Select provider: ${query}` is preserved verbatim (tests +\n // the raw-loop cursor math both depend on it). The prompt glyph is accented;\n // a blinking-style caret block trails the query.\n const caret = query.length > 0 ? color.dim('\u258F') : theme.cursor('\u258F');\n lines.push(boxRow(`${theme.accent('\u276F')} ${color.dim('Select provider:')} ${query}${caret}`));\n lines.push(boxDivider());\n\n if (scrollOffset > 0) {\n lines.push(boxRow(color.dim(` ${scrollOffset} more above \u2191`)));\n }\n\n let flat = 0;\n let lastFamily = '';\n for (const p of visible) {\n if (p.family !== lastFamily) {\n // Family section label \u2014 dim, small-caps feel via a leading accent tick.\n lines.push(boxRow(`${theme.accent('\u00B7')} ${color.dim(p.family.toUpperCase())}`));\n lastFamily = p.family;\n }\n const selected = flat === selectedIdx - scrollOffset;\n const sel = selected ? theme.cursor('\u25B6') : ' ';\n let marker: string;\n if (savedSet) {\n const mark = savedSet.has(p.id) ? color.cyan('\u25C9') : color.dim('\u25CB');\n marker = `${sel} ${mark}`;\n } else {\n marker = `${sel}`;\n }\n const id = selected ? theme.accent(color.bold(p.id)) : p.id;\n const name = selected ? p.name : color.dim(p.name);\n lines.push(boxRow(`${marker} ${padVisible(id, 24)} ${name}`));\n flat++;\n }\n\n if (scrollOffset + LIVE_PICKER_MAX_VISIBLE < ordered.length) {\n lines.push(\n boxRow(\n color.dim(` ${ordered.length - scrollOffset - LIVE_PICKER_MAX_VISIBLE} more below \u2193`),\n ),\n );\n }\n\n lines.push(boxDivider());\n lines.push(\n boxRow(\n keyHints([\n ['\u2191\u2193', 'scroll'],\n ['Enter', 'select'],\n ['Esc', 'clear'],\n ['Ctrl+C', 'quit'],\n ]),\n ),\n );\n lines.push(boxBottom());\n return lines.join('\\n');\n}\n\n/**\n * Save provider + model to the global config file.\n * Creates backups + history entries before writing.\n * Returns true if saved successfully.\n */\nexport async function saveToGlobalConfig(\n configPath: string,\n provider: string,\n model: string,\n homeFn: () => string = () => process.env.HOME ?? os.homedir(),\n): Promise<boolean> {\n try {\n const { atomicWrite } = await import('@wrongstack/core/utils');\n const fs = await import('node:fs/promises');\n\n let existing: Record<string, unknown> = {};\n try {\n const raw = await fs.readFile(configPath, 'utf8');\n existing = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // No existing config\n }\n\n const oldCfg = { ...existing };\n existing.provider = provider;\n existing.model = model;\n\n // Backup before writing \u2014 best-effort (never blocks save)\n try {\n await backupCurrent(homeFn, configPath);\n } catch (err) {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'picker.backup_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }),\n );\n }\n\n await atomicWrite(configPath, JSON.stringify(existing, null, 2), { mode: 0o600 });\n\n // Record in history \u2014 best-effort (never blocks save)\n try {\n await appendHistory(\n oldCfg,\n existing,\n `Provider/model changed: ${oldCfg.provider ?? '(none)'} \u2192 ${provider}, ${oldCfg.model ?? '(none)'} \u2192 ${model}`,\n homeFn,\n configPath,\n );\n } catch {\n // best-effort\n }\n\n return true;\n } catch (err) {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'picker.save_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }),\n );\n return false;\n }\n}\n\nexport interface PickerResult {\n provider: string;\n model: string;\n}\n\n/**\n * Interactive provider + model picker. Lists supported providers grouped\n * by wire family \u2014 by default only those with an API key (env or stored\n * config), so you see only what you can actually launch into. Falls back\n * to the full catalog when no keys are found anywhere.\n *\n * When `defaultProvider`/`defaultModel` are passed, they're pre-selected\n * so the user can press Enter to accept the previous choice.\n */\n/**\n * Live type-to-filter provider picker (TTY only). Takes over stdin in raw mode\n * and redraws the filtered, family-grouped list on every keystroke. Thin I/O\n * shell around the pure filterProviders / applyPickerKey / renderLiveProviderList\n * helpers (which are fully unit-tested). Returns the chosen provider, or\n * undefined on cancel. runPicker only calls this when stdin is a TTY; non-TTY\n * callers (CI, piped input, tests) fall through to the numbered readLine picker.\n */\n// Marker used to locate the query line within the rendered (boxed) frame.\n// renderLiveProviderList emits exactly one line containing this literal.\nconst QUERY_MARKER = 'Select provider:';\n\n/**\n * Park the terminal cursor at the end of the live query text inside the\n * boxed frame. The frame is multi-line with a border, so we (1) find which\n * physical line holds the query, (2) move up from the last line to it, then\n * (3) move to the visible column just after the typed query. Visible width\n * is measured with stripAnsi so the box border + accent colors don't offset\n * the cursor.\n */\nfunction cursorToQuery(frame: string, query: string): void {\n const rows = frame.split('\\n');\n const lastIdx = rows.length - 1;\n const queryIdx = rows.findIndex((r) => r.includes(QUERY_MARKER));\n if (queryIdx < 0) return; // frame shape changed unexpectedly \u2014 leave cursor\n const up = lastIdx - queryIdx;\n const queryLine = rows[queryIdx] ?? '';\n // Everything on the query line up to and including the typed query, minus\n // the query text itself, is the visible prefix. We locate the marker, then\n // add the marker + separator + query length in visible columns.\n const plain = stripAnsi(queryLine);\n const markerAt = plain.indexOf(QUERY_MARKER);\n // prefix = columns before the query text = markerAt + marker + ': ' gap.\n const col = markerAt + QUERY_MARKER.length + 1 + query.length + 1;\n if (up > 0) writeOut(`\\x1b[${up}A`);\n writeOut(`\\x1b[${col}G`);\n}\n\nexport async function runLiveProviderPicker(\n displayList: ResolvedProvider[],\n savedSet?: Set<string>,\n): Promise<ResolvedProvider | undefined> {\n const stdin = process.stdin;\n const out = process.stdout;\n if (!stdin.isTTY || !out.isTTY) return undefined;\n\n setOutputLineGuard(null);\n let state: ProviderPickerState = { query: '', selected: 0, status: 'typing' };\n let ordered = orderProvidersForDisplay(filterProviders(state.query, displayList));\n const visibleCount = (): number => ordered.length;\n const clamp = (): void => {\n if (state.selected >= visibleCount()) state.selected = Math.max(0, visibleCount() - 1);\n };\n clamp();\n let frame = renderLiveProviderList(state.query, ordered, state.selected, savedSet);\n writeOut(frame);\n writeOut('\\x1b7');\n cursorToQuery(frame, state.query);\n\n return new Promise<ResolvedProvider | undefined>((resolve) => {\n const wasRaw = stdin.isRaw;\n const wasPaused = stdin.isPaused();\n setRawMode(stdin, true);\n stdin.resume();\n stdin.setEncoding('utf8');\n\n const cleanup = (): void => {\n stdin.off('data', onData);\n setRawMode(stdin, wasRaw);\n if (wasPaused) stdin.pause();\n };\n const repaint = (): void => {\n writeOut('\\x1b8');\n const ups = (frame.match(/\\n/g) ?? []).length;\n writeOut(`\\x1b[${ups}A\\r\\x1b[J`);\n ordered = orderProvidersForDisplay(filterProviders(state.query, displayList));\n clamp();\n frame = renderLiveProviderList(state.query, ordered, state.selected, savedSet);\n writeOut(frame);\n writeOut('\\x1b7');\n cursorToQuery(frame, state.query);\n };\n const onData = (chunk: string): void => {\n ordered = orderProvidersForDisplay(filterProviders(state.query, displayList));\n state = applyPickerKey(state, chunk, visibleCount());\n // applyPickerKey may have changed the query (type/paste) \u2014 recompute against\n // the NEW query before resolving a selection, so a paste like \"zzz\\r\" can't\n // submit a provider from the pre-paste list.\n ordered = orderProvidersForDisplay(filterProviders(state.query, displayList));\n clamp();\n if (state.status === 'cancelled') {\n cleanup();\n writeOut('\\n');\n resolve(undefined);\n return;\n }\n if (state.status === 'submitted') {\n // Query emptied the matches mid-chunk (e.g. paste): stay in the picker.\n if (ordered.length === 0) {\n state = { ...state, status: 'typing' };\n repaint();\n return;\n }\n const pick = ordered[state.selected] ?? ordered[0];\n cleanup();\n writeOut('\\n');\n resolve(pick);\n return;\n }\n repaint();\n };\n stdin.on('data', onData);\n });\n}\n\nexport async function runPicker(deps: {\n modelsRegistry: ModelsRegistry;\n renderer: TerminalRenderer;\n reader: ReadlineInputReader;\n config?: Config | undefined;\n defaultProvider?: string | undefined;\n defaultModel?: string | undefined;\n}): Promise<PickerResult | undefined> {\n const { modelsRegistry, renderer, reader, config, defaultProvider, defaultModel } = deps;\n\n renderer.write(\n `\\n${theme.accent(color.bold('\u258C WrongStack'))} ${color.dim('Provider & Model Selection')}\\n`,\n );\n renderer.write(color.dim(`${theme.chrome('\u00B7')} Loading provider catalog\u2026\\n`));\n\n let providers: ResolvedProvider[];\n try {\n providers = await modelsRegistry.listProviders();\n } catch {\n renderer.writeError(\n 'Failed to load provider catalog. Pass --provider and --model to skip the picker.',\n );\n return undefined;\n }\n\n // Drop unsupported wire families \u2014 they need a plugin and can't be\n // selected through this path.\n const supported = providers.filter((p) => p.family !== 'unsupported');\n\n // Build the display list by overlaying saved config on top of the\n // catalog. Two kinds of saved entries matter:\n // 1. The map key matches a catalog id (`zai-coding-plan`) \u2014 the\n // user may have overridden family/baseUrl. We MUST honor those\n // overrides for grouping/display, otherwise an entry the user\n // saved as `family: \"anthropic\"` would still appear under the\n // catalog's `openai-compatible` group.\n // 2. The map key is an alias not in the catalog. Its `cfg.type` may\n // still point at a catalog id, in which case we inherit the\n // model list and display name from there.\n const catalogById = new Map(supported.map((p) => [p.id, p]));\n const overlay = config?.providers ?? {};\n const seen = new Set<string>();\n const merged: ResolvedProvider[] = [];\n for (const p of supported) {\n const cfg = overlay[p.id];\n seen.add(p.id);\n if (cfg) {\n merged.push({\n ...p,\n family: cfg.family ?? p.family,\n apiBase: cfg.baseUrl ?? p.apiBase,\n envVars: cfg.envVars && cfg.envVars.length > 0 ? cfg.envVars : p.envVars,\n // When the user has saved an explicit model list, it wins \u2014 they\n // know which models their endpoint actually serves (e.g. LM\n // Studio, vLLM, or a proxy with custom model ids). Otherwise the\n // catalog list keeps providing suggestions.\n models: visibleModelIds(\n p.id,\n config ?? ({ providers: {} } as Config),\n p.models.map((m) => m.id),\n cfg,\n ).map((m) => p.models.find((pm) => pm.id === m) ?? { id: m, name: m }),\n });\n } else {\n merged.push(p);\n }\n }\n for (const [id, cfg] of Object.entries(overlay)) {\n if (seen.has(id)) continue;\n if (!cfg?.family || cfg.family === 'unsupported') continue;\n const catalogType = cfg.type && cfg.type !== id ? cfg.type : undefined;\n const inherited = catalogType ? catalogById.get(catalogType) : undefined;\n merged.push({\n id,\n name: inherited ? `${inherited.name} ${color.dim('(alias)')}` : id,\n family: cfg.family,\n apiBase: cfg.baseUrl ?? inherited?.apiBase,\n envVars: cfg.envVars ?? inherited?.envVars ?? [],\n models: visibleModelIds(\n id,\n config ?? ({ providers: {} } as Config),\n (inherited?.models ?? []).map((m) => m.id),\n cfg,\n ).map((m) => inherited?.models.find((pm) => pm.id === m) ?? { id: m, name: m }),\n npm: inherited?.npm,\n });\n }\n\n // Filter to usable providers: those with a key, plus keyless local\n // gateways (omniroute/LiteLLM/\u2026 on a loopback address) which need no\n // credential and so are immediately launchable. If none qualify (fresh\n // install, no env vars set), fall back to the full list and prompt the\n // user to add a key \u2014 picking a keyless provider here is still useful\n // because the very next step (`wstack auth <prov>`) needs to know which.\n const keyed = merged.filter((p) => hasApiKey(p, config) || isKeylessLocalProvider(p));\n let displayList = keyed;\n let showingFallback = false;\n if (keyed.length === 0) {\n displayList = merged;\n // The full-catalog fallback only makes sense when there's actually a\n // catalog to fall back on. With an empty catalog, the only thing we'll\n // show is the keyless local presets (injected below), which need no\n // key \u2014 so don't nag the user about missing keys in that case.\n showingFallback = merged.length > 0;\n }\n\n // Surface the built-in local-server presets (OmniRoute / Ollama / vLLM /\n // LM Studio) that aren't already in the catalog or saved config. Done\n // AFTER the keyed/fallback decision so these always-keyless entries\n // don't suppress the \"no keys anywhere \u2192 show full catalog\" fallback;\n // they're simply appended to whichever list we're about to show.\n appendLocalPresetProviders(displayList);\n\n if (displayList.length === 0) {\n renderer.writeError('No supported providers found in catalog.');\n return undefined;\n }\n\n // TTY: live type-to-filter picker. Non-TTY (CI, piped, tests) falls through\n // to the numbered readLine picker below.\n if (process.stdin.isTTY) {\n const chosen = await runLiveProviderPicker(displayList);\n if (!chosen) {\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n return pickModel(chosen, modelsRegistry, renderer, reader, defaultModel);\n }\n\n // Group by family for nicer display\n const families = new Map<string, ResolvedProvider[]>();\n for (const p of displayList) {\n const list = families.get(p.family) ?? [];\n list.push(p);\n families.set(p.family, list);\n }\n\n // Build a flat numbered list (family \u2192 providers). Track which entry\n // matches the current default so we can highlight + accept Enter.\n const ordered: Array<{ provider: ResolvedProvider; index: number }> = [];\n // Preferred grouping order, then any remaining families present in the list.\n // The trailing append is essential: OAuth / subscription families\n // (anthropic-oauth, openai-codex, github-copilot) live only in saved config,\n // never the catalog \u2014 a fixed allowlist would silently drop them from the\n // launch picker even though they have keys.\n const preferredOrder = [\n 'anthropic',\n 'anthropic-oauth',\n 'openai',\n 'openai-codex',\n 'github-copilot',\n 'google',\n 'openai-compatible',\n ];\n const familyOrder = [\n ...preferredOrder.filter((f) => families.has(f)),\n ...[...families.keys()].filter((f) => !preferredOrder.includes(f)),\n ];\n let idx = 1;\n let defaultIdx: number | undefined;\n renderer.write('\\n');\n renderer.write(`${boxTop('Select a provider')}\\n`);\n for (const fam of familyOrder) {\n // Sort within each family alphabetically (case-insensitive) by id.\n const list = [...(families.get(fam) ?? [])].sort((a, b) =>\n a.id.toLowerCase().localeCompare(b.id.toLowerCase()),\n );\n if (!list || list.length === 0) continue;\n // Family section label \u2014 dim UPPERCASE with a leading accent tick, matching\n // the live picker's grouping. `fam` (a lowercased id) stays contained.\n renderer.write(`${boxRow(`${theme.accent('\u00B7')} ${color.dim(fam.toUpperCase())}`)}\\n`);\n for (const p of list) {\n const envFound = p.envVars.some((v) => !!process.env[v]);\n const entry = config?.providers?.[p.id];\n const configKey =\n (typeof entry?.apiKey === 'string' && entry.apiKey.length > 0) ||\n (Array.isArray(entry?.apiKeys) && entry?.apiKeys?.some((k) => k?.apiKey));\n // \u25CF green = env key, \u25C9 cyan = stored in config, \u25CB dim = no key\n const marker = envFound ? color.green('\u25CF') : configKey ? color.cyan('\u25C9') : color.dim('\u25CB');\n const isDefault = p.id === defaultProvider;\n if (isDefault) defaultIdx = idx;\n const idLabel = isDefault ? theme.accent(color.bold(p.id)) : p.id;\n const suffix = isDefault ? color.dim(' (default)') : '';\n renderer.write(\n `${boxRow(`${color.dim(`${idx}.`.padStart(4))} ${marker} ${padVisible(idLabel, 22)} ${color.dim(p.name)}${suffix}`)}\\n`,\n );\n ordered.push({ provider: p, index: idx });\n idx++;\n }\n }\n\n renderer.write(`${boxDivider()}\\n`);\n if (showingFallback) {\n renderer.write(\n `${boxRow(`${color.yellow('\u26A0 No API keys detected.')} ${color.dim('Run `wstack auth <provider>` after picking.')}`)}\\n`,\n );\n } else {\n renderer.write(`${boxRow(color.dim('\u25CF env key \u25C9 stored in config \u25CB no key'))}\\n`);\n }\n renderer.write(`${boxBottom()}\\n`);\n\n // Provider prompt. Enter on an empty line accepts the default when one\n // is present; otherwise we treat it as cancel.\n const defaultHint =\n defaultIdx !== undefined && defaultProvider\n ? ` ${color.dim(`[Enter = ${defaultProvider}]`)}`\n : '';\n const providerAnswer = (\n await reader.readLine(\n `\\n${color.amber('?')} Select provider (1-${ordered.length})${defaultHint} ${color.dim('[q to quit]')}: `,\n )\n ).trim();\n\n if (providerAnswer.toLowerCase() === 'q') {\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n\n if (!providerAnswer) {\n if (defaultIdx !== undefined) {\n const def = ordered[defaultIdx - 1];\n if (def) return pickModel(def.provider, modelsRegistry, renderer, reader, defaultModel);\n }\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n\n const providerIdx = Number.parseInt(providerAnswer, 10);\n if (Number.isNaN(providerIdx) || providerIdx < 1 || providerIdx > ordered.length) {\n // Try matching by id\n const byId = ordered.find((o) => o.provider.id.toLowerCase() === providerAnswer.toLowerCase());\n if (!byId) {\n renderer.writeError(`Invalid selection: \"${providerAnswer}\"`);\n return undefined;\n }\n return pickModel(byId.provider, modelsRegistry, renderer, reader, defaultModel);\n }\n\n const chosen = ordered[providerIdx - 1];\n if (!chosen) return undefined;\n // Only honor the default-model hint when the user picked the default\n // provider; switching providers invalidates it.\n const modelHint = chosen.provider.id === defaultProvider ? defaultModel : undefined;\n return pickModel(chosen.provider, modelsRegistry, renderer, reader, modelHint);\n}\n\nasync function pickModel(\n provider: ResolvedProvider,\n registry: ModelsRegistry,\n renderer: TerminalRenderer,\n reader: ReadlineInputReader,\n defaultModel?: string | undefined,\n): Promise<PickerResult | undefined> {\n // Boxed header. The `<name> (<id>) models:` text is kept contiguous (a test\n // asserts it verbatim, and colors are no-ops off-TTY).\n renderer.write(`\\n${boxTop('Select a model')}\\n`);\n renderer.write(\n `${boxRow(`${color.bold(provider.name)} ${color.dim(`(${provider.id})`)} models:`)}\\n`,\n );\n renderer.write(`${boxBottom()}\\n`);\n // openai-codex picker mirrors the official Codex CLI header; only current\n // models are listed, but legacy ids remain usable via --model / config.json.\n // Uses the same helper as the live-TTY preamble so the two paths can't drift.\n const codexBlock = codexPickerPreamble(provider);\n if (codexBlock) renderer.write(codexBlock);\n\n const models = [...provider.models].sort((a, b) =>\n (b.release_date ?? '').localeCompare(a.release_date ?? ''),\n );\n\n if (models.length === 0) {\n // No catalog models \u2014 common for a freshly-picked local-server preset\n // (OmniRoute / Ollama / LM Studio / \u2026) whose model list auto-discovers\n // at boot or is known only to the user. Instead of dead-ending, let\n // them type a model id directly. Empty input cancels.\n renderer.write(\n color.dim(\n ' No models listed yet for this provider \u2014 type a model id to use it ' +\n '(local servers auto-discover models at launch).\\n',\n ),\n );\n const typed = (\n await reader.readLine(`\\n${color.amber('?')} Model id ${color.dim('(or Enter to cancel)')}: `)\n ).trim();\n if (!typed) {\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n renderer.write(`\\n ${color.green('\u2713')} ${color.bold(provider.id)} / ${color.bold(typed)}\\n\\n`);\n return { provider: provider.id, model: typed };\n }\n\n // TTY: live type-to-filter model picker. Non-TYY (CI/piped/tests) falls\n // through to the paginated numbered picker below.\n if (process.stdin.isTTY) {\n const chosen = await runLiveModelPicker(provider, defaultModel);\n if (!chosen) {\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n renderer.write(\n `\\n ${color.green('\u2713')} ${color.bold(provider.id)} / ${color.bold(chosen.id)}\\n\\n`,\n );\n return { provider: provider.id, model: chosen.id };\n }\n\n // Find default-model index for the \"Enter = default\" hint.\n const defaultIdxInModels =\n defaultModel !== undefined ? models.findIndex((m) => m.id === defaultModel) : -1;\n\n // Show paginated \u2014 up to 30 at a time\n const pageSize = 30;\n let offset = 0;\n\n while (offset < models.length) {\n const page = models.slice(offset, offset + pageSize);\n const pageFrom = offset + 1;\n const pageTo = Math.min(offset + page.length, models.length);\n // Each page is its own box so pagination prompts sit cleanly between boxes.\n renderer.write(`${boxTop(`Models ${pageFrom}\u2013${pageTo} of ${models.length}`)}\\n`);\n for (let i = 0; i < page.length; i++) {\n const m = expectDefined(page[i]);\n const num = offset + i + 1;\n const ctxRaw = m.limit?.context ? `${(m.limit.context / 1000).toFixed(0)}k` : '?';\n const ctx = theme.ctx(ctxRaw.padStart(6));\n const cost = m.cost?.input !== undefined ? `$${m.cost.input}/$${m.cost.output ?? '?'}` : '';\n const costCol = cost ? theme.cost(cost) : '';\n const capTags: string[] = [];\n if (m.tool_call) capTags.push('tools');\n if (m.reasoning) capTags.push('reason');\n if (m.modalities?.input?.includes('image')) capTags.push('vision');\n const capStr = capTags.map((c) => theme.caps(c)).join(color.dim(' '));\n const isDefault = m.id === defaultModel;\n const idLabel = isDefault ? theme.accent(color.bold(m.id)) : m.id;\n const suffix = isDefault ? color.dim(' (default)') : '';\n const num5 = color.dim(`${num}.`.padStart(5));\n renderer.write(\n `${boxRow(`${num5} ${padVisible(idLabel, 34)} ${ctx} ${padVisible(costCol, 11)} ${capStr}${suffix}`)}\\n`,\n );\n }\n renderer.write(`${boxBottom()}\\n`);\n offset += pageSize;\n\n if (offset < models.length) {\n const more = (\n await reader.readLine(\n `\\n${color.amber('?')} Showing ${Math.min(offset, models.length)}/${models.length} \u2014 Enter number, ${color.dim('Enter')} for more, or ${color.dim('q')} to quit: `,\n )\n ).trim();\n if (more.toLowerCase() === 'q') {\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n if (!more) continue; // show next page\n return resolveModelSelection(more, models, provider, registry, renderer, reader);\n }\n }\n\n // All shown \u2014 final prompt. Enter accepts the default model when present.\n const defaultHint =\n defaultIdxInModels >= 0 && defaultModel ? ` ${color.dim(`[Enter = ${defaultModel}]`)}` : '';\n const answer = (\n await reader.readLine(\n `\\n${color.amber('?')} Select model (1-${models.length})${defaultHint} ${color.dim('[q to quit]')}: `,\n )\n ).trim();\n if (answer.toLowerCase() === 'q') {\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n if (!answer) {\n if (defaultIdxInModels >= 0 && defaultModel) {\n renderer.write(\n `\\n ${color.green('\u2713')} ${color.bold(provider.id)} / ${color.bold(defaultModel)}\\n\\n`,\n );\n return { provider: provider.id, model: defaultModel };\n }\n renderer.write(color.dim('Cancelled.\\n'));\n return undefined;\n }\n return resolveModelSelection(answer, models, provider, registry, renderer, reader);\n}\n\nasync function resolveModelSelection(\n answer: string,\n models: {\n id: string;\n name: string;\n release_date?: string | undefined;\n limit?: { context?: number | undefined };\n cost?: { input?: number | undefined; output?: number | undefined };\n tool_call?: boolean | undefined;\n reasoning?: boolean | undefined;\n modalities?: { input?: string[] | undefined };\n }[],\n provider: ResolvedProvider,\n _registry: ModelsRegistry,\n renderer: TerminalRenderer,\n _reader: ReadlineInputReader,\n): Promise<PickerResult | undefined> {\n const idx = Number.parseInt(answer, 10);\n let modelId: string | undefined;\n\n if (!Number.isNaN(idx) && idx >= 1 && idx <= models.length) {\n modelId = models[idx - 1]?.id;\n } else {\n // Try fuzzy matching by id\n const lower = answer.toLowerCase();\n const match = models.find((m) => m.id.toLowerCase() === lower);\n if (match) {\n modelId = match.id;\n } else {\n // Partial match\n const partial = models.filter((m) => m.id.toLowerCase().includes(lower));\n if (partial.length === 1) {\n modelId = partial[0]?.id;\n } else if (partial.length > 1) {\n renderer.writeError(`\"${answer}\" matches multiple models. Be more specific.`);\n return undefined;\n }\n }\n }\n\n if (!modelId) {\n // Use as-is (user might know the exact model string)\n modelId = answer;\n }\n\n renderer.write(`\\n ${color.green('\u2713')} ${color.bold(provider.id)} / ${color.bold(modelId)}\\n\\n`);\n\n return { provider: provider.id, model: modelId };\n}\n\n// --- Helpers ---\n", "export interface ProviderPickerState {\n query: string;\n selected: number;\n status: 'typing' | 'submitted' | 'cancelled';\n}\n\nexport function applyPickerKey(\n state: ProviderPickerState,\n chunk: string,\n matchCount: number,\n): ProviderPickerState {\n if (chunk === '\\x1b[A') return { ...state, selected: Math.max(0, state.selected - 1) };\n if (chunk === '\\x1b[B')\n return { ...state, selected: Math.min(Math.max(0, matchCount - 1), state.selected + 1) };\n if (chunk === '\\x1b') return { ...state, query: '', selected: 0, status: 'typing' };\n if (chunk.charCodeAt(0) === 0x1b) return state;\n\n let query = state.query;\n let selected = state.selected;\n const status: ProviderPickerState['status'] = 'typing';\n for (const ch of chunk) {\n if (ch === '\\r' || ch === '\\n') {\n return { ...state, status: matchCount > 0 ? 'submitted' : 'typing' };\n }\n if (ch === '\\x03') return { ...state, status: 'cancelled' };\n if (ch === '\\x15') {\n query = '';\n selected = 0;\n continue;\n }\n if (ch === '\\x7f' || ch === '\\b') {\n query = query.slice(0, -1);\n selected = 0;\n continue;\n }\n if (ch >= ' ' && ch !== '\\x7f') {\n query += ch;\n selected = 0;\n }\n }\n return { query, selected, status };\n}\n", "import type { ModelsDevModel, ResolvedProvider } from '@wrongstack/core/types';\nimport { color, expectDefined, setOutputLineGuard, setRawMode, writeOut } from '@wrongstack/core/utils';\nimport { applyPickerKey, type ProviderPickerState } from './picker-key-state.js';\nimport {\n boxBottom,\n boxDivider,\n boxRow,\n boxTop,\n codexPickerPreamble,\n keyHints,\n padVisible,\n theme,\n} from './picker-ui.js';\n\nexport const LIVE_PICKER_MAX_VISIBLE = 15;\n\nexport function filterModels(query: string, models: ModelsDevModel[]): ModelsDevModel[] {\n const q = query.trim().toLowerCase();\n if (!q) return [...models];\n return models.filter((m) => m.id.toLowerCase().includes(q) || m.name.toLowerCase().includes(q));\n}\n\nexport function renderLiveModelList(\n query: string,\n filtered: ModelsDevModel[],\n selectedIdx: number,\n header: string,\n): string {\n const ordered = [...filtered].sort((a, b) =>\n (b.release_date ?? '').localeCompare(a.release_date ?? ''),\n );\n const visible = ordered.slice(0, LIVE_PICKER_MAX_VISIBLE);\n\n const lines: string[] = [];\n lines.push(boxTop('Select a model'));\n lines.push(boxRow(color.dim(header)));\n const caret = query.length > 0 ? color.dim('\u258F') : theme.cursor('\u258F');\n lines.push(boxRow(`${theme.accent('\u276F')} ${color.dim('Select model:')} ${query}${caret}`));\n lines.push(boxDivider());\n\n let flat = 0;\n for (const m of visible) {\n const selected = flat === selectedIdx;\n const marker = selected ? theme.cursor('\u25B6') : ' ';\n const ctxRaw = m.limit?.context ? `${(m.limit.context / 1000).toFixed(0)}k` : '?';\n const ctx = theme.ctx(ctxRaw.padStart(6));\n const costRaw = m.cost?.input !== undefined ? `$${m.cost.input}/$${m.cost.output ?? '?'}` : '';\n const cost = costRaw ? theme.cost(costRaw) : '';\n const capTags: string[] = [];\n if (m.tool_call) capTags.push('tools');\n if (m.reasoning) capTags.push('reason');\n if (m.modalities?.input?.includes('image')) capTags.push('vision');\n const caps = capTags.map((c) => theme.caps(c)).join(color.dim(' '));\n const id = selected ? theme.accent(color.bold(m.id)) : m.id;\n lines.push(boxRow(`${marker} ${padVisible(id, 34)} ${ctx} ${padVisible(cost, 12)} ${caps}`));\n flat++;\n }\n\n if (ordered.length > LIVE_PICKER_MAX_VISIBLE) {\n lines.push(\n boxRow(color.dim(` \u2026 ${ordered.length - LIVE_PICKER_MAX_VISIBLE} more \u2014 type to filter`)),\n );\n }\n lines.push(boxDivider());\n lines.push(\n boxRow(\n keyHints([\n ['\u2191\u2193', 'move'],\n ['Enter', 'select'],\n ['Esc', 'clear'],\n ['Ctrl+C', 'quit'],\n ]),\n ),\n );\n lines.push(boxBottom());\n return lines.join('\\n');\n}\n\nexport async function runLiveModelPicker(\n provider: ResolvedProvider,\n defaultModel?: string,\n): Promise<ModelsDevModel | undefined> {\n const stdin = process.stdin;\n const out = process.stdout;\n if (!stdin.isTTY || !out.isTTY) return undefined;\n\n const header = `${provider.name} (${provider.id}) models:`;\n const byNewest = (a: ModelsDevModel, b: ModelsDevModel): number =>\n (b.release_date ?? '').localeCompare(a.release_date ?? '');\n const ranked = [...provider.models].sort(byNewest);\n const defaultIdx =\n defaultModel !== undefined ? ranked.findIndex((m) => m.id === defaultModel) : -1;\n\n setOutputLineGuard(null);\n let state: ProviderPickerState = {\n query: '',\n selected: defaultIdx >= 0 ? defaultIdx : 0,\n status: 'typing',\n };\n const order = (filtered: ModelsDevModel[]): ModelsDevModel[] => [...filtered].sort(byNewest);\n let ordered = order(filterModels(state.query, provider.models));\n const visibleCount = (): number => Math.min(ordered.length, LIVE_PICKER_MAX_VISIBLE);\n const clamp = (): void => {\n if (state.selected >= visibleCount()) state.selected = Math.max(0, visibleCount() - 1);\n };\n clamp();\n const preamble = codexPickerPreamble(provider);\n if (preamble) writeOut(preamble);\n let frame = renderLiveModelList(state.query, ordered, state.selected, header);\n writeOut(frame);\n\n return new Promise<ModelsDevModel | undefined>((resolve) => {\n const wasRaw = stdin.isRaw;\n const wasPaused = stdin.isPaused();\n setRawMode(stdin, true);\n stdin.resume();\n stdin.setEncoding('utf8');\n\n const cleanup = (): void => {\n stdin.off('data', onData);\n setRawMode(stdin, wasRaw);\n if (wasPaused) stdin.pause();\n };\n const repaint = (): void => {\n const ups = (frame.match(/\\n/g) ?? []).length;\n writeOut(`\\x1b[${ups}A\\r\\x1b[J`);\n ordered = order(filterModels(state.query, provider.models));\n clamp();\n frame = renderLiveModelList(state.query, ordered, state.selected, header);\n writeOut(frame);\n };\n const onData = (chunk: string): void => {\n ordered = order(filterModels(state.query, provider.models));\n state = applyPickerKey(state, chunk, visibleCount());\n ordered = order(filterModels(state.query, provider.models));\n clamp();\n if (state.status === 'cancelled') {\n cleanup();\n writeOut('\\n');\n resolve(undefined);\n return;\n }\n if (state.status === 'submitted') {\n if (ordered.length === 0) {\n state = { ...state, status: 'typing' };\n repaint();\n return;\n }\n const pick = ordered[state.selected] ?? expectDefined(ordered[0]);\n cleanup();\n writeOut('\\n');\n resolve(pick);\n return;\n }\n repaint();\n };\n stdin.on('data', onData);\n });\n}\n", "import type { ResolvedProvider } from '@wrongstack/core/types';\nimport { color, stripAnsi } from '@wrongstack/core/utils';\n\nexport const theme = {\n accent: color.amber,\n chrome: color.gray,\n cursor: (s: string): string => color.amber(color.bold(s)),\n ctx: color.cyan,\n cost: color.green,\n caps: color.magenta,\n};\n\nconst BOX = {\n tl: '\u256D',\n tr: '\u256E',\n bl: '\u2570',\n br: '\u256F',\n h: '\u2500',\n v: '\u2502',\n} as const;\n\nconst PICKER_MIN_WIDTH = 74;\nconst PICKER_MAX_WIDTH = 100;\n\nfunction pickerWidth(): number {\n const cols = process.stdout.columns;\n if (typeof cols !== 'number' || !Number.isFinite(cols) || cols <= 0) {\n return PICKER_MIN_WIDTH;\n }\n return Math.max(PICKER_MIN_WIDTH, Math.min(PICKER_MAX_WIDTH, cols - 2));\n}\n\nfunction visibleWidth(s: string): number {\n return stripAnsi(s).length;\n}\n\nexport function padVisible(s: string, width: number): string {\n const w = visibleWidth(s);\n if (w === width) return s;\n if (w < width) return s + ' '.repeat(width - w);\n const plain = stripAnsi(s);\n return `${plain.slice(0, Math.max(0, width - 1))}\u2026`;\n}\n\nexport function boxTop(title: string): string {\n const width = pickerWidth();\n const label = ` ${title} `;\n const pad = Math.max(0, width - visibleWidth(label) - 1);\n return theme.chrome(\n `${BOX.tl}${BOX.h}${theme.accent(color.bold(label))}${theme.chrome(BOX.h.repeat(pad))}${BOX.tr}`,\n );\n}\n\nexport function boxBottom(): string {\n return theme.chrome(`${BOX.bl}${BOX.h.repeat(pickerWidth())}${BOX.br}`);\n}\n\nexport function boxRow(content: string): string {\n return `${theme.chrome(BOX.v)} ${padVisible(content, pickerWidth() - 2)} ${theme.chrome(BOX.v)}`;\n}\n\nexport function boxDivider(): string {\n return theme.chrome(`${BOX.v}${BOX.h.repeat(pickerWidth())}${BOX.v}`);\n}\n\nexport function keyHints(pairs: Array<[string, string]>): string {\n return pairs.map(([k, label]) => `${theme.accent(k)} ${color.dim(label)}`).join(color.dim(' \u00B7 '));\n}\n\nconst CODEX_PROVIDER_ID = 'openai-codex';\nconst CODEX_PICKER_HEADER = 'Select Model and Effort';\nconst CODEX_LEGACY_NOTE =\n 'Access legacy models by running `wstack -m <model_name>` or in your `config.json`.';\n\nexport function codexPickerPreamble(provider: ResolvedProvider): string {\n if (provider.id !== CODEX_PROVIDER_ID) return '';\n return ` ${color.bold(CODEX_PICKER_HEADER)}\\n${color.dim(` ${CODEX_LEGACY_NOTE}`)}\\n\\n`;\n}\n"],
5
- "mappings": "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",
6
- "names": ["color", "expectDefined", "setOutputLineGuard", "setRawMode", "stripAnsi", "writeOut", "color", "color", "color", "stripAnsi", "writeOut", "setOutputLineGuard", "setRawMode", "chosen", "expectDefined"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/auth-menu/oauth-menu.ts", "../src/auth-menu/anthropic-oauth.ts", "../src/auth-menu/github-copilot-oauth.ts", "../src/auth-menu/helpers.ts", "../src/auth-menu/shared.ts", "../src/auth-menu/add-provider.ts", "../src/provider-id.ts", "../src/auth-menu/local.ts", "../src/auth-menu/auth-menu-audit.ts"],
4
- "sourcesContent": ["import { color } from '@wrongstack/core/utils';\nimport { runClaudeOAuthLogin } from './anthropic-oauth.js';\nimport { runCopilotOAuthLogin } from './github-copilot-oauth.js';\nimport { runCodexOAuthLogin } from './openai-codex-oauth.js';\nimport type { AuthMenuDeps } from './types.js';\n\n/** Render subscription OAuth login choices shared by the top menu and add flow. */\nexport function renderOAuthLoginOptions(deps: AuthMenuDeps, indent = ' '): void {\n deps.renderer.write(\n `${indent}${color.bold('OAuth login options')} ${color.dim('(subscription sign-in)')}\\n` +\n `${indent}${color.bold('chatgpt')} ChatGPT Plus/Pro ${color.dim('(\u2192 openai-codex)')}\\n` +\n `${indent}${color.bold('claude')} Claude Pro/Max ${color.dim('(\u2192 anthropic-oauth)')}\\n` +\n `${indent}${color.bold('copilot')} GitHub Copilot ${color.dim('(\u2192 github-copilot)')}\\n`,\n );\n}\n\nexport type OAuthMenuKind = 'chatgpt' | 'claude' | 'copilot';\n\n/**\n * Single source of truth for the OAuth vocabulary. Every surface that accepts\n * a subscription name \u2014 `wstack auth login <x>`, the OAuth submenu, and the\n * catalog-cancel fallback \u2014 resolves through {@link resolveOAuthKind}, so the\n * three never drift into accepting different spellings of the same thing.\n */\nconst OAUTH_ALIASES: Record<OAuthMenuKind, readonly string[]> = {\n chatgpt: ['chatgpt', 'openai', 'codex', 'codex-cli', 'openai-codex', 'chatgpt-plus', 'plus', 'pro'],\n claude: ['claude', 'anthropic', 'claude-pro', 'claude-max', 'anthropic-oauth', 'max'],\n copilot: ['copilot', 'github', 'gh', 'github-copilot'],\n};\n\nconst OAUTH_NUMERIC: Record<string, OAuthMenuKind> = { '1': 'chatgpt', '2': 'claude', '3': 'copilot' };\n\n/**\n * Normalize a user-typed subscription name to an OAuth kind.\n * `allowNumeric` enables the 1/2/3 menu picks (off for free-text prompts,\n * where a bare digit is far more likely to be a typo than a menu choice).\n */\nexport function resolveOAuthKind(\n choice: string,\n opts: { allowNumeric?: boolean } = {},\n): OAuthMenuKind | undefined {\n const pick = choice.trim().toLowerCase();\n if (!pick) return undefined;\n if (opts.allowNumeric !== false && OAUTH_NUMERIC[pick]) return OAUTH_NUMERIC[pick];\n for (const [kind, aliases] of Object.entries(OAUTH_ALIASES)) {\n if (aliases.includes(pick)) return kind as OAuthMenuKind;\n }\n return undefined;\n}\n\n/** Run an OAuth login for a normalized menu choice. Returns true when handled. */\nexport async function runOAuthLoginChoice(\n deps: AuthMenuDeps,\n choice: string,\n opts: { allowNumeric?: boolean } = {},\n): Promise<boolean> {\n const kind = resolveOAuthKind(choice, opts);\n if (!kind) return false;\n await runOAuthLoginKind(deps, kind);\n return true;\n}\n\n/** Run the OAuth login flow for an already-resolved kind. */\nexport async function runOAuthLoginKind(deps: AuthMenuDeps, kind: OAuthMenuKind): Promise<number> {\n if (kind === 'claude') return runClaudeOAuthLogin(deps);\n if (kind === 'copilot') return runCopilotOAuthLogin(deps);\n return runCodexOAuthLogin(deps);\n}\n\n/** Sub-menu: pick a subscription to sign in with (OAuth). */\nexport async function runOAuthLoginMenu(deps: AuthMenuDeps): Promise<void> {\n deps.renderer.write(\n `\\n ${color.bold('Login with OAuth:')}\\n` +\n color.amber(' \u26A0 Subscription tokens used outside official clients may violate provider\\n') +\n color.amber(' Terms \u2014 your account could be rate-limited or banned. An API key is the\\n') +\n color.dim(' sanctioned path for programmatic use.\\n') +\n ` ${color.bold('1')} ChatGPT Plus/Pro ${color.dim('(\u2192 openai-codex)')}\\n` +\n ` ${color.bold('2')} Claude Pro/Max ${color.dim('(\u2192 anthropic-oauth)')}\\n` +\n ` ${color.bold('3')} GitHub Copilot ${color.dim('(\u2192 github-copilot)')}\\n`,\n );\n const pick = await deps.reader.readLine(` ${color.amber('?')} Pick ${color.dim('(or b to go back)')}: `);\n await runOAuthLoginChoice(deps, pick);\n}\n", "/**\n * Anthropic \"Sign in with Claude\" OAuth (Authorization Code + PKCE) \u2014 Claude\n * Pro/Max subscription login. Parallel to the Codex flow but with Anthropic's\n * endpoints and quirks:\n * - authorize at claude.ai/oauth/authorize (params include `code=true`),\n * - the OAuth `state` is the PKCE verifier (Anthropic's convention),\n * - JSON (not form) token exchange at platform.claude.com/v1/oauth/token,\n * - loopback callback on http://localhost:53692/callback.\n *\n * Stored under the canonical `anthropic-oauth` provider (family `anthropic-oauth`)\n * so it never clobbers an API-key `anthropic` provider. The provider adapter\n * adds the Bearer + beta headers and the required Claude Code system block.\n */\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport { openBrowser, startLoopbackServer } from './loopback-server.js';\nimport { color } from '@wrongstack/core/utils';\nimport { FetchError, ParseError, type ProviderApiKey, type ProviderConfig } from '@wrongstack/core/types';\nimport {\n mutateConfigProviders,\n normalizeKeys,\n nowIso,\n writeKeysBack,\n} from '../provider-config-utils.js';\nimport type { AuthMenuDeps } from './types.js';\n\nconst CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';\nconst AUTHORIZE_URL = 'https://claude.ai/oauth/authorize';\nconst TOKEN_URL = 'https://platform.claude.com/v1/oauth/token';\nconst REDIRECT_PORT = 53692;\nconst REDIRECT_HOST = '127.0.0.1';\nconst REDIRECT_PATH = '/callback';\nconst REDIRECT_URI = `http://localhost:${REDIRECT_PORT}${REDIRECT_PATH}`;\nconst SCOPES =\n 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload';\nexport const CLAUDE_PROVIDER_ID = 'anthropic-oauth';\nconst CLAUDE_BASE_URL = 'https://api.anthropic.com';\n\nexport interface ClaudeTokens {\n access: string;\n refresh: string;\n expires: number;\n}\n\n// \u2500\u2500 PKCE \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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction base64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nexport function generatePkce(): { verifier: string; challenge: string } {\n const verifier = base64url(randomBytes(32));\n const challenge = base64url(createHash('sha256').update(verifier).digest());\n return { verifier, challenge };\n}\n\n/** Build the Claude authorize URL. Anthropic uses the PKCE verifier as `state`. */\nexport function buildAuthorizeUrl(challenge: string, verifier: string): string {\n const params = new URLSearchParams({\n code: 'true',\n client_id: CLIENT_ID,\n response_type: 'code',\n redirect_uri: REDIRECT_URI,\n scope: SCOPES,\n code_challenge: challenge,\n code_challenge_method: 'S256',\n state: verifier,\n });\n return `${AUTHORIZE_URL}?${params.toString()}`;\n}\n\nexport function parseAuthorizationInput(input: string): {\n code?: string | undefined;\n state?: string | undefined;\n} {\n const value = input.trim();\n if (!value) return {};\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get('code') ?? undefined,\n state: url.searchParams.get('state') ?? undefined,\n };\n } catch {\n /* not a URL */\n }\n if (value.includes('#')) {\n const [code, state] = value.split('#', 2);\n return { code, state };\n }\n if (value.includes('code=')) {\n const params = new URLSearchParams(value);\n return {\n code: params.get('code') ?? undefined,\n state: params.get('state') ?? undefined,\n };\n }\n return { code: value };\n}\n\n// \u2500\u2500 Token exchange / refresh (JSON) \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\ninterface TokenJson {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n}\n\nasync function readTokens(res: Response, op: string, url: string): Promise<ClaudeTokens> {\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new FetchError({\n message: `Claude token ${op} failed (${res.status}): ${text || res.statusText}`,\n status: res.status,\n context: { provider: 'anthropic-oauth', op, url },\n });\n }\n const json = (await res.json()) as TokenJson | null;\n if (!json?.access_token || !json.refresh_token || typeof json.expires_in !== 'number') {\n throw new ParseError({\n message: `Claude token ${op} response missing fields`,\n source: 'anthropic-oauth-token-response',\n context: { op },\n });\n }\n return {\n access: json.access_token,\n refresh: json.refresh_token,\n expires: Date.now() + json.expires_in * 1000,\n };\n}\n\n/** Exchange an authorization code (+ verifier, reused as state) for tokens. */\nexport async function exchangeAuthorizationCode(\n code: string,\n state: string,\n verifier: string,\n signal?: AbortSignal,\n): Promise<ClaudeTokens> {\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: JSON.stringify({\n grant_type: 'authorization_code',\n client_id: CLIENT_ID,\n code,\n state,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n }),\n signal: signal\n ? AbortSignal.any([signal, AbortSignal.timeout(30_000)])\n : AbortSignal.timeout(30_000),\n });\n return readTokens(res, 'exchange', TOKEN_URL);\n}\n\n/**\n * Fetch the account's available Claude model ids live from\n * `api.anthropic.com/v1/models` using the OAuth token. Best-effort: returns []\n * on any failure so login still succeeds with a sensible fallback list.\n */\nasync function fetchClaudeModels(accessToken: string, signal: AbortSignal): Promise<string[]> {\n try {\n const res = await fetch(`${CLAUDE_BASE_URL}/v1/models?limit=100`, {\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n 'anthropic-version': '2023-06-01',\n 'anthropic-beta': 'claude-code-20250219,oauth-2025-04-20',\n },\n signal: AbortSignal.any([signal, AbortSignal.timeout(8_000)]),\n });\n if (!res.ok) return [];\n const json = (await res.json()) as { data?: Array<{ id?: string }> } | null;\n const ids = (json?.data ?? [])\n .map((m) => m.id)\n .filter((id): id is string => typeof id === 'string' && id.startsWith('claude-'));\n return ids;\n } catch {\n return [];\n }\n}\n\n// \u2500\u2500 Loopback server \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\u2500\u2500\u2500\u2500\n\n// \u2500\u2500 Loopback server, browser opener, and callback HTML are now in\n// `./loopback-server.js` \u2014 imported at the top of this file.\n\n// \u2500\u2500 Main flow \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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ClaudeLoginOptions {\n providerId?: string;\n /**\n * External cancellation signal (e.g. the TUI auth panel's Esc). When\n * provided, the flow does NOT install its own SIGINT handler \u2014 the\n * caller owns cancellation.\n */\n signal?: AbortSignal | undefined;\n}\n\nexport async function runClaudeOAuthLogin(\n deps: AuthMenuDeps,\n opts: ClaudeLoginOptions = {},\n): Promise<number> {\n const providerId = opts.providerId ?? CLAUDE_PROVIDER_ID;\n const { verifier, challenge } = generatePkce();\n // Anthropic reuses the PKCE verifier as the OAuth state.\n const state = verifier;\n const authorizeUrl = buildAuthorizeUrl(challenge, verifier);\n // Wrap URL in OSC 8 terminal hyperlink sequences \u2014 makes it a clickable\n // link in modern terminals (Windows Terminal, iTerm2, Kitty, WezTerm, etc.).\n // The hyperlink is region-based: clicking any wrapped segment opens the URL.\n const osc8 = (url: string) => `\\x1b]8;;${url}\\x1b\\\\${url}\\x1b]8;;\\x1b\\\\`;\n\n const ac = new AbortController();\n const onSig = () => ac.abort();\n const external = opts.signal;\n if (external) {\n if (external.aborted) ac.abort();\n else external.addEventListener('abort', () => ac.abort(), { once: true });\n } else {\n process.on('SIGINT', onSig);\n }\n\n const server = await startLoopbackServer(state, [REDIRECT_PORT], ac.signal, REDIRECT_PATH, REDIRECT_HOST);\n\n deps.renderer.write(\n color.bold(`\\n Sign in with Claude \u2014 ${color.cyan(providerId)}\\n`) +\n color.dim(' Uses your Claude Pro/Max subscription (not an API key).\\n') +\n color.amber(' \u26A0 Using a subscription outside the official Claude Code client is against\\n') +\n color.amber(' Anthropic\u2019s Terms \u2014 your account could be rate-limited or banned.\\n') +\n color.dim(' Sanctioned programmatic use = an API key: ') +\n color.bold('wstack auth anthropic') +\n color.dim('\\n\\n') +\n color.bold(` ${'\u2500'.repeat(56)}\\n`) +\n color.bold(' Open this URL in your browser to sign in:\\n') +\n color.cyan(` ${osc8(authorizeUrl)}\\n`) +\n color.bold(` ${'\u2500'.repeat(56)}\\n\\n`),\n );\n\n if (server.bound) {\n openBrowser(authorizeUrl);\n deps.renderer.write(\n color.dim(' A browser window should open. Waiting for you to finish signing in...\\n') +\n color.dim(' (Listening on http://localhost:53692 \u2014 press Ctrl+C to cancel.)\\n'),\n );\n } else {\n deps.renderer.write(\n color.amber(' \u26A0 Could not start the local callback listener (port 53692 in use).\\n') +\n color.dim(' After signing in, paste the full redirect URL (or the code) below.\\n'),\n );\n }\n\n let code: string | undefined;\n try {\n if (server.bound) {\n const got = await server.waitForCode();\n // Cancelled while waiting on the loopback \u2192 return now rather than\n // dropping into the manual-paste prompt (which would block again).\n if (ac.signal.aborted) {\n deps.renderer.write(color.dim(' Cancelled.\\n'));\n return 1;\n }\n if (got) code = got.code;\n }\n\n if (!code) {\n const input = (\n await deps.reader.readLine(\n `\\n ${color.amber('?')} Paste the redirect URL or code ${color.dim('(or q to cancel)')}: `,\n )\n ).trim();\n if (input.toLowerCase() === 'q' || input === '') {\n deps.renderer.write(color.dim(' Cancelled.\\n'));\n return 1;\n }\n const parsed = parseAuthorizationInput(input);\n if (parsed.state && parsed.state !== state) {\n deps.renderer.writeError(' State mismatch \u2014 please restart the login flow.');\n return 1;\n }\n code = parsed.code;\n }\n\n if (!code) {\n deps.renderer.writeError(' No authorization code received.');\n return 1;\n }\n\n deps.renderer.write(color.dim('\\n Exchanging authorization code for tokens...\\n'));\n const tokens = await exchangeAuthorizationCode(code, state, verifier, ac.signal);\n const models = await fetchClaudeModels(tokens.access, ac.signal);\n\n const saved = await saveClaudeTokens(deps, providerId, tokens, models);\n if (!saved) return 1;\n\n deps.renderer.write(color.green('\\n \u2713 Signed in with Claude!\\n'));\n const modelHint = models[0];\n deps.renderer.writeInfo(\n ` Saved as provider ${color.bold(providerId)}${models.length ? ` (${models.length} models)` : ''}.\\n` +\n (modelHint\n ? ` Use: ${color.bold(`wstack --provider ${providerId} --model ${modelHint}`)} \"<task>\"\\n`\n : ` No model list was discovered; choose a model before starting a run.\\n`) +\n color.dim(' Tokens refresh automatically before they expire.\\n'),\n );\n return 0;\n } catch (err) {\n const msg =\n err instanceof DOMException && err.name === 'AbortError'\n ? 'Login cancelled.'\n : (err as Error).message;\n deps.renderer.writeError(` Login failed: ${msg}`);\n return 1;\n } finally {\n server.close();\n if (!external) process.off('SIGINT', onSig);\n }\n}\n\nasync function saveClaudeTokens(\n deps: AuthMenuDeps,\n providerId: string,\n tokens: ClaudeTokens,\n models: string[],\n): Promise<boolean> {\n const entry: ProviderApiKey = {\n label: 'oauth-default',\n apiKey: tokens.access,\n createdAt: nowIso(),\n authMethod: 'oauth',\n expiresAt: new Date(tokens.expires).toISOString(),\n refreshToken: tokens.refresh,\n tokenType: 'bearer',\n scope: SCOPES,\n };\n try {\n await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {\n const existing = all[providerId];\n const p: ProviderConfig = existing ? { ...existing } : { type: providerId };\n p.family = 'anthropic-oauth';\n if (!p.baseUrl) p.baseUrl = CLAUDE_BASE_URL;\n if (models.length > 0) p.models = models;\n const keys = normalizeKeys(p).filter((k) => k.label !== entry.label);\n keys.push(entry);\n writeKeysBack(p, keys);\n p.activeKey = entry.label;\n all[providerId] = p;\n }, deps.profileConfigPath);\n return true;\n } catch (err) {\n deps.renderer.writeError(` Failed to save tokens: ${(err as Error).message}`);\n return false;\n }\n}\n", "/**\n * GitHub Copilot login \u2014 GitHub OAuth **device flow** (no loopback server).\n *\n * 1. POST github.com/login/device/code \u2192 user_code + verification_uri.\n * 2. User opens the URL, enters the code; we poll login/oauth/access_token\n * until GitHub returns a long-lived OAuth token.\n * 3. Exchange that token at api.github.com/copilot_internal/v2/token for a\n * short-lived Copilot token (the chat access token).\n *\n * Stored under the canonical `github-copilot` provider (family `github-copilot`,\n * an OpenAI chat/completions-compatible wire). The GitHub OAuth token is the\n * refresh token; the provider mints fresh Copilot tokens from it transparently.\n */\n\nimport { spawn } from 'node:child_process';\nimport { color } from '@wrongstack/core/utils';\nimport { FetchError, ParseError, type ProviderApiKey, type ProviderConfig } from '@wrongstack/core/types';\nimport { copilotBaseUrlFromToken, refreshCopilotToken } from '@wrongstack/providers';\nimport {\n mutateConfigProviders,\n normalizeKeys,\n nowIso,\n writeKeysBack,\n} from '../provider-config-utils.js';\nimport type { AuthMenuDeps } from './types.js';\n\nconst CLIENT_ID = 'Iv1.b507a08c87ecfe98';\nconst DEVICE_CODE_URL = 'https://github.com/login/device/code';\nconst ACCESS_TOKEN_URL = 'https://github.com/login/oauth/access_token';\nconst COPILOT_HEADERS: Record<string, string> = {\n 'User-Agent': 'GitHubCopilotChat/0.35.0',\n 'Editor-Version': 'vscode/1.107.0',\n 'Editor-Plugin-Version': 'copilot-chat/0.35.0',\n 'Copilot-Integration-Id': 'vscode-chat',\n};\nconst COPILOT_API_VERSION = '2026-06-01';\nexport const COPILOT_PROVIDER_ID = 'github-copilot';\n\ninterface DeviceCode {\n device_code: string;\n user_code: string;\n verification_uri: string;\n interval: number;\n expires_in: number;\n}\n\nfunction openBrowser(url: string): void {\n try {\n const platform = process.platform;\n const { command, args } =\n platform === 'win32'\n ? { command: 'cmd', args: ['/c', 'start', '', url] }\n : platform === 'darwin'\n ? { command: 'open', args: [url] }\n : { command: 'xdg-open', args: [url] };\n const child = spawn(command, args, { stdio: 'ignore', windowsHide: true });\n child.on('error', () => {});\n child.unref();\n } catch {\n /* best-effort */\n }\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) return reject(new DOMException('Aborted', 'AbortError'));\n const t = setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(t);\n reject(new DOMException('Aborted', 'AbortError'));\n },\n { once: true },\n );\n });\n}\n\n/** Start the GitHub device flow. */\nexport async function startDeviceFlow(signal?: AbortSignal): Promise<DeviceCode> {\n const res = await fetch(DEVICE_CODE_URL, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n 'content-type': 'application/x-www-form-urlencoded',\n 'user-agent': COPILOT_HEADERS['User-Agent']!,\n },\n body: new URLSearchParams({ client_id: CLIENT_ID, scope: 'read:user' }).toString(),\n signal: signal\n ? AbortSignal.any([signal, AbortSignal.timeout(15_000)])\n : AbortSignal.timeout(15_000),\n });\n if (!res.ok) {\n throw new FetchError({\n message: `GitHub device-code request failed (${res.status})`,\n status: res.status,\n context: { provider: 'github-copilot', op: 'device-code', url: DEVICE_CODE_URL },\n });\n }\n const json = (await res.json()) as Partial<DeviceCode> | null;\n if (\n !json?.device_code ||\n !json.user_code ||\n !json.verification_uri ||\n typeof json.expires_in !== 'number'\n ) {\n throw new ParseError({\n message: 'Invalid device-code response',\n source: 'github-copilot-device-code-response',\n });\n }\n return {\n device_code: json.device_code,\n user_code: json.user_code,\n verification_uri: json.verification_uri,\n interval: json.interval ?? 5,\n expires_in: json.expires_in,\n };\n}\n\n/** Poll until the user authorizes; returns the GitHub OAuth token. */\nexport async function pollForGitHubToken(device: DeviceCode, signal: AbortSignal): Promise<string> {\n let intervalMs = device.interval * 1000;\n const expiresAt = Date.now() + device.expires_in * 1000;\n\n while (Date.now() < expiresAt) {\n await sleep(intervalMs, signal);\n const res = await fetch(ACCESS_TOKEN_URL, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n 'content-type': 'application/x-www-form-urlencoded',\n 'user-agent': COPILOT_HEADERS['User-Agent']!,\n },\n body: new URLSearchParams({\n client_id: CLIENT_ID,\n device_code: device.device_code,\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n }).toString(),\n signal: AbortSignal.any([signal, AbortSignal.timeout(15_000)]),\n });\n const json = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n error?: string;\n };\n if (json.access_token) return json.access_token;\n if (json.error === 'authorization_pending') continue;\n if (json.error === 'slow_down') {\n intervalMs += 5_000;\n continue;\n }\n throw new Error(`Device flow failed: ${json.error ?? 'unknown error'}`);\n }\n throw new FetchError({\n message: 'Device code expired \u2014 please restart the login.',\n status: 408, // Request Timeout\n context: { provider: 'github-copilot', op: 'device-code-poll', reason: 'expired' },\n });\n}\n\n/** Shape of the fields we read from a `/models` entry (everything optional). */\ninterface CopilotModelEntry {\n id?: unknown;\n model_picker_enabled?: unknown;\n is_chat_default?: unknown;\n is_chat_fallback?: unknown;\n vendor?: unknown;\n supported_endpoints?: unknown;\n policy?: { state?: unknown } | undefined;\n capabilities?: { type?: unknown; supports?: { tool_calls?: unknown } | undefined } | undefined;\n}\n\n/**\n * Decide whether a Copilot `/models` entry is a chat model we can actually\n * drive over this provider's wire.\n *\n * The provider POSTs to `\u2026/chat/completions`, so the discriminators are:\n * - `capabilities.type === 'chat'` \u2014 drops embeddings and completion-only ids.\n * - `capabilities.supports.tool_calls` \u2014 the agent loop needs tool calling.\n * - `supported_endpoints` (when present) must include `/chat/completions`.\n * This is the key fix: `/responses`-only ids (the `*-picker` router models,\n * `gpt-5.4-mini-free-auto`, `mai-code-1-flash*`) advertise themselves in the\n * model picker but 400 on `/chat/completions`. Absent field \u21D2 legacy chat\n * model (gpt-4o, gpt-4.1) \u21D2 allowed.\n * - `policy.state !== 'disabled'` \u2014 disabled means the user hasn't enabled the\n * model in their GitHub Copilot settings; calling it would 403.\n * - `vendor !== 'Experimental'` \u2014 drops internal previews (trajectory-compaction).\n */\nexport function isUsableCopilotChatModel(item: CopilotModelEntry): boolean {\n if (typeof item.id !== 'string' || item.id.length === 0) return false;\n const cap = item.capabilities;\n if (cap?.type !== 'chat') return false;\n if (cap.supports?.tool_calls !== true) return false;\n const eps = item.supported_endpoints;\n if (Array.isArray(eps) && !eps.includes('/chat/completions')) return false;\n if (item.policy?.state === 'disabled') return false;\n if (item.vendor === 'Experimental') return false;\n return true;\n}\n\n/** Fetch the user's usable Copilot chat-model ids (best-effort, never throws). */\nasync function fetchCopilotModels(copilotToken: string, signal: AbortSignal): Promise<string[]> {\n try {\n const base = copilotBaseUrlFromToken(copilotToken);\n const res = await fetch(`${base}/models`, {\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${copilotToken}`,\n 'X-GitHub-Api-Version': COPILOT_API_VERSION,\n ...COPILOT_HEADERS,\n },\n signal: AbortSignal.any([signal, AbortSignal.timeout(8_000)]),\n });\n if (!res.ok) return [];\n const json = (await res.json()) as { data?: CopilotModelEntry[] } | null;\n const data = json?.data;\n if (!Array.isArray(data)) return [];\n const usable = data.filter(isUsableCopilotChatModel);\n // Float the provider's own default/fallback chat model to the front so the\n // saved list's first entry is a sane `--model` default.\n usable.sort((a, b) => copilotModelRank(a) - copilotModelRank(b));\n return usable.map((m) => m.id as string);\n } catch {\n return [];\n }\n}\n\n/** Lower rank sorts first: chat default, then fallback, then everything else. */\nfunction copilotModelRank(item: CopilotModelEntry): number {\n if (item.is_chat_default === true) return 0;\n if (item.is_chat_fallback === true) return 1;\n return 2;\n}\n\nexport interface CopilotLoginOptions {\n providerId?: string;\n /**\n * External cancellation signal (e.g. the TUI auth panel's Esc). When\n * provided, the flow does NOT install its own SIGINT handler \u2014 the\n * caller owns cancellation.\n */\n signal?: AbortSignal | undefined;\n}\n\nexport async function runCopilotOAuthLogin(\n deps: AuthMenuDeps,\n opts: CopilotLoginOptions = {},\n): Promise<number> {\n const providerId = opts.providerId ?? COPILOT_PROVIDER_ID;\n const ac = new AbortController();\n const onSig = () => ac.abort();\n const external = opts.signal;\n if (external) {\n if (external.aborted) ac.abort();\n else external.addEventListener('abort', () => ac.abort(), { once: true });\n } else {\n process.on('SIGINT', onSig);\n }\n\n try {\n deps.renderer.write(\n color.bold(`\\n Sign in with GitHub Copilot \u2014 ${color.cyan(providerId)}\\n`) +\n color.dim(' Uses your GitHub Copilot subscription (not an API key).\\n') +\n color.amber(' \u26A0 Using Copilot outside its official editor integrations may violate\\n') +\n color.amber(' GitHub\u2019s Terms \u2014 your account could be rate-limited or banned.\\n\\n'),\n );\n\n const device = await startDeviceFlow(ac.signal);\n deps.renderer.write(\n color.bold(` ${'\u2500'.repeat(56)}\\n`) +\n color.bold(' Open this URL and enter the code:\\n') +\n color.cyan(` ${device.verification_uri}\\n`) +\n color.bold(' Code: ') +\n color.green(color.bold(device.user_code)) +\n '\\n' +\n color.bold(` ${'\u2500'.repeat(56)}\\n\\n`),\n );\n openBrowser(device.verification_uri);\n deps.renderer.write(color.dim(' Waiting for you to authorize in the browser...\\n'));\n\n const githubToken = await pollForGitHubToken(device, ac.signal);\n deps.renderer.write(color.dim(' Authorized. Fetching your Copilot token...\\n'));\n const copilot = await refreshCopilotToken(githubToken, ac.signal);\n const models = await fetchCopilotModels(copilot.token, ac.signal);\n\n const saved = await saveCopilotTokens(\n deps,\n providerId,\n copilot.token,\n githubToken,\n copilot.expires,\n models,\n );\n if (!saved) return 1;\n\n deps.renderer.write(color.green('\\n \u2713 Signed in with GitHub Copilot!\\n'));\n const modelHint = models[0] ?? 'gpt-4o';\n deps.renderer.writeInfo(\n ` Saved as provider ${color.bold(providerId)}${models.length ? ` (${models.length} models)` : ''}.\\n` +\n ` Use: ${color.bold(`wstack --provider ${providerId} --model ${modelHint}`)} \"<task>\"\\n` +\n color.dim(' The Copilot token refreshes automatically.\\n'),\n );\n return 0;\n } catch (err) {\n const msg =\n err instanceof DOMException && err.name === 'AbortError'\n ? 'Login cancelled.'\n : (err as Error).message;\n deps.renderer.writeError(` Login failed: ${msg}`);\n return 1;\n } finally {\n if (!external) process.off('SIGINT', onSig);\n }\n}\n\nasync function saveCopilotTokens(\n deps: AuthMenuDeps,\n providerId: string,\n copilotToken: string,\n githubToken: string,\n expires: number,\n models: string[],\n): Promise<boolean> {\n const entry: ProviderApiKey = {\n label: 'oauth-default',\n apiKey: copilotToken,\n createdAt: nowIso(),\n authMethod: 'oauth',\n expiresAt: new Date(expires).toISOString(),\n refreshToken: githubToken,\n tokenType: 'bearer',\n };\n try {\n await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {\n const existing = all[providerId];\n const p: ProviderConfig = existing ? { ...existing } : { type: providerId };\n p.family = 'github-copilot';\n if (!p.baseUrl) p.baseUrl = copilotBaseUrlFromToken(copilotToken);\n if (models.length > 0) p.models = models;\n else if (!p.models || p.models.length === 0) p.models = ['gpt-4o'];\n const keys = normalizeKeys(p).filter((k) => k.label !== entry.label);\n keys.push(entry);\n writeKeysBack(p, keys);\n p.activeKey = entry.label;\n all[providerId] = p;\n }, deps.profileConfigPath);\n return true;\n } catch (err) {\n deps.renderer.writeError(` Failed to save tokens: ${(err as Error).message}`);\n return false;\n }\n}\n", "import type { ProviderConfig } from '@wrongstack/core/types';\nimport { loadConfigProviders } from '../provider-config-utils.js';\nimport type { AuthMenuDeps } from './types.js';\n\n/** Thin wrapper \u2014 delegates to the shared config provider loader. */\nexport async function loadProviders(deps: AuthMenuDeps): Promise<Record<string, ProviderConfig>> {\n return loadConfigProviders(deps.profileConfigPath, deps.vault, {\n warn: (msg: string) => deps.renderer.writeWarning(msg),\n profileConfigPath: deps.profileConfigPath,\n });\n}\n", "import { color } from '@wrongstack/core/utils';\nimport type { ProviderApiKey, ProviderConfig, WireFamily } from '@wrongstack/core/types';\nimport { activeLabel, maskedKey, normalizeKeys } from '../provider-config-utils.js';\nimport type { AuthMenuDeps } from './types.js';\n\n/* ------------------------------------------------------------------ */\n/* Rendering helpers */\n/* ------------------------------------------------------------------ */\n\n/** Render a provider entry line in the top-level listing. */\nfunction renderProviderLine(\n renderer: AuthMenuDeps['renderer'],\n id: string,\n cfg: ProviderConfig,\n idx: number,\n): void {\n const keys = normalizeKeys(cfg);\n const active = activeLabel(cfg, keys);\n const firstKey = keys[0];\n\n let summary: string;\n if (keys.length === 0) {\n summary = color.dim('(no keys)');\n } else if (keys.length === 1) {\n summary = maskedKey(firstKey?.apiKey ?? '');\n } else {\n const activeKeyObj = active != null ? keys.find((k) => k.label === active) : undefined;\n summary =\n `${color.dim(`${keys.length} keys`)} ` +\n `${color.dim('active:')} ${color.bold(active ?? '?')} ` +\n maskedKey(activeKeyObj?.apiKey ?? firstKey?.apiKey ?? '');\n }\n\n const fam = cfg.family ? color.dim(`[${cfg.family}]`) : '';\n const aliasHint = cfg.type && cfg.type !== id ? color.dim(`\u2192 ${cfg.type}`) : '';\n\n renderer.write(\n ` ${color.dim(`${idx}.`.padStart(4))} ${id.padEnd(22)} ${fam} ${aliasHint} ${summary}\\n`,\n );\n}\n\n/** Render the header for the provider management submenu. */\nexport function renderProviderHeader(\n renderer: AuthMenuDeps['renderer'],\n providerId: string,\n cfg: ProviderConfig,\n): void {\n const keys = normalizeKeys(cfg);\n const active = activeLabel(cfg, keys);\n\n renderer.write(\n `\\n${color.bold(providerId)} ` +\n `${cfg.family ? color.dim(`[${cfg.family}]`) : color.amber('[no family]')}\\n`,\n );\n\n const details: string[] = [\n color.dim(` type: ${cfg.type ?? providerId}`),\n color.dim(` family: ${cfg.family ?? '(unset \u2192 resolved from models.dev when type matches)'}`),\n color.dim(` baseUrl: ${cfg.baseUrl ?? '(unset \u2192 catalog default)'}`),\n ];\n\n if (cfg.envVars && cfg.envVars.length > 0) {\n details.push(color.dim(` envVars: ${cfg.envVars.join(', ')}`));\n }\n if (cfg.models && cfg.models.length > 0) {\n details.push(color.dim(` models: ${cfg.models.join(', ')}`));\n }\n\n renderer.write(details.join('\\n') + '\\n');\n\n if (keys.length === 0) {\n renderer.write(color.dim(' (no keys saved)\\n'));\n } else {\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n if (key) renderKeyLine(renderer, key, i + 1, active);\n }\n }\n}\n\n/** Render a single key entry line. */\nfunction renderKeyLine(\n renderer: AuthMenuDeps['renderer'],\n key: ProviderApiKey,\n idx: number,\n active: string | undefined,\n): void {\n const marker = key.label === active ? color.green('\u25CF') : color.dim('\u25CB');\n renderer.write(\n ` ${color.dim(`${idx}.`.padStart(4))} ${marker} ${key.label.padEnd(20)} ` +\n `${maskedKey(key.apiKey)} ${color.dim(key.createdAt)}\\n`,\n );\n}\n\n/** Render action shortcuts. */\nexport function renderActions(renderer: AuthMenuDeps['renderer'], keysLength: number): void {\n renderer.write(`\\n ${color.dim('Actions:')}\\n`);\n renderer.write(` ${color.bold('a')} Add another key\\n`);\n if (keysLength > 0) {\n renderer.write(` ${color.bold('u')} <n> Update key <n>\\n`);\n renderer.write(` ${color.bold('d')} <n> Delete key <n>\\n`);\n renderer.write(` ${color.bold('s')} <n> Set key <n> as active\\n`);\n }\n renderer.write(` ${color.bold('f')} Edit family\\n`);\n renderer.write(` ${color.bold('B')} Edit baseUrl ${color.dim('(capital B \u2014 b is Back)')}\\n`);\n renderer.write(` ${color.bold('m')} Edit visible model list\\n`);\n renderer.write(` ${color.bold('x')} Remove this provider entirely\\n`);\n renderer.write(` ${color.bold('b')} Back\\n`);\n renderer.write(` ${color.bold('q')} Quit\\n`);\n}\n\n/** Render the top-level menu header. */\nexport function renderTopMenu(\n renderer: AuthMenuDeps['renderer'],\n providers: Record<string, ProviderConfig>,\n): void {\n renderer.write(`\\n${color.bold('WrongStack')} ${color.dim('\u2014 API key manager')}\\n\\n`);\n\n const ids = Object.keys(providers).sort();\n if (ids.length === 0) {\n renderer.write(color.dim(' No providers configured yet.\\n'));\n renderer.write(\n color.dim(\n ' Use (a) to add one from the models.dev catalog, (l) for a local server, or (c) for a custom provider.\\n',\n ),\n );\n } else {\n renderer.write(` ${color.dim('Saved providers:')}\\n`);\n let idx = 1;\n for (const id of ids) {\n const cfg = providers[id];\n if (!cfg) continue;\n renderProviderLine(renderer, id, cfg, idx);\n idx++;\n }\n }\n\n renderer.write(`\\n ${color.dim('Actions:')}\\n`);\n renderer.write(` ${color.bold('a')} Add a provider (from catalog)\\n`);\n renderer.write(\n ` ${color.bold('l')} Add a local server ${color.dim('(OmniRoute / Ollama / vLLM / LM Studio)')}\\n`,\n );\n renderer.write(` ${color.bold('c')} Add a custom provider\\n`);\n renderer.write(\n ` ${color.bold('s')} Login with OAuth ${color.dim('(ChatGPT / Claude / Copilot)')}\\n`,\n );\n if (ids.length > 0) {\n renderer.write(\n ` ${color.dim('1-')}${color.dim(String(ids.length))} ${color.bold('Manage a provider')}\\n`,\n );\n }\n renderer.write(` ${color.bold('q')} Quit\\n`);\n}\n\n/* ------------------------------------------------------------------ */\n/* User input helpers */\n/* ------------------------------------------------------------------ */\n\n/** Prompt for a hidden API key. Returns undefined on empty input. */\nexport async function readKeyInput(\n deps: { reader: AuthMenuDeps['reader']; renderer: AuthMenuDeps['renderer'] },\n intent: string,\n): Promise<string | undefined> {\n const key = (\n await deps.reader.readSecret(\n ` ${color.amber('?')} ${intent} ${color.dim('(hidden, paste OK)')}: `,\n )\n ).trim();\n if (!key) {\n deps.renderer.writeError('No key entered.');\n return undefined;\n }\n return key;\n}\n\n/**\n * Ask a yes/no confirmation. Returns:\n * true \u2192 user confirmed (y/yes)\n * false \u2192 user declined (n/no)\n * null \u2192 user cancelled (q)\n */\nexport async function confirm(\n deps: { reader: AuthMenuDeps['reader']; renderer: AuthMenuDeps['renderer'] },\n question: string,\n): Promise<boolean | null> {\n const answer = (\n await deps.reader.readLine(` ${color.amber('?')} ${question} ${color.dim('[y/N/q]')} `)\n )\n .trim()\n .toLowerCase();\n if (answer === 'q' || answer === 'quit') return null;\n return answer === 'y' || answer === 'yes';\n}\n\n/** Suggest a default label that doesn't conflict with existing keys. */\nexport function suggestLabel(usedLabels: Set<string>): string {\n const candidate = 'default';\n if (!usedLabels.has(candidate)) return candidate;\n let n = 2;\n while (usedLabels.has(`key${n}`)) n++;\n return `key${n}`;\n}\n\n/** Validate a wire family string. Returns the WireFamily or null. */\nexport function validateFamily(raw: string): WireFamily | null {\n const valid: WireFamily[] = ['anthropic', 'openai', 'openai-compatible', 'google'];\n return valid.includes(raw as WireFamily) ? (raw as WireFamily) : null;\n}\n", "import type { ProviderConfig, ResolvedProvider, WireFamily } from '@wrongstack/core/types';\nimport { atomicWrite, color } from '@wrongstack/core/utils';\nimport {\n mutateConfigProviders,\n normalizeKeys,\n nowIso,\n writeKeysBack,\n} from '../provider-config-utils.js';\nimport { loadProviders } from './helpers.js';\nimport {\n renderOAuthLoginOptions,\n runOAuthLoginChoice,\n} from './oauth-menu.js';\nimport * as fs from 'node:fs/promises';\nimport { runLiveProviderPicker } from '../picker.js';\nimport { nextCustomProviderId } from '../provider-id.js';\nimport { readKeyInput, suggestLabel, validateFamily } from './shared.js';\nimport type { AuthMenuDeps } from './types.js';\n\n/* ------------------------------------------------------------------ */\n/* Add from catalog \u2014 pick a known provider from models.dev */\n/* ------------------------------------------------------------------ */\n\nexport async function addFromCatalog(deps: AuthMenuDeps): Promise<boolean> {\n let catalog: ResolvedProvider[] = [];\n try {\n catalog = (await deps.modelsRegistry.listProviders()).filter((p) => p.family !== 'unsupported');\n } catch {\n deps.renderer.writeWarning('Catalog unavailable \u2014 falling back to manual entry.\\n');\n }\n\n if (catalog.length === 0) {\n return addManualEntry(deps);\n }\n\n const saved = new Set(Object.keys(await loadProviders(deps)));\n deps.renderer.write(\n color.dim(\n ` Catalog: ${catalog.length} providers. Type to filter, \u2191/\u2193 navigate, Enter to select.\\n`,\n ),\n );\n deps.renderer.write(` ${color.dim('\u25C9 already saved \u25CB no key yet')}\\n\\n`);\n renderOAuthLoginOptions(deps);\n deps.renderer.write('\\n');\n\n const chosen = await runLiveProviderPicker(catalog, saved);\n if (!chosen) {\n // User cancelled \u2014 offer OAuth as an alternative.\n deps.renderer.write(\n `\\n ${color.dim('OAuth login options:')} ${color.dim('chatgpt')}, ${color.dim('claude')}, or ${color.dim('copilot')}?\\n`,\n );\n const answer = (\n await deps.reader.readLine(\n ` ${color.amber('?')} OAuth or q to quit ${color.dim('[chatgpt/claude/copilot]')}: `,\n )\n ).trim();\n if (answer && await runOAuthLoginChoice(deps, answer, { allowNumeric: false })) {\n return true;\n }\n return false;\n }\n\n return addKeyForCatalogProvider(deps, chosen);\n}\n\n/**\n * Prompt for family/baseUrl/alias overrides, then add a key.\n * Returns true if a key was added.\n *\n * Exported for the TUI auth panel: the panel does its own catalog\n * selection (searchable list) and then drives this flow through the\n * prompt bridge for the override/label/key questions.\n */\nexport async function addKeyForCatalogProvider(\n deps: AuthMenuDeps,\n chosen: ResolvedProvider,\n): Promise<boolean> {\n deps.renderer.write(\n color.dim(`\\n Defaults from models.dev \u2014 press Enter to keep, or type overrides.\\n`),\n );\n\n // Family override\n const famRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Family ${color.dim(`[${chosen.family}]`)} ${color.dim('(q to quit)')}: `,\n )\n ).trim();\n if (famRaw === 'q') return false;\n let family: WireFamily = chosen.family as WireFamily;\n if (famRaw) {\n const validated = validateFamily(famRaw);\n if (!validated) {\n deps.renderer.writeError(\n `Invalid family: \"${famRaw}\" (must be: anthropic, openai, openai-compatible, google).`,\n );\n return false;\n }\n family = validated;\n }\n\n // Base URL override\n const baseRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Base URL ${color.dim(`[${chosen.apiBase ?? 'unset'}]`)} ${color.dim('(q to quit)')}: `,\n )\n ).trim();\n if (baseRaw === 'q') return false;\n const baseUrl: string | undefined = baseRaw || chosen.apiBase;\n\n // Alias\n const providersNow = await loadProviders(deps);\n let suggestedAlias = chosen.id;\n if (family !== (chosen.family as WireFamily)) {\n let candidate = `${chosen.id}-${family}`;\n let n = 2;\n while (providersNow[candidate]) {\n candidate = `${chosen.id}-${family}-${n}`;\n n++;\n }\n suggestedAlias = candidate;\n }\n const aliasRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Save as alias ${color.dim(`[${suggestedAlias}]`)} ${color.dim('(used with --provider <alias>)')}: `,\n )\n ).trim();\n const alias = aliasRaw || suggestedAlias;\n\n // Check for conflicting existing entry\n const existing = providersNow[alias];\n if (existing) {\n const sameFamily = (existing.family ?? (chosen.family as WireFamily)) === family;\n const sameBase = (existing.baseUrl ?? chosen.apiBase) === baseUrl;\n if (!sameFamily || !sameBase) {\n deps.renderer.writeError(\n `Alias \"${alias}\" already exists with different family/baseUrl.\\n ` +\n `Existing: family=${existing.family ?? '(unset)'}, baseUrl=${existing.baseUrl ?? '(unset)'}\\n ` +\n `New: family=${family}, baseUrl=${baseUrl ?? '(unset)'}\\n ` +\n `Pick a different alias to keep them separate.`,\n );\n return false;\n }\n }\n\n return addKeyForProvider(alias, deps, {\n type: chosen.id,\n family,\n baseUrl,\n envVars: chosen.envVars,\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Add custom provider \u2014 fully user-defined (bypasses catalog) */\n/* ------------------------------------------------------------------ */\n\nexport async function addCustomProvider(deps: AuthMenuDeps): Promise<boolean> {\n deps.renderer.write(\n `\\n${color.bold('Custom provider')} ${color.dim('\u2014 for local models or proxies not in the catalog.')}\\n`,\n );\n\n const providersNow = await loadProviders(deps);\n const idRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Provider id ${color.dim('(e.g. \"local-llama\", \"my-proxy\"; blank = auto custom-N, q to quit)')}: `,\n )\n ).trim();\n if (idRaw === 'q') return false;\n\n let type = idRaw;\n if (!type) {\n // Blank id \u2192 assign a non-colliding custom-N name instead of rejecting,\n // so a hastily-added provider still gets a stable, unique id that won't\n // clash with (or overwrite) another entry.\n type = nextCustomProviderId(Object.keys(providersNow));\n deps.renderer.write(` ${color.dim('Using generated id:')} ${color.bold(type)}\\n`);\n } else if (providersNow[type]) {\n deps.renderer.writeWarning(`\"${type}\" already exists. Pick it from the main menu to edit.`);\n return false;\n }\n\n const familyRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Wire family ${color.dim('(anthropic | openai | openai-compatible | google)')} ${color.dim('(q to quit)')}: `,\n )\n ).trim();\n if (familyRaw === 'q') return false;\n const family = validateFamily(familyRaw);\n if (!family) {\n deps.renderer.writeError(`Invalid family: \"${familyRaw}\"`);\n return false;\n }\n\n const baseUrl = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Base URL ${color.dim('(e.g. http://localhost:11434/v1, optional)')}: `,\n )\n ).trim();\n\n const modelsRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Model ids ${color.dim('(comma-separated, optional)')}: `,\n )\n ).trim();\n const models = modelsRaw\n ? modelsRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n const envVarsRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Env var names ${color.dim('(comma-separated, optional)')}: `,\n )\n ).trim();\n const envVars = envVarsRaw\n ? envVarsRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n return addKeyForProvider(type, deps, {\n type,\n family,\n ...(baseUrl ? { baseUrl } : {}),\n ...(models ? { models } : {}),\n ...(envVars ? { envVars } : {}),\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Manual entry \u2014 fallback when catalog is unavailable */\n/* ------------------------------------------------------------------ */\n\nasync function addManualEntry(deps: AuthMenuDeps): Promise<boolean> {\n const pid = (\n await deps.reader.readLine(` ${color.amber('?')} Provider id ${color.dim('[q to quit]')}: `)\n ).trim();\n if (!pid || pid === 'q') return false;\n\n const famRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Family ${color.dim('(anthropic/openai/openai-compatible/google)')}: `,\n )\n ).trim();\n const family = validateFamily(famRaw);\n if (!family) {\n deps.renderer.writeError(`Invalid family: \"${famRaw}\"`);\n return false;\n }\n\n const baseUrl = (\n await deps.reader.readLine(` ${color.amber('?')} Base URL ${color.dim('(optional)')}: `)\n ).trim();\n\n return addKeyForProvider(pid, deps, {\n type: pid,\n family,\n ...(baseUrl ? { baseUrl } : {}),\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Core: add a key to a provider */\n/* ------------------------------------------------------------------ */\n\nexport async function addKeyForProvider(\n providerId: string,\n deps: AuthMenuDeps,\n template: Partial<ProviderConfig>,\n): Promise<boolean> {\n const providers = await loadProviders(deps);\n const existing = providers[providerId];\n const existingKeys = existing ? normalizeKeys(existing) : [];\n const usedLabels = new Set(existingKeys.map((k) => k.label));\n\n const label = await promptForLabel(deps, usedLabels);\n if (!label) return false;\n\n const apiKey = await readKeyInput(deps, `API key for ${providerId}/${label}`);\n if (!apiKey) return false;\n\n await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {\n const existingProv: ProviderConfig = all[providerId] ?? {\n type: providerId,\n ...template,\n };\n if (!existingProv.type) existingProv.type = providerId;\n if (!existingProv.family && template.family) {\n existingProv.family = template.family;\n }\n if (!existingProv.baseUrl && template.baseUrl) {\n existingProv.baseUrl = template.baseUrl;\n }\n if (!existingProv.envVars && template.envVars) {\n existingProv.envVars = template.envVars;\n }\n const list = normalizeKeys(existingProv);\n list.push({ label, apiKey, createdAt: nowIso() });\n writeKeysBack(existingProv, list);\n if (!existingProv.activeKey) existingProv.activeKey = label;\n all[providerId] = existingProv;\n }, deps.profileConfigPath);\n\n deps.renderer.write(\n ` ${color.green('\u2713')} Saved ${color.bold(providerId)}/${color.bold(label)}.\\n`,\n );\n deps.renderer.write(color.dim(` Launch: wstack --provider ${providerId} \"<task>\"\\n`));\n\n // If the user has no active default yet, adopt this provider as the default\n // so the very first provider they add is immediately usable \u2014 the WebUI\n // otherwise shows a \"no model / needs setup\" screen when config.provider or\n // config.model is unset (the TUI tolerates it via its own picker). Never\n // overrides an existing default; best-effort so a miss just defers the pick.\n try {\n await adoptAsDefaultIfUnset(deps, providerId, template);\n } catch {\n /* best-effort \u2014 the user can still pick a default via the picker */\n }\n return true;\n}\n\n/**\n * Resolve a sensible default model id for a just-added provider: an explicit\n * saved model wins, otherwise the first model the catalog knows for it.\n * Returns undefined when neither source yields a model (e.g. a custom provider\n * with no `models` list and no catalog entry) \u2014 the caller then skips adoption.\n */\nasync function resolveDefaultModelId(\n deps: AuthMenuDeps,\n providerId: string,\n template: Partial<ProviderConfig>,\n): Promise<string | undefined> {\n if (template.models && template.models.length > 0) return template.models[0];\n const catalogId = template.type && template.type !== providerId ? template.type : providerId;\n const provider = await deps.modelsRegistry.getProvider(catalogId).catch(() => undefined);\n return provider?.models?.[0]?.id;\n}\n\n/**\n * Adopt `providerId` as the global default provider/model when none is set.\n * Reads the raw config (provider/model are plaintext top-level keys) so we\n * never clobber an existing choice, then persists via {@link saveToGlobalConfig}.\n */\nasync function adoptAsDefaultIfUnset(\n deps: AuthMenuDeps,\n providerId: string,\n template: Partial<ProviderConfig>,\n): Promise<void> {\n const targetPath = deps.profileConfigPath;\n let cfg: Record<string, unknown> = {};\n try {\n cfg = JSON.parse(await fs.readFile(targetPath, 'utf8')) as Record<string, unknown>;\n } catch {\n // Missing/unparsable config \u2014 treat as \"no default set\" and continue.\n }\n if (cfg['provider'] && cfg['model']) return; // already has a usable default\n\n const modelId = await resolveDefaultModelId(deps, providerId, template);\n if (!modelId) return; // nothing concrete to point the default at\n\n // Write straight to the same config path we just saved the provider into.\n // Re-serialising the parsed object preserves the vault-encrypted provider\n // blobs verbatim (we never decrypt here), and scoping the write to\n // the resolved profile target keeps it path-honest \u2014 unlike saveToGlobalConfig, whose\n // backup step targets the real ~/.wrongstack regardless of the path passed.\n cfg['provider'] = providerId;\n cfg['model'] = modelId;\n await atomicWrite(targetPath, JSON.stringify(cfg, null, 2), { mode: 0o600 });\n deps.renderer.write(\n ` ${color.green('\u2713')} Set ${color.bold(providerId)}/${color.bold(modelId)} as the default.\\n`,\n );\n}\n\nasync function promptForLabel(deps: AuthMenuDeps, usedLabels: Set<string>): Promise<string | null> {\n const defaultLabel = suggestLabel(usedLabels);\n const labelRaw = (\n await deps.reader.readLine(\n ` ${color.amber('?')} Label for this key ${color.dim(`[${defaultLabel}]`)}: `,\n )\n ).trim();\n const label = labelRaw || defaultLabel;\n if (usedLabels.has(label)) {\n deps.renderer.writeError(`Label \"${label}\" is already used. Use update (u) instead.`);\n return null;\n }\n return label;\n}\n", "/**\n * Pure helper for generating non-colliding custom provider ids.\n *\n * Shared by the `/auth` custom-provider flow (blank id \u2192 auto name) and the\n * config doctor's blank-id repair, so both surfaces name providers the same\n * way: `custom-1`, `custom-2`, \u2026 skipping any id already in the config.\n */\n\n/**\n * Return the first `custom-N` id (N \u2265 1) not present in `existing`.\n * `existing` is any iterable of the provider ids already taken.\n */\nexport function nextCustomProviderId(existing: Iterable<string>): string {\n const taken = new Set(existing);\n let n = 1;\n while (taken.has(`custom-${n}`)) n++;\n return `custom-${n}`;\n}\n", "/**\n * `wstack auth local` \u2014 quick-add shortcut for local-LLM servers.\n *\n * Three servers are first-class: Ollama, vLLM, LM Studio. They share an\n * OpenAI-compatible wire format at `/v1/chat/completions`, so each entry\n * here just declares the defaults that the matching wire preset\n * (see `@wrongstack/providers/src/presets/local-llm.ts`) expects.\n *\n * Difference that matters at the config layer:\n * - Ollama \u2192 no auth (the server rejects any Authorization header).\n * - vLLM \u2192 optional Bearer auth; key is left blank when auth is\n * disabled on the server, so the prompt is \"Enter to skip\".\n * - LM Studio \u2192 same as vLLM (optional Bearer).\n *\n * Selection is interactive by default \u2014 the user picks `1/2/3` from a\n * numbered list. A direct path is also exposed for scripting via the\n * `--name <ollama|vllm|lmstudio>` flag.\n *\n * Before saving, the shortcut runs a health probe (`GET /v1/models`)\n * to verify the server is actually reachable. The probe is opt-out via\n * `--no-probe`; failures are non-fatal by default \u2014 the user is asked\n * whether to save anyway. Every log line is run through the shared\n * `SecretScrubber` before reaching the renderer, so a Bearer token\n * accidentally captured in a probe log can never echo to the terminal\n * in plaintext.\n */\nimport type { SecretScrubber } from '@wrongstack/core/types';\nimport { color } from '@wrongstack/core/utils';\nimport { DefaultSecretScrubber } from '@wrongstack/core/security';\nimport {\n mutateConfigProviders,\n normalizeKeys,\n nowIso,\n writeKeysBack,\n} from '../provider-config-utils.js';\nimport { loadProviders } from './helpers.js';\nimport { LOCAL_LLM_PRESETS, type LocalLlmPresetEntry } from './local-presets.js';\nimport { suggestLabel } from './shared.js';\nimport type { AuthMenuDeps } from './types.js';\nimport { probeLocalLlm } from '@wrongstack/runtime/probe';\nimport type { ProbeOptions, ProbeResult } from '@wrongstack/runtime/probe';\nimport {\n type AuthAuditLogger,\n type AuthAuditEvent,\n decideAuthLocalEvents,\n NOOP_AUDIT_LOGGER,\n} from './auth-menu-audit.js';\n\n// Re-export from the runtime package so consumers (CLI tests, the\n// top-level CLI barrel) keep a stable import path. The runtime\n// package owns the canonical implementation \u2014 the WebUI server\n// imports from there too, so the probe runs in both contexts without\n// pulling the full CLI into the WebUI dependency graph.\nexport { probeLocalLlm, type ProbeOptions, type ProbeResult };\n\n// Preset data + type live in a dependency-free module so the startup\n// provider picker can import them without pulling in the probe/config\n// machinery this file depends on. Re-exported here to keep the public\n// import path (`@wrongstack/cli` barrel, tests) stable.\nexport { LOCAL_LLM_PRESETS, type LocalLlmPresetEntry };\n\nconst PRESET_BY_ID = new Map(LOCAL_LLM_PRESETS.map((p) => [p.id, p]));\n\nexport interface RunAuthLocalOptions {\n /**\n * Direct pick: skip the interactive menu and configure this preset.\n * `wstack auth local --name ollama` maps to `{ name: 'ollama' }`.\n */\n name?: string | undefined;\n /**\n * Override the default base URL. Empty / undefined falls back to the\n * preset's `defaultBaseUrl`.\n */\n baseUrl?: string | undefined;\n /**\n * Optional key to save. When omitted, the shortcut prompts the user\n * (unless the preset is `noAuth: true`).\n */\n apiKey?: string | undefined;\n /**\n * Optional label for the saved key. Defaults to \"default\" (matching\n * `addKeyForProvider` and `runAuthDirect`).\n */\n label?: string | undefined;\n /**\n * Force-skip the key prompt even for presets that normally accept a\n * key. Useful for scripting `wstack auth local --name ollama --no-key`\n * so no TTY input is required.\n */\n skipKey?: boolean | undefined;\n /**\n * Skip the reachability probe entirely. Use for scripting when the\n * local server may not be running yet (e.g. CI installing Ollama in\n * the background) but the user still wants the config in place.\n */\n noProbe?: boolean | undefined;\n /**\n * Run the probe and report, but don't save. Useful for re-checking a\n * previously-saved local provider.\n */\n probeOnly?: boolean | undefined;\n /**\n * Inject a custom `fetch` (test seam). Defaults to the global one.\n */\n fetchImpl?: typeof fetch | undefined;\n /**\n * Probe timeout override (test seam). Defaults to {@link PROBE_TIMEOUT_MS}.\n */\n probeTimeoutMs?: number | undefined;\n /**\n * Pre-populate `providers[id].models` so the user can launch\n * `wstack --provider <id> --model <picked>` right after the shortcut\n * completes. Four shapes are accepted:\n *\n * - `undefined` (or omitted) \u2192 don't touch `cfg.models`.\n * - `'first'` \u2192 take the first model id from the probe.\n * - `<N>` (a positive integer string) \u2192 take the first N ids.\n * Caps at the available list size.\n * - Anything else \u2192 treated as a literal comma-separated list of\n * model ids. Used verbatim, ignoring the probe result.\n *\n * When the probe didn't run (`noProbe: true`) or failed, only the\n * literal-list shape is meaningful \u2014 the count-based shapes return\n * an empty list and the shortcut proceeds without writing models.\n */\n models?: string | undefined;\n /**\n * Audit logger (test seam). When supplied, the function emits\n * structured `auth.local.*` events for the save lifecycle:\n * `add` / `clear` / `undo` / `probe_skip` / `probe_failed_save`.\n * The default is a no-op logger (production usage in\n * `wstack auth local` doesn't currently wire one \u2014 the WS server\n * is the source of truth for the dedicated `provider.*` message\n * types on the WebUI side; this option exists so the\n * integration test can capture the CLI flow's events for\n * end-to-end verification).\n */\n audit?: AuthAuditLogger | undefined;\n}\n\n/**\n * Quick-add entry point. Returns 0 on success, 1 on a hard error.\n *\n * The exit-code semantics are:\n * - 0 \u2192 provider saved (or `probeOnly` ran successfully / user\n * canceled with no state change / user declined save after\n * probe failure)\n * - 1 \u2192 hard failure: unknown --name, mutate threw, etc.\n */\nexport async function runAuthLocal(\n deps: AuthMenuDeps,\n opts: RunAuthLocalOptions = {},\n): Promise<number> {\n const scrubber = deps.secretScrubber ?? new DefaultSecretScrubber();\n const audit: AuthAuditLogger = opts.audit ?? NOOP_AUDIT_LOGGER;\n\n const preset = opts.name ? PRESET_BY_ID.get(opts.name.toLowerCase()) : undefined;\n if (opts.name && !preset) {\n deps.renderer.writeError(\n `Unknown local server \"${opts.name}\". Valid: ${LOCAL_LLM_PRESETS.map((p) => p.id).join(', ')}.`,\n );\n return 1;\n }\n\n const chosen = preset ?? (await pickLocalPreset(deps));\n if (!chosen) {\n // Picker returns undefined on either user-cancel (`q`) or an\n // unknown-selection. Both cases have already been reported to the\n // user via the renderer; there's no error state to surface.\n return 0;\n }\n\n // Resolve the base URL \u2014 user override, then preset default.\n const baseUrl = opts.baseUrl?.trim() || chosen.defaultBaseUrl;\n\n // Resolve the key \u2014 non-interactive path when caller provided it,\n // else prompt (unless the preset is noAuth and the user didn't opt\n // out of the prompt via --no-key).\n let apiKey: string | undefined;\n if (opts.apiKey !== undefined) {\n apiKey = opts.apiKey.trim() || undefined;\n } else if (chosen.noAuth) {\n apiKey = undefined;\n } else if (opts.skipKey) {\n apiKey = undefined;\n } else {\n apiKey = await promptOptionalKey(deps, chosen);\n }\n\n // \u2500\u2500 Health probe \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\u2500\n // Run unless the user explicitly disabled it. On failure, prompt\n // before saving \u2014 local servers being down is a common cause of\n // \"why isn't anything working\" and we'd rather catch it here.\n // The probe result is captured (not just inspected) because the\n // --model flag consumes its modelIds below.\n let probe: ProbeResult | undefined;\n let probeFailedAndSaved = false;\n if (!opts.noProbe) {\n probe = await probeLocalLlm({\n baseUrl,\n apiKey,\n noAuth: chosen.noAuth,\n presetLabel: chosen.label,\n scrubber,\n fetchImpl: opts.fetchImpl,\n timeoutMs: opts.probeTimeoutMs,\n });\n\n renderProbeResult(deps, probe);\n\n if (opts.probeOnly) {\n // Don't save \u2014 just report. Exit 0 is correct: we did exactly\n // what the user asked.\n return 0;\n }\n\n if (!probe.ok) {\n if (chosen.noAuth) {\n // Keyless loopback gateway (OmniRoute / Ollama): there's no\n // credential to validate, and these are meant to be configured\n // ahead of the server being up \u2014 OmniRoute auto-discovers its\n // model list at boot. Skip the \"Save anyway?\" detour entirely and\n // save with an informational note rather than nagging the user.\n deps.renderer.write(\n color.dim(\n ` Saving ${chosen.label} anyway \u2014 keyless local gateway needs no key ` +\n 'and discovers models when it comes up.\\n',\n ),\n );\n probeFailedAndSaved = true;\n } else {\n const saveAnyway = await promptSaveAnyway(deps);\n if (!saveAnyway) {\n deps.renderer.write(color.dim(' Cancelled. Nothing saved.\\n'));\n return 0;\n }\n probeFailedAndSaved = true;\n }\n }\n }\n\n // Resolve the model list once \u2014 passed to the save block below and\n // used for the \"Launch:\" hint so the user can copy-paste a working\n // command after the shortcut completes. `probe` may be undefined\n // (when --no-probe was passed); resolveModelList handles that.\n const resolvedModels = resolveModelList(opts.models, probe, scrubber);\n\n // Resolve the label (used for the key entry \u2014 always present so the\n // saved shape matches the rest of the config, even when apiKey is\n // undefined).\n const label = opts.label?.trim() || 'default';\n\n const providers = await loadProviders(deps);\n const existing = providers[chosen.id];\n // Capture the previous models list BEFORE the mutate, so the\n // audit-log decision (add vs clear vs undo) can compare\n // against the pre-save state. The list is defensive-copied\n // because `mutateConfigProviders` mutates `p.models` in\n // place, and the capture must survive that mutation.\n const previousModels: string[] | undefined = existing?.models\n ? [...existing.models]\n : existing?.models === undefined\n ? undefined\n : [...existing.models];\n const usedLabels = new Set(existing ? normalizeKeys(existing).map((k) => k.label) : []);\n let finalLabel = label;\n if (usedLabels.has(finalLabel)) {\n let n = 2;\n while (usedLabels.has(`${label}-${n}`)) n++;\n finalLabel = `${label}-${n}`;\n deps.renderer.writeInfo(`Label collided; saving as \"${finalLabel}\".`);\n }\n\n try {\n await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {\n const p = all[chosen.id] ?? { type: chosen.id };\n if (!p.type) p.type = chosen.id;\n // Wire family is always openai-compatible for these three.\n if (!p.family) p.family = 'openai-compatible';\n if (!p.baseUrl) p.baseUrl = baseUrl;\n // vLLM and LM Studio both rely on the `openai-compatible` family\n // for the right token-limit param. No env vars to probe \u2014 local\n // servers don't read process env for auth.\n if (!p.envVars) p.envVars = [];\n\n // Pre-populate `models` when the user passed --model. Three\n // shapes from the resolver:\n // - `null` \u2192 flag not passed; don't touch p.models\n // - `[]` \u2192 empty list (user passed --model \"\" to clear)\n // - non-empty \u2192 overwrite with the resolved list\n // The merge is intentionally write-on-write: the user's\n // explicit --model value always wins over any pre-existing\n // models entry. To preserve an existing list, simply omit the\n // flag.\n if (resolvedModels !== null) {\n p.models = [...resolvedModels];\n }\n\n if (apiKey) {\n const list = normalizeKeys(p);\n list.push({ label: finalLabel, apiKey, createdAt: nowIso() });\n writeKeysBack(p, list);\n if (!p.activeKey) p.activeKey = finalLabel;\n }\n all[chosen.id] = p;\n }, deps.profileConfigPath);\n } catch (err) {\n deps.renderer.writeError(`Failed to save ${chosen.id}: ${(err as Error).message}`);\n return 1;\n }\n\n // \u2500\u2500 Audit-log emit \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 // The `decideAuthLocalEvents` helper is a pure function that\n // maps (previous state, new state, probe outcome) \u2192 event\n // list. The lifecycle events mirror the WebUI's\n // `provider.clear_models` / `provider.undo_clear` message\n // types so the two surfaces share an audit-log vocabulary.\n const events: AuthAuditEvent[] = decideAuthLocalEvents({\n providerId: chosen.id,\n baseUrl,\n previousModels,\n newModels: resolvedModels,\n keyLabel: apiKey ? finalLabel : undefined,\n probeFailedSave: probeFailedAndSaved && probe\n ? {\n status: probe.status,\n ...(probe.detail !== undefined ? { detail: probe.detail } : {}),\n }\n : undefined,\n });\n for (const event of events) {\n audit.emit(event);\n }\n\n if (apiKey) {\n deps.renderer.write(\n ` ${color.green('\u2713')} Saved ${color.bold(chosen.id)}/${color.bold(finalLabel)} ` +\n `\u2192 ${color.cyan(baseUrl)}\\n`,\n );\n } else {\n deps.renderer.write(\n ` ${color.green('\u2713')} Saved ${color.bold(chosen.id)} ` +\n `(no key) \u2192 ${color.cyan(baseUrl)}\\n`,\n );\n }\n\n // When --model resolved to a non-empty list, the user can copy-paste\n // the first id straight into --model. When the resolver returned\n // null (no flag passed) or [] (empty literal), keep the placeholder\n // hint so the UX stays informative.\n const firstModel = resolvedModels && resolvedModels.length > 0 ? resolvedModels[0] : null;\n const modelHint = firstModel\n ? color.cyan(firstModel)\n : color.dim('<model-id>');\n\n deps.renderer.write(\n color.dim(\n ` Launch: wstack --provider ${chosen.id} --model ${modelHint} \"<task>\"\\n`,\n ),\n );\n return 0;\n}\n\n/**\n * Resolve the user-supplied `models` option against the probe result.\n *\n * - `undefined` \u2192 null (don't write `cfg.models`)\n * - `'first'` \u2192 first probe id, or null if probe failed\n * - `<positive int>` \u2192 first N probe ids, or null if probe failed\n * - literal csv \u2192 parsed list, ignoring the probe (the\n * user knows exactly which ids they want)\n *\n * Returns the resolved id list, or null when no `models` should be\n * written. Each entry is scrubbed before return \u2014 the user's literal\n * list could in theory contain a credential if they pasted it from\n * a config dump; better to scrub once here than risk echoing it back.\n */\nexport function resolveModelList(\n models: string | undefined,\n probe: ProbeResult | undefined,\n scrubber: SecretScrubber,\n): string[] | null {\n if (models === undefined) return null;\n\n // The literal-list path: a positive integer is treated as a count\n // when the probe succeeded, otherwise we fall through to the literal\n // parser below. This keeps `'5'` from being interpreted as a model\n // id named \"5\" when a probe result is available.\n const trimmed = models.trim();\n if (trimmed.length === 0) return [];\n\n // The two probe-driven shapes need a successful probe with at least\n // one model id.\n const hasProbeIds = probe?.status === 'ok' && (probe.modelIds?.length ?? 0) > 0;\n const probeIds = hasProbeIds ? (probe?.modelIds ?? []) : [];\n\n if (trimmed === 'first') {\n if (probeIds.length === 0) return null;\n return [scrubber.scrub(probeIds[0]!)];\n }\n if (/^\\d+$/.test(trimmed)) {\n if (probeIds.length === 0) return null;\n const n = Math.min(Number.parseInt(trimmed, 10), probeIds.length);\n return probeIds.slice(0, n).map((id) => scrubber.scrub(id));\n }\n\n // Literal CSV: split, trim, dedupe, scrub each, drop empties.\n const seen = new Set<string>();\n const out: string[] = [];\n for (const raw of trimmed.split(',')) {\n const id = scrubber.scrub(raw.trim());\n if (id.length === 0) continue;\n if (seen.has(id)) continue;\n seen.add(id);\n out.push(id);\n }\n return out;\n}\n\n/**\n * Render the probe result with consistent color/formatting. Always\n * passes the rendered string through the scrubber before writing.\n */\nfunction renderProbeResult(\n deps: AuthMenuDeps,\n probe: ProbeResult,\n opts: { presetLabel?: string } = {},\n): void {\n const label = opts.presetLabel ? ` ${color.bold(opts.presetLabel)}` : '';\n const elapsed = probe.elapsedMs !== undefined ? ` ${color.dim(`(${probe.elapsedMs}ms)`)}` : '';\n\n switch (probe.status) {\n case 'ok': {\n const models =\n probe.modelCount !== undefined\n ? color.dim(`, ${probe.modelCount} model${probe.modelCount === 1 ? '' : 's'}`)\n : '';\n deps.renderer.write(\n ` ${color.green('\u25CF')} ${label} health probe ok${models}${elapsed}\\n`,\n );\n break;\n }\n case 'timeout': {\n deps.renderer.write(\n ` ${color.red('\u25CF')} ${label} health probe timed out${elapsed}\\n` +\n ` ${color.dim('The server did not respond within the timeout.')}\\n` +\n ` ${color.dim('Is the local server running? Check the port and try again.')}\\n`,\n );\n break;\n }\n case 'unreachable': {\n const detail = probe.detail ? ` ${color.dim(`(${probe.detail})`)}` : '';\n deps.renderer.write(\n ` ${color.red('\u25CF')} ${label} server unreachable${detail}\\n` +\n ` ${color.dim('Could not connect. Common causes:')}\\n` +\n ` ${color.dim(' - The local server is not running')}\\n` +\n ` ${color.dim(' - The port is blocked by a firewall')}\\n` +\n ` ${color.dim(' - The base URL is wrong')}\\n`,\n );\n break;\n }\n case 'http_error': {\n const status = probe.httpStatus !== undefined ? ` HTTP ${probe.httpStatus}` : '';\n const detail = probe.detail ? ` ${color.dim(`\u2014 ${probe.detail}`)}` : '';\n deps.renderer.write(\n ` ${color.yellow('\u25CF')} ${label} health probe got${status}${detail}\\n`,\n );\n break;\n }\n case 'invalid_response': {\n deps.renderer.write(\n ` ${color.yellow('\u25CF')} ${label} health probe returned an unexpected shape\\n` +\n (probe.detail ? ` ${color.dim(probe.detail)}\\n` : ''),\n );\n break;\n }\n case 'skipped': {\n // Not currently emitted \u2014 kept for completeness in case we\n // wire a flag-driven skip in the future.\n break;\n }\n }\n}\n\n/**\n * After a failed probe, ask the user whether to save the provider\n * anyway. Default answer is N \u2014 so a misclick or piped input doesn't\n * silently create a broken config.\n */\nasync function promptSaveAnyway(deps: AuthMenuDeps): Promise<boolean> {\n const answer = (\n await deps.reader.readLine(\n `\\n${color.amber('?')} ${color.bold('Save anyway?')} ` +\n `${color.dim('[y/N]')}: `,\n )\n )\n .trim()\n .toLowerCase();\n return answer === 'y' || answer === 'yes';\n}\n\n/* -------------------------------------------------------------------------- */\n/* Interactive picker */\n/* -------------------------------------------------------------------------- */\n\n/** Show the picker, return the chosen preset or undefined on cancel. */\nasync function pickLocalPreset(deps: AuthMenuDeps): Promise<LocalLlmPresetEntry | undefined> {\n deps.renderer.write(\n `\\n${color.bold('Local LLM servers')} ${color.dim('\u2014 pick one to pre-fill the base URL')}\\n\\n`,\n );\n\n let idx = 1;\n for (const entry of LOCAL_LLM_PRESETS) {\n const auth = entry.noAuth ? color.dim('(no auth)') : color.dim('(optional auth)');\n deps.renderer.write(\n ` ${color.dim(`${idx}.`.padStart(4))} ${color.bold(entry.label.padEnd(12))} ` +\n `${color.cyan(entry.defaultBaseUrl.padEnd(34))} ${auth}\\n`,\n );\n deps.renderer.write(\n ` ${color.dim(entry.hint)}\\n`,\n );\n idx++;\n }\n\n const answer = (\n await deps.reader.readLine(\n `\\n${color.amber('?')} Pick ${color.dim(`(1-${LOCAL_LLM_PRESETS.length}, q to quit)`)}: `,\n )\n )\n .trim()\n .toLowerCase();\n\n if (!answer || answer === 'q' || answer === 'quit') return undefined;\n\n const num = Number.parseInt(answer, 10);\n if (!Number.isNaN(num) && num >= 1 && num <= LOCAL_LLM_PRESETS.length) {\n return LOCAL_LLM_PRESETS[num - 1];\n }\n const byId = LOCAL_LLM_PRESETS.find((p) => p.id === answer);\n if (byId) return byId;\n\n deps.renderer.writeError(`Unknown selection: \"${answer}\"`);\n return undefined;\n}\n\n/**\n * Prompt for a Bearer key with the option to skip (Enter on an empty\n * line). vLLM and LM Studio both run fine with auth disabled, so an\n * empty submit is a legitimate choice \u2014 it just means the shortcut\n * saves the provider without a key entry.\n */\nasync function promptOptionalKey(\n deps: AuthMenuDeps,\n preset: LocalLlmPresetEntry,\n): Promise<string | undefined> {\n const answer = (\n await deps.reader.readSecret(\n ` ${color.amber('?')} ${color.bold(preset.label)} API key ` +\n `${color.dim('(hidden \u2014 Enter to skip if auth is disabled on the server)')}: `,\n )\n ).trim();\n if (!answer) return undefined;\n return answer;\n}\n\n// Re-exported for tests.\nexport { suggestLabel };\n", "/**\n * Structured audit logger for the `wstack auth local` lifecycle.\n *\n * Emits JSON-line events to an injectable sink (default: stdout).\n * The event names mirror the WebUI's WS message types\n * (`provider.clear_models` \u2194 `auth.local.clear`,\n * `provider.undo_clear` \u2194 `auth.local.undo`) so a downstream\n * tool that filters on one convention finds the corresponding\n * events on the other surface.\n *\n * Why a dedicated logger (vs. `console.log`)?\n * - **Test seam** \u2014 tests inject an in-memory array sink and\n * assert on the recorded events. `console.log` can't be\n * captured cleanly across the test runner / reporter.\n * - **Schema stability** \u2014 the discriminated union of\n * `AuthAuditEvent` types gives downstream consumers a\n * contract they can switch on. Plain `console.log` strings\n * drift on every commit.\n * - **Redaction built in** \u2014 every event passes through a\n * `SecretScrubber` before reaching the sink, so a Bearer\n * token accidentally captured in a payload can't echo to\n * stdout / the audit file in plaintext.\n *\n * The logger is intentionally minimal: no buffering, no\n * rotation, no transport. The CLI process is short-lived and\n * emits at most a handful of events per invocation. A\n * long-running consumer (file rotation, OTLP export) would\n * belong in a dedicated audit-sink module, not here.\n */\nimport type { SecretScrubber } from '@wrongstack/core/types';\nimport { DefaultSecretScrubber } from '@wrongstack/core/security';\n\n/**\n * Discriminated union of every event the auth-menu local flow\n * can emit. New events slot in here as the lifecycle grows \u2014\n * the `type` field is the stable contract.\n */\nexport type AuthAuditEvent =\n | {\n type: 'auth.local.add';\n providerId: string;\n baseUrl: string;\n /** The resolved model list saved to disk. Empty when the\n * user didn't pass `--model`. */\n models: string[];\n /** Label of the saved key entry, if any. */\n keyLabel?: string | undefined;\n }\n | {\n /**\n * Emitted when the save replaces a previously non-empty\n * `cfg.models` allowlist with `[]`. Pairs with\n * `auth.local.undo` \u2014 a search for both events in\n * sequence surfaces a \"user changed their mind\" pair.\n */\n type: 'auth.local.clear';\n providerId: string;\n baseUrl: string;\n /** The list the user just removed. */\n previousModels: string[];\n }\n | {\n /**\n * Emitted when the save restores a non-empty `cfg.models`\n * allowlist that was previously `[]` or absent. The\n * `restoredModels` field carries the new list verbatim.\n * Pairs with `auth.local.clear`.\n */\n type: 'auth.local.undo';\n providerId: string;\n baseUrl: string;\n /** The list the user just restored. */\n restoredModels: string[];\n }\n | {\n /**\n * Emitted when the `--model` flag was probe-driven\n * (`'first'` / `'<N>'`) but the probe didn't return\n * enough ids. The flag is silently ignored in that case\n * \u2014 this event lets the audit log surface the silent\n * skip.\n */\n type: 'auth.local.probe_skip';\n providerId: string;\n baseUrl: string;\n requestedShape: 'first' | string;\n }\n | {\n /**\n * Emitted when the health probe failed AND the user chose\n * to save anyway. Pairs with the probe result line in\n * the terminal \u2014 the audit event is the durable record\n * that the provider was saved in a known-bad state.\n */\n type: 'auth.local.probe_failed_save';\n providerId: string;\n baseUrl: string;\n probeStatus: string;\n probeDetail?: string | undefined;\n };\n\n/**\n * Sink contract: receives the post-scrub, post-stringify event\n * line. The default implementation writes to stdout; tests\n * inject an in-memory array.\n */\nexport interface AuthAuditSink {\n write(line: string): void;\n}\n\n/** Default sink: one JSON line per event on stdout. */\nfunction defaultStdoutSink(): AuthAuditSink {\n // process.stdout.write is the right primitive here \u2014 it\n // bypasses the test runner's `console.log` capture and\n // never throws. Use \\n explicitly; some terminals buffer\n // until they see one.\n return {\n write(line: string) {\n process.stdout.write(`${line}\\n`);\n },\n };\n}\n\n/** Stderr sink: one JSON line per event on stderr. */\nfunction defaultStderrSink(): AuthAuditSink {\n return {\n write(line: string) {\n process.stderr.write(`${line}\\n`);\n },\n };\n}\n\n/**\n * File sink: appends one JSON line per event to the named\n * path. Uses synchronous append + newline so events are\n * durable on process exit. Wraps any I/O failure as a thrown\n * error so the caller can surface it.\n */\nexport function fileAuditSink(path: string): AuthAuditSink {\n // Lazy require so the test suite (which doesn't touch the\n // file sink) doesn't pay the cost of importing `node:fs`\n // just to read the type.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = require('node:fs') as typeof import('node:fs');\n return {\n write(line: string) {\n fs.appendFileSync(path, `${line}\\n`, { encoding: 'utf8' });\n },\n };\n}\n\n/**\n * Resolve the `--audit` flag value (parsed by `parseAuthFlags`)\n * to a concrete `AuthAuditSink`. Returns `undefined` when the\n * caller didn't pass `--audit` (no sink is wired and the\n * audit log is silent).\n *\n * Resolution rules:\n * - `true` (bare `--audit`) \u2192 stdout\n * - `'stdout'` \u2192 stdout\n * - `'stderr'` \u2192 stderr\n * - `'<file-path>'` \u2192 append to the file\n * - `undefined` \u2192 undefined (no sink)\n */\nexport function resolveAuditSink(\n flag: boolean | string | undefined,\n): AuthAuditSink | undefined {\n if (flag === undefined) return undefined;\n if (flag === true || flag === 'stdout') return defaultStdoutSink();\n if (flag === 'stderr') return defaultStderrSink();\n // At this point, `flag` is narrowed to `string` \u2014 the\n // boolean literal `true` was handled above and the\n // `string` literals 'stdout' / 'stderr' are also handled.\n // The explicit `typeof` guard documents the narrowing for\n // the reader and silences a residual `boolean` in the\n // union (TS doesn't always narrow `boolean | string`\n // through `=== literal` chains).\n if (typeof flag !== 'string') return undefined;\n return fileAuditSink(flag);\n}\n\n/** In-memory sink for tests. Records every line verbatim. */\nexport function memAuthAuditSink(): AuthAuditSink & { lines: string[] } {\n const lines: string[] = [];\n return {\n lines,\n write(line: string) {\n lines.push(line);\n },\n };\n}\n\nexport interface AuthAuditLogger {\n /** Emit an event. The payload is JSON-serialized, scrubbed,\n * and written to the sink. No-ops when the sink is\n * `undefined` (tests that don't care about the audit log\n * can pass `audit: undefined`). */\n emit(event: AuthAuditEvent): void;\n}\n\n/** No-op logger for tests that don't need the audit log. */\nexport const NOOP_AUDIT_LOGGER: AuthAuditLogger = {\n emit: () => {},\n};\n\n/**\n * Build the canonical logger. The `scrubber` runs over the\n * serialized event so a Bearer token accidentally included\n * in a payload (e.g. an echo from a misbehaving server) is\n * redacted before reaching the sink.\n */\nexport function createAuthAuditLogger(\n sink: AuthAuditSink | undefined,\n scrubber: SecretScrubber = new DefaultSecretScrubber(),\n): AuthAuditLogger {\n if (!sink) return NOOP_AUDIT_LOGGER;\n return {\n emit(event) {\n // Scrub first, then serialize. Scrubbing the object\n // directly is more reliable than scrubbing the\n // serialized line (a value could contain a quote that\n // looks like a credential when serialized).\n const scrubbed = scrubEvent(event, scrubber);\n sink.write(JSON.stringify(scrubbed));\n },\n };\n}\n\n/**\n * Run the scrubber over every string leaf of the event\n * payload. The `type` discriminator is left intact (it's a\n * contract, not data). Nested arrays (`models`,\n * `previousModels`, `restoredModels`) are scrubbed\n * element-by-element.\n */\nfunction scrubEvent(\n event: AuthAuditEvent,\n scrubber: SecretScrubber,\n): AuthAuditEvent {\n switch (event.type) {\n case 'auth.local.add':\n return {\n type: 'auth.local.add',\n providerId: scrubber.scrub(event.providerId),\n baseUrl: scrubber.scrub(event.baseUrl),\n models: event.models.map((m) => scrubber.scrub(m)),\n ...(event.keyLabel !== undefined\n ? { keyLabel: scrubber.scrub(event.keyLabel) }\n : {}),\n };\n case 'auth.local.clear':\n return {\n type: 'auth.local.clear',\n providerId: scrubber.scrub(event.providerId),\n baseUrl: scrubber.scrub(event.baseUrl),\n previousModels: event.previousModels.map((m) => scrubber.scrub(m)),\n };\n case 'auth.local.undo':\n return {\n type: 'auth.local.undo',\n providerId: scrubber.scrub(event.providerId),\n baseUrl: scrubber.scrub(event.baseUrl),\n restoredModels: event.restoredModels.map((m) => scrubber.scrub(m)),\n };\n case 'auth.local.probe_skip':\n return {\n type: 'auth.local.probe_skip',\n providerId: scrubber.scrub(event.providerId),\n baseUrl: scrubber.scrub(event.baseUrl),\n requestedShape: scrubber.scrub(event.requestedShape),\n };\n case 'auth.local.probe_failed_save':\n return {\n type: 'auth.local.probe_failed_save',\n providerId: scrubber.scrub(event.providerId),\n baseUrl: scrubber.scrub(event.baseUrl),\n probeStatus: scrubber.scrub(event.probeStatus),\n ...(event.probeDetail !== undefined\n ? { probeDetail: scrubber.scrub(event.probeDetail) }\n : {}),\n };\n }\n}\n\n/**\n * Decide which audit event(s) to emit given the previous saved\n * state and the new save's resolved values. Pure function \u2014\n * the caller is responsible for the actual `emit()` call so\n * the same input always produces the same event list (and the\n * test suite can pin it).\n *\n * - `previousModels` is `undefined` when no prior entry\n * existed. `[]` means \"the user previously cleared\".\n * - `newModels` is `null` when the `--model` flag wasn't\n * passed (don't touch `cfg.models`). `[]` means \"the user\n * passed `--model ''` to clear\". A non-empty list is the\n * resolved list (probe-driven or literal).\n */\nexport function decideAuthLocalEvents(opts: {\n providerId: string;\n baseUrl: string;\n previousModels: string[] | undefined;\n newModels: string[] | null;\n keyLabel: string | undefined;\n probeSkip?: { shape: 'first' | string } | undefined;\n probeFailedSave?: { status: string; detail?: string } | undefined;\n}): AuthAuditEvent[] {\n const events: AuthAuditEvent[] = [];\n\n // The probe-skip and probe-failed-save events are emitted\n // unconditionally when they apply (the caller decides based\n // on the runtime probe result).\n if (opts.probeSkip) {\n events.push({\n type: 'auth.local.probe_skip',\n providerId: opts.providerId,\n baseUrl: opts.baseUrl,\n requestedShape: opts.probeSkip.shape,\n });\n }\n if (opts.probeFailedSave) {\n events.push({\n type: 'auth.local.probe_failed_save',\n providerId: opts.providerId,\n baseUrl: opts.baseUrl,\n probeStatus: opts.probeFailedSave.status,\n ...(opts.probeFailedSave.detail !== undefined\n ? { probeDetail: opts.probeFailedSave.detail }\n : {}),\n });\n }\n\n // The add/clear/undo detection runs only when the user\n // actually wrote `models` (i.e. the --model flag was\n // passed). When the flag is omitted we don't change the\n // allowlist, so no lifecycle event.\n if (opts.newModels === null) return events;\n\n const hadPriorAllowlist =\n opts.previousModels !== undefined && opts.previousModels.length > 0;\n\n if (hadPriorAllowlist && opts.newModels.length === 0) {\n // Non-empty \u2192 empty: a clear.\n events.push({\n type: 'auth.local.clear',\n providerId: opts.providerId,\n baseUrl: opts.baseUrl,\n previousModels: opts.previousModels!,\n });\n return events;\n }\n\n if (!hadPriorAllowlist && opts.newModels.length > 0) {\n // No prior allowlist (either undefined or []) \u2192 non-empty\n // list: a fresh add OR an undo (we can't distinguish a\n // \"user is configuring for the first time\" add from a\n // \"user just cleared and is now restoring\" undo from\n // disk state alone \u2014 the only signal is the prior state\n // being literally [] vs. undefined).\n if (opts.previousModels !== undefined) {\n // prior was [] (or some other empty state we\n // collapsed). This is an undo.\n events.push({\n type: 'auth.local.undo',\n providerId: opts.providerId,\n baseUrl: opts.baseUrl,\n restoredModels: [...opts.newModels],\n });\n } else {\n events.push({\n type: 'auth.local.add',\n providerId: opts.providerId,\n baseUrl: opts.baseUrl,\n models: [...opts.newModels],\n ...(opts.keyLabel !== undefined ? { keyLabel: opts.keyLabel } : {}),\n });\n }\n return events;\n }\n\n if (hadPriorAllowlist && opts.newModels.length > 0) {\n // Non-empty \u2192 non-empty: the user is overwriting an\n // existing allowlist. Not strictly a clear+undo \u2014 emit a\n // plain add so the audit log records the new state.\n events.push({\n type: 'auth.local.add',\n providerId: opts.providerId,\n baseUrl: opts.baseUrl,\n models: [...opts.newModels],\n ...(opts.keyLabel !== undefined ? { keyLabel: opts.keyLabel } : {}),\n });\n return events;\n }\n\n // Both empty (no prior allowlist, --model ''): the user\n // explicitly cleared an already-empty allowlist. No-op\n // for the audit log \u2014 no state change.\n return events;\n}\n"],
5
- "mappings": "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",
6
- "names": ["color", "color", "FetchError", "ParseError", "CLIENT_ID", "openBrowser", "FetchError", "ParseError", "color", "color", "color", "color", "color", "color", "color", "DefaultSecretScrubber", "DefaultSecretScrubber", "color"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/services/project-manifest.ts"],
4
- "sourcesContent": ["import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { ConfigError } from '@wrongstack/core/types';\nimport { readProjectIdentity, withFileLock, wstackGlobalRoot } from '@wrongstack/core/utils';\n\n// Shared project-manifest types and persistence.\n\nexport interface ProjectEntry {\n /** User-friendly name (defaults to dirname, can be renamed). */\n name: string;\n /** Absolute path to the project root. */\n root: string;\n /** Stable unique slug (dirname-hash) for per-project data storage. */\n slug: string;\n /** Repo-committed identity shared by clones, worktrees, and machines. */\n projectId?: string | undefined;\n /** ISO timestamp of last use. */\n lastSeen?: string | undefined;\n /** ISO timestamp of when the project was first registered. */\n createdAt?: string | undefined;\n /** Working directory of the most recent session (may differ from root). */\n lastWorkingDir?: string | undefined;\n}\n\nexport interface ProjectsManifest {\n projects: ProjectEntry[];\n}\n\n// \u2500\u2500 Path resolution \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\nfunction projectsJsonPath(globalConfigPath?: string | undefined): string {\n const base = globalConfigPath ? path.dirname(globalConfigPath) : wstackGlobalRoot();\n return path.join(base, 'projects.json');\n}\n\nfunction projectsDataDir(globalConfigPath?: string | undefined): string {\n const base = globalConfigPath ? path.dirname(globalConfigPath) : wstackGlobalRoot();\n return path.join(base, 'projects');\n}\n\n// \u2500\u2500 Read / Write manifest \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\nexport async function loadManifest(\n globalConfigPath?: string | undefined,\n): Promise<ProjectsManifest> {\n const file = projectsJsonPath(globalConfigPath);\n try {\n const raw = await fs.readFile(file, 'utf8');\n const parsed = JSON.parse(raw) as ProjectsManifest;\n return { projects: parsed.projects ?? [] };\n } catch {\n return { projects: [] };\n }\n}\n\nexport async function saveManifest(\n manifest: ProjectsManifest,\n globalConfigPath?: string | undefined,\n): Promise<void> {\n const file = projectsJsonPath(globalConfigPath);\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, JSON.stringify(manifest, null, 2), 'utf8');\n}\n\n// \u2500\u2500 Helpers \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\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Generate a unique slug from a project root path.\n */\nexport function generateSlug(root: string): string {\n const base =\n path\n .basename(root)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40) || 'project';\n const hash = createHash('sha256').update(path.resolve(root)).digest('hex').slice(0, 6);\n return `${base}-${hash}`;\n}\n\n/**\n * Find a project entry by slug, name, or root (partial match).\n */\nexport function findProject(manifest: ProjectsManifest, query: string): ProjectEntry | undefined {\n const lower = query.toLowerCase();\n // Exact slug match first\n let found = manifest.projects.find((p) => p.slug === lower);\n if (found) return found;\n // Name match\n found = manifest.projects.find((p) => p.name.toLowerCase() === lower);\n if (found) return found;\n // Root ends-with match\n found = manifest.projects.find((p) => p.root.toLowerCase().endsWith(lower));\n if (found) return found;\n // Root contains match\n found = manifest.projects.find((p) => p.root.toLowerCase().includes(lower));\n return found;\n}\n\n/**\n * Ensure the per-project data directory exists under ~/.wrongstack/projects/<slug>/.\n */\nexport async function ensureProjectDataDir(\n slug: string,\n globalConfigPath?: string | undefined,\n): Promise<string> {\n const dir = path.join(projectsDataDir(globalConfigPath), slug);\n await fs.mkdir(dir, { recursive: true });\n return dir;\n}\n\n/**\n * Idempotent project registration: ensure `projectRoot` has an entry in\n * projects.json, creating one when missing and refreshing `lastSeen` /\n * `lastWorkingDir` when present. Returns the (created or updated) entry.\n *\n * Every surface that opens a project (CLI/TUI boot, standalone WebUI boot,\n * WebUI projects.select) funnels through this so the manifest is the single\n * source of truth for \"which projects exist\" regardless of entry point.\n * Concurrent processes booting on the same machine serialize via a file\n * lock around the read-modify-write.\n */\nexport async function touchProjectInManifest(opts: {\n projectRoot: string;\n globalConfigPath?: string | undefined;\n /** Working dir of this session when it differs from the root. */\n workingDir?: string | undefined;\n /** Friendly name for a NEWLY created entry (default: basename). */\n name?: string | undefined;\n}): Promise<ProjectEntry> {\n const root = path.resolve(opts.projectRoot);\n const projectId = (await readProjectIdentity(root).catch(() => undefined))?.projectId;\n const file = projectsJsonPath(opts.globalConfigPath);\n let entry: ProjectEntry | undefined;\n await withFileLock(file, async () => {\n const manifest = await loadManifest(opts.globalConfigPath);\n const now = new Date().toISOString();\n entry = manifest.projects.find((p) => path.resolve(p.root) === root);\n if (entry) {\n entry.lastSeen = now;\n if (projectId) entry.projectId = projectId;\n if (opts.workingDir) entry.lastWorkingDir = path.resolve(opts.workingDir);\n } else {\n entry = {\n name: opts.name ?? path.basename(root),\n root,\n slug: generateSlug(root),\n projectId,\n createdAt: now,\n lastSeen: now,\n lastWorkingDir: opts.workingDir ? path.resolve(opts.workingDir) : undefined,\n };\n manifest.projects.push(entry);\n }\n await saveManifest(manifest, opts.globalConfigPath);\n });\n await ensureProjectDataDir(expectEntry(entry).slug, opts.globalConfigPath);\n return expectEntry(entry);\n}\n\nfunction expectEntry(e: ProjectEntry | undefined): ProjectEntry {\n if (!e)\n throw new ConfigError({\n message: 'touchProjectInManifest: entry not resolved',\n code: 'CONFIG_INVALID',\n context: { phase: 'manifest-resolve' },\n });\n return e;\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }