@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.
- package/data/providers.json +44 -0
- package/dist/{acp-AJWSKWE5.js → acp-M4565YUW.js} +33 -20
- package/dist/ascii-mode-SG4PRNLP.js +7 -0
- package/dist/{auth-GRBZ7Y3D.js → auth-TE55JF4Z.js} +14 -14
- package/dist/{bench-N5K7Z5O3.js → bench-GTLPM22B.js} +2 -2
- package/dist/boot/append-system-prompt.d.ts +10 -0
- package/dist/boot/ascii-mode.d.ts +12 -0
- package/dist/boot/container-wiring.d.ts +4 -2
- package/dist/boot/dispatch-singleshot.d.ts +12 -1
- package/dist/boot/dispatch-webui.d.ts +2 -0
- package/dist/boot/goal-tui-default.d.ts +10 -0
- package/dist/boot/mcp-config-flag.d.ts +22 -0
- package/dist/boot/piped-stdin.d.ts +40 -0
- package/dist/boot/restricted-mode.d.ts +15 -0
- package/dist/boot/safe-mode.d.ts +30 -0
- package/dist/boot/single-shot-budget.d.ts +30 -0
- package/dist/boot/stream-json.d.ts +36 -0
- package/dist/boot/structured-output.d.ts +16 -0
- package/dist/boot/system-prompt-builder.d.ts +2 -0
- package/dist/boot/tool-restriction-flags.d.ts +36 -0
- package/dist/boot/worktree-sessions.d.ts +21 -0
- package/dist/boot-provider-selection.d.ts +67 -0
- package/dist/boot.d.ts +1 -38
- package/dist/{chunk-LFMVHT3R.js → chunk-2ERX3RPN.js} +11 -13
- package/dist/chunk-4TVYGG6G.js +62 -0
- package/dist/chunk-5JYDKG5B.js +154 -0
- package/dist/{chunk-3VXYY5JC.js → chunk-5UZBUV2H.js} +3 -19
- package/dist/chunk-CZTXF6HY.js +140 -0
- package/dist/{chunk-DRM7PSW7.js → chunk-ENRYW73H.js} +527 -381
- package/dist/{chunk-SKPDE62W.js → chunk-EPR42SWM.js} +36 -6
- package/dist/{chunk-YBUCXXYZ.js → chunk-F5DCFAKI.js} +1 -1
- package/dist/chunk-HDMFKTT3.js +157 -0
- package/dist/{chunk-PGKJ2OQP.js → chunk-HFZH2XJN.js} +5 -5
- package/dist/chunk-HLSHFXTO.js +97 -0
- package/dist/{chunk-QFPQXKCG.js → chunk-KOEO4CJG.js} +21 -6
- package/dist/chunk-LBPLTTZ6.js +105 -0
- package/dist/{chunk-3OCUS3VN.js → chunk-LDCGZJTC.js} +4 -4
- package/dist/chunk-LKPEBZBE.js +143 -0
- package/dist/chunk-N57IU5FG.js +58 -0
- package/dist/{chunk-2EBVTYJR.js → chunk-NRXWOMK7.js} +17 -3
- package/dist/chunk-PZQBGUVZ.js +18 -0
- package/dist/{chunk-MHEBWVXL.js → chunk-Q4INH2DG.js} +46 -2
- package/dist/{chunk-5SEYGOCH.js → chunk-RDGGWMTI.js} +2 -2
- package/dist/{chunk-BLD5DSVA.js → chunk-RGFWGUAB.js} +27 -15
- package/dist/{chunk-ZZRSG7VK.js → chunk-RZ4ZDRYA.js} +3 -3
- package/dist/{chunk-S4FFHDJG.js → chunk-SDJCLEK6.js} +6 -2
- package/dist/{chunk-U46QR4WR.js → chunk-TI7KLHYX.js} +132 -3
- package/dist/chunk-X756ZS72.js +329 -0
- package/dist/{chunk-JF2MULWF.js → chunk-YHYINL47.js} +47 -15
- package/dist/{cli-context-34Q5IJRA.js → cli-context-C7RBSWHF.js} +434 -327
- package/dist/{cli-main-AELJDBGU.js → cli-main-TQTH73ZK.js} +2948 -2315
- package/dist/cli-update-notice.d.ts +2 -1
- package/dist/config-doctor.d.ts +1 -1
- package/dist/{diag-doctor-WIFJH3XH.js → diag-doctor-BIZAFIAT.js} +2 -2
- package/dist/{execution-PYC5FCS4.js → execution-3STBD2U7.js} +2167 -1831
- package/dist/execution-chimera-review.d.ts +18 -1
- package/dist/fleet/host-types.d.ts +3 -1
- package/dist/goal-commands.d.ts +47 -0
- package/dist/goal-host.d.ts +1 -14
- package/dist/{hq-JTUTFI4L.js → hq-44F4OQH2.js} +9 -8
- package/dist/hq-fleet-control.d.ts +36 -0
- package/dist/hq-live-status.d.ts +22 -0
- package/dist/hq-publisher.d.ts +18 -0
- package/dist/hq-server/routes/command-handlers.d.ts +12 -1
- package/dist/hq-server/routes/data-handlers.d.ts +1 -1
- package/dist/hq-server/socket-credentials.d.ts +63 -0
- package/dist/hq-server/upgrade-handler.d.ts +2 -0
- package/dist/hq-server/ws.d.ts +24 -0
- package/dist/{hq-server-PC7GZMPT.js → hq-server-UIB24LU6.js} +2 -2
- package/dist/{hq-service-NW56MUP2.js → hq-service-BMMJAHRT.js} +4 -4
- package/dist/import-claude-code-AYG24RG2.js +268 -0
- package/dist/index.js +12 -8
- package/dist/live-settings-input.d.ts +1 -0
- package/dist/{mailbox-serve-WDOCH6KR.js → mailbox-serve-GNGXEQ2R.js} +3 -3
- package/dist/{modeldiag-36OGAL5C.js → modeldiag-W7XAE625.js} +9 -9
- package/dist/{per-subcommand-help-XE77MTGJ.js → per-subcommand-help-QDAQASPZ.js} +2 -2
- package/dist/permission-prompt.d.ts +14 -0
- package/dist/permission-rules-view.d.ts +18 -0
- package/dist/{permissions-CFDLXETM.js → permissions-PL27UHYD.js} +67 -45
- package/dist/{plugin-usage-S5LVGMBW.js → plugin-usage-CIGOOTX3.js} +2 -2
- package/dist/{plugins-RHBIVLI7.js → plugins-HQTXUD6A.js} +4 -2
- package/dist/preflight.d.ts +1 -1
- package/dist/{projects-LMNAGGEU.js → projects-T4CZCA25.js} +3 -6
- package/dist/provider-helpers.d.ts +7 -11
- package/dist/{providers-models-2CFG46RD.js → providers-models-5Z2PJTEW.js} +5 -5
- package/dist/release-asset-download.d.ts +10 -0
- package/dist/release-attestation.d.ts +28 -0
- package/dist/remote/remote-session.d.ts +64 -0
- package/dist/remote/remote-target.d.ts +69 -0
- package/dist/remote-GB5VXCCT.js +576 -0
- package/dist/{replay-Z3FTJEMM.js → replay-DEI566CW.js} +2 -2
- package/dist/services/commit-message.d.ts +2 -1
- package/dist/session-move-P2EC2COA.js +44 -0
- package/dist/session-move.d.ts +20 -0
- package/dist/session-stats.d.ts +10 -0
- package/dist/{sessions-config-IQUH2GXT.js → sessions-config-XHLXJ5C3.js} +109 -10
- package/dist/short-circuit-flags-5TNTJPQR.js +10 -0
- package/dist/slash-commands/command-context.d.ts +15 -5
- package/dist/slash-commands/goal-refiner.d.ts +4 -49
- package/dist/slash-commands/mcp.d.ts +2 -1
- package/dist/slash-commands/permissions.d.ts +4 -0
- package/dist/slash-commands/settings-context-mutations.d.ts +5 -0
- package/dist/slash-commands/settings-limits-mutations.d.ts +12 -0
- package/dist/slash-commands/theme.d.ts +15 -1
- package/dist/standalone-auto-update-TOTRGCSA.js +249 -0
- package/dist/standalone-auto-update.d.ts +65 -0
- package/dist/standalone-update-LZO3MNLH.js +24 -0
- package/dist/standalone-update.d.ts +37 -1
- package/dist/subcommands/handlers/import-claude-code.d.ts +52 -0
- package/dist/subcommands/handlers/permissions.d.ts +9 -3
- package/dist/subcommands/handlers/remote.d.ts +6 -0
- package/dist/subcommands/handlers/sessions-fleet.d.ts +0 -12
- package/dist/subcommands/handlers/version-help.d.ts +5 -0
- package/dist/{subcommands-ZTSIN7LG.js → subcommands-BHQYLDSD.js} +2 -2
- package/dist/tui-resume-callback.d.ts +18 -0
- package/dist/{typesafe-HVEVPA6R.js → typesafe-U7YB2RRV.js} +5 -5
- package/dist/{typesafe-topic-replay-4W73BOLV.js → typesafe-topic-replay-ZILIU3WS.js} +18 -2
- package/dist/{update-7XIOEXTD.js → update-TDZX4IL2.js} +4 -4
- package/dist/{update-check-2POMBHFB.js → update-check-J5ZVKS73.js} +3 -3
- package/dist/version-JB2UAV2A.js +11 -0
- package/dist/version-help-XJJQ7YSH.js +10 -0
- package/dist/webui-server/route-contexts.d.ts +1 -1
- package/dist/webui-server/session-start-payload.d.ts +5 -1
- package/dist/{webui-server-L2SICPTB.js → webui-server-GCXIO3JY.js} +515 -365
- package/dist/webui-server-lifecycle.d.ts +57 -0
- package/dist/webui-server-options.d.ts +10 -0
- package/dist/webui-server.d.ts +0 -14
- package/dist/wiring/brain-and-orchestration.d.ts +3 -1
- package/dist/wiring/cli-prompt-and-tools-setup.d.ts +9 -0
- package/dist/wiring/cli-slash-commands-setup.d.ts +1 -0
- package/dist/wiring/command-host-state.d.ts +2 -0
- package/dist/wiring/hq-telemetry.d.ts +12 -0
- package/dist/wiring/lifecycle-plugins.d.ts +4 -2
- package/dist/wiring/metrics.d.ts +9 -1
- package/dist/wiring/pipeline.d.ts +2 -7
- package/dist/wiring/plugins.d.ts +3 -0
- package/dist/wiring/provider-status.d.ts +1 -0
- package/dist/wiring/provider-utility-tools.d.ts +3 -1
- package/package.json +29 -28
- package/dist/chunk-2BKFWIER.js +0 -98
- package/dist/chunk-424ORSE7.js +0 -56
- package/dist/chunk-OWNC7LMD.js +0 -78
- package/dist/chunk-QBBF7GIK.js +0 -65
- package/dist/short-circuit-flags-SDT53OML.js +0 -10
- package/dist/standalone-update-MW47J3AK.js +0 -164
- 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
|
-
|
|
7
|
+
makeStdinPromptDelegate,
|
|
6
8
|
renderAgentsTemplate,
|
|
7
|
-
renderDiff
|
|
8
|
-
|
|
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-
|
|
30
|
+
} from "./chunk-N57IU5FG.js";
|
|
23
31
|
import {
|
|
24
32
|
renderDeepHelp,
|
|
25
33
|
renderFocusedHelp
|
|
26
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-EPR42SWM.js";
|
|
27
35
|
import {
|
|
28
36
|
handleHelpVersionShortCircuit
|
|
29
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-HFZH2XJN.js";
|
|
30
38
|
import {
|
|
31
39
|
DEFAULT_PORT
|
|
32
|
-
} from "./chunk-
|
|
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
|
-
|
|
42
|
-
} from "./chunk-
|
|
49
|
+
resolveLaunchMcpServers
|
|
50
|
+
} from "./chunk-HLSHFXTO.js";
|
|
43
51
|
import {
|
|
44
52
|
installProviderPersisters
|
|
45
|
-
} from "./chunk-
|
|
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-
|
|
54
|
-
import "./chunk-
|
|
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-
|
|
88
|
+
} from "./chunk-2ERX3RPN.js";
|
|
67
89
|
import "./chunk-YTEOAWOJ.js";
|
|
68
90
|
import {
|
|
69
91
|
isKeylessLocalProvider,
|
|
70
92
|
visibleModelIds
|
|
71
|
-
} from "./chunk-
|
|
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-
|
|
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:
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
885
|
+
resolve3(1);
|
|
871
886
|
});
|
|
872
887
|
child.once("exit", (code, signal) => {
|
|
873
|
-
if (typeof code === "number")
|
|
874
|
-
else
|
|
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((
|
|
914
|
+
return new Promise((resolve3) => {
|
|
900
915
|
const server = net.createServer();
|
|
901
916
|
server.once("error", (err) => {
|
|
902
917
|
if (err.code === "EADDRINUSE") {
|
|
903
|
-
|
|
918
|
+
resolve3(true);
|
|
904
919
|
} else {
|
|
905
|
-
|
|
920
|
+
resolve3(false);
|
|
906
921
|
}
|
|
907
922
|
});
|
|
908
923
|
server.once("listening", () => {
|
|
909
|
-
server.close(() =>
|
|
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-
|
|
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((
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
1176
|
-
import * as
|
|
1177
|
-
import { atomicWrite as atomicWrite2, backupConfigFile, color as
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
1412
|
+
const filePath = path6.join(directory, entry.name);
|
|
1229
1413
|
try {
|
|
1230
|
-
const stat2 = await
|
|
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
|
|
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
|
|
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
|
-
${
|
|
1268
|
-
${
|
|
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
|
-
` ${
|
|
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
|
-
` ${
|
|
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: ${
|
|
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
|
|
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
|
|
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(
|
|
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")} ${
|
|
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")} ${
|
|
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")} ${
|
|
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")} ${
|
|
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(
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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: ${
|
|
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: ${
|
|
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
|
|
1424
|
-
import { atomicWrite as atomicWrite3, color as
|
|
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 ?
|
|
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
|
-
${
|
|
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
|
-
` ${
|
|
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(
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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(
|
|
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
|
-
` ${
|
|
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(
|
|
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
|
-
` ${
|
|
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(
|
|
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
|
-
${
|
|
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(
|
|
1726
|
+
if (chosen.yolo) badges.push(color7.yellow("YOLO"));
|
|
1535
1727
|
if (chosen.autonomy !== "off")
|
|
1536
|
-
badges.push(
|
|
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
|
|
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
|
|
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
|
|
1569
|
-
import * as
|
|
1570
|
-
import { color as
|
|
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
|
|
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
|
|
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 =
|
|
1600
|
-
const file =
|
|
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
|
|
1604
|
-
await
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
` ${
|
|
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(
|
|
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(` ${
|
|
1826
|
+
renderer.write(` ${color8.green("\u2713")} Wrote ${color8.dim(file)}
|
|
1635
1827
|
`);
|
|
1636
1828
|
} catch (err) {
|
|
1637
|
-
renderer.writeError(`Failed to scaffold AGENTS.md: ${
|
|
1829
|
+
renderer.writeError(`Failed to scaffold AGENTS.md: ${toErrorMessage4(err)}`);
|
|
1638
1830
|
}
|
|
1639
1831
|
}
|
|
1640
1832
|
return true;
|
|
1641
1833
|
}
|
|
1642
|
-
const gitDir =
|
|
1834
|
+
const gitDir = path7.join(projectRoot, ".git");
|
|
1643
1835
|
let hasGit = false;
|
|
1644
1836
|
try {
|
|
1645
|
-
await
|
|
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
|
-
${
|
|
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
|
-
` ${
|
|
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(
|
|
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((
|
|
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 ?
|
|
1866
|
+
(code) => code === 0 ? resolve3() : reject(new Error(`git init failed with ${code}`))
|
|
1675
1867
|
);
|
|
1676
1868
|
});
|
|
1677
|
-
renderer.write(` ${
|
|
1869
|
+
renderer.write(` ${color8.green("\u2713")} Git repository initialized
|
|
1678
1870
|
`);
|
|
1679
1871
|
} catch (err) {
|
|
1680
|
-
renderer.writeError(`git init failed: ${
|
|
1872
|
+
renderer.writeError(`git init failed: ${toErrorMessage4(err)}
|
|
1681
1873
|
`);
|
|
1682
1874
|
}
|
|
1683
1875
|
}
|
|
1684
1876
|
} else {
|
|
1685
1877
|
renderer.write(
|
|
1686
1878
|
`
|
|
1687
|
-
${
|
|
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(` ${
|
|
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(
|
|
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
|
-
` ${
|
|
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
|
-
${
|
|
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 ?
|
|
1741
|
-
const label = isDefault ?
|
|
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
|
-
` ${
|
|
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
|
-
${
|
|
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
|
|
1807
|
-
import * as
|
|
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
|
|
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
|
|
1835
|
-
await
|
|
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((
|
|
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((
|
|
2055
|
+
await new Promise((resolve3) => {
|
|
1864
2056
|
if (old.closed) {
|
|
1865
|
-
|
|
2057
|
+
resolve3();
|
|
1866
2058
|
} else {
|
|
1867
|
-
old.once("close",
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
2162
|
+
resolve3(opt.value);
|
|
1971
2163
|
}
|
|
1972
2164
|
};
|
|
1973
2165
|
const onClose = () => {
|
|
1974
2166
|
cleanup();
|
|
1975
|
-
|
|
2167
|
+
resolve3("");
|
|
1976
2168
|
};
|
|
1977
2169
|
const onAbort = () => {
|
|
1978
2170
|
cleanup();
|
|
1979
2171
|
writeOut("\n");
|
|
1980
|
-
|
|
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((
|
|
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
|
-
|
|
2252
|
+
resolve3(buf);
|
|
2044
2253
|
return;
|
|
2045
2254
|
}
|
|
2046
2255
|
if (ch === "") {
|
|
2047
2256
|
cleanup();
|
|
2048
2257
|
writeOut("\n");
|
|
2049
|
-
|
|
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
|
|
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 ?
|
|
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} ${
|
|
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} ${
|
|
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} ${
|
|
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} ${
|
|
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(` ${
|
|
2464
|
+
this.out.write(` ${color10.dim(capped)}
|
|
2255
2465
|
`);
|
|
2256
2466
|
}
|
|
2257
2467
|
if (moreCount > 0) {
|
|
2258
2468
|
this.out.write(
|
|
2259
|
-
` ${
|
|
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
|
|
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}${
|
|
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
|
|
2709
|
+
const path10 = typeof o["path"] === "string" ? o["path"] : "";
|
|
2500
2710
|
const reps = typeof o["replacements"] === "number" ? o["replacements"] : 0;
|
|
2501
|
-
return `${
|
|
2711
|
+
return `${path10} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
|
|
2502
2712
|
}
|
|
2503
2713
|
if (name === "write") {
|
|
2504
|
-
const
|
|
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 ? `${
|
|
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
|
|
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 (
|
|
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: ${
|
|
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
|
|
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: ${
|
|
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
|
-
${
|
|
2802
|
-
${
|
|
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
|
-
|
|
2811
|
-
|
|
2812
|
-
logger
|
|
2813
|
-
|
|
2814
|
-
|
|
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:
|
|
2978
|
+
cacheDir: path9.dirname(wpaths.modelsCache),
|
|
2823
2979
|
logger
|
|
2824
2980
|
});
|
|
2825
2981
|
} catch (err) {
|
|
2826
|
-
logger.debug(`provider auto-discovery skipped: ${
|
|
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 (
|
|
3017
|
+
if (isSetupProvider2(config.provider)) {
|
|
2862
3018
|
skipPicker = true;
|
|
2863
3019
|
renderer.write(
|
|
2864
3020
|
`
|
|
2865
|
-
${
|
|
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: ${
|
|
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
|
-
${
|
|
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
|
-
` ${
|
|
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(
|
|
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
|
-
${
|
|
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
|
-
${
|
|
2949
|
-
${
|
|
2950
|
-
${
|
|
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: ${
|
|
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
|
-
${
|
|
3073
|
-
${
|
|
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-
|
|
3445
|
+
//# sourceMappingURL=cli-context-C7RBSWHF.js.map
|