@wrongstack/cli 1.0.24 → 1.0.27

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 (146) hide show
  1. package/data/providers.json +44 -0
  2. package/dist/{acp-AJWSKWE5.js → acp-M4565YUW.js} +33 -20
  3. package/dist/ascii-mode-SG4PRNLP.js +7 -0
  4. package/dist/{auth-GRBZ7Y3D.js → auth-TE55JF4Z.js} +14 -14
  5. package/dist/{bench-N5K7Z5O3.js → bench-GTLPM22B.js} +2 -2
  6. package/dist/boot/append-system-prompt.d.ts +10 -0
  7. package/dist/boot/ascii-mode.d.ts +12 -0
  8. package/dist/boot/container-wiring.d.ts +4 -2
  9. package/dist/boot/dispatch-singleshot.d.ts +12 -1
  10. package/dist/boot/dispatch-webui.d.ts +2 -0
  11. package/dist/boot/goal-tui-default.d.ts +10 -0
  12. package/dist/boot/mcp-config-flag.d.ts +22 -0
  13. package/dist/boot/piped-stdin.d.ts +40 -0
  14. package/dist/boot/restricted-mode.d.ts +15 -0
  15. package/dist/boot/safe-mode.d.ts +30 -0
  16. package/dist/boot/single-shot-budget.d.ts +30 -0
  17. package/dist/boot/stream-json.d.ts +36 -0
  18. package/dist/boot/structured-output.d.ts +16 -0
  19. package/dist/boot/system-prompt-builder.d.ts +2 -0
  20. package/dist/boot/tool-restriction-flags.d.ts +36 -0
  21. package/dist/boot/worktree-sessions.d.ts +21 -0
  22. package/dist/boot-provider-selection.d.ts +67 -0
  23. package/dist/boot.d.ts +1 -38
  24. package/dist/{chunk-LFMVHT3R.js → chunk-2ERX3RPN.js} +11 -13
  25. package/dist/chunk-4TVYGG6G.js +62 -0
  26. package/dist/chunk-5JYDKG5B.js +154 -0
  27. package/dist/{chunk-3VXYY5JC.js → chunk-5UZBUV2H.js} +3 -19
  28. package/dist/chunk-CZTXF6HY.js +140 -0
  29. package/dist/{chunk-DRM7PSW7.js → chunk-ENRYW73H.js} +527 -381
  30. package/dist/{chunk-SKPDE62W.js → chunk-EPR42SWM.js} +36 -6
  31. package/dist/{chunk-YBUCXXYZ.js → chunk-F5DCFAKI.js} +1 -1
  32. package/dist/chunk-HDMFKTT3.js +157 -0
  33. package/dist/{chunk-PGKJ2OQP.js → chunk-HFZH2XJN.js} +5 -5
  34. package/dist/chunk-HLSHFXTO.js +97 -0
  35. package/dist/{chunk-QFPQXKCG.js → chunk-KOEO4CJG.js} +21 -6
  36. package/dist/chunk-LBPLTTZ6.js +105 -0
  37. package/dist/{chunk-3OCUS3VN.js → chunk-LDCGZJTC.js} +4 -4
  38. package/dist/chunk-LKPEBZBE.js +143 -0
  39. package/dist/chunk-N57IU5FG.js +58 -0
  40. package/dist/{chunk-2EBVTYJR.js → chunk-NRXWOMK7.js} +17 -3
  41. package/dist/chunk-PZQBGUVZ.js +18 -0
  42. package/dist/{chunk-MHEBWVXL.js → chunk-Q4INH2DG.js} +46 -2
  43. package/dist/{chunk-5SEYGOCH.js → chunk-RDGGWMTI.js} +2 -2
  44. package/dist/{chunk-BLD5DSVA.js → chunk-RGFWGUAB.js} +27 -15
  45. package/dist/{chunk-ZZRSG7VK.js → chunk-RZ4ZDRYA.js} +3 -3
  46. package/dist/{chunk-S4FFHDJG.js → chunk-SDJCLEK6.js} +6 -2
  47. package/dist/{chunk-U46QR4WR.js → chunk-TI7KLHYX.js} +132 -3
  48. package/dist/chunk-X756ZS72.js +329 -0
  49. package/dist/{chunk-JF2MULWF.js → chunk-YHYINL47.js} +47 -15
  50. package/dist/{cli-context-34Q5IJRA.js → cli-context-C7RBSWHF.js} +434 -327
  51. package/dist/{cli-main-AELJDBGU.js → cli-main-TQTH73ZK.js} +2948 -2315
  52. package/dist/cli-update-notice.d.ts +2 -1
  53. package/dist/config-doctor.d.ts +1 -1
  54. package/dist/{diag-doctor-WIFJH3XH.js → diag-doctor-BIZAFIAT.js} +2 -2
  55. package/dist/{execution-PYC5FCS4.js → execution-3STBD2U7.js} +2167 -1831
  56. package/dist/execution-chimera-review.d.ts +18 -1
  57. package/dist/fleet/host-types.d.ts +3 -1
  58. package/dist/goal-commands.d.ts +47 -0
  59. package/dist/goal-host.d.ts +1 -14
  60. package/dist/{hq-JTUTFI4L.js → hq-44F4OQH2.js} +9 -8
  61. package/dist/hq-fleet-control.d.ts +36 -0
  62. package/dist/hq-live-status.d.ts +22 -0
  63. package/dist/hq-publisher.d.ts +18 -0
  64. package/dist/hq-server/routes/command-handlers.d.ts +12 -1
  65. package/dist/hq-server/routes/data-handlers.d.ts +1 -1
  66. package/dist/hq-server/socket-credentials.d.ts +63 -0
  67. package/dist/hq-server/upgrade-handler.d.ts +2 -0
  68. package/dist/hq-server/ws.d.ts +24 -0
  69. package/dist/{hq-server-PC7GZMPT.js → hq-server-UIB24LU6.js} +2 -2
  70. package/dist/{hq-service-NW56MUP2.js → hq-service-BMMJAHRT.js} +4 -4
  71. package/dist/import-claude-code-AYG24RG2.js +268 -0
  72. package/dist/index.js +12 -8
  73. package/dist/live-settings-input.d.ts +1 -0
  74. package/dist/{mailbox-serve-WDOCH6KR.js → mailbox-serve-GNGXEQ2R.js} +3 -3
  75. package/dist/{modeldiag-36OGAL5C.js → modeldiag-W7XAE625.js} +9 -9
  76. package/dist/{per-subcommand-help-XE77MTGJ.js → per-subcommand-help-QDAQASPZ.js} +2 -2
  77. package/dist/permission-prompt.d.ts +14 -0
  78. package/dist/permission-rules-view.d.ts +18 -0
  79. package/dist/{permissions-CFDLXETM.js → permissions-PL27UHYD.js} +67 -45
  80. package/dist/{plugin-usage-S5LVGMBW.js → plugin-usage-CIGOOTX3.js} +2 -2
  81. package/dist/{plugins-RHBIVLI7.js → plugins-HQTXUD6A.js} +4 -2
  82. package/dist/preflight.d.ts +1 -1
  83. package/dist/{projects-LMNAGGEU.js → projects-T4CZCA25.js} +3 -6
  84. package/dist/provider-helpers.d.ts +7 -11
  85. package/dist/{providers-models-2CFG46RD.js → providers-models-5Z2PJTEW.js} +5 -5
  86. package/dist/release-asset-download.d.ts +10 -0
  87. package/dist/release-attestation.d.ts +28 -0
  88. package/dist/remote/remote-session.d.ts +64 -0
  89. package/dist/remote/remote-target.d.ts +69 -0
  90. package/dist/remote-GB5VXCCT.js +576 -0
  91. package/dist/{replay-Z3FTJEMM.js → replay-DEI566CW.js} +2 -2
  92. package/dist/services/commit-message.d.ts +2 -1
  93. package/dist/session-move-P2EC2COA.js +44 -0
  94. package/dist/session-move.d.ts +20 -0
  95. package/dist/session-stats.d.ts +10 -0
  96. package/dist/{sessions-config-IQUH2GXT.js → sessions-config-XHLXJ5C3.js} +109 -10
  97. package/dist/short-circuit-flags-5TNTJPQR.js +10 -0
  98. package/dist/slash-commands/command-context.d.ts +15 -5
  99. package/dist/slash-commands/goal-refiner.d.ts +4 -49
  100. package/dist/slash-commands/mcp.d.ts +2 -1
  101. package/dist/slash-commands/permissions.d.ts +4 -0
  102. package/dist/slash-commands/settings-context-mutations.d.ts +5 -0
  103. package/dist/slash-commands/settings-limits-mutations.d.ts +12 -0
  104. package/dist/slash-commands/theme.d.ts +15 -1
  105. package/dist/standalone-auto-update-TOTRGCSA.js +249 -0
  106. package/dist/standalone-auto-update.d.ts +65 -0
  107. package/dist/standalone-update-LZO3MNLH.js +24 -0
  108. package/dist/standalone-update.d.ts +37 -1
  109. package/dist/subcommands/handlers/import-claude-code.d.ts +52 -0
  110. package/dist/subcommands/handlers/permissions.d.ts +9 -3
  111. package/dist/subcommands/handlers/remote.d.ts +6 -0
  112. package/dist/subcommands/handlers/sessions-fleet.d.ts +0 -12
  113. package/dist/subcommands/handlers/version-help.d.ts +5 -0
  114. package/dist/{subcommands-ZTSIN7LG.js → subcommands-BHQYLDSD.js} +2 -2
  115. package/dist/tui-resume-callback.d.ts +18 -0
  116. package/dist/{typesafe-HVEVPA6R.js → typesafe-U7YB2RRV.js} +5 -5
  117. package/dist/{typesafe-topic-replay-4W73BOLV.js → typesafe-topic-replay-ZILIU3WS.js} +18 -2
  118. package/dist/{update-7XIOEXTD.js → update-TDZX4IL2.js} +4 -4
  119. package/dist/{update-check-2POMBHFB.js → update-check-J5ZVKS73.js} +3 -3
  120. package/dist/version-JB2UAV2A.js +11 -0
  121. package/dist/version-help-XJJQ7YSH.js +10 -0
  122. package/dist/webui-server/route-contexts.d.ts +1 -1
  123. package/dist/webui-server/session-start-payload.d.ts +5 -1
  124. package/dist/{webui-server-L2SICPTB.js → webui-server-GCXIO3JY.js} +515 -365
  125. package/dist/webui-server-lifecycle.d.ts +57 -0
  126. package/dist/webui-server-options.d.ts +10 -0
  127. package/dist/webui-server.d.ts +0 -14
  128. package/dist/wiring/brain-and-orchestration.d.ts +3 -1
  129. package/dist/wiring/cli-prompt-and-tools-setup.d.ts +9 -0
  130. package/dist/wiring/cli-slash-commands-setup.d.ts +1 -0
  131. package/dist/wiring/command-host-state.d.ts +2 -0
  132. package/dist/wiring/hq-telemetry.d.ts +12 -0
  133. package/dist/wiring/lifecycle-plugins.d.ts +4 -2
  134. package/dist/wiring/metrics.d.ts +9 -1
  135. package/dist/wiring/pipeline.d.ts +2 -7
  136. package/dist/wiring/plugins.d.ts +3 -0
  137. package/dist/wiring/provider-status.d.ts +1 -0
  138. package/dist/wiring/provider-utility-tools.d.ts +3 -1
  139. package/package.json +29 -28
  140. package/dist/chunk-2BKFWIER.js +0 -98
  141. package/dist/chunk-424ORSE7.js +0 -56
  142. package/dist/chunk-OWNC7LMD.js +0 -78
  143. package/dist/chunk-QBBF7GIK.js +0 -65
  144. package/dist/short-circuit-flags-SDT53OML.js +0 -10
  145. package/dist/standalone-update-MW47J3AK.js +0 -164
  146. package/dist/version-help-WZ623NWM.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-U46QR4WR.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";
