@wrongstack/cli 1.0.19 → 1.0.26

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 (195) hide show
  1. package/data/providers.json +44 -0
  2. package/dist/{acp-INCNOH42.js → acp-LI665LO2.js} +18 -7
  3. package/dist/arg-parser.d.ts +1 -0
  4. package/dist/ascii-mode-SG4PRNLP.js +7 -0
  5. package/dist/{auth-YXK3EDUL.js → auth-TE55JF4Z.js} +68 -22
  6. package/dist/auth-menu/direct.d.ts +1 -0
  7. package/dist/auth-menu/local.d.ts +2 -0
  8. package/dist/auth-menu/oauth-menu.d.ts +3 -1
  9. package/dist/auth-menu/panel-service.d.ts +20 -0
  10. package/dist/{bench-YBU6BVQP.js → bench-GTLPM22B.js} +2 -2
  11. package/dist/boot/append-system-prompt.d.ts +10 -0
  12. package/dist/boot/ascii-mode.d.ts +12 -0
  13. package/dist/boot/config-backup-recovery.d.ts +2 -1
  14. package/dist/boot/container-wiring.d.ts +4 -2
  15. package/dist/boot/dispatch-singleshot.d.ts +4 -1
  16. package/dist/boot/dispatch-webui.d.ts +11 -0
  17. package/dist/boot/mcp-config-flag.d.ts +22 -0
  18. package/dist/boot/piped-stdin.d.ts +40 -0
  19. package/dist/boot/restricted-mode.d.ts +15 -0
  20. package/dist/boot/safe-mode.d.ts +30 -0
  21. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  22. package/dist/boot/single-shot-budget.d.ts +30 -0
  23. package/dist/boot/stream-json.d.ts +36 -0
  24. package/dist/boot/structured-output.d.ts +16 -0
  25. package/dist/boot/system-prompt-builder.d.ts +2 -0
  26. package/dist/boot/tool-restriction-flags.d.ts +36 -0
  27. package/dist/boot/tui-project-picker-callback.d.ts +1 -1
  28. package/dist/boot/tui-settings-adapter.d.ts +15 -2
  29. package/dist/boot/worktree-sessions.d.ts +21 -0
  30. package/dist/{boot-auto-thin-MANHOYHE.js → boot-auto-thin-6Q56FY3F.js} +3 -2
  31. package/dist/boot-provider-selection.d.ts +67 -0
  32. package/dist/boot.d.ts +1 -38
  33. package/dist/{chunk-JY52HWL6.js → chunk-2EBVTYJR.js} +2 -2
  34. package/dist/{chunk-RDHFXOJM.js → chunk-2ERX3RPN.js} +112 -65
  35. package/dist/chunk-4TVYGG6G.js +62 -0
  36. package/dist/chunk-5JYDKG5B.js +154 -0
  37. package/dist/{chunk-KEPABQYT.js → chunk-5SEYGOCH.js} +8 -82
  38. package/dist/{chunk-3VXYY5JC.js → chunk-5UZBUV2H.js} +3 -19
  39. package/dist/chunk-BBHWW6LR.js +549 -0
  40. package/dist/chunk-BEHGRNOQ.js +58 -0
  41. package/dist/chunk-CZTXF6HY.js +140 -0
  42. package/dist/{chunk-JX6KL7OF.js → chunk-EPR42SWM.js} +39 -8
  43. package/dist/chunk-F5DCFAKI.js +36 -0
  44. package/dist/chunk-HLSHFXTO.js +97 -0
  45. package/dist/{chunk-CJTBLTS4.js → chunk-KJS5543T.js} +4 -3
  46. package/dist/{chunk-DE7BZDNK.js → chunk-KOEO4CJG.js} +27 -4
  47. package/dist/{chunk-SIS37L3W.js → chunk-L2RVEQWO.js} +211 -193
  48. package/dist/chunk-LBPLTTZ6.js +105 -0
  49. package/dist/chunk-LDCGZJTC.js +46 -0
  50. package/dist/chunk-LKPEBZBE.js +143 -0
  51. package/dist/chunk-LUMETJFO.js +171 -0
  52. package/dist/{chunk-KK2LB3ZS.js → chunk-OAVBM55Q.js} +9 -5
  53. package/dist/chunk-PZQBGUVZ.js +18 -0
  54. package/dist/{chunk-C3Z4N6A6.js → chunk-Q4INH2DG.js} +51 -3
  55. package/dist/chunk-R4QGL6GB.js +10 -0
  56. package/dist/{chunk-YLQEGYV4.js → chunk-RZ4ZDRYA.js} +14 -4
  57. package/dist/chunk-S4FFHDJG.js +93 -0
  58. package/dist/chunk-SFBFYIOW.js +271 -0
  59. package/dist/{chunk-RMQNCHGO.js → chunk-TI7KLHYX.js} +136 -11
  60. package/dist/{chunk-2ENZU66X.js → chunk-WQV2NP57.js} +5 -5
  61. package/dist/{chunk-B4JLSXZB.js → chunk-WSTVGC2C.js} +73 -45
  62. package/dist/chunk-X756ZS72.js +329 -0
  63. package/dist/{chunk-XJ7K67PP.js → chunk-YHYINL47.js} +63 -24
  64. package/dist/{chunk-2VMJ3E5Z.js → chunk-YTEOAWOJ.js} +6 -2
  65. package/dist/{chunk-GPPRNAKW.js → chunk-ZMX5HRLI.js} +2 -2
  66. package/dist/{cli-context-33F74CSZ.js → cli-context-UVGAN3NO.js} +496 -384
  67. package/dist/cli-entry-point.d.ts +2 -0
  68. package/dist/{cli-main-FNGMKPBA.js → cli-main-TN3KZ2P6.js} +3561 -2724
  69. package/dist/cli-update-notice.d.ts +2 -1
  70. package/dist/config-doctor.d.ts +10 -2
  71. package/dist/{config-transfer-2YF3CRTN.js → config-transfer-RUWLDCNK.js} +34 -13
  72. package/dist/{diag-doctor-ANPRUYFM.js → diag-doctor-BIZAFIAT.js} +2 -2
  73. package/dist/execute-deps.d.ts +2 -1
  74. package/dist/{execution-A6WJLSOC.js → execution-7QIP6GRY.js} +2384 -2055
  75. package/dist/fleet/host-types.d.ts +3 -1
  76. package/dist/goal-commands.d.ts +47 -0
  77. package/dist/goal-host.d.ts +1 -14
  78. package/dist/{hq-XQWQTRDA.js → hq-GLZ7QESM.js} +277 -261
  79. package/dist/hq-command-controller.d.ts +1 -1
  80. package/dist/{hq-server-IIBZQZU4.js → hq-server-YTKDVQPY.js} +2 -2
  81. package/dist/{hq-service-L5INQFM4.js → hq-service-BMMJAHRT.js} +11 -4
  82. package/dist/import-claude-code-32PCSIQI.js +236 -0
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.js +19 -10
  85. package/dist/kanban-supervisor-67ECABTD.js +7 -0
  86. package/dist/live-settings-input.d.ts +7 -0
  87. package/dist/{mailbox-serve-3GFOK2I7.js → mailbox-serve-NW5VZG7R.js} +3 -3
  88. package/dist/{mcp-DC5WSBOO.js → mcp-LBS45HWZ.js} +4 -4
  89. package/dist/modeldiag-36VODVIH.js +828 -0
  90. package/dist/{per-subcommand-help-DHTYU524.js → per-subcommand-help-QDAQASPZ.js} +3 -3
  91. package/dist/permission-prompt-mirror.d.ts +1 -1
  92. package/dist/permission-prompt.d.ts +16 -2
  93. package/dist/permission-rules-view.d.ts +18 -0
  94. package/dist/{permissions-CFDLXETM.js → permissions-PL27UHYD.js} +67 -45
  95. package/dist/plugin-config.d.ts +12 -0
  96. package/dist/plugin-management-types.d.ts +31 -0
  97. package/dist/plugin-management.d.ts +2 -30
  98. package/dist/plugin-package-install.d.ts +3 -0
  99. package/dist/{plugin-usage-M6KET4OZ.js → plugin-usage-CIGOOTX3.js} +6 -5
  100. package/dist/{plugins-WJLW6ULV.js → plugins-HQTXUD6A.js} +6 -3
  101. package/dist/preflight.d.ts +1 -1
  102. package/dist/{projects-LMNAGGEU.js → projects-T4CZCA25.js} +3 -6
  103. package/dist/provider-config-utils.d.ts +1 -6
  104. package/dist/provider-helpers.d.ts +7 -11
  105. package/dist/{providers-models-LFNZ5WI7.js → providers-models-5Z2PJTEW.js} +44 -34
  106. package/dist/release-asset-download.d.ts +13 -0
  107. package/dist/release-attestation.d.ts +28 -0
  108. package/dist/remote/remote-session.d.ts +64 -0
  109. package/dist/remote/remote-target.d.ts +69 -0
  110. package/dist/remote-O5WXHLWV.js +561 -0
  111. package/dist/{replay-Z3FTJEMM.js → replay-DEI566CW.js} +2 -2
  112. package/dist/services/commit-message.d.ts +2 -1
  113. package/dist/services/dispatch-classifier.d.ts +39 -5
  114. package/dist/session-move-P2EC2COA.js +44 -0
  115. package/dist/session-move.d.ts +20 -0
  116. package/dist/session-stats.d.ts +10 -0
  117. package/dist/{sessions-config-UL45XKX7.js → sessions-config-SXTTLNXA.js} +47 -9
  118. package/dist/settings-menu.d.ts +2 -0
  119. package/dist/short-circuit-flags-74Y5N6CF.js +10 -0
  120. package/dist/{simpleui-dist-CXSIDAXZ.js → simpleui-dist-7BQISSEP.js} +7 -3
  121. package/dist/skill-suggest-L2EVWB6R.js +290 -0
  122. package/dist/slash-commands/command-context.d.ts +15 -5
  123. package/dist/slash-commands/effort.d.ts +1 -1
  124. package/dist/slash-commands/fallback.d.ts +1 -1
  125. package/dist/slash-commands/gitid.d.ts +1 -1
  126. package/dist/slash-commands/goal-refiner.d.ts +4 -49
  127. package/dist/slash-commands/jev.d.ts +4 -0
  128. package/dist/slash-commands/mcp.d.ts +2 -1
  129. package/dist/slash-commands/openai-quota.d.ts +15 -0
  130. package/dist/slash-commands/permissions.d.ts +4 -0
  131. package/dist/slash-commands/sdd-task-mutations.d.ts +4 -0
  132. package/dist/slash-commands/settings-context-mutations.d.ts +5 -0
  133. package/dist/slash-commands/settings-keys.d.ts +2 -0
  134. package/dist/slash-commands/settings-limits-mutations.d.ts +12 -0
  135. package/dist/slash-commands/settings-reset.d.ts +6 -0
  136. package/dist/standalone-auto-update-TOTRGCSA.js +249 -0
  137. package/dist/standalone-auto-update.d.ts +65 -0
  138. package/dist/standalone-update-LZO3MNLH.js +24 -0
  139. package/dist/standalone-update.d.ts +55 -0
  140. package/dist/subcommands/handlers/hq-alerts.d.ts +3 -0
  141. package/dist/subcommands/handlers/hq-audit.d.ts +46 -0
  142. package/dist/subcommands/handlers/hq-data-dir.d.ts +13 -0
  143. package/dist/subcommands/handlers/import-claude-code.d.ts +42 -0
  144. package/dist/subcommands/handlers/permissions.d.ts +9 -3
  145. package/dist/subcommands/handlers/remote.d.ts +6 -0
  146. package/dist/subcommands/handlers/skill-suggest.d.ts +21 -0
  147. package/dist/subcommands/handlers/typesafe-brain-replay.d.ts +26 -0
  148. package/dist/subcommands/handlers/typesafe-judgment-check.d.ts +3 -0
  149. package/dist/subcommands/handlers/typesafe-topic-replay.d.ts +19 -0
  150. package/dist/subcommands/handlers/typesafe-triage-replay.d.ts +18 -0
  151. package/dist/subcommands/handlers/typesafe.d.ts +23 -0
  152. package/dist/subcommands/handlers/version-help.d.ts +5 -0
  153. package/dist/{subcommands-XSLXMIDP.js → subcommands-Q6ORSB2E.js} +2 -2
  154. package/dist/tui-resume-callback.d.ts +18 -0
  155. package/dist/typesafe-U7YB2RRV.js +316 -0
  156. package/dist/typesafe-brain-replay-C5276FVR.js +222 -0
  157. package/dist/typesafe-judgment-check-GGYYV5UF.js +29 -0
  158. package/dist/typesafe-topic-replay-ZILIU3WS.js +234 -0
  159. package/dist/typesafe-triage-replay-FGAW7QM7.js +215 -0
  160. package/dist/{update-5DPB4YD4.js → update-TDZX4IL2.js} +4 -3
  161. package/dist/{update-check-BS3DHTSI.js → update-check-J5ZVKS73.js} +3 -2
  162. package/dist/update-check.d.ts +1 -1
  163. package/dist/version-JB2UAV2A.js +11 -0
  164. package/dist/version-help-XJJQ7YSH.js +10 -0
  165. package/dist/version.d.ts +3 -2
  166. package/dist/webui-client-observability.d.ts +7 -0
  167. package/dist/webui-server/route-contexts.d.ts +1 -1
  168. package/dist/webui-server/session-start-payload.d.ts +5 -1
  169. package/dist/{webui-server-MRPGTTKL.js → webui-server-YTHLRFD2.js} +577 -370
  170. package/dist/webui-server-lifecycle.d.ts +57 -0
  171. package/dist/webui-server-options.d.ts +11 -0
  172. package/dist/webui-server.d.ts +1 -1
  173. package/dist/wiring/brain-and-orchestration.d.ts +3 -1
  174. package/dist/wiring/cli-prompt-and-tools-setup.d.ts +9 -0
  175. package/dist/wiring/cli-slash-commands-setup.d.ts +1 -0
  176. package/dist/wiring/domain-glossary.d.ts +5 -4
  177. package/dist/wiring/lifecycle-plugins.d.ts +4 -2
  178. package/dist/wiring/metrics.d.ts +9 -1
  179. package/dist/wiring/pipeline.d.ts +2 -7
  180. package/dist/wiring/plugins.d.ts +4 -1
  181. package/dist/wiring/provider-persisters.d.ts +24 -0
  182. package/dist/wiring/provider-runtime.d.ts +9 -1
  183. package/dist/wiring/provider-status.d.ts +1 -0
  184. package/dist/wiring/provider-utility-tools.d.ts +3 -1
  185. package/dist/wiring/runtime-dispatch-state.d.ts +3 -1
  186. package/package.json +28 -28
  187. package/dist/chunk-2CZEORLV.js +0 -54
  188. package/dist/chunk-672UXYL3.js +0 -65
  189. package/dist/chunk-6WRKAACA.js +0 -96
  190. package/dist/chunk-DR2OXU46.js +0 -174
  191. package/dist/chunk-JACOMTIH.js +0 -275
  192. package/dist/chunk-XJXDOF63.js +0 -28
  193. package/dist/modeldiag-CJSFHZ3J.js +0 -1356
  194. package/dist/short-circuit-flags-7GQIGMVD.js +0 -10
  195. package/dist/version-help-WXI42PZ3.js +0 -10
