@robota-sdk/agent-cli 3.0.0-beta.33 → 3.0.0-beta.35

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/dist/node/bin.cjs CHANGED
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/cli.ts
27
- var import_node_fs3 = require("fs");
27
+ var import_node_fs4 = require("fs");
28
28
  var import_node_path5 = require("path");
29
29
  var import_node_url = require("url");
30
30
  var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
@@ -163,11 +163,11 @@ var PrintTerminal = class {
163
163
  };
164
164
 
165
165
  // src/ui/render.tsx
166
- var import_ink12 = require("ink");
166
+ var import_ink14 = require("ink");
167
167
 
168
168
  // src/ui/App.tsx
169
- var import_react13 = require("react");
170
- var import_ink11 = require("ink");
169
+ var import_react16 = require("react");
170
+ var import_ink13 = require("ink");
171
171
  var import_agent_core3 = require("@robota-sdk/agent-core");
172
172
 
173
173
  // src/ui/hooks/useSession.ts
@@ -175,25 +175,69 @@ var import_react = require("react");
175
175
  var import_agent_sdk = require("@robota-sdk/agent-sdk");
176
176
 
177
177
  // src/utils/edit-diff.ts
178
- function generateDiffLines(oldStr, newStr) {
178
+ var import_node_fs2 = require("fs");
179
+ var CONTEXT_LINES = 2;
180
+ function generateDiffLines(oldStr, newStr, startLine = 1) {
179
181
  if (oldStr === newStr) return [];
180
182
  const lines = [];
181
- for (const line of oldStr.split("\n")) {
182
- lines.push({ type: "remove", text: line });
183
+ const oldLines = oldStr.split("\n");
184
+ const newLines = newStr.split("\n");
185
+ for (let i = 0; i < oldLines.length; i++) {
186
+ lines.push({ type: "remove", text: oldLines[i], lineNumber: startLine + i });
183
187
  }
184
- for (const line of newStr.split("\n")) {
185
- lines.push({ type: "add", text: line });
188
+ for (let i = 0; i < newLines.length; i++) {
189
+ lines.push({ type: "add", text: newLines[i], lineNumber: startLine + i });
186
190
  }
187
191
  return lines;
188
192
  }
189
- function extractEditDiff(toolName, toolArgs) {
193
+ function generateDiffLinesWithContext(oldStr, newStr, startLine, filePath) {
194
+ if (oldStr === newStr) return [];
195
+ const diffLines = generateDiffLines(oldStr, newStr, startLine);
196
+ let fileLines;
197
+ try {
198
+ fileLines = (0, import_node_fs2.readFileSync)(filePath, "utf-8").split("\n");
199
+ } catch {
200
+ return diffLines;
201
+ }
202
+ const result = [];
203
+ const contextStart = Math.max(0, startLine - 1 - CONTEXT_LINES);
204
+ for (let i = contextStart; i < startLine - 1; i++) {
205
+ if (i < fileLines.length) {
206
+ result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
207
+ }
208
+ }
209
+ result.push(...diffLines);
210
+ const newLineCount = newStr.split("\n").length;
211
+ const afterStart = startLine - 1 + newLineCount;
212
+ for (let i = afterStart; i < afterStart + CONTEXT_LINES; i++) {
213
+ if (i < fileLines.length) {
214
+ result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
215
+ }
216
+ }
217
+ return result;
218
+ }
219
+ function extractEditDiff(toolName, toolArgs, startLine) {
190
220
  if (toolName !== "Edit" || !toolArgs) return null;
191
221
  const filePath = toolArgs.file_path ?? toolArgs.filePath;
192
222
  const oldStr = toolArgs.old_string ?? toolArgs.oldString;
193
223
  const newStr = toolArgs.new_string ?? toolArgs.newString;
194
224
  if (typeof filePath !== "string") return null;
195
225
  if (typeof oldStr !== "string" || typeof newStr !== "string") return null;
196
- const lines = generateDiffLines(oldStr, newStr);
226
+ let sl = startLine ?? 0;
227
+ if (!sl) {
228
+ try {
229
+ const fileContent = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
230
+ const idx = fileContent.indexOf(newStr);
231
+ if (idx >= 0) {
232
+ sl = fileContent.substring(0, idx).split("\n").length;
233
+ } else {
234
+ sl = 1;
235
+ }
236
+ } catch {
237
+ sl = 1;
238
+ }
239
+ }
240
+ const lines = generateDiffLinesWithContext(oldStr, newStr, sl, filePath);
197
241
  if (lines.length === 0) return null;
198
242
  return { file: filePath, lines };
199
243
  }
@@ -271,9 +315,20 @@ function useSession(props) {
271
315
  setActiveTools((prev) => {
272
316
  const updated = prev.map((t) => {
273
317
  if (!(t.toolName === event.toolName && t.isRunning)) return t;
318
+ let startLine;
319
+ if (event.toolResultData && event.toolName === "Edit") {
320
+ try {
321
+ const parsed = JSON.parse(event.toolResultData);
322
+ if (typeof parsed.startLine === "number") {
323
+ startLine = parsed.startLine;
324
+ }
325
+ } catch {
326
+ }
327
+ }
274
328
  const editDiff = extractEditDiff(
275
329
  event.toolName,
276
- t._toolArgs
330
+ t._toolArgs,
331
+ startLine
277
332
  );
278
333
  const finished = {
279
334
  ...t,
@@ -465,18 +520,9 @@ async function handlePluginCommand(args, addMessage, callbacks) {
465
520
  try {
466
521
  switch (subcommand) {
467
522
  case "":
468
- case void 0: {
469
- const plugins = await callbacks.listInstalled();
470
- if (plugins.length === 0) {
471
- addMessage({ role: "system", content: "No plugins installed." });
472
- } else {
473
- const lines = plugins.map(
474
- (p) => ` ${p.name} \u2014 ${p.description} [${p.enabled ? "enabled" : "disabled"}]`
475
- );
476
- addMessage({ role: "system", content: `Installed plugins:
477
- ${lines.join("\n")}` });
478
- }
479
- return { handled: true };
523
+ case void 0:
524
+ case "manage": {
525
+ return { handled: true, triggerPluginTUI: true };
480
526
  }
481
527
  case "install": {
482
528
  if (!subArgs) {
@@ -623,7 +669,7 @@ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages
623
669
 
624
670
  // src/ui/hooks/useSlashCommands.ts
625
671
  var EXIT_DELAY_MS = 500;
626
- function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks) {
672
+ function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks, setShowPluginTUI) {
627
673
  return (0, import_react3.useCallback)(
628
674
  async (input) => {
629
675
  const parts = input.slice(1).split(/\s+/);
@@ -643,6 +689,9 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
643
689
  pendingModelChangeRef.current = result.pendingModelId;
644
690
  setPendingModelId(result.pendingModelId);
645
691
  }
692
+ if (result.triggerPluginTUI) {
693
+ setShowPluginTUI?.(true);
694
+ }
646
695
  if (result.exitRequested) {
647
696
  setTimeout(() => exit(), EXIT_DELAY_MS);
648
697
  }
@@ -656,7 +705,8 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
656
705
  registry,
657
706
  pendingModelChangeRef,
658
707
  setPendingModelId,
659
- pluginCallbacks
708
+ pluginCallbacks,
709
+ setShowPluginTUI
660
710
  ]
661
711
  );
662
712
  }
@@ -1040,22 +1090,7 @@ function createBuiltinCommands() {
1040
1090
  { name: "cost", description: "Show session info", source: "builtin" },
1041
1091
  { name: "context", description: "Context window info", source: "builtin" },
1042
1092
  { name: "permissions", description: "Permission rules", source: "builtin" },
1043
- {
1044
- name: "plugin",
1045
- description: "Manage plugins",
1046
- source: "builtin",
1047
- subcommands: [
1048
- { name: "install", description: "Install a plugin (name@marketplace)", source: "builtin" },
1049
- {
1050
- name: "uninstall",
1051
- description: "Uninstall a plugin (name@marketplace)",
1052
- source: "builtin"
1053
- },
1054
- { name: "enable", description: "Enable a plugin (name@marketplace)", source: "builtin" },
1055
- { name: "disable", description: "Disable a plugin (name@marketplace)", source: "builtin" },
1056
- { name: "marketplace", description: "Manage marketplace sources", source: "builtin" }
1057
- ]
1058
- },
1093
+ { name: "plugin", description: "Manage plugins", source: "builtin" },
1059
1094
  { name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
1060
1095
  { name: "reset", description: "Delete settings and exit", source: "builtin" },
1061
1096
  { name: "exit", description: "Exit CLI", source: "builtin" }
@@ -1073,7 +1108,7 @@ var BuiltinCommandSource = class {
1073
1108
  };
1074
1109
 
1075
1110
  // src/commands/skill-source.ts
1076
- var import_node_fs2 = require("fs");
1111
+ var import_node_fs3 = require("fs");
1077
1112
  var import_node_path2 = require("path");
1078
1113
  var import_node_os = require("os");
1079
1114
  var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
@@ -1122,27 +1157,27 @@ function buildCommand(frontmatter, content, fallbackName) {
1122
1157
  return cmd;
1123
1158
  }
1124
1159
  function scanSkillsDir(skillsDir) {
1125
- if (!(0, import_node_fs2.existsSync)(skillsDir)) return [];
1160
+ if (!(0, import_node_fs3.existsSync)(skillsDir)) return [];
1126
1161
  const commands = [];
1127
- const entries = (0, import_node_fs2.readdirSync)(skillsDir, { withFileTypes: true });
1162
+ const entries = (0, import_node_fs3.readdirSync)(skillsDir, { withFileTypes: true });
1128
1163
  for (const entry of entries) {
1129
1164
  if (!entry.isDirectory()) continue;
1130
1165
  const skillFile = (0, import_node_path2.join)(skillsDir, entry.name, "SKILL.md");
1131
- if (!(0, import_node_fs2.existsSync)(skillFile)) continue;
1132
- const content = (0, import_node_fs2.readFileSync)(skillFile, "utf-8");
1166
+ if (!(0, import_node_fs3.existsSync)(skillFile)) continue;
1167
+ const content = (0, import_node_fs3.readFileSync)(skillFile, "utf-8");
1133
1168
  const frontmatter = parseFrontmatter(content);
1134
1169
  commands.push(buildCommand(frontmatter, content, entry.name));
1135
1170
  }
1136
1171
  return commands;
1137
1172
  }
1138
1173
  function scanCommandsDir(commandsDir) {
1139
- if (!(0, import_node_fs2.existsSync)(commandsDir)) return [];
1174
+ if (!(0, import_node_fs3.existsSync)(commandsDir)) return [];
1140
1175
  const commands = [];
1141
- const entries = (0, import_node_fs2.readdirSync)(commandsDir, { withFileTypes: true });
1176
+ const entries = (0, import_node_fs3.readdirSync)(commandsDir, { withFileTypes: true });
1142
1177
  for (const entry of entries) {
1143
1178
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
1144
1179
  const filePath = (0, import_node_path2.join)(commandsDir, entry.name);
1145
- const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
1180
+ const content = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
1146
1181
  const frontmatter = parseFrontmatter(content);
1147
1182
  const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
1148
1183
  commands.push(buildCommand(frontmatter, content, fallbackName));
@@ -1322,18 +1357,50 @@ function usePluginCallbacks(cwd) {
1322
1357
  return {
1323
1358
  listInstalled: async () => {
1324
1359
  const plugins = await loader.loadAll();
1325
- return plugins.map((p) => ({
1326
- name: p.manifest.name,
1327
- description: p.manifest.description,
1328
- enabled: true
1360
+ const enabledMap = settingsStore.getEnabledPlugins();
1361
+ return plugins.map((p) => {
1362
+ const parts = p.pluginDir.split("/");
1363
+ const cacheIdx = parts.indexOf("cache");
1364
+ const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] : "";
1365
+ const fullId = marketplaceName ? `${p.manifest.name}@${marketplaceName}` : p.manifest.name;
1366
+ return {
1367
+ name: fullId,
1368
+ description: p.manifest.description,
1369
+ enabled: enabledMap[fullId] !== false && enabledMap[p.manifest.name] !== false
1370
+ };
1371
+ });
1372
+ },
1373
+ listAvailablePlugins: async (marketplaceName) => {
1374
+ let manifest;
1375
+ try {
1376
+ manifest = marketplace.fetchManifest(marketplaceName);
1377
+ } catch {
1378
+ return [];
1379
+ }
1380
+ const installed = installer.getInstalledPlugins();
1381
+ const installedNames = new Set(Object.values(installed).map((r) => r.pluginName));
1382
+ return manifest.plugins.map((p) => ({
1383
+ name: p.name,
1384
+ description: p.description,
1385
+ installed: installedNames.has(p.name)
1329
1386
  }));
1330
1387
  },
1331
- install: async (pluginId) => {
1388
+ install: async (pluginId, scope) => {
1332
1389
  const [name, marketplaceName] = pluginId.split("@");
1333
1390
  if (!name || !marketplaceName) {
1334
1391
  throw new Error("Plugin ID must be in format: name@marketplace");
1335
1392
  }
1336
- await installer.install(name, marketplaceName);
1393
+ if (scope === "project") {
1394
+ const projectPluginsDir = (0, import_node_path4.join)(cwd, ".robota", "plugins");
1395
+ const projectInstaller = new import_agent_sdk4.BundlePluginInstaller({
1396
+ pluginsDir: projectPluginsDir,
1397
+ settingsStore,
1398
+ marketplaceClient: marketplace
1399
+ });
1400
+ await projectInstaller.install(name, marketplaceName);
1401
+ } else {
1402
+ await installer.install(name, marketplaceName);
1403
+ }
1337
1404
  },
1338
1405
  uninstall: async (pluginId) => {
1339
1406
  await installer.uninstall(pluginId);
@@ -1391,23 +1458,41 @@ function renderMarkdown(md) {
1391
1458
  // src/ui/DiffBlock.tsx
1392
1459
  var import_ink = require("ink");
1393
1460
  var import_jsx_runtime = require("react/jsx-runtime");
1394
- var MAX_DIFF_LINES = 10;
1395
- var TRUNCATED_SHOW = 8;
1461
+ var MAX_DIFF_LINES = 12;
1462
+ var TRUNCATED_SHOW = 10;
1396
1463
  function DiffBlock({ file, lines }) {
1397
1464
  const truncated = lines.length > MAX_DIFF_LINES;
1398
1465
  const visible = truncated ? lines.slice(0, TRUNCATED_SHOW) : lines;
1399
1466
  const remaining = lines.length - TRUNCATED_SHOW;
1467
+ const maxLineNum = Math.max(...visible.map((l) => l.lineNumber), 0);
1468
+ const numWidth = String(maxLineNum).length;
1400
1469
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginLeft: 4, children: [
1401
1470
  file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
1402
1471
  "\u2502 ",
1403
1472
  file
1404
1473
  ] }),
1405
- visible.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: line.type === "remove" ? "red" : "greenBright", children: [
1406
- "\u2502 ",
1407
- line.type === "remove" ? "-" : "+",
1408
- " ",
1409
- line.text
1410
- ] }, i)),
1474
+ visible.map((line, i) => {
1475
+ const lineNum = String(line.lineNumber).padStart(numWidth, " ");
1476
+ if (line.type === "context") {
1477
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
1478
+ "\u2502 ",
1479
+ lineNum,
1480
+ " ",
1481
+ line.text
1482
+ ] }, i);
1483
+ }
1484
+ const prefix = line.type === "remove" ? "-" : "+";
1485
+ const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
1486
+ const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
1487
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: fgColor, backgroundColor: bgColor, children: [
1488
+ "\u2502 ",
1489
+ lineNum,
1490
+ " ",
1491
+ prefix,
1492
+ " ",
1493
+ line.text
1494
+ ] }, i);
1495
+ }),
1411
1496
  truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
1412
1497
  "\u2502 ... and ",
1413
1498
  remaining,
@@ -2060,8 +2145,459 @@ function StreamingIndicator({ text, activeTools }) {
2060
2145
  ] });
2061
2146
  }
2062
2147
 
2063
- // src/ui/App.tsx
2148
+ // src/ui/PluginTUI.tsx
2149
+ var import_react15 = require("react");
2150
+
2151
+ // src/ui/MenuSelect.tsx
2152
+ var import_react13 = require("react");
2153
+ var import_ink11 = require("ink");
2064
2154
  var import_jsx_runtime11 = require("react/jsx-runtime");
2155
+ function MenuSelect({
2156
+ title,
2157
+ items,
2158
+ onSelect,
2159
+ onBack,
2160
+ loading,
2161
+ error
2162
+ }) {
2163
+ const [selected, setSelected] = (0, import_react13.useState)(0);
2164
+ const selectedRef = (0, import_react13.useRef)(0);
2165
+ const resolvedRef = (0, import_react13.useRef)(false);
2166
+ const doSelect = (0, import_react13.useCallback)(
2167
+ (index) => {
2168
+ if (resolvedRef.current || items.length === 0) return;
2169
+ resolvedRef.current = true;
2170
+ onSelect(items[index].value);
2171
+ },
2172
+ [items, onSelect]
2173
+ );
2174
+ (0, import_ink11.useInput)((input, key) => {
2175
+ if (resolvedRef.current) return;
2176
+ if (key.escape) {
2177
+ resolvedRef.current = true;
2178
+ onBack();
2179
+ return;
2180
+ }
2181
+ if (loading || error || items.length === 0) return;
2182
+ if (key.upArrow) {
2183
+ const next = selectedRef.current > 0 ? selectedRef.current - 1 : selectedRef.current;
2184
+ selectedRef.current = next;
2185
+ setSelected(next);
2186
+ } else if (key.downArrow) {
2187
+ const next = selectedRef.current < items.length - 1 ? selectedRef.current + 1 : selectedRef.current;
2188
+ selectedRef.current = next;
2189
+ setSelected(next);
2190
+ } else if (key.return) {
2191
+ doSelect(selectedRef.current);
2192
+ }
2193
+ });
2194
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
2195
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "yellow", bold: true, children: title }),
2196
+ loading && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: "Loading..." }) }),
2197
+ error && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { marginTop: 1, flexDirection: "column", children: [
2198
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "red", children: error }),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: "Press Esc to go back" })
2200
+ ] }),
2201
+ !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { children: [
2202
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
2203
+ i === selected ? "> " : " ",
2204
+ item.label
2205
+ ] }),
2206
+ item.hint && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { dimColor: true, children: [
2207
+ " ",
2208
+ item.hint
2209
+ ] })
2210
+ ] }, item.value)) }),
2211
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
2212
+ ] });
2213
+ }
2214
+
2215
+ // src/ui/TextPrompt.tsx
2216
+ var import_react14 = require("react");
2217
+ var import_ink12 = require("ink");
2218
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2219
+ function TextPrompt({
2220
+ title,
2221
+ placeholder,
2222
+ onSubmit,
2223
+ onCancel,
2224
+ validate
2225
+ }) {
2226
+ const [value, setValue] = (0, import_react14.useState)("");
2227
+ const [error, setError] = (0, import_react14.useState)();
2228
+ const resolvedRef = (0, import_react14.useRef)(false);
2229
+ const valueRef = (0, import_react14.useRef)("");
2230
+ const handleSubmit = (0, import_react14.useCallback)(() => {
2231
+ if (resolvedRef.current) return;
2232
+ const trimmed = valueRef.current.trim();
2233
+ if (!trimmed) return;
2234
+ if (validate) {
2235
+ const err = validate(trimmed);
2236
+ if (err) {
2237
+ setError(err);
2238
+ return;
2239
+ }
2240
+ }
2241
+ resolvedRef.current = true;
2242
+ onSubmit(trimmed);
2243
+ }, [validate, onSubmit]);
2244
+ (0, import_ink12.useInput)((input, key) => {
2245
+ if (resolvedRef.current) return;
2246
+ if (key.escape) {
2247
+ resolvedRef.current = true;
2248
+ onCancel();
2249
+ return;
2250
+ }
2251
+ if (key.return) {
2252
+ handleSubmit();
2253
+ return;
2254
+ }
2255
+ if (key.backspace || key.delete) {
2256
+ valueRef.current = valueRef.current.slice(0, -1);
2257
+ setValue(valueRef.current);
2258
+ setError(void 0);
2259
+ return;
2260
+ }
2261
+ if (input && !key.ctrl && !key.meta) {
2262
+ valueRef.current = valueRef.current + input;
2263
+ setValue(valueRef.current);
2264
+ setError(void 0);
2265
+ }
2266
+ });
2267
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
2268
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "yellow", bold: true, children: title }),
2269
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { marginTop: 1, children: [
2270
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "> " }),
2271
+ value ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { children: value }) : placeholder ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { dimColor: true, children: placeholder }) : null,
2272
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "\u2588" })
2273
+ ] }),
2274
+ error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "red", children: error }),
2275
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { dimColor: true, children: " Enter Submit Esc Cancel" })
2276
+ ] });
2277
+ }
2278
+
2279
+ // src/ui/plugin-tui-handlers.ts
2280
+ function handleMainSelect(value, nav) {
2281
+ if (value === "marketplace") {
2282
+ nav.push({ screen: "marketplace-list" });
2283
+ } else if (value === "installed") {
2284
+ nav.push({ screen: "installed-list" });
2285
+ }
2286
+ }
2287
+ function handleMarketplaceListSelect(value, nav) {
2288
+ if (value === "__add__") {
2289
+ nav.push({ screen: "marketplace-add" });
2290
+ } else {
2291
+ nav.push({ screen: "marketplace-action", context: { marketplace: value } });
2292
+ }
2293
+ }
2294
+ function handleMarketplaceActionSelect(value, marketplace, callbacks, nav) {
2295
+ if (value === "browse") {
2296
+ nav.push({ screen: "marketplace-browse", context: { marketplace } });
2297
+ } else if (value === "update") {
2298
+ callbacks.marketplaceUpdate(marketplace).then(() => {
2299
+ nav.notify(`Updated marketplace "${marketplace}".`);
2300
+ nav.pop();
2301
+ }).catch((err) => {
2302
+ nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
2303
+ });
2304
+ } else if (value === "remove") {
2305
+ nav.setConfirm({
2306
+ message: `Remove marketplace "${marketplace}" and all its plugins?`,
2307
+ onConfirm: () => {
2308
+ nav.setConfirm(void 0);
2309
+ callbacks.marketplaceRemove(marketplace).then(() => {
2310
+ nav.notify(`Removed marketplace "${marketplace}".`);
2311
+ nav.popN(2);
2312
+ }).catch((err) => {
2313
+ nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
2314
+ });
2315
+ },
2316
+ onCancel: () => nav.setConfirm(void 0)
2317
+ });
2318
+ }
2319
+ }
2320
+ function handleMarketplaceBrowseSelect(value, marketplace, items, nav) {
2321
+ const fullId = `${value}@${marketplace}`;
2322
+ const item = items.find((i) => i.value === value);
2323
+ if (item?.hint === "installed") {
2324
+ nav.push({ screen: "installed-action", context: { pluginId: fullId } });
2325
+ } else {
2326
+ nav.push({ screen: "marketplace-install-scope", context: { marketplace, pluginId: fullId } });
2327
+ }
2328
+ }
2329
+ function handleInstallScopeSelect(value, pluginId, callbacks, nav) {
2330
+ const scope = value;
2331
+ callbacks.install(pluginId, scope).then(() => {
2332
+ nav.notify(`Installed plugin "${pluginId}" (${scope} scope).`);
2333
+ nav.popN(2);
2334
+ }).catch((err) => {
2335
+ nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
2336
+ });
2337
+ }
2338
+ function handleInstalledListSelect(value, callbacks, nav) {
2339
+ nav.setConfirm({
2340
+ message: `Uninstall plugin "${value}"?`,
2341
+ onConfirm: () => {
2342
+ nav.setConfirm(void 0);
2343
+ callbacks.uninstall(value).then(() => {
2344
+ nav.notify(`Uninstalled plugin "${value}".`);
2345
+ nav.refresh();
2346
+ }).catch((err) => {
2347
+ nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
2348
+ });
2349
+ },
2350
+ onCancel: () => nav.setConfirm(void 0)
2351
+ });
2352
+ }
2353
+ function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
2354
+ if (value === "uninstall") {
2355
+ nav.setConfirm({
2356
+ message: `Uninstall plugin "${pluginId}"?`,
2357
+ onConfirm: () => {
2358
+ nav.setConfirm(void 0);
2359
+ callbacks.uninstall(pluginId).then(() => {
2360
+ nav.notify(`Uninstalled plugin "${pluginId}".`);
2361
+ nav.popN(2);
2362
+ }).catch((err) => {
2363
+ nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
2364
+ });
2365
+ },
2366
+ onCancel: () => nav.setConfirm(void 0)
2367
+ });
2368
+ }
2369
+ }
2370
+
2371
+ // src/ui/PluginTUI.tsx
2372
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2373
+ function PluginTUI({ callbacks, onClose, addMessage }) {
2374
+ const [stack, setStack] = (0, import_react15.useState)([{ screen: "main" }]);
2375
+ const [items, setItems] = (0, import_react15.useState)([]);
2376
+ const [loading, setLoading] = (0, import_react15.useState)(false);
2377
+ const [error, setError] = (0, import_react15.useState)();
2378
+ const [confirm, setConfirm] = (0, import_react15.useState)();
2379
+ const [refreshCounter, setRefreshCounter] = (0, import_react15.useState)(0);
2380
+ const current = stack[stack.length - 1] ?? { screen: "main" };
2381
+ const push = (0, import_react15.useCallback)((state) => {
2382
+ setStack((prev) => [...prev, state]);
2383
+ setItems([]);
2384
+ setError(void 0);
2385
+ }, []);
2386
+ const pop = (0, import_react15.useCallback)(() => {
2387
+ setStack((prev) => {
2388
+ if (prev.length <= 1) {
2389
+ onClose();
2390
+ return prev;
2391
+ }
2392
+ return prev.slice(0, -1);
2393
+ });
2394
+ setItems([]);
2395
+ setError(void 0);
2396
+ }, [onClose]);
2397
+ const popN = (0, import_react15.useCallback)(
2398
+ (n) => {
2399
+ setStack((prev) => {
2400
+ const next = prev.slice(0, Math.max(1, prev.length - n));
2401
+ if (next.length === 0) {
2402
+ onClose();
2403
+ return prev;
2404
+ }
2405
+ return next;
2406
+ });
2407
+ setItems([]);
2408
+ setError(void 0);
2409
+ },
2410
+ [onClose]
2411
+ );
2412
+ const notify = (0, import_react15.useCallback)(
2413
+ (content) => {
2414
+ addMessage?.({ role: "system", content });
2415
+ },
2416
+ [addMessage]
2417
+ );
2418
+ const refresh = (0, import_react15.useCallback)(() => {
2419
+ setItems([]);
2420
+ setRefreshCounter((c) => c + 1);
2421
+ }, []);
2422
+ const nav = { push, pop, popN, notify, setConfirm, refresh };
2423
+ (0, import_react15.useEffect)(() => {
2424
+ const screen2 = current.screen;
2425
+ if (screen2 === "marketplace-list") {
2426
+ setLoading(true);
2427
+ callbacks.marketplaceList().then((sources) => {
2428
+ const baseItems = [{ label: "Add Marketplace", value: "__add__" }];
2429
+ const sourceItems = sources.map((s) => ({
2430
+ label: s.name,
2431
+ value: s.name,
2432
+ hint: s.type
2433
+ }));
2434
+ setItems([...baseItems, ...sourceItems]);
2435
+ setLoading(false);
2436
+ }).catch((err) => {
2437
+ setError(err instanceof Error ? err.message : String(err));
2438
+ setLoading(false);
2439
+ });
2440
+ } else if (screen2 === "marketplace-browse") {
2441
+ const marketplace = current.context?.marketplace ?? "";
2442
+ setLoading(true);
2443
+ callbacks.listAvailablePlugins(marketplace).then((plugins) => {
2444
+ setItems(
2445
+ plugins.map((p) => ({
2446
+ label: p.name,
2447
+ value: p.name,
2448
+ hint: p.installed ? "installed" : p.description
2449
+ }))
2450
+ );
2451
+ setLoading(false);
2452
+ }).catch((err) => {
2453
+ setError(err instanceof Error ? err.message : String(err));
2454
+ setLoading(false);
2455
+ });
2456
+ } else if (screen2 === "installed-list") {
2457
+ setLoading(true);
2458
+ callbacks.listInstalled().then((plugins) => {
2459
+ setItems(
2460
+ plugins.map((p) => ({
2461
+ label: p.name,
2462
+ value: p.name,
2463
+ hint: p.description
2464
+ }))
2465
+ );
2466
+ setLoading(false);
2467
+ }).catch((err) => {
2468
+ setError(err instanceof Error ? err.message : String(err));
2469
+ setLoading(false);
2470
+ });
2471
+ }
2472
+ }, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
2473
+ const handleSelect = (0, import_react15.useCallback)(
2474
+ (value) => {
2475
+ const screen2 = current.screen;
2476
+ const ctx = current.context;
2477
+ if (screen2 === "main") handleMainSelect(value, nav);
2478
+ else if (screen2 === "marketplace-list") handleMarketplaceListSelect(value, nav);
2479
+ else if (screen2 === "marketplace-action")
2480
+ handleMarketplaceActionSelect(value, ctx?.marketplace ?? "", callbacks, nav);
2481
+ else if (screen2 === "marketplace-browse")
2482
+ handleMarketplaceBrowseSelect(value, ctx?.marketplace ?? "", items, nav);
2483
+ else if (screen2 === "marketplace-install-scope")
2484
+ handleInstallScopeSelect(value, ctx?.pluginId ?? "", callbacks, nav);
2485
+ else if (screen2 === "installed-list") handleInstalledListSelect(value, callbacks, nav);
2486
+ else if (screen2 === "installed-action")
2487
+ handleInstalledActionSelect(value, ctx?.pluginId ?? "", callbacks, nav);
2488
+ },
2489
+ [current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
2490
+ );
2491
+ const handleTextSubmit = (0, import_react15.useCallback)(
2492
+ (value) => {
2493
+ if (current.screen === "marketplace-add") {
2494
+ callbacks.marketplaceAdd(value).then((name) => {
2495
+ notify(`Added marketplace "${name}" from ${value}.`);
2496
+ pop();
2497
+ }).catch((err) => {
2498
+ notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
2499
+ pop();
2500
+ });
2501
+ }
2502
+ },
2503
+ [current.screen, callbacks, notify, pop]
2504
+ );
2505
+ if (confirm) {
2506
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2507
+ ConfirmPrompt,
2508
+ {
2509
+ message: confirm.message,
2510
+ onSelect: (index) => {
2511
+ if (index === 0) confirm.onConfirm();
2512
+ else confirm.onCancel();
2513
+ }
2514
+ }
2515
+ );
2516
+ }
2517
+ const screen = current.screen;
2518
+ if (screen === "marketplace-add") {
2519
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2520
+ TextPrompt,
2521
+ {
2522
+ title: "Add Marketplace Source",
2523
+ placeholder: "owner/repo or git URL",
2524
+ onSubmit: handleTextSubmit,
2525
+ onCancel: pop,
2526
+ validate: (v) => !v.includes("/") ? "Must be owner/repo or a git URL" : void 0
2527
+ }
2528
+ );
2529
+ }
2530
+ if (screen === "marketplace-action") {
2531
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2532
+ MenuSelect,
2533
+ {
2534
+ title: `Marketplace: ${current.context?.marketplace ?? ""}`,
2535
+ items: [
2536
+ { label: "Browse plugins", value: "browse" },
2537
+ { label: "Update", value: "update" },
2538
+ { label: "Remove", value: "remove" }
2539
+ ],
2540
+ onSelect: handleSelect,
2541
+ onBack: pop
2542
+ },
2543
+ stack.length
2544
+ );
2545
+ }
2546
+ if (screen === "marketplace-install-scope") {
2547
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2548
+ MenuSelect,
2549
+ {
2550
+ title: `Install scope for "${current.context?.pluginId ?? ""}"`,
2551
+ items: [
2552
+ { label: "User scope", value: "user" },
2553
+ { label: "Project scope", value: "project" }
2554
+ ],
2555
+ onSelect: handleSelect,
2556
+ onBack: pop
2557
+ },
2558
+ stack.length
2559
+ );
2560
+ }
2561
+ if (screen === "installed-action") {
2562
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2563
+ MenuSelect,
2564
+ {
2565
+ title: `Plugin: ${current.context?.pluginId ?? ""}`,
2566
+ items: [{ label: "Uninstall", value: "uninstall" }],
2567
+ onSelect: handleSelect,
2568
+ onBack: pop
2569
+ },
2570
+ stack.length
2571
+ );
2572
+ }
2573
+ const titleMap = {
2574
+ main: "Plugin Management",
2575
+ "marketplace-list": "Marketplace",
2576
+ "marketplace-browse": `Browse: ${current.context?.marketplace ?? ""}`,
2577
+ "installed-list": "Installed Plugins"
2578
+ };
2579
+ const staticItemsMap = {
2580
+ main: [
2581
+ { label: "Marketplace", value: "marketplace" },
2582
+ { label: "Installed Plugins", value: "installed" }
2583
+ ]
2584
+ };
2585
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2586
+ MenuSelect,
2587
+ {
2588
+ title: titleMap[screen] ?? "Plugin Management",
2589
+ items: staticItemsMap[screen] ?? items,
2590
+ onSelect: handleSelect,
2591
+ onBack: pop,
2592
+ loading,
2593
+ error
2594
+ },
2595
+ `${screen}-${stack.length}-${refreshCounter}`
2596
+ );
2597
+ }
2598
+
2599
+ // src/ui/App.tsx
2600
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2065
2601
  var EXIT_DELAY_MS2 = 500;