12
- import {
13
- fmtTok,
14
- patchConfig
15
- } from "./chunk-EWKESL4L.js";
16
20
  import {
17
21
  parseWebuiSessionChildOptions,
18
22
  writeWebuiSessionChildError
19
23
  } from "./chunk-ZMX5HRLI.js";
24
+ import {
25
+ fmtTok,
26
+ patchConfig
27
+ } from "./chunk-EWKESL4L.js";
20
28
  import {
21
29
  subcommands
22
- } from "./chunk-424ORSE7.js";
30
+ } from "./chunk-N57IU5FG.js";
23
31
  import {
24
32
  renderDeepHelp,
25
33
  renderFocusedHelp
26
- } from "./chunk-SKPDE62W.js";
34
+ } from "./chunk-EPR42SWM.js";
27
35
  import {
28
36
  handleHelpVersionShortCircuit
29
- } from "./chunk-PGKJ2OQP.js";
37
+ } from "./chunk-HFZH2XJN.js";
30
38
  import {
31
39
  DEFAULT_PORT
32
- } from "./chunk-DRM7PSW7.js";
40
+ } from "./chunk-ENRYW73H.js";
33
41
  import "./chunk-HXJYHAR4.js";
34
42
  import {
35
43
  resolveHqPasswordInput
@@ -38,20 +46,34 @@ import {
38
46
  normalizeHqPublicOrigin
39
47
  } from "./chunk-5EA6OTLJ.js";
40
48
  import {
41
- parseHqIpAllowlist
42
- } from "./chunk-Q7E3BPDU.js";
49
+ resolveLaunchMcpServers
50
+ } from "./chunk-HLSHFXTO.js";
43
51
  import {
44
52
  installProviderPersisters
45
- } from "./chunk-3OCUS3VN.js";
53
+ } from "./chunk-LDCGZJTC.js";
54
+ import {
55
+ parseHqIpAllowlist
56
+ } from "./chunk-Q7E3BPDU.js";
46
57
  import {
47
58
  discoverAndMergeProviders
48
59
  } from "./chunk-D5GB5MHA.js";
60
+ import {
61
+ runUpdateCommand
62
+ } from "./chunk-KOEO4CJG.js";
63
+ import "./chunk-U3SS4NRH.js";
49
64
  import {
50
65
  applyNodeEnvDefault,
51
66
  applySessionShellDefault,
52
67
  runPreflight
53
- } from "./chunk-QBBF7GIK.js";
54
- import "./chunk-2BKFWIER.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";
74
+ import {
75
+ CLI_VERSION
76
+ } from "./chunk-F5DCFAKI.js";
55
77
  import {
56
78
  addFromCatalog,
57
79
  boxBottom,
@@ -63,31 +85,23 @@ import {
63
85
  runPicker,
64
86
  saveToGlobalConfig,
65
87
  theme
66
- } from "./chunk-LFMVHT3R.js";
88
+ } from "./chunk-2ERX3RPN.js";
67
89
  import "./chunk-YTEOAWOJ.js";
68
90
  import {
69
91
  isKeylessLocalProvider,
70
92
  visibleModelIds
71
- } from "./chunk-3VXYY5JC.js";
93
+ } from "./chunk-5UZBUV2H.js";
94
+ import {
95
+ resolveActiveApiKey
96
+ } from "./chunk-LUMETJFO.js";
97
+ import "./chunk-DAKVBMD4.js";
72
98
  import {
73
99
  activeProfileConfigPath
74
100
  } from "./chunk-YMXXOOFN.js";
75
101
  import "./chunk-WSTVGC2C.js";
76
102
  import {
77
103
  parseArgs
78
- } from "./chunk-MHEBWVXL.js";
79
- import "./chunk-DAKVBMD4.js";
80
- import {
81
- resolveActiveApiKey
82
- } from "./chunk-LUMETJFO.js";
83
- import {
84
- runUpdateCommand
85
- } from "./chunk-QFPQXKCG.js";
86
- import "./chunk-U3SS4NRH.js";
87
- import "./chunk-ZZRSG7VK.js";
88
- import {
89
- CLI_VERSION
90
- } from "./chunk-YBUCXXYZ.js";
104
+ } from "./chunk-Q4INH2DG.js";
91
105
 
92
106
  // src/cli-context.ts
93
107
  import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
