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