2066
2602
  function mergeHooksIntoConfig(configHooks, pluginHooks) {
2067
2603
  const pluginKeys = Object.keys(pluginHooks);
@@ -2080,7 +2616,7 @@ function mergeHooksIntoConfig(configHooks, pluginHooks) {
2080
2616
  return merged;
2081
2617
  }
2082
2618
  function App(props) {
2083
- const { exit } = (0, import_ink11.useApp)();
2619
+ const { exit } = (0, import_ink13.useApp)();
2084
2620
  const { registry, pluginHooks } = useCommandRegistry(props.cwd ?? process.cwd());
2085
2621
  const configWithPluginHooks = {
2086
2622
  ...props.config,
@@ -2093,15 +2629,16 @@ function App(props) {
2093
2629
  { ...props, config: configWithPluginHooks }
2094
2630
  );
2095
2631
  const { messages, setMessages, addMessage } = useMessages();
2096
- const [isThinking, setIsThinking] = (0, import_react13.useState)(false);
2632
+ const [isThinking, setIsThinking] = (0, import_react16.useState)(false);
2097
2633
  const initialCtx = session.getContextState();
2098
- const [contextState, setContextState] = (0, import_react13.useState)({
2634
+ const [contextState, setContextState] = (0, import_react16.useState)({
2099
2635
  percentage: initialCtx.usedPercentage,
2100
2636
  usedTokens: initialCtx.usedTokens,
2101
2637
  maxTokens: initialCtx.maxTokens
2102
2638
  });
2103
- const pendingModelChangeRef = (0, import_react13.useRef)(null);
2104
- const [pendingModelId, setPendingModelId] = (0, import_react13.useState)(null);
2639
+ const pendingModelChangeRef = (0, import_react16.useRef)(null);
2640
+ const [pendingModelId, setPendingModelId] = (0, import_react16.useState)(null);
2641
+ const [showPluginTUI, setShowPluginTUI] = (0, import_react16.useState)(false);
2105
2642
  const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
2106
2643
  const handleSlashCommand = useSlashCommands(
2107
2644
  session,
@@ -2111,7 +2648,8 @@ function App(props) {
2111
2648
  registry,
2112
2649
  pendingModelChangeRef,
2113
2650
  setPendingModelId,
2114
- pluginCallbacks
2651
+ pluginCallbacks,
2652
+ setShowPluginTUI
2115
2653
  );
2116
2654
  const handleSubmit = useSubmitHandler(
2117
2655
  session,
@@ -2122,33 +2660,33 @@ function App(props) {
2122
2660
  setContextState,
2123
2661
  registry
2124
2662
  );
2125
- (0, import_ink11.useInput)(
2663
+ (0, import_ink13.useInput)(
2126
2664
  (_input, key) => {
2127
2665
  if (key.ctrl && _input === "c") exit();
2128
2666
  if (key.escape && isThinking) session.abort();
2129
2667
  },
2130
- { isActive: !permissionRequest }
2668
+ { isActive: !permissionRequest && !showPluginTUI }
2131
2669
  );
2132
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", children: [
2133
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2134
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "cyan", bold: true, children: `
2670
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2671
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2672
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { color: "cyan", bold: true, children: `
2135
2673
  ____ ___ ____ ___ _____ _
2136
2674
  | _ \\ / _ \\| __ ) / _ \\_ _|/ \\
2137
2675
  | |_) | | | | _ \\| | | || | / _ \\
2138
2676
  | _ <| |_| | |_) | |_| || |/ ___ \\
2139
2677
  |_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
2140
2678
  ` }),
2141
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { dimColor: true, children: [
2679
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Text, { dimColor: true, children: [
2142
2680
  " v",
2143
2681
  props.version ?? "0.0.0"
2144
2682
  ] })
2145
2683
  ] }),
2146
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2147
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MessageList, { messages }),
2148
- isThinking && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
2684
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2685
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageList, { messages }),
2686
+ isThinking && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
2149
2687
  ] }),
2150
- permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PermissionPrompt, { request: permissionRequest }),
2151
- pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2688
+ permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PermissionPrompt, { request: permissionRequest }),
2689
+ pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2152
2690
  ConfirmPrompt,
2153
2691
  {
2154
2692
  message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
@@ -2176,7 +2714,15 @@ function App(props) {
2176
2714
  }
2177
2715
  }
2178
2716
  ),
2179
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2717
+ showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2718
+ PluginTUI,
2719
+ {
2720
+ callbacks: pluginCallbacks,
2721
+ onClose: () => setShowPluginTUI(false),
2722
+ addMessage: (msg) => addMessage(msg)
2723
+ }
2724
+ ),
2725
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2180
2726
  StatusBar,
2181
2727
  {
2182
2728
  permissionMode: session.getPermissionMode(),
@@ -2189,20 +2735,20 @@ function App(props) {
2189
2735
  contextMaxTokens: contextState.maxTokens
2190
2736
  }
2191
2737
  ),
2192
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2738
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2193
2739
  InputArea,
2194
2740
  {
2195
2741
  onSubmit: handleSubmit,
2196
- isDisabled: isThinking || !!permissionRequest,
2742
+ isDisabled: isThinking || !!permissionRequest || showPluginTUI,
2197
2743
  registry
2198
2744
  }
2199
2745
  ),
2200
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { children: " " })
2746
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { children: " " })
2201
2747
  ] });
2202
2748
  }
2203
2749
 
2204
2750
  // src/ui/render.tsx
2205
- var import_jsx_runtime12 = require("react/jsx-runtime");
2751
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2206
2752
  function renderApp(options) {
2207
2753
  process.on("unhandledRejection", (reason) => {
2208
2754
  process.stderr.write(`
@@ -2213,7 +2759,7 @@ function renderApp(options) {
2213
2759
  `);
2214
2760
  }
2215
2761
  });
2216
- const instance = (0, import_ink12.render)(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(App, { ...options }), {
2762
+ const instance = (0, import_ink14.render)(/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(App, { ...options }), {
2217
2763
  exitOnCtrlC: true
2218
2764
  });
2219
2765
  instance.waitUntilExit().catch((err) => {
@@ -2228,9 +2774,9 @@ function renderApp(options) {
2228
2774
  // src/cli.ts
2229
2775
  var import_meta = {};
2230
2776
  function checkSettingsFile(filePath) {
2231
- if (!(0, import_node_fs3.existsSync)(filePath)) return "missing";
2777
+ if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
2232
2778
  try {
2233
- const raw = (0, import_node_fs3.readFileSync)(filePath, "utf8").trim();
2779
+ const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8").trim();
2234
2780
  if (raw.length === 0) return "incomplete";
2235
2781
  const parsed = JSON.parse(raw);
2236
2782
  const provider = parsed.provider;
@@ -2247,7 +2793,7 @@ function readVersion() {
2247
2793
  const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
2248
2794
  for (const pkgPath of candidates) {
2249
2795
  try {
2250
- const raw = (0, import_node_fs3.readFileSync)(pkgPath, "utf-8");
2796
+ const raw = (0, import_node_fs4.readFileSync)(pkgPath, "utf-8");
2251
2797
  const pkg = JSON.parse(raw);
2252
2798
  if (pkg.version !== void 0 && pkg.name !== void 0) {
2253
2799
  return pkg.version;
@@ -2335,7 +2881,7 @@ async function ensureConfig(cwd) {
2335
2881
  }
2336
2882
  const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
2337
2883
  const settingsDir = (0, import_node_path5.dirname)(userPath);
2338
- (0, import_node_fs3.mkdirSync)(settingsDir, { recursive: true });
2884
+ (0, import_node_fs4.mkdirSync)(settingsDir, { recursive: true });
2339
2885
  const settings = {
2340
2886
  provider: {
2341
2887
  name: "anthropic",
@@ -2346,7 +2892,7 @@ async function ensureConfig(cwd) {
2346
2892
  if (language) {
2347
2893
  settings.language = language;
2348
2894
  }
2349
- (0, import_node_fs3.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
2895
+ (0, import_node_fs4.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
2350
2896
  process.stdout.write(`
2351
2897
  Config saved to ${userPath}
2352
2898