@@ -192,12 +206,13 @@ function wireContainer(deps) {
192
206
  events,
193
207
  permission: {
194
208
  yolo: deps.config.yolo,
209
+ launchAllowedTools: deps.launchAllowedTools,
195
210
  // Wrapped so the REPL's terminal prompt also appears on the HQ
196
211
  // dashboard and can be answered from there. The wrapper is a no-op
197
212
  // until `approvalMirror.current` is populated (HQ telemetry boot), and
198
213
  // the terminal prompt itself behaves exactly as it always has.
199
214
  promptDelegate: makeMirroredPromptDelegate({
200
- inner: makePromptDelegate(deps.reader),
215
+ inner: makeStdinPromptDelegate(deps.reader),
201
216
  getRegistry: () => approvalMirror.current,
202
217
  getSessionId: () => approvalMirror.sessionId?.()
203
218
  })
@@ -475,7 +490,7 @@ async function promptModeArrow(deps) {
475
490
  const { renderer } = deps;
476
491
  const stdin = process.stdin;
477
492
  const out = (s) => renderer.write(s);
478
- return await new Promise((resolve2) => {
493
+ return await new Promise((resolve3) => {
479
494
  let index = 0;
480
495
  let drawn = 0;
481
496
  let remaining = Math.round(MENU_TIMEOUT_MS / 1e3);
@@ -530,7 +545,7 @@ async function promptModeArrow(deps) {
530
545
  out("\x1B[0J");
531
546
  out(finalLine);
532
547
  out("\x1B[?25h");
533
- resolve2(result);
548
+ resolve3(result);
534
549
  };
535
550
  const pick = () => {
536
551
  const opt = MODE_OPTIONS[index];
@@ -589,7 +604,7 @@ async function promptModeArrow(deps) {
589
604
  setRawMode(stdin, true);
590
605
  stdin.resume();
591
606
  } catch {
592
- resolve2(null);
607
+ resolve3(null);
593
608
  return;
594
609
  }
595
610
  out("\x1B[?25l");
@@ -854,7 +869,7 @@ async function launchDesktop(args) {
854
869
  );
855
870
  return 1;
856
871
  }
857
- return await new Promise((resolve2) => {
872
+ return await new Promise((resolve3) => {
858
873
  const env = { ...process.env };
859
874
  if (native) delete env["ELECTRON_RUN_AS_NODE"];
860
875
  const child = spawn(executable, launchArgs, {
@@ -867,11 +882,11 @@ async function launchDesktop(args) {
867
882
  `${color2.red("\u2717 Failed to start WrongStack Desktop:")} ${err.message}
868
883
  `
869
884
  );
870
- resolve2(1);
885
+ resolve3(1);
871
886
  });
872
887
  child.once("exit", (code, signal) => {
873
- if (typeof code === "number") resolve2(code);
874
- else resolve2(signal ? 1 : 0);
888
+ if (typeof code === "number") resolve3(code);
889
+ else resolve3(signal ? 1 : 0);
875
890
  });
876
891
  });
877
892
  }
@@ -896,24 +911,24 @@ async function isHqAlreadyRunning(dataDir) {
896
911
  return null;
897
912
  }
898
913
  async function isPortInUse(host, port) {
899
- return new Promise((resolve2) => {
914
+ return new Promise((resolve3) => {
900
915
  const server = net.createServer();
901
916
  server.once("error", (err) => {
902
917
  if (err.code === "EADDRINUSE") {
903
- resolve2(true);
918
+ resolve3(true);
904
919
  } else {
905
- resolve2(false);
920
+ resolve3(false);
906
921
  }
907
922
  });
908
923
  server.once("listening", () => {
909
- server.close(() => resolve2(false));
924
+ server.close(() => resolve3(false));
910
925
  });
911
926
  server.listen(port, host);
912
927
  });
913
928
  }
914
929
  async function handleHqShortCircuit(flags) {
915
930
  if (flags["hq"] !== true) return null;
916
- const { startHqServer } = await import("./hq-server-PC7GZMPT.js");
931
+ const { startHqServer } = await import("./hq-server-UIB24LU6.js");
917
932
  const tunnelRequested = flags["tunnel"] === true;
918
933
  const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
919
934
  let publicOrigin;
@@ -1127,7 +1142,7 @@ ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
1127
1142
  } catch {
1128
1143
  }
1129
1144
  }
1130
- await new Promise((resolve2) => {
1145
+ await new Promise((resolve3) => {
1131
1146
  const shutdown = async () => {
1132
1147
  const results = await Promise.allSettled([
1133
1148
  ...tunnel ? [tunnel.close()] : [],
@@ -1146,7 +1161,7 @@ ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
1146
1161
  })
1147
1162
  );
1148
1163
  }
1149
- resolve2();
1164
+ resolve3();
1150
1165
  };
1151
1166
  process.on("SIGINT", shutdown);
1152
1167
  process.on("SIGTERM", shutdown);
@@ -1155,26 +1170,195 @@ ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
1155
1170
  }
1156
1171
 
1157
1172
  // src/boot.ts
1158
- import * as fs6 from "node:fs/promises";
1159
- import { createRequire as createRequire4 } from "node:module";
1160
1173
  import * as os from "node:os";
1161
- 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";
1162
1181
  import { fileURLToPath } from "node:url";
1163
- import { moduleUrlFor, toErrorMessage as toErrorMessage4, wrongstackPackageJsonPath as wrongstackPackageJsonPath3 } 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
1164
1323
  import { DefaultLogger } from "@wrongstack/core/infrastructure";
1165
1324
  import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
1166
- import { DefaultModelsRegistry } from "@wrongstack/core/models";
1325
+ import { DefaultModelsRegistry, startCatalog } from "@wrongstack/core/models";
1167
1326
  import { ToolRegistry } from "@wrongstack/core/registry";
1168
1327
  import { normalizeTokenSavingTier } from "@wrongstack/core/types";
1169
- import { color as color10, isStdinTTY as isStdinTTY2, writeErr } from "@wrongstack/core/utils";
1170
- import { isSetupProvider, SETUP_MODEL_ID, SETUP_PROVIDER_ID } from "@wrongstack/providers";
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";
1171
1330
  import { createDefaultContainer as createDefaultContainer2 } from "@wrongstack/runtime";
1172
1331
  import { registerBuiltinToolTier } from "@wrongstack/tools/tool-tier";
1173
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
+
1174
1358
  // src/boot/config-backup-recovery.ts
1175
- import * as fs2 from "node:fs/promises";
1176
- import * as path4 from "node:path";
1177
- 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";
1178
1362
  function isRecord(value) {
1179
1363
  return value !== null && typeof value === "object" && !Array.isArray(value);
1180
1364
  }
@@ -1185,7 +1369,7 @@ function providerIds(value) {
1185
1369
  }
1186
1370
  async function defaultProfileProvidersAreEmpty(profilePath) {
1187
1371
  try {
1188
- const parsed = JSON.parse(await fs2.readFile(profilePath, "utf8"));
1372
+ const parsed = JSON.parse(await fs4.readFile(profilePath, "utf8"));
1189
1373
  return providerIds(parsed).length === 0;
1190
1374
  } catch {
1191
1375
  return false;
@@ -1208,7 +1392,7 @@ function profileSnapshotTimestamp(fileName, fallback) {
1208
1392
  );
1209
1393
  }
1210
1394
  async function findLatestProviderBackup(globalRoot, profileName = "default") {
1211
- const directory = path4.join(globalRoot, "config-history");
1395
+ const directory = path6.join(globalRoot, "config-history");
1212
1396
  const escapedProfile = profileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1213
1397
  const filePattern = new RegExp(
1214
1398
  `^profiles-${escapedProfile}-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}\\.json$`,
@@ -1217,7 +1401,7 @@ async function findLatestProviderBackup(globalRoot, profileName = "default") {
1217
1401
  const candidates = [];
1218
1402
  let entries;
1219
1403
  try {
1220
- entries = await fs2.readdir(directory, { withFileTypes: true });
1404
+ entries = await fs4.readdir(directory, { withFileTypes: true });
1221
1405
  } catch {
1222
1406
  return void 0;
1223
1407
  }
@@ -1225,9 +1409,9 @@ async function findLatestProviderBackup(globalRoot, profileName = "default") {
1225
1409
  if (!entry.isFile() || !filePattern.test(entry.name)) {
1226
1410
  continue;
1227
1411
  }
1228
- const filePath = path4.join(directory, entry.name);
1412
+ const filePath = path6.join(directory, entry.name);
1229
1413
  try {
1230
- const stat2 = await fs2.stat(filePath);
1414
+ const stat2 = await fs4.stat(filePath);
1231
1415
  candidates.push({
1232
1416
  filePath,
1233
1417
  fileName: entry.name,
@@ -1239,7 +1423,7 @@ async function findLatestProviderBackup(globalRoot, profileName = "default") {
1239
1423
  candidates.sort((a, b) => b.modifiedAtMs - a.modifiedAtMs);
1240
1424
  for (const candidate of candidates) {
1241
1425
  try {
1242
- const raw = await fs2.readFile(candidate.filePath, "utf8");
1426
+ const raw = await fs4.readFile(candidate.filePath, "utf8");
1243
1427
  const parsed = JSON.parse(raw);
1244
1428
  const ids = providerIds(parsed);
1245
1429
  if (ids.length === 0) continue;
@@ -1251,7 +1435,7 @@ async function findLatestProviderBackup(globalRoot, profileName = "default") {
1251
1435
  }
1252
1436
  async function restoreDefaultProfileBackup(opts) {
1253
1437
  await backupConfigFile(opts.profilePath, { globalRoot: opts.globalRoot });
1254
- await fs2.mkdir(path4.dirname(opts.profilePath), { recursive: true });
1438
+ await fs4.mkdir(path6.dirname(opts.profilePath), { recursive: true });
1255
1439
  await atomicWrite2(opts.profilePath, opts.backup.raw, { mode: 384 });
1256
1440
  }
1257
1441
  async function maybeRestoreDefaultProfileFromBackup(opts) {
@@ -1264,12 +1448,12 @@ async function maybeRestoreDefaultProfileFromBackup(opts) {
1264
1448
  const providerSummary = remainder > 0 ? `${shownProviders} +${remainder}` : shownProviders;
1265
1449
  opts.renderer.write(
1266
1450
  `
1267
- ${color4.amber("\u25CB")} ${color4.bold(profileName)} profile has no saved providers.
1268
- ${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})`)}
1269
1453
  `
1270
1454
  );
1271
1455
  const answer = (await opts.reader.readLine(
1272
- ` ${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]")} `
1273
1457
  )).trim().toLowerCase();
1274
1458
  if (answer === "n" || answer === "no") return false;
1275
1459
  try {
@@ -1279,17 +1463,25 @@ async function maybeRestoreDefaultProfileFromBackup(opts) {
1279
1463
  profilePath: opts.profilePath
1280
1464
  });
1281
1465
  opts.renderer.write(
1282
- ` ${color4.green("\u2713")} Restored all settings from ${color4.dim(backup.fileName)}
1466
+ ` ${color5.green("\u2713")} Restored all settings from ${color5.dim(backup.fileName)}
1283
1467
  `
1284
1468
  );
1285
1469
  return true;
1286
1470
  } catch (err) {
1287
- opts.renderer.writeWarning(`Could not restore config backup: ${toErrorMessage(err)}
1471
+ opts.renderer.writeWarning(`Could not restore config backup: ${toErrorMessage2(err)}
1288
1472
  `);
1289
1473
  return false;
1290
1474
  }
1291
1475
  }
1292
1476
 
1477
+ // src/boot/goal-tui-default.ts
1478
+ function applyGoalTuiDefault(flags, positional) {
1479
+ const prompt = flags["prompt"];
1480
+ if ((typeof flags["goal"] === "string" || typeof flags["ask"] === "string") && positional.length === 0 && !(typeof prompt === "string" && prompt.length > 0)) {
1481
+ flags["tui"] = true;
1482
+ }
1483
+ }
1484
+
1293
1485
  // src/boot/system-prompt-menu.ts
1294
1486
  import {
1295
1487
  countSystemPromptTokens,
@@ -1298,11 +1490,11 @@ import {
1298
1490
  SYSTEM_PROMPT_VARIANT_OPTIONS,
1299
1491
  SYSTEM_PROMPT_VARIANTS
1300
1492
  } from "@wrongstack/core/agent";
1301
- import { color as color8 } from "@wrongstack/core/utils";
1493
+ import { color as color9 } from "@wrongstack/core/utils";
1302
1494
 
1303
1495
  // src/pre-launch/first-run.ts
1304
1496
  import { hasProviderCredential } from "@wrongstack/core/models";
1305
- import { color as color5, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
1497
+ import { color as color6, toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
1306
1498
  import { PROVIDER_DEFINITIONS } from "@wrongstack/providers/definitions";
1307
1499
  async function hasAnyCredential(config, modelsRegistry, env = process.env) {
1308
1500
  for (const cfg of Object.values(config.providers ?? {})) {
@@ -1328,39 +1520,39 @@ function renderWelcome(renderer) {
1328
1520
  renderer.write(`${boxTop("Welcome to WrongStack")}
1329
1521
  `);
1330
1522
  renderer.write(
1331
- `${boxRow(color5.dim("No model is connected yet. Pick how you want to connect one:"))}
1523
+ `${boxRow(color6.dim("No model is connected yet. Pick how you want to connect one:"))}
1332
1524
  `
1333
1525
  );
1334
1526
  renderer.write(`${boxDivider()}
1335
1527
  `);
1336
1528
  renderer.write(
1337
1529
  `${boxRow(
1338
- `${theme.accent("1")} ${color5.bold("Sign in with a subscription")} ${color5.dim("ChatGPT \xB7 Claude \xB7 GitHub Copilot")}`
1530
+ `${theme.accent("1")} ${color6.bold("Sign in with a subscription")} ${color6.dim("ChatGPT \xB7 Claude \xB7 GitHub Copilot")}`
1339
1531
  )}
1340
1532
  `
1341
1533
  );
1342
1534
  renderer.write(
1343
1535
  `${boxRow(
1344
- `${theme.accent("2")} ${color5.bold("Add an API key")} ${color5.dim("Anthropic \xB7 OpenAI \xB7 Google \xB7 OpenRouter \xB7 \u2026")}`
1536
+ `${theme.accent("2")} ${color6.bold("Add an API key")} ${color6.dim("Anthropic \xB7 OpenAI \xB7 Google \xB7 OpenRouter \xB7 \u2026")}`
1345
1537
  )}
1346
1538
  `
1347
1539
  );
1348
1540
  renderer.write(
1349
1541
  `${boxRow(
1350
- `${theme.accent("3")} ${color5.bold("Use a local server")} ${color5.dim("Ollama \xB7 LM Studio \xB7 vLLM \xB7 OmniRoute")}`
1542
+ `${theme.accent("3")} ${color6.bold("Use a local server")} ${color6.dim("Ollama \xB7 LM Studio \xB7 vLLM \xB7 OmniRoute")}`
1351
1543
  )}
1352
1544
  `
1353
1545
  );
1354
1546
  renderer.write(
1355
1547
  `${boxRow(
1356
- `${theme.accent("4")} ${color5.bold("Continue without a key")} ${color5.dim("setup mode \u2014 explore the app, no model")}`
1548
+ `${theme.accent("4")} ${color6.bold("Continue without a key")} ${color6.dim("setup mode \u2014 explore the app, no model")}`
1357
1549
  )}
1358
1550
  `
1359
1551
  );
1360
1552
  renderer.write(`${boxDivider()}
1361
1553
  `);
1362
1554
  renderer.write(
1363
- `${boxRow(color5.dim("You can change this any time with /auth inside the app, or `wstack auth`."))}
1555
+ `${boxRow(color6.dim("You can change this any time with /auth inside the app, or `wstack auth`."))}
1364
1556
  `
1365
1557
  );
1366
1558
  renderer.write(`${boxBottom()}
@@ -1379,12 +1571,12 @@ async function runFirstRunSetup(deps) {
1379
1571
  renderWelcome(renderer);
1380
1572
  const answer = (await reader.readLine(
1381
1573
  `
1382
- ${color5.amber("?")} Choose ${color5.dim("(1-4)")} ${color5.dim("[q to quit]")}: `
1574
+ ${color6.amber("?")} Choose ${color6.dim("(1-4)")} ${color6.dim("[q to quit]")}: `
1383
1575
  )).trim().toLowerCase();
1384
1576
  if (!answer || answer === "q" || answer === "quit" || answer === "exit") {
1385
1577
  renderer.write(
1386
1578
  `
1387
- ${color5.dim("No provider configured. Run")} ${color5.bold("wstack auth")} ${color5.dim("when you are ready.")}
1579
+ ${color6.dim("No provider configured. Run")} ${color6.bold("wstack auth")} ${color6.dim("when you are ready.")}
1388
1580
 
1389
1581
  `
1390
1582
  );
@@ -1401,14 +1593,14 @@ ${color5.amber("?")} Choose ${color5.dim("(1-4)")} ${color5.dim("[q to quit]")}:
1401
1593
  try {
1402
1594
  await flow();
1403
1595
  } catch (err) {
1404
- renderer.writeWarning(`Setup step did not complete: ${toErrorMessage2(err)}
1596
+ renderer.writeWarning(`Setup step did not complete: ${toErrorMessage3(err)}
1405
1597
  `);
1406
1598
  }
1407
1599
  let updated;
1408
1600
  try {
1409
1601
  updated = await deps.reloadConfig();
1410
1602
  } catch (err) {
1411
- renderer.writeWarning(`Could not re-read config: ${toErrorMessage2(err)}
1603
+ renderer.writeWarning(`Could not re-read config: ${toErrorMessage3(err)}
1412
1604
  `);
1413
1605
  continue;
1414
1606
  }
@@ -1420,8 +1612,8 @@ ${color5.amber("?")} Choose ${color5.dim("(1-4)")} ${color5.dim("[q to quit]")}:
1420
1612
  }
1421
1613
 
1422
1614
  // src/pre-launch/launch-prompts.ts
1423
- import * as fs3 from "node:fs/promises";
1424
- import { atomicWrite as atomicWrite3, color as color6 } from "@wrongstack/core/utils";
1615
+ import * as fs5 from "node:fs/promises";
1616
+ import { atomicWrite as atomicWrite3, color as color7 } from "@wrongstack/core/utils";
1425
1617
  var LaunchAbortedError = class extends Error {
1426
1618
  exitCode = 0;
1427
1619
  constructor() {
@@ -1452,19 +1644,19 @@ async function runLaunchPrompts(opts) {
1452
1644
  yolo: yoloPinned ?? lastChoices.yolo,
1453
1645
  autonomy: autonomyPinned ?? lastChoices.autonomy
1454
1646
  };
1455
- const onOff = (v) => v ? color6.green("on") : color6.dim("off");
1647
+ const onOff = (v) => v ? color7.green("on") : color7.dim("off");
1456
1648
  const modeLabel = effective.mode.toUpperCase();
1457
1649
  renderer.write(
1458
1650
  `
1459
- ${color6.dim("Last settings:")} ${color6.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Autonomy ${effective.autonomy === "auto" ? color6.green("auto") : color6.dim("off")}
1651
+ ${color7.dim("Last settings:")} ${color7.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Autonomy ${effective.autonomy === "auto" ? color7.green("auto") : color7.dim("off")}
1460
1652
  `
1461
1653
  );
1462
1654
  const answer = (await reader.readLine(
1463
- ` ${color6.amber("?")} Continue with these? ${color6.dim("[Y/n/q]")} ${color6.dim("(auto Y in 5s)")} `,
1655
+ ` ${color7.amber("?")} Continue with these? ${color7.dim("[Y/n/q]")} ${color7.dim("(auto Y in 5s)")} `,
1464
1656
  { timeoutMs: 5e3, defaultAnswer: "y" }
1465
1657
  )).trim().toLowerCase();
1466
1658
  if (answer === "q") {
1467
- renderer.write(color6.dim(" Goodbye!\n"));
1659
+ renderer.write(color7.dim(" Goodbye!\n"));
1468
1660
  throw new LaunchAbortedError();
1469
1661
  }
1470
1662
  if (answer !== "n" && answer !== "no") {
@@ -1472,7 +1664,7 @@ async function runLaunchPrompts(opts) {
1472
1664
  const badgeStr2 = badges2.length > 0 ? ` (${badges2.join(" \xB7 ")})` : "";
1473
1665
  renderer.write(
1474
1666
  `
1475
- ${color6.green("\u25B6")} Launching in ${color6.bold(modeLabel)} mode${badgeStr2}
1667
+ ${color7.green("\u25B6")} Launching in ${color7.bold(modeLabel)} mode${badgeStr2}
1476
1668
 
1477
1669
  `
1478
1670
  );
@@ -1485,10 +1677,10 @@ async function runLaunchPrompts(opts) {
1485
1677
  } else {
1486
1678
  const answer = (await reader.readLine(
1487
1679
  `
1488
- ${color6.amber("?")} Interactive mode: ${color6.bold("T")}UI / ${color6.bold("R")}EPL ${color6.dim("[T/r/q]")} `
1680
+ ${color7.amber("?")} Interactive mode: ${color7.bold("T")}UI / ${color7.bold("R")}EPL ${color7.dim("[T/r/q]")} `
1489
1681
  )).trim().toLowerCase();
1490
1682
  if (answer === "q") {
1491
- renderer.write(color6.dim(" Goodbye!\n"));
1683
+ renderer.write(color7.dim(" Goodbye!\n"));
1492
1684
  throw new LaunchAbortedError();
1493
1685
  }
1494
1686
  mode = answer === "r" || answer === "repl" ? "repl" : "tui";
@@ -1498,10 +1690,10 @@ async function runLaunchPrompts(opts) {
1498
1690
  yolo = yoloPinned;
1499
1691
  } else {
1500
1692
  const answer = (await reader.readLine(
1501
- ` ${color6.amber("?")} YOLO mode ${color6.dim("(auto-approve tool calls)")} ${color6.dim("[Y/n/q]")} `
1693
+ ` ${color7.amber("?")} YOLO mode ${color7.dim("(auto-approve tool calls)")} ${color7.dim("[Y/n/q]")} `
1502
1694
  )).trim().toLowerCase();
1503
1695
  if (answer === "q") {
1504
- renderer.write(color6.dim(" Goodbye!\n"));
1696
+ renderer.write(color7.dim(" Goodbye!\n"));
1505
1697
  throw new LaunchAbortedError();
1506
1698
  }
1507
1699
  yolo = answer !== "n" && answer !== "no";
@@ -1511,10 +1703,10 @@ async function runLaunchPrompts(opts) {
1511
1703
  autonomy = autonomyPinned;
1512
1704
  } else {
1513
1705
  const answer = (await reader.readLine(
1514
- ` ${color6.amber("?")} Autonomy mode ${color6.dim("(auto-continue \u2014 agent picks next step)")} ${color6.dim("[Y/n/q]")} `
1706
+ ` ${color7.amber("?")} Autonomy mode ${color7.dim("(auto-continue \u2014 agent picks next step)")} ${color7.dim("[Y/n/q]")} `
1515
1707
  )).trim().toLowerCase();
1516
1708
  if (answer === "q") {
1517
- renderer.write(color6.dim(" Goodbye!\n"));
1709
+ renderer.write(color7.dim(" Goodbye!\n"));
1518
1710
  throw new LaunchAbortedError();
1519
1711
  }
1520
1712
  autonomy = answer !== "n" && answer !== "no" ? "auto" : "off";
@@ -1523,7 +1715,7 @@ async function runLaunchPrompts(opts) {
1523
1715
  const badgeStr = badges.length > 0 ? ` (${badges.join(" \xB7 ")})` : "";
1524
1716
  renderer.write(
1525
1717
  `
1526
- ${color6.green("\u25B6")} Launching in ${color6.bold(mode.toUpperCase())} mode${badgeStr}
1718
+ ${color7.green("\u25B6")} Launching in ${color7.bold(mode.toUpperCase())} mode${badgeStr}
1527
1719
 
1528
1720
  `
1529
1721
  );
@@ -1531,21 +1723,21 @@ async function runLaunchPrompts(opts) {
1531
1723
  }
1532
1724
  function buildBadges(chosen) {
1533
1725
  const badges = [];
1534
- if (chosen.yolo) badges.push(color6.yellow("YOLO"));
1726
+ if (chosen.yolo) badges.push(color7.yellow("YOLO"));
1535
1727
  if (chosen.autonomy !== "off")
1536
- badges.push(color6.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
1728
+ badges.push(color7.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
1537
1729
  return badges;
1538
1730
  }
1539
1731
  async function persistLaunchChoices(configPath, choices) {
1540
1732
  let fileExists = false;
1541
1733
  try {
1542
- await fs3.access(configPath);
1734
+ await fs5.access(configPath);
1543
1735
  fileExists = true;
1544
1736
  } catch {
1545
1737
  }
1546
1738
  let existing = {};
1547
1739
  try {
1548
- const raw = await fs3.readFile(configPath, "utf8");
1740
+ const raw = await fs5.readFile(configPath, "utf8");
1549
1741
  existing = JSON.parse(raw);
1550
1742
  } catch (err) {
1551
1743
  if (fileExists) {
@@ -1565,9 +1757,9 @@ async function persistLaunchChoices(configPath, choices) {
1565
1757
  }
1566
1758
 
1567
1759
  // src/pre-launch/project-check.ts
1568
- import * as fs4 from "node:fs/promises";
1569
- import * as path5 from "node:path";
1570
- import { color as color7, toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
1760
+ import * as fs6 from "node:fs/promises";
1761
+ import * as path7 from "node:path";
1762
+ import { color as color8, toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
1571
1763
  var MANIFESTS = [
1572
1764
  "package.json",
1573
1765
  "pyproject.toml",
@@ -1582,13 +1774,13 @@ var MANIFESTS = [
1582
1774
  ];
1583
1775
  async function detectProjectKind(projectRoot) {
1584
1776
  try {
1585
- await fs4.access(path5.join(projectRoot, ".wrongstack", "AGENTS.md"));
1777
+ await fs6.access(path7.join(projectRoot, ".wrongstack", "AGENTS.md"));
1586
1778
  return "initialized";
1587
1779
  } catch {
1588
1780
  }
1589
1781
  for (const m of MANIFESTS) {
1590
1782
  try {
1591
- await fs4.access(path5.join(projectRoot, m));
1783
+ await fs6.access(path7.join(projectRoot, m));
1592
1784
  return "project";
1593
1785
  } catch {
1594
1786
  }
@@ -1596,12 +1788,12 @@ async function detectProjectKind(projectRoot) {
1596
1788
  return "empty";
1597
1789
  }
1598
1790
  async function scaffoldAgentsMd(projectRoot) {
1599
- const dir = path5.join(projectRoot, ".wrongstack");
1600
- const file = path5.join(dir, "AGENTS.md");
1791
+ const dir = path7.join(projectRoot, ".wrongstack");
1792
+ const file = path7.join(dir, "AGENTS.md");
1601
1793
  const facts = await detectProjectFacts(projectRoot);
1602
1794
  const body = renderAgentsTemplate(facts);
1603
- await fs4.mkdir(dir, { recursive: true });
1604
- await fs4.writeFile(file, body, "utf8");
1795
+ await fs6.mkdir(dir, { recursive: true });
1796
+ await fs6.writeFile(file, body, "utf8");
1605
1797
  return file;
1606
1798
  }
1607
1799
  async function runProjectCheck(opts) {
@@ -1610,7 +1802,7 @@ async function runProjectCheck(opts) {
1610
1802
  if (kind === "initialized") {
1611
1803
  renderer.write(
1612
1804
  `
1613
- ${color7.green("\u2713")} Project initialized ${color7.dim(`(${path5.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
1805
+ ${color8.green("\u2713")} Project initialized ${color8.dim(`(${path7.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
1614
1806
  `
1615
1807
  );
1616
1808
  return true;
@@ -1618,51 +1810,51 @@ async function runProjectCheck(opts) {
1618
1810
  if (kind === "project") {
1619
1811
  renderer.write(
1620
1812
  `
1621
- ${color7.amber("\u25CF")} Project detected ${color7.dim(`(${projectRoot})`)} but ${color7.bold(".wrongstack/AGENTS.md")} is missing.
1813
+ ${color8.amber("\u25CF")} Project detected ${color8.dim(`(${projectRoot})`)} but ${color8.bold(".wrongstack/AGENTS.md")} is missing.
1622
1814
  `
1623
1815
  );
1624
1816
  const answer2 = (await reader.readLine(
1625
- ` ${color7.amber("?")} Scaffold ${color7.bold("AGENTS.md")} now? ${color7.dim("[y/N/q]")} `
1817
+ ` ${color8.amber("?")} Scaffold ${color8.bold("AGENTS.md")} now? ${color8.dim("[y/N/q]")} `
1626
1818
  )).trim().toLowerCase();
1627
1819
  if (answer2 === "q") {
1628
- renderer.write(color7.dim(" Cancelled.\n"));
1820
+ renderer.write(color8.dim(" Cancelled.\n"));
1629
1821
  return false;
1630
1822
  }
1631
1823
  if (answer2 === "y" || answer2 === "yes") {
1632
1824
  try {
1633
1825
  const file = await scaffoldAgentsMd(projectRoot);
1634
- renderer.write(` ${color7.green("\u2713")} Wrote ${color7.dim(file)}
1826
+ renderer.write(` ${color8.green("\u2713")} Wrote ${color8.dim(file)}
1635
1827
  `);
1636
1828
  } catch (err) {
1637
- renderer.writeError(`Failed to scaffold AGENTS.md: ${toErrorMessage3(err)}`);
1829
+ renderer.writeError(`Failed to scaffold AGENTS.md: ${toErrorMessage4(err)}`);
1638
1830
  }
1639
1831
  }
1640
1832
  return true;
1641
1833
  }
1642
- const gitDir = path5.join(projectRoot, ".git");
1834
+ const gitDir = path7.join(projectRoot, ".git");
1643
1835
  let hasGit = false;
1644
1836
  try {
1645
- await fs4.access(gitDir);
1837
+ await fs6.access(gitDir);
1646
1838
  hasGit = true;
1647
1839
  } catch {
1648
1840
  }
1649
1841
  if (!hasGit) {
1650
1842
  renderer.write(
1651
1843
  `
1652
- ${color7.dim("\u25CB")} ${color7.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1844
+ ${color8.dim("\u25CB")} ${color8.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1653
1845
  `
1654
1846
  );
1655
1847
  const answer2 = (await reader.readLine(
1656
- ` ${color7.amber("?")} No git repo found. ${color7.bold("Initialize git?")} ${color7.dim("[y/N/q]")} `
1848
+ ` ${color8.amber("?")} No git repo found. ${color8.bold("Initialize git?")} ${color8.dim("[y/N/q]")} `
1657
1849
  )).trim().toLowerCase();
1658
1850
  if (answer2 === "q") {
1659
- renderer.write(color7.dim(" Cancelled.\n"));
1851
+ renderer.write(color8.dim(" Cancelled.\n"));
1660
1852
  return false;
1661
1853
  }
1662
1854
  if (answer2 === "y" || answer2 === "yes") {
1663
1855
  try {
1664
1856
  const { spawn: spawn2 } = await import("node:child_process");
1665
- await new Promise((resolve2, reject) => {
1857
+ await new Promise((resolve3, reject) => {
1666
1858
  const child = spawn2("git", ["init"], {
1667
1859
  cwd,
1668
1860
  signal: AbortSignal.timeout(1e4),
@@ -1671,26 +1863,26 @@ async function runProjectCheck(opts) {
1671
1863
  child.on("error", reject);
1672
1864
  child.on(
1673
1865
  "close",
1674
- (code) => code === 0 ? resolve2() : reject(new Error(`git init failed with ${code}`))
1866
+ (code) => code === 0 ? resolve3() : reject(new Error(`git init failed with ${code}`))
1675
1867
  );
1676
1868
  });
1677
- renderer.write(` ${color7.green("\u2713")} Git repository initialized
1869
+ renderer.write(` ${color8.green("\u2713")} Git repository initialized
1678
1870
  `);
1679
1871
  } catch (err) {
1680
- renderer.writeError(`git init failed: ${toErrorMessage3(err)}
1872
+ renderer.writeError(`git init failed: ${toErrorMessage4(err)}
1681
1873
  `);
1682
1874
  }
1683
1875
  }
1684
1876
  } else {
1685
1877
  renderer.write(
1686
1878
  `
1687
- ${color7.dim("\u25CB")} ${color7.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1879
+ ${color8.dim("\u25CB")} ${color8.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1688
1880
  `
1689
1881
  );
1690
1882
  }
1691
- const answer = (await reader.readLine(` ${color7.amber("?")} Continue anyway? ${color7.dim("[Y/n/q]")} `)).trim().toLowerCase();
1883
+ const answer = (await reader.readLine(` ${color8.amber("?")} Continue anyway? ${color8.dim("[Y/n/q]")} `)).trim().toLowerCase();
1692
1884
  if (answer === "q" || answer === "n" || answer === "no") {
1693
- renderer.write(color7.dim(" Cancelled.\n"));
1885
+ renderer.write(color8.dim(" Cancelled.\n"));
1694
1886
  return false;
1695
1887
  }
1696
1888
  return true;
@@ -1725,28 +1917,28 @@ async function runSystemPromptMenu(deps) {
1725
1917
  const defaultVariant = lastVariant ?? "default";
1726
1918
  if (lastVariant) {
1727
1919
  const answer2 = (await reader.readLine(
1728
- ` ${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)")} `,
1920
+ ` ${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)")} `,
1729
1921
  { timeoutMs: SUMMARY_TIMEOUT_MS2, defaultAnswer: "y" }
1730
1922
  )).trim().toLowerCase();
1731
1923
  if (answer2 === "q" || answer2 === "quit") throw new LaunchAbortedError();
1732
1924
  if (answer2 !== "n" && answer2 !== "no") return lastVariant;
1733
1925
  }
1734
1926
  renderer.write(`
1735
- ${color8.amber("?")} System prompt:
1927
+ ${color9.amber("?")} System prompt:
1736
1928
  `);
1737
1929
  for (const [index, opt] of SYSTEM_PROMPT_OPTIONS.entries()) {
1738
1930
  const num2 = index + 1;
1739
1931
  const isDefault = opt.variant === defaultVariant;
1740
- const marker = isDefault ? color8.cyan("\u25CF") : color8.dim("\u25CB");
1741
- const label = isDefault ? color8.bold(opt.label) : opt.label;
1932
+ const marker = isDefault ? color9.cyan("\u25CF") : color9.dim("\u25CB");
1933
+ const label = isDefault ? color9.bold(opt.label) : opt.label;
1742
1934
  renderer.write(
1743
- ` ${color8.dim(`${num2}.`)} ${marker} ${label.padEnd(9)} ${color8.dim(`~${fmtTok(tokens[opt.variant])} tokens`)} ${color8.dim(opt.hint)}
1935
+ ` ${color9.dim(`${num2}.`)} ${marker} ${label.padEnd(9)} ${color9.dim(`~${fmtTok(tokens[opt.variant])} tokens`)} ${color9.dim(opt.hint)}
1744
1936
  `
1745
1937
  );
1746
1938
  }
1747
1939
  const answer = (await reader.readLine(
1748
1940
  `
1749
- ${color8.amber("?")} Select system prompt ${color8.dim(`[1-${SYSTEM_PROMPT_OPTIONS.length}, Enter = ${labelFor(defaultVariant)}, q to quit]`)}: `
1941
+ ${color9.amber("?")} Select system prompt ${color9.dim(`[1-${SYSTEM_PROMPT_OPTIONS.length}, Enter = ${labelFor(defaultVariant)}, q to quit]`)}: `
1750
1942
  )).trim().toLowerCase();
1751
1943
  if (answer === "q" || answer === "quit") throw new LaunchAbortedError();
1752
1944
  if (!answer) return defaultVariant;
@@ -1803,8 +1995,8 @@ async function bootConfig(flags) {
1803
1995
  }
1804
1996
 
1805
1997
  // src/input-reader.ts
1806
- import * as fs5 from "node:fs/promises";
1807
- import * as path6 from "node:path";
1998
+ import * as fs7 from "node:fs/promises";
1999
+ import * as path8 from "node:path";
1808
2000
  import * as readline from "node:readline";
1809
2001
  import {
1810
2002
  resolveWstackPaths,
@@ -1823,7 +2015,7 @@ var ReadlineInputReader = class {
1823
2015
  }
1824
2016
  async loadHistory() {
1825
2017
  try {
1826
- const raw = await fs5.readFile(this.historyFile, "utf8");
2018
+ const raw = await fs7.readFile(this.historyFile, "utf8");
1827
2019
  this.history = raw.split("\n").filter(Boolean).slice(-1e3);
1828
2020
  } catch {
1829
2021
  this.history = [];
@@ -1831,8 +2023,8 @@ var ReadlineInputReader = class {
1831
2023
  }
1832
2024
  async saveHistory() {
1833
2025
  try {
1834
- await fs5.mkdir(path6.dirname(this.historyFile), { recursive: true });
1835
- await fs5.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
2026
+ await fs7.mkdir(path8.dirname(this.historyFile), { recursive: true });
2027
+ await fs7.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
1836
2028
  } catch {
1837
2029
  }
1838
2030
  }
@@ -1853,25 +2045,25 @@ var ReadlineInputReader = class {
1853
2045
  async readLine(prompt, timeoutOpts) {
1854
2046
  if (this.history.length === 0) await this.loadHistory();
1855
2047
  while (this.pending) {
1856
- await new Promise((resolve2) => setTimeout(resolve2, 50));
2048
+ await new Promise((resolve3) => setTimeout(resolve3, 50));
1857
2049
  }
1858
2050
  this.pending = true;
1859
2051
  try {
1860
2052
  if (this.rl) {
1861
2053
  const old = this.rl;
1862
2054
  this.rl = void 0;
1863
- await new Promise((resolve2) => {
2055
+ await new Promise((resolve3) => {
1864
2056
  if (old.closed) {
1865
- resolve2();
2057
+ resolve3();
1866
2058
  } else {
1867
- old.once("close", resolve2);
2059
+ old.once("close", resolve3);
1868
2060
  old.close();
1869
2061
  }
1870
2062
  });
1871
2063
  }
1872
2064
  const fresh = this.ensure();
1873
2065
  this.installPromptGuard(fresh);
1874
- const line = await new Promise((resolve2) => {
2066
+ const line = await new Promise((resolve3) => {
1875
2067
  let settled = false;
1876
2068
  let timeoutHandle;
1877
2069
  const settle = (line2) => {
@@ -1879,7 +2071,7 @@ var ReadlineInputReader = class {
1879
2071
  settled = true;
1880
2072
  if (timeoutHandle) clearTimeout(timeoutHandle);
1881
2073
  setOutputLineGuard(null);
1882
- resolve2(line2);
2074
+ resolve3(line2);
1883
2075
  };
1884
2076
  if (timeoutOpts) {
1885
2077
  timeoutHandle = setTimeout(() => {
@@ -1946,7 +2138,7 @@ var ReadlineInputReader = class {
1946
2138
  const signal = opts.signal;
1947
2139
  if (signal?.aborted) return "";
1948
2140
  writeOut(prompt);
1949
- return new Promise((resolve2) => {
2141
+ return new Promise((resolve3) => {
1950
2142
  const stdin = process.stdin;
1951
2143
  const wasRaw = stdin.isRaw;
1952
2144
  const wasPaused = stdin.isPaused();
@@ -1957,7 +2149,7 @@ var ReadlineInputReader = class {
1957
2149
  if (key === "") {
1958
2150
  cleanup();
1959
2151
  writeOut("\n");
1960
- resolve2("");
2152
+ resolve3("");
1961
2153
  return;
1962
2154
  }
1963
2155
  const opt = options.find(
@@ -1967,17 +2159,17 @@ var ReadlineInputReader = class {
1967
2159
  cleanup();
1968
2160
  writeOut(`${opt.key}
1969
2161
  `);
1970
- resolve2(opt.value);
2162
+ resolve3(opt.value);
1971
2163
  }
1972
2164
  };
1973
2165
  const onClose = () => {
1974
2166
  cleanup();
1975
- resolve2("");
2167
+ resolve3("");
1976
2168
  };
1977
2169
  const onAbort = () => {
1978
2170
  cleanup();
1979
2171
  writeOut("\n");
1980
- resolve2("");
2172
+ resolve3("");
1981
2173
  };
1982
2174
  const cleanup = () => {
1983
2175
  stdin.off("data", onData);
@@ -2011,7 +2203,7 @@ var ReadlineInputReader = class {
2011
2203
  this.rl?.close();
2012
2204
  this.rl = void 0;
2013
2205
  writeOut(prompt);
2014
- return new Promise((resolve2) => {
2206
+ return new Promise((resolve3) => {
2015
2207
  let buf = "";
2016
2208
  const wasRaw = stdin.isRaw;
2017
2209
  const cleanup = () => {
@@ -2034,19 +2226,36 @@ var ReadlineInputReader = class {
2034
2226
  const eraseAll = () => {
2035
2227
  for (let i = 0; i < buf.length; i++) eraseChar();
2036
2228
  };
2229
+ let escState = 0;
2037
2230
  const onData = (chunk) => {
2038
2231
  for (const ch of chunk) {
2232
+ if (escState === 1) {
2233
+ escState = ch === "[" ? 2 : ch === "O" ? 3 : 0;
2234
+ continue;
2235
+ }
2236
+ if (escState === 2) {
2237
+ if (ch >= "@" && ch <= "~") escState = 0;
2238
+ continue;
2239
+ }
2240
+ if (escState === 3) {
2241
+ escState = 0;
2242
+ continue;
2243
+ }
2244
+ if (ch === "\x1B") {
2245
+ escState = 1;
2246
+ continue;
2247
+ }
2039
2248
  if (ch === "\r" || ch === "\n") {
2040
2249
  cleanup();
2041
2250
  writeOut(` ${dim(`[${buf.length} chars]`)}
2042
2251
  `);
2043
- resolve2(buf);
2252
+ resolve3(buf);
2044
2253
  return;
2045
2254
  }
2046
2255
  if (ch === "") {
2047
2256
  cleanup();
2048
2257
  writeOut("\n");
2049
- resolve2("");
2258
+ resolve3("");
2050
2259
  return;
2051
2260
  }
2052
2261
  if (ch === "") {
@@ -2072,6 +2281,7 @@ var ReadlineInputReader = class {
2072
2281
  buf += ch;
2073
2282
  writeOut("\u2022");
2074
2283
  }
2284
+ if (escState === 1) escState = 0;
2075
2285
  };
2076
2286
  stdin.on("data", onData);
2077
2287
  });
@@ -2089,7 +2299,7 @@ function dim(s) {
2089
2299
  }
2090
2300
 
2091
2301
  // src/renderer.ts
2092
- import { color as color9 } from "@wrongstack/core/utils";
2302
+ import { color as color10 } from "@wrongstack/core/utils";
2093
2303
  var TerminalRenderer = class _TerminalRenderer {
2094
2304
  out;
2095
2305
  err;
@@ -2202,7 +2412,7 @@ var TerminalRenderer = class _TerminalRenderer {
2202
2412
  if (!this.lineStart) this.out.write("\n");
2203
2413
  const arrow = theme2.primary("\u2192");
2204
2414
  const display = formatInputSummary(input);
2205
- this.out.write(`${arrow} ${theme2.bold(name)}${display ? color9.dim(` ${display}`) : ""}
2415
+ this.out.write(`${arrow} ${theme2.bold(name)}${display ? color10.dim(` ${display}`) : ""}
2206
2416
  `);
2207
2417
  this.lineStart = true;
2208
2418
  }
@@ -2219,7 +2429,7 @@ var TerminalRenderer = class _TerminalRenderer {
2219
2429
  if (isError) {
2220
2430
  const firstLine = txt.split("\n")[0] ?? "";
2221
2431
  const truncated = firstLine.length > 200 ? `${firstLine.slice(0, 197)}\u2026` : firstLine;
2222
- this.out.write(` ${prefix} ${color9.dim(truncated)}
2432
+ this.out.write(` ${prefix} ${color10.dim(truncated)}
2223
2433
  `);
2224
2434
  this.lineStart = true;
2225
2435
  return;
@@ -2227,7 +2437,7 @@ var TerminalRenderer = class _TerminalRenderer {
2227
2437
  const isEditLike = name === "edit" || name === "write";
2228
2438
  const diff = extractDiff(content);
2229
2439
  if (isEditLike && diff) {
2230
- this.out.write(` ${prefix} ${color9.dim(summarize(content, name))}
2440
+ this.out.write(` ${prefix} ${color10.dim(summarize(content, name))}
2231
2441
  `);
2232
2442
  const rendered = renderDiff(diff).split("\n").map((l) => ` ${l}`).join("\n");
2233
2443
  this.out.write(`${rendered}
@@ -2238,7 +2448,7 @@ var TerminalRenderer = class _TerminalRenderer {
2238
2448
  const summary = summarize(content, name);
2239
2449
  const isReadLike = name === "read" || name === "grep" || name === "glob" || name === "bash" || name === "exec";
2240
2450
  if (renderMode === "simple") {
2241
- this.out.write(` ${prefix} ${color9.dim(summary || compactSingleLine(bodyText))}
2451
+ this.out.write(` ${prefix} ${color10.dim(summary || compactSingleLine(bodyText))}
2242
2452
  `);
2243
2453
  this.lineStart = true;
2244
2454
  return;
@@ -2247,16 +2457,16 @@ var TerminalRenderer = class _TerminalRenderer {
2247
2457
  const lines = bodyText.split("\n");
2248
2458
  const head = lines.slice(0, previewLines).map((l) => l.replace(/\s+$/, ""));
2249
2459
  const moreCount = Math.max(0, lines.length - head.length);
2250
- this.out.write(` ${prefix} ${color9.dim(summary)}
2460
+ this.out.write(` ${prefix} ${color10.dim(summary)}
2251
2461
  `);
2252
2462
  for (const l of head) {
2253
2463
  const capped = l.length > 200 ? `${l.slice(0, 197)}\u2026` : l;
2254
- this.out.write(` ${color9.dim(capped)}
2464
+ this.out.write(` ${color10.dim(capped)}
2255
2465
  `);
2256
2466
  }
2257
2467
  if (moreCount > 0) {
2258
2468
  this.out.write(
2259
- ` ${color9.dim(`+${moreCount} more line${moreCount === 1 ? "" : "s"}`)}
2469
+ ` ${color10.dim(`+${moreCount} more line${moreCount === 1 ? "" : "s"}`)}
2260
2470
  `
2261
2471
  );
2262
2472
  }
@@ -2395,7 +2605,7 @@ function renderMarkdown(s) {
2395
2605
  return theme2.primary(theme2.bold(`${hashes} ${text}`));
2396
2606
  });
2397
2607
  out = out.replace(/```([a-zA-Z0-9_+-]*)\n([\s\S]*?)```/g, (_m, _lang, code) => {
2398
- return color9.gray(`
2608
+ return color10.gray(`
2399
2609
  \u250C\u2500
2400
2610
  ${code.replace(/^/gm, "\u2502 ")}\u2514\u2500`);
2401
2611
  });
@@ -2403,7 +2613,7 @@ ${code.replace(/^/gm, "\u2502 ")}\u2514\u2500`);
2403
2613
  out = out.replace(/\*\*([^*]+)\*\*/g, (_m, text) => theme2.bold(text));
2404
2614
  out = out.replace(
2405
2615
  /(^|[^*])\*([^*\n]+)\*([^*]|$)/g,
2406
- (_m, l, t, r) => `${l}${color9.italic(t)}${r}`
2616
+ (_m, l, t, r) => `${l}${color10.italic(t)}${r}`
2407
2617
  );
2408
2618
  return out;
2409
2619
  }
@@ -2496,14 +2706,14 @@ function summarize(value, name) {
2496
2706
  if (typeof v === "object" && v !== null) {
2497
2707
  const o = v;
2498
2708
  if (name === "edit") {
2499
- const path8 = typeof o["path"] === "string" ? o["path"] : "";
2709
+ const path10 = typeof o["path"] === "string" ? o["path"] : "";
2500
2710
  const reps = typeof o["replacements"] === "number" ? o["replacements"] : 0;
2501
- return `${path8} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
2711
+ return `${path10} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
2502
2712
  }
2503
2713
  if (name === "write") {
2504
- const path8 = typeof o["path"] === "string" ? o["path"] : "";
2714
+ const path10 = typeof o["path"] === "string" ? o["path"] : "";
2505
2715
  const bytes = typeof o["bytes"] === "number" ? o["bytes"] : void 0;
2506
- return bytes !== void 0 ? `${path8} ${bytes}B` : path8;
2716
+ return bytes !== void 0 ? `${path10} ${bytes}B` : path10;
2507
2717
  }
2508
2718
  if (name === "read") {
2509
2719
  return summarizeRead(o);
@@ -2521,13 +2731,13 @@ function summarize(value, name) {
2521
2731
  return "";
2522
2732
  }
2523
2733
  function summarizeRead(o) {
2524
- const path8 = typeof o["path"] === "string" ? o["path"] : "";
2734
+ const path10 = typeof o["path"] === "string" ? o["path"] : "";
2525
2735
  const total = typeof o["total_lines"] === "number" ? o["total_lines"] : void 0;
2526
2736
  const truncated = o["truncated"] === true;
2527
2737
  const cached = o["cached"] === true;
2528
2738
  const note = typeof o["note"] === "string" ? o["note"] : void 0;
2529
2739
  const parts = [];
2530
- if (path8) parts.push(path8);
2740
+ if (path10) parts.push(path10);
2531
2741
  if (total !== void 0) parts.push(`${total} line${total === 1 ? "" : "s"}`);
2532
2742
  const flags = [];
2533
2743
  if (truncated) flags.push("truncated");
@@ -2575,86 +2785,6 @@ function compactSingleLine(text) {
2575
2785
 
2576
2786
  // src/boot.ts
2577
2787
  var GITHUB_PROVIDERS_OVERLAY_URL = "https://raw.githubusercontent.com/WrongStack/WrongStack/main/packages/cli/data/providers.json";
2578
- function resolveBundledOverlayFile() {
2579
- try {
2580
- return fileURLToPath(
2581
- new URL("../data/providers.json", moduleUrlFor(import.meta.url, "@wrongstack/cli"))
2582
- );
2583
- } catch {
2584
- return void 0;
2585
- }
2586
- }
2587
- async function validateSavedProviderModel(config, modelsRegistry) {
2588
- const providerId = config.provider;
2589
- const modelId = config.model;
2590
- if (!providerId || !modelId) return { ok: false, reason: "missing provider/model" };
2591
- if (isSetupProvider(providerId)) return { ok: true };
2592
- const saved = config.providers?.[providerId];
2593
- const lookupId = saved?.type && saved.type !== providerId ? saved.type : providerId;
2594
- const catalogProvider = await modelsRegistry.getProvider(lookupId).catch(() => void 0);
2595
- if (!catalogProvider && !saved?.family)
2596
- return { ok: false, reason: `provider "${providerId}" is no longer available` };
2597
- const hasCredential = (catalogProvider?.envVars ?? saved?.envVars ?? []).some(
2598
- (envVar) => Boolean(process.env[envVar])
2599
- ) || saved !== void 0 && resolveActiveApiKey(saved) !== void 0 || isKeylessLocalProvider({
2600
- apiBase: saved?.baseUrl ?? catalogProvider?.apiBase,
2601
- envVars: saved?.envVars ?? catalogProvider?.envVars
2602
- });
2603
- if (!hasCredential) return { ok: false, reason: `provider "${providerId}" has no usable key` };
2604
- const visible = visibleModelIds(
2605
- providerId,
2606
- config,
2607
- (catalogProvider?.models ?? []).map((m) => m.id),
2608
- saved
2609
- );
2610
- if (visible.length > 0 && !visible.includes(modelId)) {
2611
- return {
2612
- ok: false,
2613
- reason: `model "${modelId}" is no longer available for provider "${providerId}"`
2614
- };
2615
- }
2616
- return { ok: true };
2617
- }
2618
- async function autoSelectSavedProvider(config, modelsRegistry) {
2619
- const providers = config.providers ?? {};
2620
- const entries = config.provider && providers[config.provider] ? [[config.provider, providers[config.provider]]] : Object.entries(providers);
2621
- for (const [id, cfg] of entries) {
2622
- if (!cfg) continue;
2623
- let model = cfg.models?.[0];
2624
- if (!model) {
2625
- const catalogId = cfg.type && cfg.type !== id ? cfg.type : id;
2626
- const catalog = await modelsRegistry.getProvider(catalogId).catch(() => void 0);
2627
- model = catalog?.models?.[0]?.id;
2628
- }
2629
- if (model) return { provider: id, model };
2630
- }
2631
- return void 0;
2632
- }
2633
- function resolveBundledSkillsDir2() {
2634
- try {
2635
- const req = createRequire4(import.meta.url);
2636
- const corePkg = wrongstackPackageJsonPath3("@wrongstack/core", (id) => req.resolve(id));
2637
- return path7.join(path7.dirname(corePkg), "skills");
2638
- } catch {
2639
- return void 0;
2640
- }
2641
- }
2642
- function resolveBundledPromptsDir2() {
2643
- try {
2644
- const req = createRequire4(import.meta.url);
2645
- const corePkg = wrongstackPackageJsonPath3("@wrongstack/core", (id) => req.resolve(id));
2646
- return path7.join(path7.dirname(corePkg), "data", "prompts");
2647
- } catch {
2648
- return void 0;
2649
- }
2650
- }
2651
- function isHomeDirectory(cwd, userHome) {
2652
- if (!cwd || !userHome) return false;
2653
- return path7.resolve(cwd) === path7.resolve(userHome);
2654
- }
2655
- function shouldPrintYoloNotice(lastChoices, yoloPinned, yolo) {
2656
- return !lastChoices && yoloPinned === void 0 && yolo;
2657
- }
2658
2788
  async function boot(argv) {
2659
2789
  const { flags, positional } = parseArgs(argv);
2660
2790
  if (positional[0] === "update") {
@@ -2666,6 +2796,14 @@ async function boot(argv) {
2666
2796
  flags
2667
2797
  });
2668
2798
  }
2799
+ if (positional[0] === "remote" || typeof flags["remote"] === "string") {
2800
+ const { runRemoteCommand } = await import("./remote-GB5VXCCT.js");
2801
+ return runRemoteCommand(
2802
+ positional[0] === "remote" ? positional.slice(1) : positional,
2803
+ flags,
2804
+ new TerminalRenderer()
2805
+ );
2806
+ }
2669
2807
  if (positional[0] === "resume" && positional[1] && !subcommands["__noop_resume_marker"]) {
2670
2808
  flags["resume"] = positional[1];
2671
2809
  positional.splice(0, 2);
@@ -2674,14 +2812,34 @@ async function boot(argv) {
2674
2812
  try {
2675
2813
  bootResult = await bootConfig(flags);
2676
2814
  } catch (err) {
2677
- writeErr(`Config error: ${toErrorMessage4(err)}
2815
+ writeErr(`Config error: ${toErrorMessage5(err)}
2678
2816
  `);
2679
2817
  return 2;
2680
2818
  }
2681
2819
  let { paths, config, vault } = bootResult;
2820
+ try {
2821
+ resolveToolRestriction(flags);
2822
+ resolveLaunchAllowedTools(flags);
2823
+ parseOutputFormat(flags["output-format"]);
2824
+ announceSafeMode(flags, writeErr);
2825
+ activateRestrictedMode(flags, writeErr);
2826
+ const launchMcp = await resolveLaunchMcpServers(flags, paths.cwd);
2827
+ if (launchMcp) flags["mcp-config"] = JSON.stringify({ mcpServers: launchMcp });
2828
+ const schema = await resolveJsonSchemaFlag(flags["json-schema"], paths.cwd);
2829
+ if (schema) flags["json-schema"] = JSON.stringify(schema);
2830
+ const appended = await resolveAppendedSystemPrompt(flags, paths.cwd);
2831
+ delete flags["append-system-prompt-file"];
2832
+ if (appended) flags["append-system-prompt"] = appended;
2833
+ else delete flags["append-system-prompt"];
2834
+ } catch (err) {
2835
+ writeErr(`wstack: ${toErrorMessage5(err)}
2836
+ `);
2837
+ return 2;
2838
+ }
2682
2839
  let first = positional[0];
2683
2840
  const mayOfferConfigRecovery = isStdinTTY2() && (positional.length === 0 || first === "quick") && typeof flags["prompt"] !== "string" && !flags["webui"] && !flags["no-interactive"] && !flags["skip"];
2684
- const renderer = new TerminalRenderer();
2841
+ const machineOutput = flags["output-json"] === true || flags["output-format"] === "json" || flags["output-format"] === "stream-json";
2842
+ const renderer = new TerminalRenderer(machineOutput ? { out: process.stderr } : void 0);
2685
2843
  const reader = new ReadlineInputReader({ historyFile: paths.wpaths.historyFile });
2686
2844
  if (mayOfferConfigRecovery) {
2687
2845
  const recoveryProfile = config.activeProfile ?? "default";
@@ -2697,7 +2855,7 @@ async function boot(argv) {
2697
2855
  bootResult = await bootConfig(flags);
2698
2856
  ({ paths, config, vault } = bootResult);
2699
2857
  } catch (err) {
2700
- writeErr(`Config error after backup restore: ${toErrorMessage4(err)}
2858
+ writeErr(`Config error after backup restore: ${toErrorMessage5(err)}
2701
2859
  `);
2702
2860
  await reader.close();
2703
2861
  return 2;
@@ -2798,8 +2956,8 @@ async function boot(argv) {
2798
2956
  if (isHomeDirectory(cwd, userHome)) {
2799
2957
  writeErr(
2800
2958
  `
2801
- ${color10.red(color10.bold("\u26A0 This is not a working directory."))}
2802
- ${color10.red("Please open wstack in a project folder.")}
2959
+ ${color11.red(color11.bold("\u26A0 This is not a working directory."))}
2960
+ ${color11.red("Please open wstack in a project folder.")}
2803
2961
 
2804
2962
  `
2805
2963
  );
@@ -2807,23 +2965,21 @@ async function boot(argv) {
2807
2965
  return 1;
2808
2966
  }
2809
2967
  if (!flags["no-models-refresh"]) {
2810
- try {
2811
- await modelsRegistry.refresh();
2812
- logger.info("models.dev catalog refreshed");
2813
- } catch (err) {
2814
- const msg = toErrorMessage4(err);
2815
- logger.warn(`models.dev refresh failed (${msg}); using cached catalog`);
2816
- }
2968
+ await startCatalog({
2969
+ registry: modelsRegistry,
2970
+ logger,
2971
+ shortLived: positional.length > 0 || typeof flags["prompt"] === "string"
2972
+ });
2817
2973
  }
2818
2974
  try {
2819
2975
  await discoverAndMergeProviders({
2820
2976
  config,
2821
2977
  registry: modelsRegistry,
2822
- cacheDir: path7.dirname(wpaths.modelsCache),
2978
+ cacheDir: path9.dirname(wpaths.modelsCache),
2823
2979
  logger
2824
2980
  });
2825
2981
  } catch (err) {
2826
- logger.debug(`provider auto-discovery skipped: ${toErrorMessage4(err)}`);
2982
+ logger.debug(`provider auto-discovery skipped: ${toErrorMessage5(err)}`);
2827
2983
  }
2828
2984
  const isSingleShot = positional.length > 0 || typeof flags["prompt"] === "string";
2829
2985
  const isInteractiveTTY = isStdinTTY2() && !isSingleShot && !flags["webui"] && !flags["no-interactive"] && !flags["skip"];
@@ -2858,11 +3014,11 @@ async function boot(argv) {
2858
3014
  if (isStdinTTY2() && !noInteractiveMode) {
2859
3015
  let picked;
2860
3016
  let skipPicker = false;
2861
- if (isSetupProvider(config.provider)) {
3017
+ if (isSetupProvider2(config.provider)) {
2862
3018
  skipPicker = true;
2863
3019
  renderer.write(
2864
3020
  `
2865
- ${color10.amber("\u25B6")} ${color10.bold("Setup mode")} ${color10.dim("\u2014 no model connected. Run")} ${color10.bold("/auth")} ${color10.dim("to connect one.")}
3021
+ ${color11.amber("\u25B6")} ${color11.bold("Setup mode")} ${color11.dim("\u2014 no model connected. Run")} ${color11.bold("/auth")} ${color11.dim("to connect one.")}
2866
3022
 
2867
3023
  `
2868
3024
  );
@@ -2889,7 +3045,7 @@ async function boot(argv) {
2889
3045
  config = reloaded.config;
2890
3046
  vault = reloaded.vault;
2891
3047
  } catch (err) {
2892
- writeErr(`Config error after setup: ${toErrorMessage4(err)}
3048
+ writeErr(`Config error after setup: ${toErrorMessage5(err)}
2893
3049
  `);
2894
3050
  await reader.close();
2895
3051
  return 2;
@@ -2902,7 +3058,7 @@ async function boot(argv) {
2902
3058
  const savedStatus = await validateSavedProviderModel(config, modelsRegistry);
2903
3059
  renderer.write(
2904
3060
  `
2905
- ${color10.dim("Last settings:")} ${color10.bold(savedProvider)} / ${color10.bold(savedModel)}
3061
+ ${color11.dim("Last settings:")} ${color11.bold(savedProvider)} / ${color11.bold(savedModel)}
2906
3062
  `
2907
3063
  );
2908
3064
  if (!savedStatus.ok) {
@@ -2912,11 +3068,11 @@ async function boot(argv) {
2912
3068
  );
2913
3069
  } else {
2914
3070
  const answer = (await reader.readLine(
2915
- ` ${color10.amber("?")} Continue with these? ${color10.dim("[Y/n/q]")} ${color10.dim("(auto Y in 5s)")} `,
3071
+ ` ${color11.amber("?")} Continue with these? ${color11.dim("[Y/n/q]")} ${color11.dim("(auto Y in 5s)")} `,
2916
3072
  { timeoutMs: 5e3, defaultAnswer: "y" }
2917
3073
  )).trim().toLowerCase();
2918
3074
  if (answer === "q") {
2919
- renderer.write(color10.dim(" Goodbye!\n"));
3075
+ renderer.write(color11.dim(" Goodbye!\n"));
2920
3076
  await reader.close();
2921
3077
  return 0;
2922
3078
  }
@@ -2924,7 +3080,7 @@ async function boot(argv) {
2924
3080
  skipPicker = true;
2925
3081
  renderer.write(
2926
3082
  `
2927
- ${color10.green("\u25B6")} ${color10.bold(savedProvider)} / ${color10.bold(savedModel)}
3083
+ ${color11.green("\u25B6")} ${color11.bold(savedProvider)} / ${color11.bold(savedModel)}
2928
3084
 
2929
3085
  `
2930
3086
  );
@@ -2945,9 +3101,9 @@ async function boot(argv) {
2945
3101
  if (!config.provider || !config.model) {
2946
3102
  renderer.write(
2947
3103
  `
2948
- ${color10.dim("No provider selected.")}
2949
- ${color10.dim("Run")} ${color10.bold("wstack auth")} ${color10.dim("to add a key or sign in, or start with no model:")}
2950
- ${color10.bold(`wstack --provider ${SETUP_PROVIDER_ID} --model ${SETUP_MODEL_ID}`)}
3104
+ ${color11.dim("No provider selected.")}
3105
+ ${color11.dim("Run")} ${color11.bold("wstack auth")} ${color11.dim("to add a key or sign in, or start with no model:")}
3106
+ ${color11.bold(`wstack --provider ${SETUP_PROVIDER_ID} --model ${SETUP_MODEL_ID}`)}
2951
3107
 
2952
3108
  `
2953
3109
  );
@@ -3017,7 +3173,7 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
3017
3173
  }
3018
3174
  if (promptMenu.persistError) {
3019
3175
  renderer.writeWarning(
3020
- `Could not save system prompt variant to config: ${toErrorMessage4(promptMenu.persistError)}
3176
+ `Could not save system prompt variant to config: ${toErrorMessage5(promptMenu.persistError)}
3021
3177
  `
3022
3178
  );
3023
3179
  }
@@ -3069,8 +3225,8 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
3069
3225
  if (shouldPrintYoloNotice(lastChoices, yoloPinned, choices.yolo)) {
3070
3226
  writeErr(
3071
3227
  `
3072
- ${color10.yellow("YOLO is on")}: non-denied tool calls, including shell and file writes, run without confirmation.
3073
- ${color10.dim("Explicit deny rules still apply. Use")} --no-yolo ${color10.dim("or")} /yolo off ${color10.dim("to require prompts.")}
3228
+ ${color11.yellow("YOLO is on")}: non-denied tool calls, including shell and file writes, run without confirmation.
3229
+ ${color11.dim("Explicit deny rules still apply. Use")} --no-yolo ${color11.dim("or")} /yolo off ${color11.dim("to require prompts.")}
3074
3230
 
3075
3231
  `
3076
3232
  );
@@ -3104,6 +3260,7 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
3104
3260
  }
3105
3261
  flags["autonomy"] = effectiveChoices.autonomy;
3106
3262
  }
3263
+ applyGoalTuiDefault(flags, positional);
3107
3264
  flags["director"] = true;
3108
3265
  return {
3109
3266
  config,
@@ -3121,64 +3278,13 @@ To start the app with no model connected, pass --provider ${SETUP_PROVIDER_ID} -
3121
3278
  needsSetup: !noInteractiveMode ? false : !config.provider || !config.model
3122
3279
  };
3123
3280
  }
3124
- async function checkGitInCwd(opts) {
3125
- const { cwd, renderer, reader } = opts;
3126
- const cwdGit = path7.join(cwd, ".git");
3127
- let hasCwdGit = false;
3128
- try {
3129
- await fs6.access(cwdGit);
3130
- hasCwdGit = true;
3131
- } catch {
3132
- }
3133
- if (!hasCwdGit) {
3134
- renderer.write(
3135
- `
3136
- ${color10.amber("\u25CB")} This folder has no ${color10.bold(".git")} repository.
3137
- `
3138
- );
3139
- const answer = (await reader.readLine(` ${color10.amber("?")} Initialize one here? ${color10.dim("[y/N]")} `)).trim().toLowerCase();
3140
- if (answer === "y" || answer === "yes") {
3141
- try {
3142
- const { spawn: spawn2 } = await import("node:child_process");
3143
- await new Promise((resolve2, reject) => {
3144
- const child = spawn2("git", ["init"], {
3145
- cwd,
3146
- signal: AbortSignal.timeout(1e4),
3147
- windowsHide: true
3148
- });
3149
- child.on("error", reject);
3150
- child.on(
3151
- "close",
3152
- (code) => code === 0 ? resolve2() : reject(new Error(`git init failed with ${code}`))
3153
- );
3154
- });
3155
- renderer.write(` ${color10.green("\u2713")} Git repository initialized
3156
- `);
3157
- hasCwdGit = true;
3158
- } catch (err) {
3159
- renderer.writeError(`git init failed: ${toErrorMessage4(err)}
3160
- `);
3161
- }
3162
- }
3163
- }
3164
- const parentDir = path7.dirname(cwd);
3165
- if (parentDir !== cwd) {
3166
- try {
3167
- await fs6.access(path7.join(parentDir, ".git"));
3168
- renderer.write(
3169
- ` ${color10.dim("\u2139")} A ${color10.bold(".git")} repo exists in the parent directory: ${color10.dim(parentDir)}
3170
- `
3171
- );
3172
- } catch {
3173
- }
3174
- }
3175
- }
3176
3281
 
3177
3282
  // src/cli-context.ts
3178
3283
  async function initializeCli(argv) {
3179
3284
  applyNodeEnvDefault();
3180
3285
  applySessionShellDefault();
3181
3286
  const earlyFlags = parseArgs(argv).flags;
3287
+ applyAsciiMode(earlyFlags);
3182
3288
  const earlyExit = await handleHelpVersionShortCircuit(argv);
3183
3289
  if (earlyExit !== null) return earlyExit;
3184
3290
  const desktopExit = await handleDesktopShortCircuit(earlyFlags, argv);
@@ -3319,7 +3425,8 @@ async function initializeCli(argv) {
3319
3425
  logger,
3320
3426
  reader,
3321
3427
  renderer,
3322
- modelsRegistry
3428
+ modelsRegistry,
3429
+ launchAllowedTools: resolveLaunchAllowedTools(ctx.flags)
3323
3430
  });
3324
3431
  const configStore = container.resolve(TOKENS3.ConfigStore);
3325
3432
  return {
@@ -3335,4 +3442,4 @@ async function initializeCli(argv) {
3335
3442
  export {
3336
3443
  initializeCli
3337
3444
  };
3338
- //# sourceMappingURL=cli-context-34Q5IJRA.js.map
3445
+ //# sourceMappingURL=cli-context-C7RBSWHF.js.map