luckerr 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +267 -0
  2. package/README.zh-CN.md +237 -0
  3. package/dashboard/app.css +3022 -0
  4. package/dashboard/dist/app.js +30137 -0
  5. package/dashboard/dist/app.js.map +1 -0
  6. package/dashboard/dist/vendor-hljs.css +10 -0
  7. package/dashboard/dist/vendor-uplot.css +1 -0
  8. package/dashboard/index.html +19 -0
  9. package/data/deepseek-tokenizer.json.gz +0 -0
  10. package/dist/cli/acp-EOOAI4F5.js +712 -0
  11. package/dist/cli/acp-EOOAI4F5.js.map +1 -0
  12. package/dist/cli/chat-7J6GJXL2.js +51 -0
  13. package/dist/cli/chat-7J6GJXL2.js.map +1 -0
  14. package/dist/cli/chunk-2425HK6U.js +54 -0
  15. package/dist/cli/chunk-2425HK6U.js.map +1 -0
  16. package/dist/cli/chunk-25T6CVUP.js +172 -0
  17. package/dist/cli/chunk-25T6CVUP.js.map +1 -0
  18. package/dist/cli/chunk-2UQP6H6T.js +31 -0
  19. package/dist/cli/chunk-2UQP6H6T.js.map +1 -0
  20. package/dist/cli/chunk-56OAJILV.js +47 -0
  21. package/dist/cli/chunk-56OAJILV.js.map +1 -0
  22. package/dist/cli/chunk-5FTI4KXH.js +150 -0
  23. package/dist/cli/chunk-5FTI4KXH.js.map +1 -0
  24. package/dist/cli/chunk-5TWQD73O.js +2846 -0
  25. package/dist/cli/chunk-5TWQD73O.js.map +1 -0
  26. package/dist/cli/chunk-653BOCMK.js +40 -0
  27. package/dist/cli/chunk-653BOCMK.js.map +1 -0
  28. package/dist/cli/chunk-6ALJTWWQ.js +2663 -0
  29. package/dist/cli/chunk-6ALJTWWQ.js.map +1 -0
  30. package/dist/cli/chunk-6DRKA2IL.js +341 -0
  31. package/dist/cli/chunk-6DRKA2IL.js.map +1 -0
  32. package/dist/cli/chunk-6LV63NJV.js +634 -0
  33. package/dist/cli/chunk-6LV63NJV.js.map +1 -0
  34. package/dist/cli/chunk-74EX7SUH.js +25293 -0
  35. package/dist/cli/chunk-74EX7SUH.js.map +1 -0
  36. package/dist/cli/chunk-74U5RKTX.js +60611 -0
  37. package/dist/cli/chunk-74U5RKTX.js.map +1 -0
  38. package/dist/cli/chunk-ANJSUESV.js +143 -0
  39. package/dist/cli/chunk-ANJSUESV.js.map +1 -0
  40. package/dist/cli/chunk-DB2Z3DKZ.js +54 -0
  41. package/dist/cli/chunk-DB2Z3DKZ.js.map +1 -0
  42. package/dist/cli/chunk-DDIH3ZAA.js +400 -0
  43. package/dist/cli/chunk-DDIH3ZAA.js.map +1 -0
  44. package/dist/cli/chunk-ELN3Z3B2.js +621 -0
  45. package/dist/cli/chunk-ELN3Z3B2.js.map +1 -0
  46. package/dist/cli/chunk-F6BSQJGV.js +200 -0
  47. package/dist/cli/chunk-F6BSQJGV.js.map +1 -0
  48. package/dist/cli/chunk-FET2UAG5.js +246 -0
  49. package/dist/cli/chunk-FET2UAG5.js.map +1 -0
  50. package/dist/cli/chunk-FFJ342IJ.js +190 -0
  51. package/dist/cli/chunk-FFJ342IJ.js.map +1 -0
  52. package/dist/cli/chunk-GB3247B6.js +130 -0
  53. package/dist/cli/chunk-GB3247B6.js.map +1 -0
  54. package/dist/cli/chunk-HC2J4U3G.js +373 -0
  55. package/dist/cli/chunk-HC2J4U3G.js.map +1 -0
  56. package/dist/cli/chunk-HRUZAIHQ.js +42 -0
  57. package/dist/cli/chunk-HRUZAIHQ.js.map +1 -0
  58. package/dist/cli/chunk-J3ZJFUDL.js +308 -0
  59. package/dist/cli/chunk-J3ZJFUDL.js.map +1 -0
  60. package/dist/cli/chunk-J5XJHLWM.js +55 -0
  61. package/dist/cli/chunk-J5XJHLWM.js.map +1 -0
  62. package/dist/cli/chunk-JFGLMRZ6.js +160 -0
  63. package/dist/cli/chunk-JFGLMRZ6.js.map +1 -0
  64. package/dist/cli/chunk-JMBMLOBP.js +26 -0
  65. package/dist/cli/chunk-JMBMLOBP.js.map +1 -0
  66. package/dist/cli/chunk-JMWHXZEL.js +551 -0
  67. package/dist/cli/chunk-JMWHXZEL.js.map +1 -0
  68. package/dist/cli/chunk-KEQGPJBO.js +209 -0
  69. package/dist/cli/chunk-KEQGPJBO.js.map +1 -0
  70. package/dist/cli/chunk-M4K6U37F.js +232 -0
  71. package/dist/cli/chunk-M4K6U37F.js.map +1 -0
  72. package/dist/cli/chunk-MIJI2WMN.js +95 -0
  73. package/dist/cli/chunk-MIJI2WMN.js.map +1 -0
  74. package/dist/cli/chunk-MPAO3JNR.js +128 -0
  75. package/dist/cli/chunk-MPAO3JNR.js.map +1 -0
  76. package/dist/cli/chunk-PZOFBEDC.js +873 -0
  77. package/dist/cli/chunk-PZOFBEDC.js.map +1 -0
  78. package/dist/cli/chunk-RAILYQLN.js +46 -0
  79. package/dist/cli/chunk-RAILYQLN.js.map +1 -0
  80. package/dist/cli/chunk-RR35VQVT.js +90 -0
  81. package/dist/cli/chunk-RR35VQVT.js.map +1 -0
  82. package/dist/cli/chunk-RRA7VPW4.js +417 -0
  83. package/dist/cli/chunk-RRA7VPW4.js.map +1 -0
  84. package/dist/cli/chunk-RU36QVN3.js +452 -0
  85. package/dist/cli/chunk-RU36QVN3.js.map +1 -0
  86. package/dist/cli/chunk-RUBIINXR.js +1819 -0
  87. package/dist/cli/chunk-RUBIINXR.js.map +1 -0
  88. package/dist/cli/chunk-S4XVGLRW.js +499 -0
  89. package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
  90. package/dist/cli/chunk-TUK7OWJA.js +51 -0
  91. package/dist/cli/chunk-TUK7OWJA.js.map +1 -0
  92. package/dist/cli/chunk-VALDDV76.js +580 -0
  93. package/dist/cli/chunk-VALDDV76.js.map +1 -0
  94. package/dist/cli/chunk-WQOGPYGN.js +11390 -0
  95. package/dist/cli/chunk-WQOGPYGN.js.map +1 -0
  96. package/dist/cli/chunk-WREKDFXT.js +34320 -0
  97. package/dist/cli/chunk-WREKDFXT.js.map +1 -0
  98. package/dist/cli/chunk-Y7XQU2EL.js +270 -0
  99. package/dist/cli/chunk-Y7XQU2EL.js.map +1 -0
  100. package/dist/cli/chunk-YBVCZJU4.js +54 -0
  101. package/dist/cli/chunk-YBVCZJU4.js.map +1 -0
  102. package/dist/cli/chunk-YLIHDXUQ.js +749 -0
  103. package/dist/cli/chunk-YLIHDXUQ.js.map +1 -0
  104. package/dist/cli/chunk-YV5XXFD7.js +767 -0
  105. package/dist/cli/chunk-YV5XXFD7.js.map +1 -0
  106. package/dist/cli/chunk-ZRCNIYRQ.js +101 -0
  107. package/dist/cli/chunk-ZRCNIYRQ.js.map +1 -0
  108. package/dist/cli/code-CRKVCMFZ.js +155 -0
  109. package/dist/cli/code-CRKVCMFZ.js.map +1 -0
  110. package/dist/cli/commands-QLMD3T7B.js +356 -0
  111. package/dist/cli/commands-QLMD3T7B.js.map +1 -0
  112. package/dist/cli/commit-53PP32NC.js +293 -0
  113. package/dist/cli/commit-53PP32NC.js.map +1 -0
  114. package/dist/cli/desktop-R6W5CLJ5.js +1046 -0
  115. package/dist/cli/desktop-R6W5CLJ5.js.map +1 -0
  116. package/dist/cli/devtools-YECO25QO.js +3719 -0
  117. package/dist/cli/devtools-YECO25QO.js.map +1 -0
  118. package/dist/cli/diff-LYNRCJZE.js +166 -0
  119. package/dist/cli/diff-LYNRCJZE.js.map +1 -0
  120. package/dist/cli/doctor-5IBP4R5J.js +28 -0
  121. package/dist/cli/doctor-5IBP4R5J.js.map +1 -0
  122. package/dist/cli/events-QN6KLN2V.js +340 -0
  123. package/dist/cli/events-QN6KLN2V.js.map +1 -0
  124. package/dist/cli/index.js +3500 -0
  125. package/dist/cli/index.js.map +1 -0
  126. package/dist/cli/mcp-FGKEH7RG.js +277 -0
  127. package/dist/cli/mcp-FGKEH7RG.js.map +1 -0
  128. package/dist/cli/mcp-browse-YCND4NWT.js +178 -0
  129. package/dist/cli/mcp-browse-YCND4NWT.js.map +1 -0
  130. package/dist/cli/mcp-inspect-V34J3VX5.js +143 -0
  131. package/dist/cli/mcp-inspect-V34J3VX5.js.map +1 -0
  132. package/dist/cli/package.json +3 -0
  133. package/dist/cli/prompt-I775PNKT.js +16 -0
  134. package/dist/cli/prompt-I775PNKT.js.map +1 -0
  135. package/dist/cli/prune-sessions-KGIIYD3P.js +44 -0
  136. package/dist/cli/prune-sessions-KGIIYD3P.js.map +1 -0
  137. package/dist/cli/replay-RDXLUAOE.js +292 -0
  138. package/dist/cli/replay-RDXLUAOE.js.map +1 -0
  139. package/dist/cli/run-RCAC2RYW.js +223 -0
  140. package/dist/cli/run-RCAC2RYW.js.map +1 -0
  141. package/dist/cli/server-FFU6TLYJ.js +3658 -0
  142. package/dist/cli/server-FFU6TLYJ.js.map +1 -0
  143. package/dist/cli/sessions-QT26MQAE.js +107 -0
  144. package/dist/cli/sessions-QT26MQAE.js.map +1 -0
  145. package/dist/cli/setup-VV4WKXHV.js +767 -0
  146. package/dist/cli/setup-VV4WKXHV.js.map +1 -0
  147. package/dist/cli/stats-JVZPQWAN.js +15 -0
  148. package/dist/cli/stats-JVZPQWAN.js.map +1 -0
  149. package/dist/cli/update-KYI3OVJP.js +15 -0
  150. package/dist/cli/update-KYI3OVJP.js.map +1 -0
  151. package/dist/cli/version-ANYORXTI.js +34 -0
  152. package/dist/cli/version-ANYORXTI.js.map +1 -0
  153. package/dist/index.d.ts +2557 -0
  154. package/dist/index.js +15000 -0
  155. package/dist/index.js.map +1 -0
  156. package/package.json +106 -0