@@ -1,35 +1,43 @@
1
1
  import {
2
+ activateRestrictedMode,
3
+ announceSafeMode,
2
4
  applySimpleUiFullAutoProfile,
3
5
  detectProjectFacts,
4
6
  isSimpleUiFullAuto,
5
- makePromptDelegate,
7
+ makeStdinPromptDelegate,
6
8
  renderAgentsTemplate,
7
- renderDiff
8
- } from "./chunk-RMQNCHGO.js";
9
+ renderDiff,
10
+ resolveLaunchAllowedTools,
11
+ resolveToolRestriction
12
+ } from "./chunk-TI7KLHYX.js";
13
+ import {
14
+ parseOutputFormat,
15
+ resolveJsonSchemaFlag
16
+ } from "./chunk-LKPEBZBE.js";
9
17
  import {
10
18
  theme as theme2
11
19
  } from "./chunk-QD544J2B.js";
20
+ import {
21
+ parseWebuiSessionChildOptions,
22
+ writeWebuiSessionChildError
23
+ } from "./chunk-ZMX5HRLI.js";
12
24
  import {
13
25
  fmtTok,
14
26
  patchConfig
15
27
  } from "./chunk-EWKESL4L.js";
16
- import {
17
- parseWebuiSessionChildOptions,
18
- writeWebuiSessionChildError
19
- } from "./chunk-GPPRNAKW.js";
20
28
  import {
21
29
  subcommands
22
- } from "./chunk-2CZEORLV.js";
30
+ } from "./chunk-BEHGRNOQ.js";
23
31
  import {
24
32
  renderDeepHelp,
25
33
  renderFocusedHelp
26
- } from "./chunk-JX6KL7OF.js";
34
+ } from "./chunk-EPR42SWM.js";
27
35
  import {
28
36
  handleHelpVersionShortCircuit
29
- } from "./chunk-2ENZU66X.js";
37
+ } from "./chunk-WQV2NP57.js";
30
38
  import {
31
39
  DEFAULT_PORT
32
- } from "./chunk-KK2LB3ZS.js";
40
+ } from "./chunk-OAVBM55Q.js";
33
41
  import "./chunk-HXJYHAR4.js";
34
42
  import {
35
43
  resolveHqPasswordInput
@@ -37,21 +45,35 @@ import {
37
45
  import {
38
46
  normalizeHqPublicOrigin
39
47
  } from "./chunk-5EA6OTLJ.js";
48
+ import {
49
+ resolveLaunchMcpServers
50
+ } from "./chunk-HLSHFXTO.js";
51
+ import {
52
+ installProviderPersisters
53
+ } from "./chunk-LDCGZJTC.js";
40
54
  import {
41
55
  parseHqIpAllowlist
42
56
  } from "./chunk-Q7E3BPDU.js";
43
57
  import {
44
58
  discoverAndMergeProviders
45
59
  } from "./chunk-D5GB5MHA.js";
60
+ import {
61
+ runUpdateCommand
62
+ } from "./chunk-KOEO4CJG.js";
63
+ import "./chunk-U3SS4NRH.js";
46
64
  import {
47
65
  applyNodeEnvDefault,
48
66
  applySessionShellDefault,
49
67
  runPreflight
50
- } from "./chunk-672UXYL3.js";
51
- import "./chunk-6WRKAACA.js";
68
+ } from "./chunk-LBPLTTZ6.js";
69
+ import "./chunk-RZ4ZDRYA.js";
70
+ import {
71
+ applyAsciiMode
72
+ } from "./chunk-PZQBGUVZ.js";
73
+ import "./chunk-5JYDKG5B.js";
52
74
  import {
53
75
  CLI_VERSION
54
- } from "./chunk-XJXDOF63.js";
76
+ } from "./chunk-F5DCFAKI.js";
55
77
  import {
56
78
  addFromCatalog,
57
79
  boxBottom,
@@ -63,36 +85,27 @@ import {
63
85
  runPicker,
64
86
  saveToGlobalConfig,
65
87
  theme
66
- } from "./chunk-RDHFXOJM.js";
67
- import "./chunk-2VMJ3E5Z.js";
68
- import "./chunk-B4JLSXZB.js";
88
+ } from "./chunk-2ERX3RPN.js";
89
+ import "./chunk-YTEOAWOJ.js";
69
90
  import {
70
91
  isKeylessLocalProvider,
71
92
  visibleModelIds
72
- } from "./chunk-3VXYY5JC.js";
93
+ } from "./chunk-5UZBUV2H.js";
94
+ import {
95
+ resolveActiveApiKey
96
+ } from "./chunk-LUMETJFO.js";
97
+ import "./chunk-DAKVBMD4.js";
73
98
  import {
74
99
  activeProfileConfigPath
75
100
  } from "./chunk-YMXXOOFN.js";
101
+ import "./chunk-WSTVGC2C.js";
76
102
  import {
77
103
  parseArgs
78
- } from "./chunk-C3Z4N6A6.js";
79
- import "./chunk-DAKVBMD4.js";
80
- import {
81
- mutateConfigProviders,
82
- normalizeKeys,
83
- resolveActiveApiKey,
84
- writeKeysBack
85
- } from "./chunk-DR2OXU46.js";
86
- import {
87
- runUpdateCommand
88
- } from "./chunk-DE7BZDNK.js";
89
- import "./chunk-U3SS4NRH.js";
90
- import "./chunk-YLQEGYV4.js";
104
+ } from "./chunk-Q4INH2DG.js";
91
105
 
92
106
  // src/cli-context.ts
93
107
  import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
94
108
  import { writeErr as writeErr2 } from "@wrongstack/core/utils";
95
- import { setOAuthTokenPersister, setProviderModelPersister } from "@wrongstack/providers";
96
109
 
97
110
  // src/boot/container-wiring.ts
98
111
  import { DefaultPathResolver } from "@wrongstack/core/infrastructure";
@@ -102,10 +115,11 @@ import { createDefaultContainer } from "@wrongstack/runtime";
102
115
  // src/cli-bundled-prompts.ts
103
116
  import { createRequire } from "node:module";
104
117
  import * as path from "node:path";
118
+ import { wrongstackPackageJsonPath } from "@wrongstack/core/utils";
105
119
  function resolveBundledPromptsDir() {
106
120
  try {
107
121
  const req = createRequire(import.meta.url);
108
- const corePkg = req.resolve("@wrongstack/core/package.json");
122
+ const corePkg = wrongstackPackageJsonPath("@wrongstack/core", (id) => req.resolve(id));
109
123
  return path.join(path.dirname(corePkg), "data", "prompts");
110
124
  } catch {
111
125
  return void 0;
@@ -115,10 +129,11 @@ function resolveBundledPromptsDir() {
115
129
  // src/cli-bundled-skills.ts
116
130
  import { createRequire as createRequire2 } from "node:module";
117
131
  import * as path2 from "node:path";
132
+ import { wrongstackPackageJsonPath as wrongstackPackageJsonPath2 } from "@wrongstack/core/utils";
118
133
  function resolveBundledSkillsDir() {
119
134
  try {
120
135
  const req = createRequire2(import.meta.url);
121
- const corePkg = req.resolve("@wrongstack/core/package.json");
136
+ const corePkg = wrongstackPackageJsonPath2("@wrongstack/core", (id) => req.resolve(id));
122
137
  return path2.join(path2.dirname(corePkg), "skills");
123
138
  } catch {
124
139
  return void 0;
@@ -167,7 +182,7 @@ function makeMirroredPromptDelegate(deps) {
167
182
  const typed = await deps.inner(tool, input, suggestedPattern, controller.signal);
168
183
  if (remoteDecision !== void 0) return remoteDecision;
169
184
  settled = true;
170
- const decision = typed === "yes" || typed === "always" || typed === "deny" ? typed : "no";
185
+ const decision = typed === "yes" || typed === "always" || typed === "always-exact" || typed === "always-command" || typed === "always-tool" || typed === "deny" ? typed : "no";
171
186
  finish(decision);
172
187
  return decision;
173
188
  } finally {
@@ -191,12 +206,13 @@ function wireContainer(deps) {
191
206
  events,
192
207
  permission: {
193
208
  yolo: deps.config.yolo,
209
+ launchAllowedTools: deps.launchAllowedTools,
194
210
  // Wrapped so the REPL's terminal prompt also appears on the HQ
195
211
  // dashboard and can be answered from there. The wrapper is a no-op
196
212
  // until `approvalMirror.current` is populated (HQ telemetry boot), and
197
213
  // the terminal prompt itself behaves exactly as it always has.
198
214
  promptDelegate: makeMirroredPromptDelegate({
199
- inner: makePromptDelegate(deps.reader),
215
+ inner: makeStdinPromptDelegate(deps.reader),
200
216
  getRegistry: () => approvalMirror.current,
201
217
  getSessionId: () => approvalMirror.sessionId?.()
202
218
  })
@@ -474,7 +490,7 @@ async function promptModeArrow(deps) {
474
490
  const { renderer } = deps;
475
491
  const stdin = process.stdin;
476
492
  const out = (s) => renderer.write(s);
477
- return await new Promise((resolve2) => {
493
+ return await new Promise((resolve3) => {
478
494
  let index = 0;
479
495
  let drawn = 0;
480
496
  let remaining = Math.round(MENU_TIMEOUT_MS / 1e3);
@@ -529,7 +545,7 @@ async function promptModeArrow(deps) {
529
545
  out("\x1B[0J");
530
546
  out(finalLine);
531
547
  out("\x1B[?25h");
532
- resolve2(result);
548
+ resolve3(result);
533
549
  };
534
550
  const pick = () => {
535
551
  const opt = MODE_OPTIONS[index];
@@ -588,7 +604,7 @@ async function promptModeArrow(deps) {
588
604
  setRawMode(stdin, true);
589
605
  stdin.resume();
590
606
  } catch {
591
- resolve2(null);
607
+ resolve3(null);
592
608
  return;
593
609
  }
594
610
  out("\x1B[?25l");
@@ -761,9 +777,40 @@ async function persistMenuChoice(globalConfigPath, choice) {
761
777
 
762
778
  // src/boot/short-circuit-desktop.ts
763
779
  import { spawn } from "node:child_process";
780
+ import { statSync } from "node:fs";
764
781
  import { createRequire as createRequire3 } from "node:module";
782
+ import { homedir } from "node:os";
765
783
  import * as path3 from "node:path";
766
784
  import { color as color2 } from "@wrongstack/core/utils";
785
+ function desktopExecutableCandidates(platform, home, env) {
786
+ const join7 = platform === "win32" ? path3.win32.join : path3.posix.join;
787
+ const managed = join7(home, ".wrongstack", "desktop");
788
+ if (platform === "win32") {
789
+ const local = env["LOCALAPPDATA"] || join7(home, "AppData", "Local");
790
+ return [
791
+ join7(managed, "WrongStack.exe"),
792
+ join7(local, "Programs", "WrongStack", "WrongStack.exe")
793
+ ];
794
+ }
795
+ if (platform === "darwin") {
796
+ return [
797
+ join7(managed, "WrongStack.app", "Contents", "MacOS", "WrongStack"),
798
+ join7(home, "Applications", "WrongStack.app", "Contents", "MacOS", "WrongStack"),
799
+ "/Applications/WrongStack.app/Contents/MacOS/WrongStack"
800
+ ];
801
+ }
802
+ if (platform === "linux") {
803
+ return [join7(managed, "WrongStack.AppImage"), "/opt/WrongStack/wrongstack-desktop"];
804
+ }
805
+ return [];
806
+ }
807
+ function isFile(candidate) {
808
+ try {
809
+ return statSync(candidate).isFile();
810
+ } catch {
811
+ return false;
812
+ }
813
+ }
767
814
  function stripDesktopLauncherArgs(argv) {
768
815
  const out = [];
769
816
  for (let i = 0; i < argv.length; i++) {
@@ -784,35 +831,50 @@ async function handleDesktopShortCircuit(flags, argv) {
784
831
  return launchDesktop(stripDesktopLauncherArgs(argv));
785
832
  }
786
833
  async function launchDesktop(args) {
787
- const req = createRequire3(import.meta.url);
788
- let launcherPath;
789
- try {
790
- const desktopPkgPath = req.resolve("@wrongstack/desktop/package.json");
791
- launcherPath = path3.join(path3.dirname(desktopPkgPath), "bin", "wrongstack-desktop.js");
792
- } catch {
834
+ const override = process.env["WRONGSTACK_DESKTOP_EXECUTABLE"]?.trim();
835
+ if (override && (!path3.isAbsolute(override) || !isFile(override))) {
793
836
  process.stderr.write(
794
- [
795
- color2.red("\u2717 WrongStack Desktop is not installed."),
796
- "",
797
- "Install the desktop package:",
798
- " npm install -g @wrongstack/desktop",
799
- "",
800
- "The umbrella package also supports desktop when installed with optional dependencies:",
801
- " npm install -g wrongstack",
802
- ""
803
- ].join("\n")
837
+ "WRONGSTACK_DESKTOP_EXECUTABLE must point to an existing absolute executable path.\n"
804
838
  );
805
839
  return 1;
806
840
  }
807
- return await new Promise((resolve2) => {
808
- const executable = selectDesktopLauncherExecutable(
809
- process.execPath,
810
- typeof globalThis.Bun !== "undefined",
811
- process.env["NODE"]
812
- );
813
- const child = spawn(executable, [launcherPath, ...args], {
841
+ const native = override || desktopExecutableCandidates(process.platform, homedir(), process.env).find(isFile);
842
+ let executable = native;
843
+ let launchArgs = args;
844
+ if (!executable)
845
+ try {
846
+ const req = createRequire3(import.meta.url);
847
+ const desktopPkgPath = req.resolve("@wrongstack/desktop/package.json");
848
+ launchArgs = [
849
+ path3.join(path3.dirname(desktopPkgPath), "bin", "wrongstack-desktop.js"),
850
+ ...args
851
+ ];
852
+ executable = selectDesktopLauncherExecutable(
853
+ process.execPath,
854
+ typeof globalThis.Bun !== "undefined",
855
+ process.env["NODE"]
856
+ );
857
+ } catch {
858
+ process.stderr.write(
859
+ [
860
+ color2.red("\u2717 WrongStack Desktop is not installed."),
861
+ "",
862
+ "Download WrongStack Desktop from GitHub Releases:",
863
+ " https://github.com/WrongStack/WrongStack/releases/latest",
864
+ "",
865
+ "For a portable or custom installation, set WRONGSTACK_DESKTOP_EXECUTABLE",
866
+ "to the absolute path of the Desktop executable (on macOS: WrongStack.app/Contents/MacOS/WrongStack).",
867
+ ""
868
+ ].join("\n")
869
+ );
870
+ return 1;
871
+ }
872
+ return await new Promise((resolve3) => {
873
+ const env = { ...process.env };
874
+ if (native) delete env["ELECTRON_RUN_AS_NODE"];
875
+ const child = spawn(executable, launchArgs, {
814
876
  stdio: "inherit",
815
- env: process.env,
877
+ env,
816
878
  windowsHide: false
817
879
  });
818
880
  child.once("error", (err) => {
@@ -820,11 +882,11 @@ async function launchDesktop(args) {
820
882
  `${color2.red("\u2717 Failed to start WrongStack Desktop:")} ${err.message}
821
883
  `
822
884
  );
823
- resolve2(1);
885
+ resolve3(1);
824
886
  });
825
887
  child.once("exit", (code, signal) => {
826
- if (typeof code === "number") resolve2(code);
827
- else resolve2(signal ? 1 : 0);
888
+ if (typeof code === "number") resolve3(code);
889
+ else resolve3(signal ? 1 : 0);
828
890
  });
829
891
  });
830
892
  }
@@ -849,24 +911,24 @@ async function isHqAlreadyRunning(dataDir) {
849
911
  return null;
850
912
  }
851
913
  async function isPortInUse(host, port) {
852
- return new Promise((resolve2) => {
914
+ return new Promise((resolve3) => {
853
915
  const server = net.createServer();
854
916
  server.once("error", (err) => {
855
917
  if (err.code === "EADDRINUSE") {
856
- resolve2(true);
918
+ resolve3(true);
857
919
  } else {
858
- resolve2(false);
920
+ resolve3(false);
859
921
  }
860
922
  });
861
923
  server.once("listening", () => {
862
- server.close(() => resolve2(false));
924
+ server.close(() => resolve3(false));
863
925
  });
864
926
  server.listen(port, host);
865
927
  });
866
928
  }
867
929
  async function handleHqShortCircuit(flags) {
868
930
  if (flags["hq"] !== true) return null;
869
- const { startHqServer } = await import("./hq-server-IIBZQZU4.js");
931
+ const { startHqServer } = await import("./hq-server-YTKDVQPY.js");
870
932
  const tunnelRequested = flags["tunnel"] === true;
871
933
  const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
872
934
  let publicOrigin;
@@ -1080,7 +1142,7 @@ ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
1080
1142
  } catch {
1081
1143
  }
1082
1144
  }
1083
- await new Promise((resolve2) => {
1145
+ await new Promise((resolve3) => {
1084
1146
  const shutdown = async () => {
1085
1147
  const results = await Promise.allSettled([
1086
1148
  ...tunnel ? [tunnel.close()] : [],
@@ -1099,7 +1161,7 @@ ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
1099
1161
  })
1100
1162
  );
1101
1163
  }
1102
- resolve2();
1164
+ resolve3();
1103
1165
  };
1104
1166
  process.on("SIGINT", shutdown);
1105
1167
  process.on("SIGTERM", shutdown);
@@ -1108,26 +1170,195 @@ ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
1108
1170
  }
1109
1171
 
1110
1172
  // src/boot.ts
1111
- import * as fs6 from "node:fs/promises";
1112
- import { createRequire as createRequire4 } from "node:module";
1113
1173
  import * as os from "node:os";
1114
- import * as path7 from "node:path";
1174
+ import * as path9 from "node:path";
1175
+ import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
1176
+
1177
+ // src/boot-provider-selection.ts
1178
+ import * as fs2 from "node:fs/promises";
1179
+ import { createRequire as createRequire4 } from "node:module";
1180
+ import * as path4 from "node:path";
1115
1181
  import { fileURLToPath } from "node:url";
1116
- import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
1182
+ import {
1183
+ color as color4,
1184
+ moduleUrlFor,
1185
+ toErrorMessage,
1186
+ wrongstackPackageJsonPath as wrongstackPackageJsonPath3
1187
+ } from "@wrongstack/core/utils";
1188
+ import { isSetupProvider } from "@wrongstack/providers";
1189
+ function resolveBundledOverlayFile() {
1190
+ try {
1191
+ return fileURLToPath(
1192
+ new URL("../data/providers.json", moduleUrlFor(import.meta.url, "@wrongstack/cli"))
1193
+ );
1194
+ } catch {
1195
+ return void 0;
1196
+ }
1197
+ }
1198
+ async function validateSavedProviderModel(config, modelsRegistry) {
1199
+ const providerId = config.provider;
1200
+ const modelId = config.model;
1201
+ if (!providerId || !modelId) return { ok: false, reason: "missing provider/model" };
1202
+ if (isSetupProvider(providerId)) return { ok: true };
1203
+ const saved = config.providers?.[providerId];
1204
+ const lookupId = saved?.type && saved.type !== providerId ? saved.type : providerId;
1205
+ const catalogProvider = await modelsRegistry.getProvider(lookupId).catch(() => void 0);
1206
+ if (!catalogProvider && !saved?.family)
1207
+ return { ok: false, reason: `provider "${providerId}" is no longer available` };
1208
+ const hasCredential = (catalogProvider?.envVars ?? saved?.envVars ?? []).some(
1209
+ (envVar) => Boolean(process.env[envVar])
1210
+ ) || saved !== void 0 && resolveActiveApiKey(saved) !== void 0 || isKeylessLocalProvider({
1211
+ apiBase: saved?.baseUrl ?? catalogProvider?.apiBase,
1212
+ envVars: saved?.envVars ?? catalogProvider?.envVars
1213
+ });
1214
+ if (!hasCredential) return { ok: false, reason: `provider "${providerId}" has no usable key` };
1215
+ const visible = visibleModelIds(
1216
+ providerId,
1217
+ config,
1218
+ (catalogProvider?.models ?? []).map((m) => m.id),
1219
+ saved
1220
+ );
1221
+ if (visible.length > 0 && !visible.includes(modelId)) {
1222
+ return {
1223
+ ok: false,
1224
+ reason: `model "${modelId}" is no longer available for provider "${providerId}"`
1225
+ };
1226
+ }
1227
+ return { ok: true };
1228
+ }
1229
+ async function autoSelectSavedProvider(config, modelsRegistry) {
1230
+ const providers = config.providers ?? {};
1231
+ const entries = config.provider && providers[config.provider] ? [[config.provider, providers[config.provider]]] : Object.entries(providers);
1232
+ for (const [id, cfg] of entries) {
1233
+ if (!cfg) continue;
1234
+ let model = cfg.models?.[0];
1235
+ if (!model) {
1236
+ const catalogId = cfg.type && cfg.type !== id ? cfg.type : id;
1237
+ const catalog = await modelsRegistry.getProvider(catalogId).catch(() => void 0);
1238
+ model = catalog?.models?.[0]?.id;
1239
+ }
1240
+ if (model) return { provider: id, model };
1241
+ }
1242
+ return void 0;
1243
+ }
1244
+ function resolveBundledSkillsDir2() {
1245
+ try {
1246
+ const req = createRequire4(import.meta.url);
1247
+ const corePkg = wrongstackPackageJsonPath3("@wrongstack/core", (id) => req.resolve(id));
1248
+ return path4.join(path4.dirname(corePkg), "skills");
1249
+ } catch {
1250
+ return void 0;
1251
+ }
1252
+ }
1253
+ function resolveBundledPromptsDir2() {
1254
+ try {
1255
+ const req = createRequire4(import.meta.url);
1256
+ const corePkg = wrongstackPackageJsonPath3("@wrongstack/core", (id) => req.resolve(id));
1257
+ return path4.join(path4.dirname(corePkg), "data", "prompts");
1258
+ } catch {
1259
+ return void 0;
1260
+ }
1261
+ }
1262
+ function isHomeDirectory(cwd, userHome) {
1263
+ if (!cwd || !userHome) return false;
1264
+ return path4.resolve(cwd) === path4.resolve(userHome);
1265
+ }
1266
+ function shouldPrintYoloNotice(lastChoices, yoloPinned, yolo) {
1267
+ return !lastChoices && yoloPinned === void 0 && yolo;
1268
+ }
1269
+ async function checkGitInCwd(opts) {
1270
+ const { cwd, renderer, reader } = opts;
1271
+ const cwdGit = path4.join(cwd, ".git");
1272
+ let hasCwdGit = false;
1273
+ try {
1274
+ await fs2.access(cwdGit);
1275
+ hasCwdGit = true;
1276
+ } catch {
1277
+ }
1278
+ if (!hasCwdGit) {
1279
+ renderer.write(
1280
+ `
1281
+ ${color4.amber("\u25CB")} This folder has no ${color4.bold(".git")} repository.
1282
+ `
1283
+ );
1284
+ const answer = (await reader.readLine(` ${color4.amber("?")} Initialize one here? ${color4.dim("[y/N]")} `)).trim().toLowerCase();
1285
+ if (answer === "y" || answer === "yes") {
1286
+ try {
1287
+ const { spawn: spawn2 } = await import("node:child_process");
1288
+ await new Promise((resolve3, reject) => {
1289
+ const child = spawn2("git", ["init"], {
1290
+ cwd,
1291
+ signal: AbortSignal.timeout(1e4),
1292
+ windowsHide: true
1293
+ });
1294
+ child.on("error", reject);
1295
+ child.on(
1296
+ "close",
1297
+ (code) => code === 0 ? resolve3() : reject(new Error(`git init failed with ${code}`))
1298
+ );
1299
+ });
1300
+ renderer.write(` ${color4.green("\u2713")} Git repository initialized
1301
+ `);
1302
+ hasCwdGit = true;
1303
+ } catch (err) {
1304
+ renderer.writeError(`git init failed: ${toErrorMessage(err)}
1305
+ `);
1306
+ }
1307
+ }
1308
+ }
1309
+ const parentDir = path4.dirname(cwd);
1310
+ if (parentDir !== cwd) {
1311
+ try {
1312
+ await fs2.access(path4.join(parentDir, ".git"));
1313
+ renderer.write(
1314
+ ` ${color4.dim("\u2139")} A ${color4.bold(".git")} repo exists in the parent directory: ${color4.dim(parentDir)}
1315
+ `
1316
+ );
1317
+ } catch {
1318
+ }
1319
+ }
1320
+ }
1321
+
1322
+ // src/boot.ts
1117
1323
  import { DefaultLogger } from "@wrongstack/core/infrastructure";
1118
1324
  import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
1119
- import { DefaultModelsRegistry } from "@wrongstack/core/models";
1325
+ import { DefaultModelsRegistry, startCatalog } from "@wrongstack/core/models";
1120
1326
  import { ToolRegistry } from "@wrongstack/core/registry";
1121
1327
  import { normalizeTokenSavingTier } from "@wrongstack/core/types";
1122
- import { isSetupProvider, SETUP_MODEL_ID, SETUP_PROVIDER_ID } from "@wrongstack/providers";
1123
- import { color as color10, isStdinTTY as isStdinTTY2, writeErr } from "@wrongstack/core/utils";
1328
+ import { color as color11, isStdinTTY as isStdinTTY2, writeErr } from "@wrongstack/core/utils";
1329
+ import { isSetupProvider as isSetupProvider2, SETUP_MODEL_ID, SETUP_PROVIDER_ID } from "@wrongstack/providers";
1124
1330
  import { createDefaultContainer as createDefaultContainer2 } from "@wrongstack/runtime";
1125
1331
  import { registerBuiltinToolTier } from "@wrongstack/tools/tool-tier";
1126
1332
 
1333
+ // src/boot/append-system-prompt.ts
1334
+ import * as fs3 from "node:fs/promises";
1335
+ import * as path5 from "node:path";
1336
+ async function resolveAppendedSystemPrompt(flags, cwd) {
1337
+ const parts = [];
1338
+ const inline = flags["append-system-prompt"];
1339
+ if (typeof inline === "string" && inline.trim()) parts.push(inline.trim());
1340
+ const file = flags["append-system-prompt-file"];
1341
+ if (file === true) {
1342
+ throw new Error("--append-system-prompt-file needs a path");
1343
+ }
1344
+ if (typeof file === "string" && file.trim()) {
1345
+ const resolved = path5.resolve(cwd, file.trim());
1346
+ let text;
1347
+ try {
1348
+ text = await fs3.readFile(resolved, "utf8");
1349
+ } catch (err) {
1350
+ const reason = err.code ?? String(err);
1351
+ throw new Error(`--append-system-prompt-file: cannot read ${resolved} (${reason})`);
1352
+ }
1353
+ if (text.trim()) parts.push(text.trim());
1354
+ }
1355
+ return parts.length > 0 ? parts.join("\n\n") : void 0;
1356
+ }
1357
+
1127
1358
  // src/boot/config-backup-recovery.ts
1128
- import * as fs2 from "node:fs/promises";
1129
- import * as path4 from "node:path";
1130
- import { atomicWrite as atomicWrite2, backupConfigFile, color as color4, toErrorMessage } from "@wrongstack/core/utils";
1359
+ import * as fs4 from "node:fs/promises";
1360
+ import * as path6 from "node:path";
1361
+ import { atomicWrite as atomicWrite2, backupConfigFile, color as color5, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
1131
1362
  function isRecord(value) {
1132
1363
  return value !== null && typeof value === "object" && !Array.isArray(value);
1133
1364
  }
@@ -1138,7 +1369,7 @@ function providerIds(value) {
1138
1369
  }
1139
1370
  async function defaultProfileProvidersAreEmpty(profilePath) {
1140
1371
  try {
1141
- const parsed = JSON.parse(await fs2.readFile(profilePath, "utf8"));
1372
+ const parsed = JSON.parse(await fs4.readFile(profilePath, "utf8"));
1142
1373
  return providerIds(parsed).length === 0;
1143
1374
  } catch {
1144
1375
  return false;
@@ -1160,22 +1391,27 @@ function profileSnapshotTimestamp(fileName, fallback) {
1160
1391
  Number(millisecond)
1161
1392
  );
1162
1393
  }
1163
- async function findLatestProviderBackup(globalRoot) {
1164
- const directory = path4.join(globalRoot, "config-history");
1394
+ async function findLatestProviderBackup(globalRoot, profileName = "default") {
1395
+ const directory = path6.join(globalRoot, "config-history");
1396
+ const escapedProfile = profileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1397
+ const filePattern = new RegExp(
1398
+ `^profiles-${escapedProfile}-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}\\.json$`,
1399
+ "i"
1400
+ );
1165
1401
  const candidates = [];
1166
1402
  let entries;
1167
1403
  try {
1168
- entries = await fs2.readdir(directory, { withFileTypes: true });
1404
+ entries = await fs4.readdir(directory, { withFileTypes: true });
1169
1405
  } catch {
1170
1406
  return void 0;
1171
1407
  }
1172
1408
  for (const entry of entries) {
1173
- if (!entry.isFile() || !/^profiles-default-config-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}\.json$/i.test(entry.name)) {
1409
+ if (!entry.isFile() || !filePattern.test(entry.name)) {
1174
1410
  continue;
1175
1411
  }
1176
- const filePath = path4.join(directory, entry.name);
1412
+ const filePath = path6.join(directory, entry.name);
1177
1413
  try {
1178
- const stat2 = await fs2.stat(filePath);
1414
+ const stat2 = await fs4.stat(filePath);
1179
1415
  candidates.push({
1180
1416
  filePath,
1181
1417
  fileName: entry.name,
@@ -1187,7 +1423,7 @@ async function findLatestProviderBackup(globalRoot) {
1187
1423
  candidates.sort((a, b) => b.modifiedAtMs - a.modifiedAtMs);
1188
1424
  for (const candidate of candidates) {
1189
1425
  try {
1190
- const raw = await fs2.readFile(candidate.filePath, "utf8");
1426
+ const raw = await fs4.readFile(candidate.filePath, "utf8");
1191
1427
  const parsed = JSON.parse(raw);
1192
1428
  const ids = providerIds(parsed);
1193
1429
  if (ids.length === 0) continue;
@@ -1199,24 +1435,25 @@ async function findLatestProviderBackup(globalRoot) {
1199
1435
  }
1200
1436
  async function restoreDefaultProfileBackup(opts) {
1201
1437
  await backupConfigFile(opts.profilePath, { globalRoot: opts.globalRoot });
1202
- await fs2.mkdir(path4.dirname(opts.profilePath), { recursive: true });
1438
+ await fs4.mkdir(path6.dirname(opts.profilePath), { recursive: true });
1203
1439
  await atomicWrite2(opts.profilePath, opts.backup.raw, { mode: 384 });
1204
1440
  }
1205
1441
  async function maybeRestoreDefaultProfileFromBackup(opts) {
1206
1442
  if (!await defaultProfileProvidersAreEmpty(opts.profilePath)) return false;
1207
- const backup = await findLatestProviderBackup(opts.globalRoot);
1443
+ const profileName = opts.profileName ?? "default";
1444
+ const backup = await findLatestProviderBackup(opts.globalRoot, profileName);
1208
1445
  if (!backup) return false;
1209
1446
  const shownProviders = backup.providerIds.slice(0, 5).join(", ");
1210
1447
  const remainder = backup.providerIds.length - 5;
1211
1448
  const providerSummary = remainder > 0 ? `${shownProviders} +${remainder}` : shownProviders;
1212
1449
  opts.renderer.write(
1213
1450
  `
1214
- ${color4.amber("\u25CB")} ${color4.bold("default")} profile has no saved providers.
1215
- ${color4.dim("Latest usable backup:")} ${color4.bold(backup.fileName)} ${color4.dim(`(${backup.providerIds.length} provider: ${providerSummary})`)}
1451
+ ${color5.amber("\u25CB")} ${color5.bold(profileName)} profile has no saved providers.
1452
+ ${color5.dim("Latest usable backup:")} ${color5.bold(backup.fileName)} ${color5.dim(`(${backup.providerIds.length} provider: ${providerSummary})`)}
1216
1453
  `
1217
1454
  );
1218
1455
  const answer = (await opts.reader.readLine(
1219
- ` ${color4.amber("?")} Restore all settings from this backup? ${color4.dim("[Y/n]")} `
1456
+ ` ${color5.amber("?")} Restore all settings from this backup? ${color5.dim("[Y/n]")} `
1220
1457
  )).trim().toLowerCase();
1221
1458
  if (answer === "n" || answer === "no") return false;
1222
1459
  try {
@@ -1226,12 +1463,12 @@ async function maybeRestoreDefaultProfileFromBackup(opts) {
1226
1463
  profilePath: opts.profilePath
1227
1464
  });
1228
1465
  opts.renderer.write(
1229
- ` ${color4.green("\u2713")} Restored all settings from ${color4.dim(backup.fileName)}
1466
+ ` ${color5.green("\u2713")} Restored all settings from ${color5.dim(backup.fileName)}
1230
1467
  `
1231
1468
  );
1232
1469
  return true;
1233
1470
  } catch (err) {
1234
- opts.renderer.writeWarning(`Could not restore config backup: ${toErrorMessage(err)}
1471
+ opts.renderer.writeWarning(`Could not restore config backup: ${toErrorMessage2(err)}
1235
1472
  `);
1236
1473
  return false;
1237
1474
  }
@@ -1245,11 +1482,11 @@ import {
1245
1482
  SYSTEM_PROMPT_VARIANT_OPTIONS,
1246
1483
  SYSTEM_PROMPT_VARIANTS
1247
1484
  } from "@wrongstack/core/agent";
1248
- import { color as color8 } from "@wrongstack/core/utils";
1485
+ import { color as color9 } from "@wrongstack/core/utils";
1249
1486
 
1250
1487
  // src/pre-launch/first-run.ts
1251
1488
  import { hasProviderCredential } from "@wrongstack/core/models";
1252
- import { color as color5, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
1489
+ import { color as color6, toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
1253
1490
  import { PROVIDER_DEFINITIONS } from "@wrongstack/providers/definitions";
1254
1491
  async function hasAnyCredential(config, modelsRegistry, env = process.env) {
1255
1492
  for (const cfg of Object.values(config.providers ?? {})) {
@@ -1275,39 +1512,39 @@ function renderWelcome(renderer) {
1275
1512
  renderer.write(`${boxTop("Welcome to WrongStack")}
1276
1513
  `);
1277
1514
  renderer.write(
1278
- `${boxRow(color5.dim("No model is connected yet. Pick how you want to connect one:"))}
1515
+ `${boxRow(color6.dim("No model is connected yet. Pick how you want to connect one:"))}
1279
1516
  `
1280
1517
  );
1281
1518
  renderer.write(`${boxDivider()}
1282
1519
  `);
1283
1520
  renderer.write(
1284
1521
  `${boxRow(
1285
- `${theme.accent("1")} ${color5.bold("Sign in with a subscription")} ${color5.dim("ChatGPT \xB7 Claude \xB7 GitHub Copilot")}`
1522
+ `${theme.accent("1")} ${color6.bold("Sign in with a subscription")} ${color6.dim("ChatGPT \xB7 Claude \xB7 GitHub Copilot")}`
1286
1523
  )}
1287
1524
  `
1288
1525
  );
1289
1526
  renderer.write(
1290
1527
  `${boxRow(
1291
- `${theme.accent("2")} ${color5.bold("Add an API key")} ${color5.dim("Anthropic \xB7 OpenAI \xB7 Google \xB7 OpenRouter \xB7 \u2026")}`
1528
+ `${theme.accent("2")} ${color6.bold("Add an API key")} ${color6.dim("Anthropic \xB7 OpenAI \xB7 Google \xB7 OpenRouter \xB7 \u2026")}`
1292
1529
  )}
1293
1530
  `
1294
1531
  );
1295
1532
  renderer.write(
1296
1533
  `${boxRow(
1297
- `${theme.accent("3")} ${color5.bold("Use a local server")} ${color5.dim("Ollama \xB7 LM Studio \xB7 vLLM \xB7 OmniRoute")}`
1534
+ `${theme.accent("3")} ${color6.bold("Use a local server")} ${color6.dim("Ollama \xB7 LM Studio \xB7 vLLM \xB7 OmniRoute")}`
1298
1535
  )}
1299
1536
  `
1300
1537
  );
1301
1538
  renderer.write(
1302
1539
  `${boxRow(
1303
- `${theme.accent("4")} ${color5.bold("Continue without a key")} ${color5.dim("setup mode \u2014 explore the app, no model")}`
1540
+ `${theme.accent("4")} ${color6.bold("Continue without a key")} ${color6.dim("setup mode \u2014 explore the app, no model")}`
1304
1541
  )}
1305
1542
  `
1306
1543
  );
1307
1544
  renderer.write(`${boxDivider()}
1308
1545
  `);
1309
1546
  renderer.write(
1310
- `${boxRow(color5.dim("You can change this any time with /auth inside the app, or `wstack auth`."))}
1547
+ `${boxRow(color6.dim("You can change this any time with /auth inside the app, or `wstack auth`."))}
1311
1548
  `
1312
1549
  );
1313
1550
  renderer.write(`${boxBottom()}
@@ -1326,12 +1563,12 @@ async function runFirstRunSetup(deps) {
1326
1563
  renderWelcome(renderer);
1327
1564
  const answer = (await reader.readLine(
1328
1565
  `
1329
- ${color5.amber("?")} Choose ${color5.dim("(1-4)")} ${color5.dim("[q to quit]")}: `
1566
+ ${color6.amber("?")} Choose ${color6.dim("(1-4)")} ${color6.dim("[q to quit]")}: `
1330
1567
  )).trim().toLowerCase();
1331
1568
  if (!answer || answer === "q" || answer === "quit" || answer === "exit") {
1332
1569
  renderer.write(
1333
1570
  `
1334
- ${color5.dim("No provider configured. Run")} ${color5.bold("wstack auth")} ${color5.dim("when you are ready.")}
1571
+ ${color6.dim("No provider configured. Run")} ${color6.bold("wstack auth")} ${color6.dim("when you are ready.")}
1335
1572
 
1336
1573
  `
1337
1574
  );
@@ -1348,14 +1585,14 @@ ${color5.amber("?")} Choose ${color5.dim("(1-4)")} ${color5.dim("[q to quit]")}:
1348
1585
  try {
1349
1586
  await flow();
1350
1587
  } catch (err) {
1351
- renderer.writeWarning(`Setup step did not complete: ${toErrorMessage2(err)}
1588
+ renderer.writeWarning(`Setup step did not complete: ${toErrorMessage3(err)}
1352
1589
  `);
1353
1590
  }
1354
1591
  let updated;
1355
1592
  try {
1356
1593
  updated = await deps.reloadConfig();
1357
1594
  } catch (err) {
1358
- renderer.writeWarning(`Could not re-read config: ${toErrorMessage2(err)}
1595
+ renderer.writeWarning(`Could not re-read config: ${toErrorMessage3(err)}
1359
1596
  `);
1360
1597
  continue;
1361
1598
  }
@@ -1367,8 +1604,8 @@ ${color5.amber("?")} Choose ${color5.dim("(1-4)")} ${color5.dim("[q to quit]")}:
1367
1604
  }
1368
1605
 
1369
1606
  // src/pre-launch/launch-prompts.ts
1370
- import * as fs3 from "node:fs/promises";
1371
- import { atomicWrite as atomicWrite3, color as color6 } from "@wrongstack/core/utils";
1607
+ import * as fs5 from "node:fs/promises";
1608
+ import { atomicWrite as atomicWrite3, color as color7 } from "@wrongstack/core/utils";
1372
1609
  var LaunchAbortedError = class extends Error {
1373
1610
  exitCode = 0;
1374
1611
  constructor() {
@@ -1399,19 +1636,19 @@ async function runLaunchPrompts(opts) {
1399
1636
  yolo: yoloPinned ?? lastChoices.yolo,
1400
1637
  autonomy: autonomyPinned ?? lastChoices.autonomy
1401
1638
  };
1402
- const onOff = (v) => v ? color6.green("on") : color6.dim("off");
1639
+ const onOff = (v) => v ? color7.green("on") : color7.dim("off");
1403
1640
  const modeLabel = effective.mode.toUpperCase();
1404
1641
  renderer.write(
1405
1642
  `
1406
- ${color6.dim("Last settings:")} ${color6.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Autonomy ${effective.autonomy === "auto" ? color6.green("auto") : color6.dim("off")}
1643
+ ${color7.dim("Last settings:")} ${color7.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Autonomy ${effective.autonomy === "auto" ? color7.green("auto") : color7.dim("off")}
1407
1644
  `
1408
1645
  );
1409
1646
  const answer = (await reader.readLine(
1410
- ` ${color6.amber("?")} Continue with these? ${color6.dim("[Y/n/q]")} ${color6.dim("(auto Y in 5s)")} `,
1647
+ ` ${color7.amber("?")} Continue with these? ${color7.dim("[Y/n/q]")} ${color7.dim("(auto Y in 5s)")} `,
1411
1648
  { timeoutMs: 5e3, defaultAnswer: "y" }
1412
1649
  )).trim().toLowerCase();
1413
1650
  if (answer === "q") {
1414
- renderer.write(color6.dim(" Goodbye!\n"));
1651
+ renderer.write(color7.dim(" Goodbye!\n"));
1415
1652
  throw new LaunchAbortedError();
1416
1653
  }
1417
1654
  if (answer !== "n" && answer !== "no") {
@@ -1419,7 +1656,7 @@ async function runLaunchPrompts(opts) {
1419
1656
  const badgeStr2 = badges2.length > 0 ? ` (${badges2.join(" \xB7 ")})` : "";
1420
1657
  renderer.write(
1421
1658
  `
1422
- ${color6.green("\u25B6")} Launching in ${color6.bold(modeLabel)} mode${badgeStr2}
1659
+ ${color7.green("\u25B6")} Launching in ${color7.bold(modeLabel)} mode${badgeStr2}
1423
1660
 
1424
1661
  `
1425
1662
  );
@@ -1432,10 +1669,10 @@ async function runLaunchPrompts(opts) {
1432
1669
  } else {
1433
1670
  const answer = (await reader.readLine(
1434
1671
  `
1435
- ${color6.amber("?")} Interactive mode: ${color6.bold("T")}UI / ${color6.bold("R")}EPL ${color6.dim("[T/r/q]")} `
1672
+ ${color7.amber("?")} Interactive mode: ${color7.bold("T")}UI / ${color7.bold("R")}EPL ${color7.dim("[T/r/q]")} `
1436
1673
  )).trim().toLowerCase();
1437
1674
  if (answer === "q") {
1438
- renderer.write(color6.dim(" Goodbye!\n"));
1675
+ renderer.write(color7.dim(" Goodbye!\n"));
1439
1676
  throw new LaunchAbortedError();
1440
1677
  }
1441
1678
  mode = answer === "r" || answer === "repl" ? "repl" : "tui";
@@ -1445,10 +1682,10 @@ async function runLaunchPrompts(opts) {
1445
1682
  yolo = yoloPinned;
1446
1683
  } else {
1447
1684
  const answer = (await reader.readLine(
1448
- ` ${color6.amber("?")} YOLO mode ${color6.dim("(auto-approve tool calls)")} ${color6.dim("[Y/n/q]")} `
1685
+ ` ${color7.amber("?")} YOLO mode ${color7.dim("(auto-approve tool calls)")} ${color7.dim("[Y/n/q]")} `
1449
1686
  )).trim().toLowerCase();
1450
1687
  if (answer === "q") {
1451
- renderer.write(color6.dim(" Goodbye!\n"));
1688
+ renderer.write(color7.dim(" Goodbye!\n"));
1452
1689
  throw new LaunchAbortedError();
1453
1690
  }
1454
1691
  yolo = answer !== "n" && answer !== "no";
@@ -1458,10 +1695,10 @@ async function runLaunchPrompts(opts) {
1458
1695
  autonomy = autonomyPinned;
1459
1696
  } else {
1460
1697
  const answer = (await reader.readLine(
1461
- ` ${color6.amber("?")} Autonomy mode ${color6.dim("(auto-continue \u2014 agent picks next step)")} ${color6.dim("[Y/n/q]")} `
1698
+ ` ${color7.amber("?")} Autonomy mode ${color7.dim("(auto-continue \u2014 agent picks next step)")} ${color7.dim("[Y/n/q]")} `
1462
1699
  )).trim().toLowerCase();
1463
1700
  if (answer === "q") {
1464
- renderer.write(color6.dim(" Goodbye!\n"));
1701
+ renderer.write(color7.dim(" Goodbye!\n"));
1465
1702
  throw new LaunchAbortedError();
1466
1703
  }
1467
1704
  autonomy = answer !== "n" && answer !== "no" ? "auto" : "off";
@@ -1470,7 +1707,7 @@ async function runLaunchPrompts(opts) {
1470
1707
  const badgeStr = badges.length > 0 ? ` (${badges.join(" \xB7 ")})` : "";
1471
1708
  renderer.write(
1472
1709
  `
1473
- ${color6.green("\u25B6")} Launching in ${color6.bold(mode.toUpperCase())} mode${badgeStr}
1710
+ ${color7.green("\u25B6")} Launching in ${color7.bold(mode.toUpperCase())} mode${badgeStr}
1474
1711
 
1475
1712
  `
1476
1713
  );
@@ -1478,21 +1715,21 @@ async function runLaunchPrompts(opts) {
1478
1715
  }
1479
1716
  function buildBadges(chosen) {
1480
1717
  const badges = [];
1481
- if (chosen.yolo) badges.push(color6.yellow("YOLO"));
1718
+ if (chosen.yolo) badges.push(color7.yellow("YOLO"));
1482
1719
  if (chosen.autonomy !== "off")
1483
- badges.push(color6.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
1720
+ badges.push(color7.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
1484
1721
  return badges;
1485
1722
  }
1486
1723
  async function persistLaunchChoices(configPath, choices) {
1487
1724
  let fileExists = false;
1488
1725
  try {
1489
- await fs3.access(configPath);
1726
+ await fs5.access(configPath);
1490
1727
  fileExists = true;
1491
1728
  } catch {
1492
1729
  }
1493
1730
  let existing = {};
1494
1731
  try {
1495
- const raw = await fs3.readFile(configPath, "utf8");
1732
+ const raw = await fs5.readFile(configPath, "utf8");
1496
1733
  existing = JSON.parse(raw);
1497
1734
  } catch (err) {
1498
1735
  if (fileExists) {
@@ -1512,9 +1749,9 @@ async function persistLaunchChoices(configPath, choices) {
1512
1749
  }
1513
1750
 
1514
1751
  // src/pre-launch/project-check.ts
1515
- import * as fs4 from "node:fs/promises";
1516
- import * as path5 from "node:path";
1517
- import { color as color7, toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
1752
+ import * as fs6 from "node:fs/promises";
1753
+ import * as path7 from "node:path";
1754
+ import { color as color8, toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
1518
1755
  var MANIFESTS = [
1519
1756
  "package.json",
1520
1757
  "pyproject.toml",
@@ -1529,13 +1766,13 @@ var MANIFESTS = [
1529
1766
  ];
1530
1767
  async function detectProjectKind(projectRoot) {
1531
1768
  try {
1532
- await fs4.access(path5.join(projectRoot, ".wrongstack", "AGENTS.md"));
1769
+ await fs6.access(path7.join(projectRoot, ".wrongstack", "AGENTS.md"));
1533
1770
  return "initialized";
1534
1771
  } catch {
1535
1772
  }
1536
1773
  for (const m of MANIFESTS) {
1537
1774
  try {
1538
- await fs4.access(path5.join(projectRoot, m));
1775
+ await fs6.access(path7.join(projectRoot, m));
1539
1776
  return "project";
1540
1777
  } catch {
1541
1778
  }
@@ -1543,12 +1780,12 @@ async function detectProjectKind(projectRoot) {
1543
1780
  return "empty";
1544
1781
  }
1545
1782
  async function scaffoldAgentsMd(projectRoot) {
1546
- const dir = path5.join(projectRoot, ".wrongstack");
1547
- const file = path5.join(dir, "AGENTS.md");
1783
+ const dir = path7.join(projectRoot, ".wrongstack");
1784
+ const file = path7.join(dir, "AGENTS.md");
1548
1785
  const facts = await detectProjectFacts(projectRoot);
1549
1786
  const body = renderAgentsTemplate(facts);
1550
- await fs4.mkdir(dir, { recursive: true });
1551
- await fs4.writeFile(file, body, "utf8");
1787
+ await fs6.mkdir(dir, { recursive: true });
1788
+ await fs6.writeFile(file, body, "utf8");
1552
1789
  return file;
1553
1790
  }
1554
1791
  async function runProjectCheck(opts) {
@@ -1557,7 +1794,7 @@ async function runProjectCheck(opts) {
1557
1794
  if (kind === "initialized") {
1558
1795
  renderer.write(
1559
1796
  `
1560
- ${color7.green("\u2713")} Project initialized ${color7.dim(`(${path5.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
1797
+ ${color8.green("\u2713")} Project initialized ${color8.dim(`(${path7.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
1561
1798
  `
1562
1799
  );
1563
1800
  return true;
@@ -1565,51 +1802,51 @@ async function runProjectCheck(opts) {
1565
1802
  if (kind === "project") {
1566
1803
  renderer.write(
1567
1804
  `
1568
- ${color7.amber("\u25CF")} Project detected ${color7.dim(`(${projectRoot})`)} but ${color7.bold(".wrongstack/AGENTS.md")} is missing.
1805
+ ${color8.amber("\u25CF")} Project detected ${color8.dim(`(${projectRoot})`)} but ${color8.bold(".wrongstack/AGENTS.md")} is missing.
1569
1806
  `
1570
1807
  );
1571
1808
  const answer2 = (await reader.readLine(
1572
- ` ${color7.amber("?")} Scaffold ${color7.bold("AGENTS.md")} now? ${color7.dim("[y/N/q]")} `
1809
+ ` ${color8.amber("?")} Scaffold ${color8.bold("AGENTS.md")} now? ${color8.dim("[y/N/q]")} `
1573
1810
  )).trim().toLowerCase();
1574
1811
  if (answer2 === "q") {
1575
- renderer.write(color7.dim(" Cancelled.\n"));
1812
+ renderer.write(color8.dim(" Cancelled.\n"));
1576
1813
  return false;
1577
1814
  }
1578
1815
  if (answer2 === "y" || answer2 === "yes") {
1579
1816
  try {
1580
1817
  const file = await scaffoldAgentsMd(projectRoot);
1581
- renderer.write(` ${color7.green("\u2713")} Wrote ${color7.dim(file)}
1818
+ renderer.write(` ${color8.green("\u2713")} Wrote ${color8.dim(file)}
1582
1819
  `);
1583
1820
  } catch (err) {
1584
- renderer.writeError(`Failed to scaffold AGENTS.md: ${toErrorMessage3(err)}`);
1821
+ renderer.writeError(`Failed to scaffold AGENTS.md: ${toErrorMessage4(err)}`);
1585
1822
  }
1586
1823
  }
1587
1824
  return true;
1588
1825
  }
1589
- const gitDir = path5.join(projectRoot, ".git");
1826
+ const gitDir = path7.join(projectRoot, ".git");
1590
1827
  let hasGit = false;
1591
1828
  try {
1592
- await fs4.access(gitDir);
1829
+ await fs6.access(gitDir);
1593
1830
  hasGit = true;
1594
1831
  } catch {
1595
1832
  }
1596
1833
  if (!hasGit) {
1597
1834
  renderer.write(
1598
1835
  `
1599
- ${color7.dim("\u25CB")} ${color7.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1836
+ ${color8.dim("\u25CB")} ${color8.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1600
1837
  `
1601
1838
  );
1602
1839
  const answer2 = (await reader.readLine(
1603
- ` ${color7.amber("?")} No git repo found. ${color7.bold("Initialize git?")} ${color7.dim("[y/N/q]")} `
1840
+ ` ${color8.amber("?")} No git repo found. ${color8.bold("Initialize git?")} ${color8.dim("[y/N/q]")} `
1604
1841
  )).trim().toLowerCase();
1605
1842
  if (answer2 === "q") {
1606
- renderer.write(color7.dim(" Cancelled.\n"));
1843
+ renderer.write(color8.dim(" Cancelled.\n"));
1607
1844
  return false;
1608
1845
  }
1609
1846
  if (answer2 === "y" || answer2 === "yes") {
1610
1847
  try {
1611
1848
  const { spawn: spawn2 } = await import("node:child_process");
1612
- await new Promise((resolve2, reject) => {
1849
+ await new Promise((resolve3, reject) => {
1613
1850
  const child = spawn2("git", ["init"], {
1614
1851
  cwd,
1615
1852
  signal: AbortSignal.timeout(1e4),
@@ -1618,26 +1855,26 @@ async function runProjectCheck(opts) {
1618
1855
  child.on("error", reject);
1619
1856
  child.on(
1620
1857
  "close",
1621
- (code) => code === 0 ? resolve2() : reject(new Error(`git init failed with ${code}`))
1858
+ (code) => code === 0 ? resolve3() : reject(new Error(`git init failed with ${code}`))
1622
1859
  );
1623
1860
  });
1624
- renderer.write(` ${color7.green("\u2713")} Git repository initialized
1861
+ renderer.write(` ${color8.green("\u2713")} Git repository initialized
1625
1862
  `);
1626
1863
  } catch (err) {
1627
- renderer.writeError(`git init failed: ${toErrorMessage3(err)}
1864
+ renderer.writeError(`git init failed: ${toErrorMessage4(err)}
1628
1865
  `);
1629
1866
  }
1630
1867
  }
1631
1868
  } else {
1632
1869
  renderer.write(
1633
1870
  `
1634
- ${color7.dim("\u25CB")} ${color7.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1871
+ ${color8.dim("\u25CB")} ${color8.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1635
1872
  `
1636
1873
  );
1637
1874
  }
1638
- const answer = (await reader.readLine(` ${color7.amber("?")} Continue anyway? ${color7.dim("[Y/n/q]")} `)).trim().toLowerCase();
1875
+ const answer = (await reader.readLine(` ${color8.amber("?")} Continue anyway? ${color8.dim("[Y/n/q]")} `)).trim().toLowerCase();
1639
1876
  if (answer === "q" || answer === "n" || answer === "no") {
1640
- renderer.write(color7.dim(" Cancelled.\n"));
1877
+ renderer.write(color8.dim(" Cancelled.\n"));
1641
1878
  return false;
1642
1879
  }
1643
1880
  return true;
@@ -1672,28 +1909,28 @@ async function runSystemPromptMenu(deps) {
1672
1909
  const defaultVariant = lastVariant ?? "default";
1673
1910
  if (lastVariant) {
1674
1911
  const answer2 = (await reader.readLine(
1675
- ` ${color8.amber("?")} Continue with ${color8.bold(labelFor(lastVariant))} system prompt ${color8.dim(`(~${fmtTok(tokens[lastVariant])} tokens)`)}? ${color8.dim("[Y/n/q]")} ${color8.dim("(auto Y in 5s)")} `,
1912
+ ` ${color9.amber("?")} Continue with ${color9.bold(labelFor(lastVariant))} system prompt ${color9.dim(`(~${fmtTok(tokens[lastVariant])} tokens)`)}? ${color9.dim("[Y/n/q]")} ${color9.dim("(auto Y in 5s)")} `,
1676
1913
  { timeoutMs: SUMMARY_TIMEOUT_MS2, defaultAnswer: "y" }
1677
1914
  )).trim().toLowerCase();
1678
1915
  if (answer2 === "q" || answer2 === "quit") throw new LaunchAbortedError();
1679
1916
  if (answer2 !== "n" && answer2 !== "no") return lastVariant;
1680
1917
  }
1681
1918
  renderer.write(`
1682
- ${color8.amber("?")} System prompt:
1919
+ ${color9.amber("?")} System prompt:
1683
1920
  `);
1684
1921
  for (const [index, opt] of SYSTEM_PROMPT_OPTIONS.entries()) {
1685
1922
  const num2 = index + 1;
1686
1923
  const isDefault = opt.variant === defaultVariant;
1687
- const marker = isDefault ? color8.cyan("\u25CF") : color8.dim("\u25CB");
1688
- const label = isDefault ? color8.bold(opt.label) : opt.label;
1924
+ const marker = isDefault ? color9.cyan("\u25CF") : color9.dim("\u25CB");
1925
+ const label = isDefault ? color9.bold(opt.label) : opt.label;
1689
1926
  renderer.write(
1690
- ` ${color8.dim(`${num2}.`)} ${marker} ${label.padEnd(9)} ${color8.dim(`~${fmtTok(tokens[opt.variant])} tokens`)} ${color8.dim(opt.hint)}
1927
+ ` ${color9.dim(`${num2}.`)} ${marker} ${label.padEnd(9)} ${color9.dim(`~${fmtTok(tokens[opt.variant])} tokens`)} ${color9.dim(opt.hint)}
1691
1928
  `
1692
1929
  );
1693
1930
  }
1694
1931
  const answer = (await reader.readLine(
1695
1932
  `
1696
- ${color8.amber("?")} Select system prompt ${color8.dim(`[1-${SYSTEM_PROMPT_OPTIONS.length}, Enter = ${labelFor(defaultVariant)}, q to quit]`)}: `
1933
+ ${color9.amber("?")} Select system prompt ${color9.dim(`[1-${SYSTEM_PROMPT_OPTIONS.length}, Enter = ${labelFor(defaultVariant)}, q to quit]`)}: `
1697
1934
  )).trim().toLowerCase();
1698
1935
  if (answer === "q" || answer === "quit") throw new LaunchAbortedError();
1699
1936
  if (!answer) return defaultVariant;
@@ -1750,8 +1987,8 @@ async function bootConfig(flags) {
1750
1987
  }
1751
1988
 
1752
1989
  // src/input-reader.ts
1753
- import * as fs5 from "node:fs/promises";
1754
- import * as path6 from "node:path";
1990
+ import * as fs7 from "node:fs/promises";
1991
+ import * as path8 from "node:path";
1755
1992
  import * as readline from "node:readline";
1756
1993
  import {
1757
1994
  resolveWstackPaths,
@@ -1770,7 +2007,7 @@ var ReadlineInputReader = class {
1770
2007
  }
1771
2008
  async loadHistory() {
1772
2009
  try {
1773
- const raw = await fs5.readFile(this.historyFile, "utf8");
2010
+ const raw = await fs7.readFile(this.historyFile, "utf8");
1774
2011
  this.history = raw.split("\n").filter(Boolean).slice(-1e3);
1775
2012
  } catch {
1776
2013
  this.history = [];
@@ -1778,8 +2015,8 @@ var ReadlineInputReader = class {
1778
2015
  }
1779
2016
  async saveHistory() {
1780
2017
  try {
1781
- await fs5.mkdir(path6.dirname(this.historyFile), { recursive: true });
1782
- await fs5.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
2018
+ await fs7.mkdir(path8.dirname(this.historyFile), { recursive: true });
2019
+ await fs7.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
1783
2020
  } catch {
1784
2021
  }
1785
2022
  }
@@ -1800,25 +2037,25 @@ var ReadlineInputReader = class {
1800
2037
  async readLine(prompt, timeoutOpts) {
1801
2038
  if (this.history.length === 0) await this.loadHistory();
1802
2039
  while (this.pending) {
1803
- await new Promise((resolve2) => setTimeout(resolve2, 50));
2040
+ await new Promise((resolve3) => setTimeout(resolve3, 50));
1804
2041
  }
1805
2042
  this.pending = true;
1806
2043
  try {
1807
2044
  if (this.rl) {
1808
2045
  const old = this.rl;
1809
2046
  this.rl = void 0;
1810
- await new Promise((resolve2) => {
2047
+ await new Promise((resolve3) => {
1811
2048
  if (old.closed) {
1812
- resolve2();
2049
+ resolve3();
1813
2050
  } else {
1814
- old.once("close", resolve2);
2051
+ old.once("close", resolve3);
1815
2052
  old.close();
1816
2053
  }
1817
2054
  });
1818
2055
  }
1819
2056
  const fresh = this.ensure();
1820
2057
  this.installPromptGuard(fresh);
1821
- const line = await new Promise((resolve2) => {
2058
+ const line = await new Promise((resolve3) => {
1822
2059
  let settled = false;
1823
2060
  let timeoutHandle;
1824
2061
  const settle = (line2) => {
@@ -1826,7 +2063,7 @@ var ReadlineInputReader = class {
1826
2063
  settled = true;
1827
2064
  if (timeoutHandle) clearTimeout(timeoutHandle);
1828
2065
  setOutputLineGuard(null);
1829
- resolve2(line2);
2066
+ resolve3(line2);
1830
2067
  };
1831
2068
  if (timeoutOpts) {
1832
2069
  timeoutHandle = setTimeout(() => {
@@ -1893,7 +2130,7 @@ var ReadlineInputReader = class {
1893
2130
  const signal = opts.signal;
1894
2131
  if (signal?.aborted) return "";
1895
2132
  writeOut(prompt);
1896
- return new Promise((resolve2) => {
2133
+ return new Promise((resolve3) => {
1897
2134
  const stdin = process.stdin;
1898
2135
  const wasRaw = stdin.isRaw;
1899
2136
  const wasPaused = stdin.isPaused();
@@ -1904,7 +2141,7 @@ var ReadlineInputReader = class {
1904
2141
  if (key === "") {
1905
2142
  cleanup();
1906
2143
  writeOut("\n");
1907
- resolve2("");
2144
+ resolve3("");
1908
2145
  return;
1909
2146
  }
1910
2147
  const opt = options.find(
@@ -1914,17 +2151,17 @@ var ReadlineInputReader = class {
1914
2151
  cleanup();
1915
2152
  writeOut(`${opt.key}
1916
2153
  `);
1917
- resolve2(opt.value);
2154
+ resolve3(opt.value);
1918
2155
  }
1919
2156
  };
1920
2157
  const onClose = () => {
1921
2158
  cleanup();
1922
- resolve2("");
2159
+ resolve3("");
1923
2160
  };
1924
2161
  const onAbort = () => {
1925
2162
  cleanup();
1926
2163
  writeOut("\n");
1927
- resolve2("");
2164
+ resolve3("");
1928
2165
  };
1929
2166
  const cleanup = () => {
1930
2167
  stdin.off("data", onData);
@@ -1958,7 +2195,7 @@ var ReadlineInputReader = class {
1958
2195
  this.rl?.close();
1959
2196
  this.rl = void 0;
1960
2197
  writeOut(prompt);
1961
- return new Promise((resolve2) => {
2198
+ return new Promise((resolve3) => {
1962
2199
  let buf = "";
1963
2200
  const wasRaw = stdin.isRaw;
1964
2201
  const cleanup = () => {
@@ -1987,13 +2224,13 @@ var ReadlineInputReader = class {
1987
2224
  cleanup();
1988
2225
  writeOut(` ${dim(`[${buf.length} chars]`)}
1989
2226
  `);
1990
- resolve2(buf);
2227
+ resolve3(buf);
1991
2228
  return;
1992
2229
  }
1993
2230
  if (ch === "") {
1994
2231
  cleanup();
1995
2232
  writeOut("\n");
1996
- resolve2("");
2233
+ resolve3("");
1997
2234
  return;
1998
2235
  }
1999
2236
  if (ch === "") {
@@ -2036,7 +2273,7 @@ function dim(s) {
2036
2273
  }
2037
2274
 
2038
2275
  // src/renderer.ts
2039
- import { color as color9 } from "@wrongstack/core/utils";
2276
+ import { color as color10 } from "@wrongstack/core/utils";
2040
2277
  var TerminalRenderer = class _TerminalRenderer {
2041
2278
  out;
2042
2279
  err;
@@ -2149,7 +2386,7 @@ var TerminalRenderer = class _TerminalRenderer {
2149
2386
  if (!this.lineStart) this.out.write("\n");
2150
2387
  const arrow = theme2.primary("\u2192");
2151
2388
  const display = formatInputSummary(input);
2152
- this.out.write(`${arrow} ${theme2.bold(name)}${display ? color9.dim(` ${display}`) : ""}
2389
+ this.out.write(`${arrow} ${theme2.bold(name)}${display ? color10.dim(` ${display}`) : ""}
2153
2390
  `);
2154
2391
  this.lineStart = true;
2155
2392
  }
@@ -2166,7 +2403,7 @@ var TerminalRenderer = class _TerminalRenderer {
2166
2403
  if (isError) {
2167
2404
  const firstLine = txt.split("\n")[0] ?? "";
2168
2405
  const truncated = firstLine.length > 200 ? `${firstLine.slice(0, 197)}\u2026` : firstLine;
2169
- this.out.write(` ${prefix} ${color9.dim(truncated)}
2406
+ this.out.write(` ${prefix} ${color10.dim(truncated)}
2170
2407
  `);
2171
2408
  this.lineStart = true;
2172
2409
  return;
@@ -2174,7 +2411,7 @@ var TerminalRenderer = class _TerminalRenderer {
2174
2411
  const isEditLike = name === "edit" || name === "write";
2175
2412
  const diff = extractDiff(content);
2176
2413
  if (isEditLike && diff) {
2177
- this.out.write(` ${prefix} ${color9.dim(summarize(content, name))}
2414
+ this.out.write(` ${prefix} ${color10.dim(summarize(content, name))}
2178
2415
  `);
2179
2416
  const rendered = renderDiff(diff).split("\n").map((l) => ` ${l}`).join("\n");
2180
2417
  this.out.write(`${rendered}
@@ -2185,7 +2422,7 @@ var TerminalRenderer = class _TerminalRenderer {
2185
2422
  const summary = summarize(content, name);
2186
2423
  const isReadLike = name === "read" || name === "grep" || name === "glob" || name === "bash" || name === "exec";
2187
2424
  if (renderMode === "simple") {
2188
- this.out.write(` ${prefix} ${color9.dim(summary || compactSingleLine(bodyText))}
2425
+ this.out.write(` ${prefix} ${color10.dim(summary || compactSingleLine(bodyText))}
2189
2426
  `);
2190
2427
  this.lineStart = true;
2191
2428
  return;
@@ -2194,16 +2431,16 @@ var TerminalRenderer = class _TerminalRenderer {
2194
2431
  const lines = bodyText.split("\n");
2195
2432
  const head = lines.slice(0, previewLines).map((l) => l.replace(/\s+$/, ""));
2196
2433
  const moreCount = Math.max(0, lines.length - head.length);
2197
- this.out.write(` ${prefix} ${color9.dim(summary)}
2434
+ this.out.write(` ${prefix} ${color10.dim(summary)}
2198
2435
  `);
2199
2436
  for (const l of head) {
2200
2437
  const capped = l.length > 200 ? `${l.slice(0, 197)}\u2026` : l;
2201
- this.out.write(` ${color9.dim(capped)}
2438
+ this.out.write(` ${color10.dim(capped)}
2202
2439
  `);
2203
2440
  }
2204
2441
  if (moreCount > 0) {
2205
2442
  this.out.write(
2206
- ` ${color9.dim(`+${moreCount} more line${moreCount === 1 ? "" : "s"}`)}
2443
+ ` ${color10.dim(`+${moreCount} more line${moreCount === 1 ? "" : "s"}`)}
2207
2444
  `
2208
2445
  );
2209
2446
  }
@@ -2342,7 +2579,7 @@ function renderMarkdown(s) {
2342
2579
  return theme2.primary(theme2.bold(`${hashes} ${text}`));
2343
2580
  });
2344
2581
  out = out.replace(/```([a-zA-Z0-9_+-]*)\n([\s\S]*?)```/g, (_m, _lang, code) => {
2345
- return color9.gray(`
2582
+ return color10.gray(`
2346
2583
  \u250C\u2500
2347
2584
  ${code.replace(/^/gm, "\u2502 ")}\u2514\u2500`);
2348
2585
  });
@@ -2350,7 +2587,7 @@ ${code.replace(/^/gm, "\u2502 ")}\u2514\u2500`);
2350
2587
  out = out.replace(/\*\*([^*]+)\*\*/g, (_m, text) => theme2.bold(text));
2351
2588
  out = out.replace(
2352
2589
  /(^|[^*])\*([^*\n]+)\*([^*]|$)/g,
2353
- (_m, l, t, r) => `${l}${color9.italic(t)}${r}`
2590
+ (_m, l, t, r) => `${l}${color10.italic(t)}${r}`
2354
2591
  );
2355
2592
  return out;
2356
2593
  }
@@ -2443,14 +2680,14 @@ function summarize(value, name) {
2443
2680
  if (typeof v === "object" && v !== null) {
2444
2681
  const o = v;
2445
2682
  if (name === "edit") {
2446
- const path8 = typeof o["path"] === "string" ? o["path"] : "";
2683
+ const path10 = typeof o["path"] === "string" ? o["path"] : "";
2447
2684
  const reps = typeof o["replacements"] === "number" ? o["replacements"] : 0;
2448
- return `${path8} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
2685
+ return `${path10} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
2449
2686
  }
2450
2687
  if (name === "write") {
2451
- const path8 = typeof o["path"] === "string" ? o["path"] : "";
2688
+ const path10 = typeof o["path"] === "string" ? o["path"] : "";
2452
2689
  const bytes = typeof o["bytes"] === "number" ? o["bytes"] : void 0;
2453
- return bytes !== void 0 ? `${path8} ${bytes}B` : path8;
2690
+ return bytes !== void 0 ? `${path10} ${bytes}B` : path10;
2454
2691
  }
2455
2692
  if (name === "read") {
2456
2693
  return summarizeRead(o);
@@ -2468,13 +2705,13 @@ function summarize(value, name) {
2468
2705
  return "";
2469
2706
  }
2470
2707
  function summarizeRead(o) {
2471
- const path8 = typeof o["path"] === "string" ? o["path"] : "";
2708
+ const path10 = typeof o["path"] === "string" ? o["path"] : "";
2472
2709
  const total = typeof o["total_lines"] === "number" ? o["total_lines"] : void 0;
2473
2710
  const truncated = o["truncated"] === true;
2474
2711
  const cached = o["cached"] === true;
2475
2712
  const note = typeof o["note"] === "string" ? o["note"] : void 0;
2476
2713
  const parts = [];
2477
- if (path8) parts.push(path8);
2714
+ if (path10) parts.push(path10);
2478
2715
  if (total !== void 0) parts.push(`${total} line${total === 1 ? "" : "s"}`);
2479
2716
  const flags = [];
2480
2717
  if (truncated) flags.push("truncated");
@@ -2522,84 +2759,6 @@ function compactSingleLine(text) {
2522
2759
 
2523
2760
  // src/boot.ts
2524
2761
  var GITHUB_PROVIDERS_OVERLAY_URL = "https://raw.githubusercontent.com/WrongStack/WrongStack/main/packages/cli/data/providers.json";
2525
- function resolveBundledOverlayFile() {
2526
- try {
2527
- return fileURLToPath(new URL("../data/providers.json", import.meta.url));
2528
- } catch {
2529
- return void 0;
2530
- }
2531
- }
2532
- async function validateSavedProviderModel(config, modelsRegistry) {
2533
- const providerId = config.provider;
2534
- const modelId = config.model;
2535
- if (!providerId || !modelId) return { ok: false, reason: "missing provider/model" };
2536
- if (isSetupProvider(providerId)) return { ok: true };
2537
- const saved = config.providers?.[providerId];
2538
- const lookupId = saved?.type && saved.type !== providerId ? saved.type : providerId;
2539
- const catalogProvider = await modelsRegistry.getProvider(lookupId).catch(() => void 0);
2540
- if (!catalogProvider && !saved?.family)
2541
- return { ok: false, reason: `provider "${providerId}" is no longer available` };
2542
- const hasCredential = (catalogProvider?.envVars ?? saved?.envVars ?? []).some(
2543
- (envVar) => Boolean(process.env[envVar])
2544
- ) || saved !== void 0 && resolveActiveApiKey(saved) !== void 0 || isKeylessLocalProvider({
2545
- apiBase: saved?.baseUrl ?? catalogProvider?.apiBase,
2546
- envVars: saved?.envVars ?? catalogProvider?.envVars
2547
- });
2548
- if (!hasCredential) return { ok: false, reason: `provider "${providerId}" has no usable key` };
2549
- const visible = visibleModelIds(
2550
- providerId,
2551
- config,
2552
- (catalogProvider?.models ?? []).map((m) => m.id),
2553
- saved
2554
- );
2555
- if (visible.length > 0 && !visible.includes(modelId)) {
2556
- return {
2557
- ok: false,
2558
- reason: `model "${modelId}" is no longer available for provider "${providerId}"`
2559
- };
2560
- }
2561
- return { ok: true };
2562
- }
2563
- async function autoSelectSavedProvider(config, modelsRegistry) {
2564
- const providers = config.providers ?? {};
2565
- const entries = config.provider && providers[config.provider] ? [[config.provider, providers[config.provider]]] : Object.entries(providers);
2566
- for (const [id, cfg] of entries) {
2567
- if (!cfg) continue;
2568
- let model = cfg.models?.[0];
2569
- if (!model) {
2570
- const catalogId = cfg.type && cfg.type !== id ? cfg.type : id;
2571
- const catalog = await modelsRegistry.getProvider(catalogId).catch(() => void 0);
2572
- model = catalog?.models?.[0]?.id;
2573
- }
2574
- if (model) return { provider: id, model };
2575
- }
2576
- return void 0;
2577
- }
2578
- function resolveBundledSkillsDir2() {
2579
- try {
2580
- const req = createRequire4(import.meta.url);
2581
- const corePkg = req.resolve("@wrongstack/core/package.json");
2582
- return path7.join(path7.dirname(corePkg), "skills");
2583
- } catch {
2584
- return void 0;
2585
- }
2586
- }
2587
- function resolveBundledPromptsDir2() {
2588
- try {
2589
- const req = createRequire4(import.meta.url);
2590
- const corePkg = req.resolve("@wrongstack/core/package.json");
2591
- return path7.join(path7.dirname(corePkg), "data", "prompts");
2592
- } catch {
2593
- return void 0;
2594
- }
2595
- }
2596
- function isHomeDirectory(cwd, userHome) {
2597
- if (!cwd || !userHome) return false;
2598
- return path7.resolve(cwd) === path7.resolve(userHome);
2599
- }
2600
- function shouldPrintYoloNotice(lastChoices, yoloPinned, yolo) {
2601
- return !lastChoices && yoloPinned === void 0 && yolo;
2602
- }
2603
2762
  async function boot(argv) {
2604
2763
  const { flags, positional } = parseArgs(argv);
2605
2764
  if (positional[0] === "update") {
@@ -2611,6 +2770,14 @@ async function boot(argv) {
2611
2770
  flags
2612
2771
  });
2613
2772
  }
2773
+ if (positional[0] === "remote" || typeof flags["remote"] === "string") {
2774
+ const { runRemoteCommand } = await import("./remote-O5WXHLWV.js");
2775
+ return runRemoteCommand(
2776
+ positional[0] === "remote" ? positional.slice(1) : positional,
2777
+ flags,
2778
+ new TerminalRenderer()
2779
+ );
2780
+ }
2614
2781
  if (positional[0] === "resume" && positional[1] && !subcommands["__noop_resume_marker"]) {
2615
2782
  flags["resume"] = positional[1];
2616
2783
  positional.splice(0, 2);
@@ -2619,19 +2786,41 @@ async function boot(argv) {
2619
2786
  try {
2620
2787
  bootResult = await bootConfig(flags);
2621
2788
  } catch (err) {
2622
- writeErr(`Config error: ${toErrorMessage4(err)}
2789
+ writeErr(`Config error: ${toErrorMessage5(err)}
2623
2790
  `);
2624
2791
  return 2;
2625
2792
  }
2626
2793
  let { paths, config, vault } = bootResult;
2794
+ try {
2795
+ resolveToolRestriction(flags);
2796
+ resolveLaunchAllowedTools(flags);
2797
+ parseOutputFormat(flags["output-format"]);
2798
+ announceSafeMode(flags, writeErr);
2799
+ activateRestrictedMode(flags, writeErr);
2800
+ const launchMcp = await resolveLaunchMcpServers(flags, paths.cwd);
2801
+ if (launchMcp) flags["mcp-config"] = JSON.stringify({ mcpServers: launchMcp });
2802
+ const schema = await resolveJsonSchemaFlag(flags["json-schema"], paths.cwd);
2803
+ if (schema) flags["json-schema"] = JSON.stringify(schema);
2804
+ const appended = await resolveAppendedSystemPrompt(flags, paths.cwd);
2805
+ delete flags["append-system-prompt-file"];
2806
+ if (appended) flags["append-system-prompt"] = appended;
2807
+ else delete flags["append-system-prompt"];
2808
+ } catch (err) {
2809
+ writeErr(`wstack: ${toErrorMessage5(err)}
2810
+ `);
2811
+ return 2;
2812
+ }
2627
2813
  let first = positional[0];
2628
- const mayOfferConfigRecovery = isStdinTTY2() && (positional.length === 0 || first === "quick") && (!config.activeProfile || config.activeProfile === "default") && typeof flags["prompt"] !== "string" && !flags["webui"] && !flags["no-interactive"] && !flags["skip"];
2629
- const renderer = new TerminalRenderer();
2814
+ const mayOfferConfigRecovery = isStdinTTY2() && (positional.length === 0 || first === "quick") && typeof flags["prompt"] !== "string" && !flags["webui"] && !flags["no-interactive"] && !flags["skip"];
2815
+ const machineOutput = flags["output-json"] === true || flags["output-format"] === "json" || flags["output-format"] === "stream-json";
2816
+ const renderer = new TerminalRenderer(machineOutput ? { out: process.stderr } : void 0);
2630
2817
  const reader = new ReadlineInputReader({ historyFile: paths.wpaths.historyFile });
2631
2818
  if (mayOfferConfigRecovery) {
2819
+ const recoveryProfile = config.activeProfile ?? "default";
2632
2820
  const restored = await maybeRestoreDefaultProfileFromBackup({
2633
2821
  globalRoot: paths.wpaths.globalRoot,
2634
- profilePath: paths.wpaths.profileConfig("default"),
2822
+ profilePath: paths.wpaths.profileConfig(recoveryProfile),
2823
+ profileName: recoveryProfile,
2635
2824
  renderer,
2636
2825
  reader
2637
2826
  });
@@ -2640,7 +2829,7 @@ async function boot(argv) {
2640
2829
  bootResult = await bootConfig(flags);
2641
2830
  ({ paths, config, vault } = bootResult);
2642
2831
  } catch (err) {
2643
- writeErr(`Config error after backup restore: ${toErrorMessage4(err)}
2832
+ writeErr(`Config error after backup restore: ${toErrorMessage5(err)}
2644
2833
  `);
2645
2834
  await reader.close();
2646
2835
  return 2;
@@ -2693,6 +2882,7 @@ async function boot(argv) {
2693
2882
  });
2694
2883
  const subcommandHandler = first ? subcommands[first] : void 0;
2695
2884
  if (first && subcommandHandler) {
2885
+ installProviderPersisters({ config, paths: wpaths, vault, logger });
2696
2886
  if (flags["help"] === true || flags["h"] === true) {
2697
2887
  const deepSub = positional[1];
2698
2888
  if (deepSub && renderDeepHelp(`${first}:${deepSub}`, renderer)) {
@@ -2740,8 +2930,8 @@ async function boot(argv) {
2740
2930
  if (isHomeDirectory(cwd, userHome)) {
2741
2931
  writeErr(
2742
2932
  `
2743
- ${color10.red(color10.bold("\u26A0 This is not a working directory."))}
2744
- ${color10.red("Please open wstack in a project folder.")}
2933
+ ${color11.red(color11.bold("\u26A0 This is not a working directory."))}
2934
+ ${color11.red("Please open wstack in a project folder.")}
2745
2935
 
2746
2936
  `
2747
2937
  );
@@ -2749,23 +2939,21 @@ async function boot(argv) {
2749
2939
  return 1;
2750
2940
  }
2751
2941
  if (!flags["no-models-refresh"]) {
2752
- try {
2753
- await modelsRegistry.refresh();
2754
- logger.info("models.dev catalog refreshed");
2755
- } catch (err) {
2756
- const msg = toErrorMessage4(err);
2757
- logger.warn(`models.dev refresh failed (${msg}); using cached catalog`);
2758
- }
2942
+ await startCatalog({
2943
+ registry: modelsRegistry,
2944
+ logger,
2945
+ shortLived: positional.length > 0 || typeof flags["prompt"] === "string"
2946
+ });
2759
2947
  }
2760
2948
  try {
2761
2949
  await discoverAndMergeProviders({
2762
2950
  config,
2763
2951
  registry: modelsRegistry,
2764
- cacheDir: path7.dirname(wpaths.modelsCache),
2952
+ cacheDir: path9.dirname(wpaths.modelsCache),
2765
2953
  logger
2766
2954
  });
2767
2955
  } catch (err) {
2768
- logger.debug(`provider auto-discovery skipped: ${toErrorMessage4(err)}`);
2956
+ logger.debug(`provider auto-discovery skipped: ${toErrorMessage5(err)}`);
2769
2957
  }
2770
2958
  const isSingleShot = positional.length > 0 || typeof flags["prompt"] === "string";
2771
2959
  const isInteractiveTTY = isStdinTTY2() && !isSingleShot && !flags["webui"] && !flags["no-interactive"] && !flags["skip"];
@@ -2800,11 +2988,11 @@ async function boot(argv) {
2800
2988
  if (isStdinTTY2() && !noInteractiveMode) {
2801
2989
  let picked;
2802
2990
  let skipPicker = false;
2803
- if (isSetupProvider(config.provider)) {
2991
+ if (isSetupProvider2(config.provider)) {
2804
2992
  skipPicker = true;
2805
2993
  renderer.write(
2806
2994
  `
2807
- ${color10.amber("\u25B6")} ${color10.bold("Setup mode")} ${color10.dim("\u2014 no model connected. Run")} ${color10.bold("/auth")} ${color10.dim("to connect one.")}
2995
+ ${color11.amber("\u25B6")} ${color11.bold("Setup mode")} ${color11.dim("\u2014 no model connected. Run")} ${color11.bold("/auth")} ${color11.dim("to connect one.")}
2808
2996
 
2809
2997
  `
2810
2998
  );
@@ -2831,7 +3019,7 @@ async function boot(argv) {
2831
3019
  config = reloaded.config;
2832
3020
  vault = reloaded.vault;
2833
3021
  } catch (err) {
2834
- writeErr(`Config error after setup: ${toErrorMessage4(err)}
3022
+ writeErr(`Config error after setup: ${toErrorMessage5(err)}
2835
3023
  `);
2836
3024
  await reader.close();
2837
3025
  return 2;
@@ -2844,7 +3032,7 @@ async function boot(argv) {
2844
3032
  const savedStatus = await validateSavedProviderModel(config, modelsRegistry);
2845
3033
  renderer.write(
2846
3034
  `
2847
- ${color10.dim("Last settings:")} ${color10.bold(savedProvider)} / ${color10.bold(savedModel)}
3035
+ ${color11.dim("Last settings:")} ${color11.bold(savedProvider)} / ${color11.bold(savedModel)}
2848
3036
  `
2849
3037
  );
2850
3038
  if (!savedStatus.ok) {
@@ -2854,11 +3042,11 @@ async function boot(argv) {
2854
3042
  );
2855
3043
  } else {
2856
3044
  const answer = (await reader.readLine(
2857
- ` ${color10.amber("?")} Continue with these? ${color10.dim("[Y/n/q]")} ${color10.dim("(auto Y in 5s)")} `,
3045
+ ` ${color11.amber("?")} Continue with these? ${color11.dim("[Y/n/q]")} ${color11.dim("(auto Y in 5s)")} `,
2858
3046
  { timeoutMs: 5e3, defaultAnswer: "y" }
2859
3047
  )).trim().toLowerCase();
2860
3048
  if (answer === "q") {
2861
- renderer.write(color10.dim(" Goodbye!\n"));
3049
+ renderer.write(color11.dim(" Goodbye!\n"));
2862
3050
  await reader.close();
2863
3051
  return 0;
2864
3052
  }
@@ -2866,7 +3054,7 @@ async function boot(argv) {
2866
3054
  skipPicker = true;
2867
3055
  renderer.write(
2868
3056
  `
2869
- ${color10.green("\u25B6")} ${color10.bold(savedProvider)} / ${color10.bold(savedModel)}
3057
+ ${color11.green("\u25B6")} ${color11.bold(savedProvider)} / ${color11.bold(savedModel)}
2870
3058
 
2871
3059
  `
2872
3060
  );
@@ -2887,9 +3075,9 @@ async function boot(argv) {
2887
3075
  if (!config.provider || !config.model) {
2888
3076
  renderer.write(
2889
3077
  `
2890
- ${color10.dim("No provider selected.")}
2891
- ${color10.dim("Run")} ${color10.bold("wstack auth")} ${color10.dim("to add a key or sign in, or start with no model:")}
2892
- ${color10.bold(`wstack --provider ${SETUP_PROVIDER_ID} --model ${SETUP_MODEL_ID}`)}
3078
+ ${color11.dim("No provider selected.")}
3079
+ ${color11.dim("Run")} ${color11.bold("wstack auth")} ${color11.dim("to add a key or sign in, or start with no model:")}
3080
+ ${color11.bold(`wstack --provider ${SETUP_PROVIDER_ID} --model ${SETUP_MODEL_ID}`)}
2893
3081
 
2894
3082
  `
2895
3083
  );
@@ -2959,7 +3147,7 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
2959
3147
  }
2960
3148
  if (promptMenu.persistError) {
2961
3149
  renderer.writeWarning(
2962
- `Could not save system prompt variant to config: ${toErrorMessage4(promptMenu.persistError)}
3150
+ `Could not save system prompt variant to config: ${toErrorMessage5(promptMenu.persistError)}
2963
3151
  `
2964
3152
  );
2965
3153
  }
@@ -3011,8 +3199,8 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
3011
3199
  if (shouldPrintYoloNotice(lastChoices, yoloPinned, choices.yolo)) {
3012
3200
  writeErr(
3013
3201
  `
3014
- ${color10.yellow("YOLO is on")}: non-denied tool calls, including shell and file writes, run without confirmation.
3015
- ${color10.dim("Explicit deny rules still apply. Use")} --no-yolo ${color10.dim("or")} /yolo off ${color10.dim("to require prompts.")}
3202
+ ${color11.yellow("YOLO is on")}: non-denied tool calls, including shell and file writes, run without confirmation.
3203
+ ${color11.dim("Explicit deny rules still apply. Use")} --no-yolo ${color11.dim("or")} /yolo off ${color11.dim("to require prompts.")}
3016
3204
 
3017
3205
  `
3018
3206
  );
@@ -3063,64 +3251,13 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
3063
3251
  needsSetup: !noInteractiveMode ? false : !config.provider || !config.model
3064
3252
  };
3065
3253
  }
3066
- async function checkGitInCwd(opts) {
3067
- const { cwd, renderer, reader } = opts;
3068
- const cwdGit = path7.join(cwd, ".git");
3069
- let hasCwdGit = false;
3070
- try {
3071
- await fs6.access(cwdGit);
3072
- hasCwdGit = true;
3073
- } catch {
3074
- }
3075
- if (!hasCwdGit) {
3076
- renderer.write(
3077
- `
3078
- ${color10.amber("\u25CB")} This folder has no ${color10.bold(".git")} repository.
3079
- `
3080
- );
3081
- const answer = (await reader.readLine(` ${color10.amber("?")} Initialize one here? ${color10.dim("[y/N]")} `)).trim().toLowerCase();
3082
- if (answer === "y" || answer === "yes") {
3083
- try {
3084
- const { spawn: spawn2 } = await import("node:child_process");
3085
- await new Promise((resolve2, reject) => {
3086
- const child = spawn2("git", ["init"], {
3087
- cwd,
3088
- signal: AbortSignal.timeout(1e4),
3089
- windowsHide: true
3090
- });
3091
- child.on("error", reject);
3092
- child.on(
3093
- "close",
3094
- (code) => code === 0 ? resolve2() : reject(new Error(`git init failed with ${code}`))
3095
- );
3096
- });
3097
- renderer.write(` ${color10.green("\u2713")} Git repository initialized
3098
- `);
3099
- hasCwdGit = true;
3100
- } catch (err) {
3101
- renderer.writeError(`git init failed: ${toErrorMessage4(err)}
3102
- `);
3103
- }
3104
- }
3105
- }
3106
- const parentDir = path7.dirname(cwd);
3107
- if (parentDir !== cwd) {
3108
- try {
3109
- await fs6.access(path7.join(parentDir, ".git"));
3110
- renderer.write(
3111
- ` ${color10.dim("\u2139")} A ${color10.bold(".git")} repo exists in the parent directory: ${color10.dim(parentDir)}
3112
- `
3113
- );
3114
- } catch {
3115
- }
3116
- }
3117
- }
3118
3254
 
3119
3255
  // src/cli-context.ts
3120
3256
  async function initializeCli(argv) {
3121
3257
  applyNodeEnvDefault();
3122
3258
  applySessionShellDefault();
3123
3259
  const earlyFlags = parseArgs(argv).flags;
3260
+ applyAsciiMode(earlyFlags);
3124
3261
  const earlyExit = await handleHelpVersionShortCircuit(argv);
3125
3262
  if (earlyExit !== null) return earlyExit;
3126
3263
  const desktopExit = await handleDesktopShortCircuit(earlyFlags, argv);
@@ -3253,33 +3390,7 @@ async function initializeCli(argv) {
3253
3390
  }
3254
3391
  const { config, vault, wpaths, cwd, modelsRegistry, renderer, reader, logger } = ctx;
3255
3392
  const { updateInfo: refreshedUpdateInfo } = await runPreflight(config, ctx.updateInfo);
3256
- const profileConfigPath = activeProfileConfigPath(wpaths, config);
3257
- setOAuthTokenPersister((providerId, creds) => {
3258
- void mutateConfigProviders(profileConfigPath, vault, (all) => {
3259
- const p = all[providerId];
3260
- if (!p) return;
3261
- const keys = normalizeKeys(p);
3262
- const active = p.activeKey ? keys.find((k) => k.label === p.activeKey) : keys[0];
3263
- if (!active) return;
3264
- active.apiKey = creds.accessToken;
3265
- active.refreshToken = creds.refreshToken;
3266
- active.expiresAt = new Date(creds.expiresAt).toISOString();
3267
- if (creds.accountId) active.accountId = creds.accountId;
3268
- writeKeysBack(p, keys);
3269
- }).catch(() => {
3270
- });
3271
- });
3272
- setProviderModelPersister((providerId, models) => {
3273
- if (models.length === 0) return;
3274
- void mutateConfigProviders(profileConfigPath, vault, (all) => {
3275
- const p = all[providerId];
3276
- if (!p) return;
3277
- const live = models.map((m) => m.id);
3278
- if (p.models?.length === live.length && p.models.every((id, i) => id === live[i])) return;
3279
- p.models = live;
3280
- }).catch(() => {
3281
- });
3282
- });
3393
+ installProviderPersisters({ config, paths: wpaths, vault, logger });
3283
3394
  const { events, container, approvalMirror } = wireContainer({
3284
3395
  config,
3285
3396
  wpaths,
@@ -3287,7 +3398,8 @@ async function initializeCli(argv) {
3287
3398
  logger,
3288
3399
  reader,
3289
3400
  renderer,
3290
- modelsRegistry
3401
+ modelsRegistry,
3402
+ launchAllowedTools: resolveLaunchAllowedTools(ctx.flags)
3291
3403
  });
3292
3404
  const configStore = container.resolve(TOKENS3.ConfigStore);
3293
3405
  return {
@@ -3303,4 +3415,4 @@ async function initializeCli(argv) {
3303
3415
  export {
3304
3416
  initializeCli
3305
3417
  };
3306
- //# sourceMappingURL=cli-context-33F74CSZ.js.map
3418
+ //# sourceMappingURL=cli-context-UVGAN3NO.js.map