@@ -0,0 +1,767 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+ import {
4
+ MultiSelect,
5
+ SingleSelect,
6
+ useKeystroke
7
+ } from "./chunk-ELN3Z3B2.js";
8
+ import {
9
+ ThemeProvider,
10
+ useTheme
11
+ } from "./chunk-JFGLMRZ6.js";
12
+ import {
13
+ Box_default,
14
+ Text,
15
+ render_default,
16
+ require_react,
17
+ source_default,
18
+ use_app_default,
19
+ use_input_default
20
+ } from "./chunk-WREKDFXT.js";
21
+ import {
22
+ PRESET_DESCRIPTIONS
23
+ } from "./chunk-2425HK6U.js";
24
+ import {
25
+ loadDotenv
26
+ } from "./chunk-2UQP6H6T.js";
27
+ import {
28
+ MCP_CATALOG
29
+ } from "./chunk-56OAJILV.js";
30
+ import {
31
+ detectSystemLanguage,
32
+ getLanguage,
33
+ getSupportedLanguages,
34
+ notifyLanguageChange,
35
+ onLanguageChange,
36
+ setLanguage,
37
+ t
38
+ } from "./chunk-5TWQD73O.js";
39
+ import {
40
+ defaultConfigPath,
41
+ isPlausibleKey,
42
+ listThemeNames,
43
+ loadApiKey,
44
+ loadBaseUrl,
45
+ loadTheme,
46
+ readConfig,
47
+ redactKey,
48
+ resolveThemePreference,
49
+ writeConfig
50
+ } from "./chunk-6ALJTWWQ.js";
51
+ import {
52
+ getProvider,
53
+ listProviders
54
+ } from "./chunk-JMWHXZEL.js";
55
+ import {
56
+ __toESM
57
+ } from "./chunk-TUK7OWJA.js";
58
+
59
+ // src/cli/commands/setup.tsx
60
+ var import_react3 = __toESM(require_react(), 1);
61
+
62
+ // src/cli/ui/Wizard.tsx
63
+ import { mkdirSync, statSync } from "fs";
64
+
65
+ // node_modules/ink-text-input/build/index.js
66
+ var import_react = __toESM(require_react(), 1);
67
+ function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
68
+ const [state, setState] = (0, import_react.useState)({
69
+ cursorOffset: (originalValue || "").length,
70
+ cursorWidth: 0
71
+ });
72
+ const { cursorOffset, cursorWidth } = state;
73
+ (0, import_react.useEffect)(() => {
74
+ setState((previousState) => {
75
+ if (!focus || !showCursor) {
76
+ return previousState;
77
+ }
78
+ const newValue = originalValue || "";
79
+ if (previousState.cursorOffset > newValue.length - 1) {
80
+ return {
81
+ cursorOffset: newValue.length,
82
+ cursorWidth: 0
83
+ };
84
+ }
85
+ return previousState;
86
+ });
87
+ }, [originalValue, focus, showCursor]);
88
+ const cursorActualWidth = highlightPastedText ? cursorWidth : 0;
89
+ const value = mask ? mask.repeat(originalValue.length) : originalValue;
90
+ let renderedValue = value;
91
+ let renderedPlaceholder = placeholder ? source_default.grey(placeholder) : void 0;
92
+ if (showCursor && focus) {
93
+ renderedPlaceholder = placeholder.length > 0 ? source_default.inverse(placeholder[0]) + source_default.grey(placeholder.slice(1)) : source_default.inverse(" ");
94
+ renderedValue = value.length > 0 ? "" : source_default.inverse(" ");
95
+ let i = 0;
96
+ for (const char of value) {
97
+ renderedValue += i >= cursorOffset - cursorActualWidth && i <= cursorOffset ? source_default.inverse(char) : char;
98
+ i++;
99
+ }
100
+ if (value.length > 0 && cursorOffset === value.length) {
101
+ renderedValue += source_default.inverse(" ");
102
+ }
103
+ }
104
+ use_input_default((input, key) => {
105
+ if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
106
+ return;
107
+ }
108
+ if (key.return) {
109
+ if (onSubmit) {
110
+ onSubmit(originalValue);
111
+ }
112
+ return;
113
+ }
114
+ let nextCursorOffset = cursorOffset;
115
+ let nextValue = originalValue;
116
+ let nextCursorWidth = 0;
117
+ if (key.leftArrow) {
118
+ if (showCursor) {
119
+ nextCursorOffset--;
120
+ }
121
+ } else if (key.rightArrow) {
122
+ if (showCursor) {
123
+ nextCursorOffset++;
124
+ }
125
+ } else if (key.backspace || key.delete) {
126
+ if (cursorOffset > 0) {
127
+ nextValue = originalValue.slice(0, cursorOffset - 1) + originalValue.slice(cursorOffset, originalValue.length);
128
+ nextCursorOffset--;
129
+ }
130
+ } else {
131
+ nextValue = originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset, originalValue.length);
132
+ nextCursorOffset += input.length;
133
+ if (input.length > 1) {
134
+ nextCursorWidth = input.length;
135
+ }
136
+ }
137
+ if (cursorOffset < 0) {
138
+ nextCursorOffset = 0;
139
+ }
140
+ if (cursorOffset > originalValue.length) {
141
+ nextCursorOffset = originalValue.length;
142
+ }
143
+ setState({
144
+ cursorOffset: nextCursorOffset,
145
+ cursorWidth: nextCursorWidth
146
+ });
147
+ if (nextValue !== originalValue) {
148
+ onChange(nextValue);
149
+ }
150
+ }, { isActive: focus });
151
+ return import_react.default.createElement(Text, null, placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue);
152
+ }
153
+ var build_default = TextInput;
154
+
155
+ // src/cli/ui/Wizard.tsx
156
+ var import_react2 = __toESM(require_react(), 1);
157
+ var CATALOG_BY_NAME = new Map(MCP_CATALOG.map((e) => [e.name, e]));
158
+ var LANGUAGE_LABELS = {
159
+ EN: "English",
160
+ "zh-CN": "\u7B80\u4F53\u4E2D\u6587"
161
+ };
162
+ function Wizard({
163
+ onComplete,
164
+ onCancel,
165
+ existingApiKey,
166
+ forceApiKeyStep = false,
167
+ validateApiKey = validateDeepSeekApiKey,
168
+ initial
169
+ }) {
170
+ const { exit } = use_app_default();
171
+ const [, setLanguageVersion] = (0, import_react2.useState)(0);
172
+ (0, import_react2.useEffect)(() => onLanguageChange(() => setLanguageVersion((v) => v + 1)), []);
173
+ const [previewTheme, setPreviewTheme] = (0, import_react2.useState)(
174
+ () => resolveThemePreference(initial?.theme ?? loadTheme(), process.env.LUCKERR_THEME)
175
+ );
176
+ const [step, setStep] = (0, import_react2.useState)("language");
177
+ const [data, setData] = (0, import_react2.useState)(() => ({
178
+ language: getLanguage(),
179
+ theme: resolveThemePreference(initial?.theme ?? loadTheme(), process.env.LUCKERR_THEME),
180
+ apiKey: existingApiKey ?? "",
181
+ providerKeys: loadProviderKeysFromConfig(),
182
+ preset: initial?.preset ?? "auto",
183
+ selectedCatalog: deriveInitialCatalog(initial?.mcp ?? []),
184
+ catalogArgs: {}
185
+ }));
186
+ const [error, setError] = (0, import_react2.useState)(null);
187
+ use_input_default((_input, key) => {
188
+ if (key.escape && step !== "saved" && onCancel) onCancel();
189
+ });
190
+ const content = (() => {
191
+ if (step === "language") {
192
+ return /* @__PURE__ */ import_react2.default.createElement(
193
+ LanguageStep,
194
+ {
195
+ initialValue: data.language,
196
+ onSubmit: (lang) => {
197
+ setLanguage(lang);
198
+ notifyLanguageChange();
199
+ setData((d) => ({ ...d, language: lang }));
200
+ setStep("theme");
201
+ }
202
+ }
203
+ );
204
+ }
205
+ if (step === "theme") {
206
+ return /* @__PURE__ */ import_react2.default.createElement(
207
+ ThemeStep,
208
+ {
209
+ initialValue: data.theme,
210
+ onPreview: setPreviewTheme,
211
+ onSubmit: (theme) => {
212
+ setData((d) => ({ ...d, theme }));
213
+ setStep("providerKeys");
214
+ }
215
+ }
216
+ );
217
+ }
218
+ if (step === "providerKeys") {
219
+ return /* @__PURE__ */ import_react2.default.createElement(
220
+ ProviderKeysStep,
221
+ {
222
+ providerKeys: data.providerKeys,
223
+ onUpdate: (providerKeys) => {
224
+ setData((d) => ({ ...d, providerKeys }));
225
+ setError(null);
226
+ },
227
+ onSubmit: () => {
228
+ const hasAny = data.apiKey || Object.keys(data.providerKeys).length > 0;
229
+ if (!hasAny) {
230
+ setError(t("wizard.providerKeysNeeded"));
231
+ return;
232
+ }
233
+ setError(null);
234
+ setStep("preset");
235
+ },
236
+ error
237
+ }
238
+ );
239
+ }
240
+ if (step === "apiKey") {
241
+ return /* @__PURE__ */ import_react2.default.createElement(
242
+ ApiKeyStep,
243
+ {
244
+ initialValue: data.apiKey,
245
+ validateApiKey,
246
+ onSubmit: (key) => {
247
+ setData((d) => ({ ...d, apiKey: key }));
248
+ setError(null);
249
+ setStep("preset");
250
+ },
251
+ error,
252
+ onError: setError
253
+ }
254
+ );
255
+ }
256
+ if (step === "preset") {
257
+ return /* @__PURE__ */ import_react2.default.createElement(StepFrame, { title: t("wizard.presetTitle"), step: 1, total: 3 }, /* @__PURE__ */ import_react2.default.createElement(
258
+ SingleSelect,
259
+ {
260
+ items: presetItems(),
261
+ initialValue: data.preset,
262
+ onSubmit: (preset) => {
263
+ setData((d) => ({ ...d, preset }));
264
+ setStep("mcp");
265
+ }
266
+ }
267
+ ), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.selectFooter"))));
268
+ }
269
+ if (step === "mcp") {
270
+ return /* @__PURE__ */ import_react2.default.createElement(StepFrame, { title: t("wizard.mcpTitle"), step: 2, total: 3 }, /* @__PURE__ */ import_react2.default.createElement(
271
+ MultiSelect,
272
+ {
273
+ items: mcpItems(),
274
+ initialSelected: data.selectedCatalog,
275
+ onSubmit: (selected) => {
276
+ setData((d) => ({ ...d, selectedCatalog: selected }));
277
+ const needsArgs = selected.some((name) => CATALOG_BY_NAME.get(name)?.userArgs);
278
+ setStep(needsArgs ? "mcpArgs" : "review");
279
+ },
280
+ footer: t("wizard.mcpFooterMulti")
281
+ }
282
+ ));
283
+ }
284
+ if (step === "mcpArgs") {
285
+ const pending = data.selectedCatalog.filter((name) => {
286
+ const entry2 = CATALOG_BY_NAME.get(name);
287
+ return entry2?.userArgs && !data.catalogArgs[name];
288
+ });
289
+ if (pending.length === 0) {
290
+ setStep("review");
291
+ return null;
292
+ }
293
+ const currentName = pending[0];
294
+ const entry = CATALOG_BY_NAME.get(currentName);
295
+ return /* @__PURE__ */ import_react2.default.createElement(
296
+ McpArgsStep,
297
+ {
298
+ entry,
299
+ error,
300
+ onSubmit: (value) => {
301
+ setData((d) => ({
302
+ ...d,
303
+ catalogArgs: { ...d.catalogArgs, [currentName]: value }
304
+ }));
305
+ setError(null);
306
+ },
307
+ onError: setError
308
+ }
309
+ );
310
+ }
311
+ if (step === "review") {
312
+ const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
313
+ return /* @__PURE__ */ import_react2.default.createElement(StepFrame, { title: t("wizard.reviewTitle"), step: 3, total: 3 }, /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react2.default.createElement(
314
+ SummaryLine,
315
+ {
316
+ label: t("wizard.reviewLabelLanguage"),
317
+ value: LANGUAGE_LABELS[data.language]
318
+ }
319
+ ), /* @__PURE__ */ import_react2.default.createElement(SummaryLine, { label: t("wizard.reviewLabelApiKey"), value: redactKey(data.apiKey) }), /* @__PURE__ */ import_react2.default.createElement(
320
+ SummaryLine,
321
+ {
322
+ label: t("wizard.reviewLabelProviders"),
323
+ value: formatProviderSummary(data.providerKeys)
324
+ }
325
+ ), /* @__PURE__ */ import_react2.default.createElement(SummaryLine, { label: t("wizard.reviewLabelTheme"), value: data.theme }), /* @__PURE__ */ import_react2.default.createElement(SummaryLine, { label: t("wizard.reviewLabelPreset"), value: data.preset }), /* @__PURE__ */ import_react2.default.createElement(
326
+ SummaryLine,
327
+ {
328
+ label: t("wizard.reviewLabelMcp"),
329
+ value: specs.length === 0 ? t("wizard.reviewMcpNone") : t("wizard.reviewMcpServers", { count: specs.length })
330
+ }
331
+ ), specs.map((spec, i) => (
332
+ // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
333
+ /* @__PURE__ */ import_react2.default.createElement(Box_default, { key: i, paddingLeft: 14 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, "\xB7 ", spec))
334
+ )), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("wizard.reviewSavesTo", { path: defaultConfigPath() }))), error ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "red" }, error)) : null, /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.reviewFooter")))), /* @__PURE__ */ import_react2.default.createElement(
335
+ ReviewConfirm,
336
+ {
337
+ onConfirm: () => {
338
+ try {
339
+ const specsNow = data.selectedCatalog.map(
340
+ (name) => buildSpec(name, data.catalogArgs)
341
+ );
342
+ const prev = readConfig();
343
+ const next = {
344
+ ...prev,
345
+ apiKey: data.apiKey,
346
+ providerKeys: data.providerKeys,
347
+ preset: data.preset,
348
+ theme: data.theme,
349
+ mcp: specsNow,
350
+ setupCompleted: true
351
+ };
352
+ writeConfig(next);
353
+ setStep("saved");
354
+ onComplete(next);
355
+ } catch (e) {
356
+ setError(t("wizard.reviewSaveError", { message: e.message }));
357
+ }
358
+ }
359
+ }
360
+ ));
361
+ }
362
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "green" }, t("wizard.savedTitle")), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("ui.welcome"))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.savedFooter"))), /* @__PURE__ */ import_react2.default.createElement(ExitOnEnter, { onExit: exit }));
363
+ })();
364
+ return /* @__PURE__ */ import_react2.default.createElement(ThemeProvider, { name: previewTheme }, content);
365
+ }
366
+ var THEME_NAMES = listThemeNames();
367
+ function ThemeStep({
368
+ initialValue,
369
+ onPreview,
370
+ onSubmit
371
+ }) {
372
+ const initialIndex = Math.max(0, THEME_NAMES.indexOf(initialValue));
373
+ const [index, setIndex] = (0, import_react2.useState)(initialIndex);
374
+ const theme = useTheme();
375
+ use_input_default((_input, key) => {
376
+ if (key.upArrow) {
377
+ const next = (index - 1 + THEME_NAMES.length) % THEME_NAMES.length;
378
+ setIndex(next);
379
+ onPreview(THEME_NAMES[next]);
380
+ } else if (key.downArrow) {
381
+ const next = (index + 1) % THEME_NAMES.length;
382
+ setIndex(next);
383
+ onPreview(THEME_NAMES[next]);
384
+ } else if (key.return) {
385
+ onSubmit(THEME_NAMES[index]);
386
+ }
387
+ });
388
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: theme.tone.brand, paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: theme.tone.brand }, t("wizard.themeTitle")), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.themeSubtitle"))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, THEME_NAMES.map((name, i) => /* @__PURE__ */ import_react2.default.createElement(Box_default, { key: name }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: i === index ? theme.tone.brand : void 0 }, i === index ? "\u25B8 " : " "), /* @__PURE__ */ import_react2.default.createElement(Text, { bold: i === index, color: i === index ? theme.fg.strong : theme.fg.body }, name), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.meta }, " \u2014 "), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.meta }, t(`wizard.themeCaption.${name}`))))), /* @__PURE__ */ import_react2.default.createElement(
389
+ Box_default,
390
+ {
391
+ marginTop: 1,
392
+ flexDirection: "column",
393
+ borderStyle: "round",
394
+ borderColor: theme.fg.faint,
395
+ paddingX: 1
396
+ },
397
+ /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.meta }, t("wizard.themeSampleHeading")),
398
+ /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.accent }, "\u25C6 "), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.accent }, t("wizard.themeSampleReasoning"))),
399
+ /* @__PURE__ */ import_react2.default.createElement(Box_default, null, /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.info }, "\u25A3 "), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.body }, "fs.readFile("), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.ok }, '"main.ts"'), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.body }, ")")),
400
+ /* @__PURE__ */ import_react2.default.createElement(Box_default, null, /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.meta }, "~/project/main.ts:42")),
401
+ /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.ok }, "ok"), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.faint }, " \xB7 "), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.warn }, "warn"), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.fg.faint }, " \xB7 "), /* @__PURE__ */ import_react2.default.createElement(Text, { color: theme.tone.err }, "err"))
402
+ ), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.themeFooter"))));
403
+ }
404
+ function LanguageStep({
405
+ initialValue,
406
+ onSubmit
407
+ }) {
408
+ const items = getSupportedLanguages().map((code) => ({
409
+ value: code,
410
+ label: LANGUAGE_LABELS[code],
411
+ hint: code === detectSystemLanguage() ? "(detected)" : void 0
412
+ }));
413
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, t("wizard.languageTitle")), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.languageSubtitle"))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(
414
+ SingleSelect,
415
+ {
416
+ items,
417
+ initialValue,
418
+ onSubmit,
419
+ footer: t("wizard.selectFooter")
420
+ }
421
+ )));
422
+ }
423
+ function ApiKeyStep({
424
+ initialValue,
425
+ validateApiKey,
426
+ onSubmit,
427
+ error,
428
+ onError
429
+ }) {
430
+ const [value, setValue] = (0, import_react2.useState)("");
431
+ const [checking, setChecking] = (0, import_react2.useState)(false);
432
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, t("wizard.welcomeTitle")), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("wizard.apiKeyPrompt"))), /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.apiKeyGetOne")), /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.apiKeySavedLocally", { path: defaultConfigPath() })), initialValue ? /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.apiKeyPreview", { redacted: redactKey(initialValue) })) : null, /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, t("wizard.apiKeyInputLabel")), /* @__PURE__ */ import_react2.default.createElement(
433
+ build_default,
434
+ {
435
+ value,
436
+ onChange: setValue,
437
+ onSubmit: (raw) => {
438
+ const trimmed = raw.trim() || initialValue?.trim() || "";
439
+ if (!isPlausibleKey(trimmed)) {
440
+ onError(t("wizard.apiKeyInvalid"));
441
+ setValue("");
442
+ return;
443
+ }
444
+ setChecking(true);
445
+ onError(null);
446
+ void validateApiKey(trimmed).then((result) => {
447
+ setChecking(false);
448
+ if (!result.ok) {
449
+ onError(
450
+ result.reason === "rejected" ? t("wizard.apiKeyRejected") : t("wizard.apiKeyCheckFailed", { message: result.message ?? "unknown" })
451
+ );
452
+ setValue("");
453
+ return;
454
+ }
455
+ onSubmit(trimmed);
456
+ });
457
+ },
458
+ mask: "\u2022",
459
+ placeholder: "sk-..."
460
+ }
461
+ )), checking ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "yellow" }, t("wizard.apiKeyChecking"))) : error ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "red" }, error)) : value ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.apiKeyPreview", { redacted: redactKey(value) }))) : null);
462
+ }
463
+ function loadProviderKeysFromConfig() {
464
+ const cfg = readConfig();
465
+ const keys = {};
466
+ if (cfg.providerKeys) {
467
+ for (const [id, key] of Object.entries(cfg.providerKeys)) {
468
+ if (typeof key === "string" && key.trim()) keys[id] = key;
469
+ }
470
+ }
471
+ for (const p of listProviders()) {
472
+ const envVal = process.env[p.auth.envKey];
473
+ if (envVal && !keys[p.id]) keys[p.id] = envVal;
474
+ }
475
+ return keys;
476
+ }
477
+ function formatProviderSummary(providerKeys) {
478
+ const ids = Object.keys(providerKeys);
479
+ if (ids.length === 0) return t("wizard.providerKeysNone");
480
+ const names = ids.map((id) => {
481
+ const p = getProvider(id);
482
+ return p?.label ?? id;
483
+ }).join(", ");
484
+ return names;
485
+ }
486
+ function ProviderKeysStep({
487
+ providerKeys,
488
+ onUpdate,
489
+ onSubmit,
490
+ error
491
+ }) {
492
+ const providers = listProviders();
493
+ const [editing, setEditing] = (0, import_react2.useState)(null);
494
+ const [inputValue, setInputValue] = (0, import_react2.useState)("");
495
+ if (!editing) {
496
+ const items = providers.map((p) => {
497
+ const hasKey = !!providerKeys[p.id];
498
+ const envKey = process.env[p.auth.envKey];
499
+ let hint;
500
+ if (envKey && hasKey) {
501
+ hint = t("wizard.providerKeysDetected");
502
+ } else if (hasKey) {
503
+ hint = redactKey(providerKeys[p.id]);
504
+ }
505
+ return {
506
+ value: p.id,
507
+ label: `${hasKey ? "\u2713" : "\u25CB"} ${p.label}`,
508
+ hint
509
+ };
510
+ });
511
+ const configuredCount = Object.keys(providerKeys).length;
512
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, t("wizard.providerKeysTitle")), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("wizard.providerKeysSubtitle"))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, configuredCount > 0 ? t("wizard.providerKeysConfigured", { count: configuredCount }) : t("wizard.providerKeysNone"))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(
513
+ SingleSelect,
514
+ {
515
+ items,
516
+ onSubmit: (id) => {
517
+ setEditing(id);
518
+ setInputValue(providerKeys[id] ?? "");
519
+ },
520
+ footer: t("wizard.providerKeysFooter")
521
+ }
522
+ )), error ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "red" }, error)) : null, /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, configuredCount > 0 ? "[Space] continue \xB7 [Enter] edit key \xB7 [Esc] cancel" : t("wizard.providerKeysFooter"))), /* @__PURE__ */ import_react2.default.createElement(
523
+ ProviderKeysConfirm,
524
+ {
525
+ hasKeys: configuredCount > 0,
526
+ onConfirm: onSubmit
527
+ }
528
+ ));
529
+ }
530
+ const provider = getProvider(editing);
531
+ if (!provider) {
532
+ setEditing(null);
533
+ return null;
534
+ }
535
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, t("wizard.providerKeysTitle")), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("wizard.providerKeysInputFor", { label: provider.label }))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(
536
+ build_default,
537
+ {
538
+ value: inputValue,
539
+ onChange: setInputValue,
540
+ onSubmit: (raw) => {
541
+ const trimmed = raw.trim();
542
+ if (trimmed === "") {
543
+ const next2 = { ...providerKeys };
544
+ delete next2[editing];
545
+ onUpdate(next2);
546
+ setEditing(null);
547
+ return;
548
+ }
549
+ if (!isPlausibleKey(trimmed)) {
550
+ setInputValue("");
551
+ return;
552
+ }
553
+ const next = { ...providerKeys, [editing]: trimmed };
554
+ onUpdate(next);
555
+ setEditing(null);
556
+ },
557
+ placeholder: provider.auth.envKey
558
+ }
559
+ )), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.providerKeysGetOne", {
560
+ url: provider.endpoints.chat.replace(/\/+$/, "")
561
+ }))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.apiKeySavedLocally", { path: defaultConfigPath() }))), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, "[Enter] save \xB7 [Esc] back \xB7 empty input removes key")));
562
+ }
563
+ function ProviderKeysConfirm({
564
+ hasKeys,
565
+ onConfirm
566
+ }) {
567
+ use_input_default((_input, key) => {
568
+ if (key.return && hasKeys) onConfirm();
569
+ if (_input === " " && hasKeys) onConfirm();
570
+ });
571
+ useKeystroke((ev) => {
572
+ if (ev.return && hasKeys) onConfirm();
573
+ if (ev.input === " " && hasKeys) onConfirm();
574
+ });
575
+ return null;
576
+ }
577
+ async function validateDeepSeekApiKey(apiKey, opts = {}) {
578
+ const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
579
+ let baseUrl = opts.baseUrl ?? loadBaseUrl() ?? "https://api.deepseek.com";
580
+ while (baseUrl.endsWith("/")) baseUrl = baseUrl.slice(0, -1);
581
+ const ctrl = new AbortController();
582
+ const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 1e4);
583
+ try {
584
+ const resp = await fetchImpl(`${baseUrl}/user/balance`, {
585
+ method: "GET",
586
+ headers: { Authorization: `Bearer ${apiKey}` },
587
+ signal: ctrl.signal
588
+ });
589
+ if (resp.ok) return { ok: true };
590
+ if (resp.status === 401 || resp.status === 403) return { ok: false, reason: "rejected" };
591
+ return { ok: false, reason: "failed", message: `DeepSeek ${resp.status}` };
592
+ } catch (e) {
593
+ return { ok: false, reason: "failed", message: e.message };
594
+ } finally {
595
+ clearTimeout(timer);
596
+ }
597
+ }
598
+ function McpArgsStep({
599
+ entry,
600
+ error,
601
+ onSubmit,
602
+ onError
603
+ }) {
604
+ const [value, setValue] = (0, import_react2.useState)("");
605
+ const [pendingCreate, setPendingCreate] = (0, import_react2.useState)(null);
606
+ use_input_default((input, key) => {
607
+ if (!pendingCreate) return;
608
+ const ch = input.toLowerCase();
609
+ if (ch === "y" || key.return) {
610
+ try {
611
+ mkdirSync(pendingCreate, { recursive: true });
612
+ const created = pendingCreate;
613
+ setPendingCreate(null);
614
+ setValue("");
615
+ onError(null);
616
+ onSubmit(created);
617
+ } catch (e) {
618
+ onError(
619
+ t("wizard.mcpArgsDirCreateFailed", {
620
+ path: pendingCreate,
621
+ message: e.message
622
+ })
623
+ );
624
+ setPendingCreate(null);
625
+ }
626
+ } else if (ch === "n" || key.escape) {
627
+ setPendingCreate(null);
628
+ onError(null);
629
+ }
630
+ });
631
+ if (pendingCreate) {
632
+ return /* @__PURE__ */ import_react2.default.createElement(StepFrame, { title: t("wizard.mcpArgsTitle", { name: entry.name }), step: 2, total: 3 }, /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("wizard.mcpArgsDirMissing", { path: pendingCreate })), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.mcpArgsDirCreateHint"))), error ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "red" }, error)) : null));
633
+ }
634
+ return /* @__PURE__ */ import_react2.default.createElement(StepFrame, { title: t("wizard.mcpArgsTitle", { name: entry.name }), step: 2, total: 3 }, /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react2.default.createElement(Text, null, entry.summary), entry.note ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, null, t("wizard.mcpArgsRequiredParam")), /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, entry.userArgs)), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ import_react2.default.createElement(
635
+ build_default,
636
+ {
637
+ value,
638
+ onChange: setValue,
639
+ onSubmit: (raw) => {
640
+ const trimmed = raw.trim();
641
+ if (!trimmed) {
642
+ onError(t("wizard.mcpArgsEmpty", { name: entry.name }));
643
+ return;
644
+ }
645
+ if (entry.name === "filesystem") {
646
+ const check = checkFilesystemPath(trimmed);
647
+ if (check.kind === "missing") {
648
+ setPendingCreate(trimmed);
649
+ return;
650
+ }
651
+ if (check.kind === "not-a-dir") {
652
+ onError(t("wizard.mcpArgsNotADir", { path: trimmed }));
653
+ return;
654
+ }
655
+ }
656
+ onSubmit(trimmed);
657
+ setValue("");
658
+ },
659
+ placeholder: placeholderFor(entry)
660
+ }
661
+ )), error ? /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react2.default.createElement(Text, { color: "red" }, error)) : null));
662
+ }
663
+ function checkFilesystemPath(p) {
664
+ try {
665
+ return { kind: statSync(p).isDirectory() ? "ok" : "not-a-dir" };
666
+ } catch {
667
+ return { kind: "missing" };
668
+ }
669
+ }
670
+ function ReviewConfirm({ onConfirm }) {
671
+ use_input_default((_i, key) => {
672
+ if (key.return) onConfirm();
673
+ });
674
+ return null;
675
+ }
676
+ function ExitOnEnter({ onExit }) {
677
+ use_input_default((_i, key) => {
678
+ if (key.return) onExit();
679
+ });
680
+ return null;
681
+ }
682
+ function StepFrame({
683
+ title,
684
+ step,
685
+ total,
686
+ children
687
+ }) {
688
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ import_react2.default.createElement(Box_default, null, /* @__PURE__ */ import_react2.default.createElement(Text, { dimColor: true }, t("wizard.stepCounter", { step, total })), /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ import_react2.default.createElement(Box_default, { marginTop: 1, flexDirection: "column" }, children));
689
+ }
690
+ function SummaryLine({ label, value }) {
691
+ return /* @__PURE__ */ import_react2.default.createElement(Box_default, null, /* @__PURE__ */ import_react2.default.createElement(Text, null, label.padEnd(12)), /* @__PURE__ */ import_react2.default.createElement(Text, { bold: true }, value));
692
+ }
693
+ function presetItems() {
694
+ return ["auto", "flash", "pro"].map((name) => ({
695
+ value: name,
696
+ label: `${name} \u2014 ${PRESET_DESCRIPTIONS[name].headline}`,
697
+ hint: PRESET_DESCRIPTIONS[name].cost
698
+ }));
699
+ }
700
+ function mcpItems() {
701
+ return MCP_CATALOG.map((entry) => {
702
+ const hintParts = [entry.summary];
703
+ if (entry.userArgs) hintParts.push(t("wizard.mcpUserArgsHint", { arg: entry.userArgs }));
704
+ if (entry.note) hintParts.push(entry.note);
705
+ return {
706
+ value: entry.name,
707
+ label: entry.name,
708
+ hint: hintParts.join(" \xB7 ")
709
+ };
710
+ });
711
+ }
712
+ function placeholderFor(entry) {
713
+ if (entry.name === "filesystem") return "e.g. /tmp/luckerr-sandbox";
714
+ if (entry.name === "sqlite") return "e.g. ./notes.sqlite";
715
+ return entry.userArgs ?? "";
716
+ }
717
+ function deriveInitialCatalog(existingSpecs) {
718
+ const packageToName = new Map(MCP_CATALOG.map((e) => [e.package, e.name]));
719
+ const out = [];
720
+ for (const spec of existingSpecs) {
721
+ for (const [pkg, name] of packageToName) {
722
+ if (spec.includes(pkg)) {
723
+ out.push(name);
724
+ break;
725
+ }
726
+ }
727
+ }
728
+ return out;
729
+ }
730
+ function buildSpec(name, argsByName) {
731
+ const entry = CATALOG_BY_NAME.get(name);
732
+ if (!entry) return name;
733
+ const userArg = entry.userArgs ? argsByName[name] : void 0;
734
+ const tail = userArg ? ` ${quoteIfNeeded(userArg)}` : "";
735
+ return `${entry.name}=npx -y ${entry.package}${tail}`;
736
+ }
737
+ function quoteIfNeeded(s) {
738
+ return /\s|"/.test(s) ? `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : s;
739
+ }
740
+
741
+ // src/cli/commands/setup.tsx
742
+ async function setupCommand(opts = {}) {
743
+ loadDotenv();
744
+ const existingKey = loadApiKey();
745
+ const existing = readConfig();
746
+ const { waitUntilExit, unmount } = render_default(
747
+ /* @__PURE__ */ import_react3.default.createElement(
748
+ Wizard,
749
+ {
750
+ existingApiKey: existingKey,
751
+ initial: { preset: existing.preset, mcp: existing.mcp, theme: existing.theme },
752
+ forceApiKeyStep: opts.forceKeyStep,
753
+ onComplete: () => {
754
+ },
755
+ onCancel: () => {
756
+ unmount();
757
+ }
758
+ }
759
+ ),
760
+ { exitOnCtrlC: true, patchConsole: false }
761
+ );
762
+ await waitUntilExit();
763
+ }
764
+ export {
765
+ setupCommand
766
+ };
767
+ //# sourceMappingURL=setup-VV4WKXHV.js.map