@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 +639 -93
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-EPCRZIQ6.js → chunk-27OPEZHA.js} +629 -83
- package/dist/node/index.cjs +639 -93
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
package/dist/node/index.cjs
CHANGED
|
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
40
40
|
var import_agent_sdk7 = require("@robota-sdk/agent-sdk");
|
|
41
41
|
|
|
42
42
|
// src/cli.ts
|
|
43
|
-
var
|
|
43
|
+
var import_node_fs4 = require("fs");
|
|
44
44
|
var import_node_path5 = require("path");
|
|
45
45
|
var import_node_url = require("url");
|
|
46
46
|
var import_agent_sdk5 = require("@robota-sdk/agent-sdk");
|
|
@@ -179,11 +179,11 @@ var PrintTerminal = class {
|
|
|
179
179
|
};
|
|
180
180
|
|
|
181
181
|
// src/ui/render.tsx
|
|
182
|
-
var
|
|
182
|
+
var import_ink14 = require("ink");
|
|
183
183
|
|
|
184
184
|
// src/ui/App.tsx
|
|
185
|
-
var
|
|
186
|
-
var
|
|
185
|
+
var import_react16 = require("react");
|
|
186
|
+
var import_ink13 = require("ink");
|
|
187
187
|
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
188
188
|
|
|
189
189
|
// src/ui/hooks/useSession.ts
|
|
@@ -191,25 +191,69 @@ var import_react = require("react");
|
|
|
191
191
|
var import_agent_sdk = require("@robota-sdk/agent-sdk");
|
|
192
192
|
|
|
193
193
|
// src/utils/edit-diff.ts
|
|
194
|
-
|
|
194
|
+
var import_node_fs2 = require("fs");
|
|
195
|
+
var CONTEXT_LINES = 2;
|
|
196
|
+
function generateDiffLines(oldStr, newStr, startLine = 1) {
|
|
195
197
|
if (oldStr === newStr) return [];
|
|
196
198
|
const lines = [];
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
const oldLines = oldStr.split("\n");
|
|
200
|
+
const newLines = newStr.split("\n");
|
|
201
|
+
for (let i = 0; i < oldLines.length; i++) {
|
|
202
|
+
lines.push({ type: "remove", text: oldLines[i], lineNumber: startLine + i });
|
|
199
203
|
}
|
|
200
|
-
for (
|
|
201
|
-
lines.push({ type: "add", text:
|
|
204
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
205
|
+
lines.push({ type: "add", text: newLines[i], lineNumber: startLine + i });
|
|
202
206
|
}
|
|
203
207
|
return lines;
|
|
204
208
|
}
|
|
205
|
-
function
|
|
209
|
+
function generateDiffLinesWithContext(oldStr, newStr, startLine, filePath) {
|
|
210
|
+
if (oldStr === newStr) return [];
|
|
211
|
+
const diffLines = generateDiffLines(oldStr, newStr, startLine);
|
|
212
|
+
let fileLines;
|
|
213
|
+
try {
|
|
214
|
+
fileLines = (0, import_node_fs2.readFileSync)(filePath, "utf-8").split("\n");
|
|
215
|
+
} catch {
|
|
216
|
+
return diffLines;
|
|
217
|
+
}
|
|
218
|
+
const result = [];
|
|
219
|
+
const contextStart = Math.max(0, startLine - 1 - CONTEXT_LINES);
|
|
220
|
+
for (let i = contextStart; i < startLine - 1; i++) {
|
|
221
|
+
if (i < fileLines.length) {
|
|
222
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
result.push(...diffLines);
|
|
226
|
+
const newLineCount = newStr.split("\n").length;
|
|
227
|
+
const afterStart = startLine - 1 + newLineCount;
|
|
228
|
+
for (let i = afterStart; i < afterStart + CONTEXT_LINES; i++) {
|
|
229
|
+
if (i < fileLines.length) {
|
|
230
|
+
result.push({ type: "context", text: fileLines[i], lineNumber: i + 1 });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
function extractEditDiff(toolName, toolArgs, startLine) {
|
|
206
236
|
if (toolName !== "Edit" || !toolArgs) return null;
|
|
207
237
|
const filePath = toolArgs.file_path ?? toolArgs.filePath;
|
|
208
238
|
const oldStr = toolArgs.old_string ?? toolArgs.oldString;
|
|
209
239
|
const newStr = toolArgs.new_string ?? toolArgs.newString;
|
|
210
240
|
if (typeof filePath !== "string") return null;
|
|
211
241
|
if (typeof oldStr !== "string" || typeof newStr !== "string") return null;
|
|
212
|
-
|
|
242
|
+
let sl = startLine ?? 0;
|
|
243
|
+
if (!sl) {
|
|
244
|
+
try {
|
|
245
|
+
const fileContent = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
246
|
+
const idx = fileContent.indexOf(newStr);
|
|
247
|
+
if (idx >= 0) {
|
|
248
|
+
sl = fileContent.substring(0, idx).split("\n").length;
|
|
249
|
+
} else {
|
|
250
|
+
sl = 1;
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
sl = 1;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const lines = generateDiffLinesWithContext(oldStr, newStr, sl, filePath);
|
|
213
257
|
if (lines.length === 0) return null;
|
|
214
258
|
return { file: filePath, lines };
|
|
215
259
|
}
|
|
@@ -287,9 +331,20 @@ function useSession(props) {
|
|
|
287
331
|
setActiveTools((prev) => {
|
|
288
332
|
const updated = prev.map((t) => {
|
|
289
333
|
if (!(t.toolName === event.toolName && t.isRunning)) return t;
|
|
334
|
+
let startLine;
|
|
335
|
+
if (event.toolResultData && event.toolName === "Edit") {
|
|
336
|
+
try {
|
|
337
|
+
const parsed = JSON.parse(event.toolResultData);
|
|
338
|
+
if (typeof parsed.startLine === "number") {
|
|
339
|
+
startLine = parsed.startLine;
|
|
340
|
+
}
|
|
341
|
+
} catch {
|
|
342
|
+
}
|
|
343
|
+
}
|
|
290
344
|
const editDiff = extractEditDiff(
|
|
291
345
|
event.toolName,
|
|
292
|
-
t._toolArgs
|
|
346
|
+
t._toolArgs,
|
|
347
|
+
startLine
|
|
293
348
|
);
|
|
294
349
|
const finished = {
|
|
295
350
|
...t,
|
|
@@ -481,18 +536,9 @@ async function handlePluginCommand(args, addMessage, callbacks) {
|
|
|
481
536
|
try {
|
|
482
537
|
switch (subcommand) {
|
|
483
538
|
case "":
|
|
484
|
-
case void 0:
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
addMessage({ role: "system", content: "No plugins installed." });
|
|
488
|
-
} else {
|
|
489
|
-
const lines = plugins.map(
|
|
490
|
-
(p) => ` ${p.name} \u2014 ${p.description} [${p.enabled ? "enabled" : "disabled"}]`
|
|
491
|
-
);
|
|
492
|
-
addMessage({ role: "system", content: `Installed plugins:
|
|
493
|
-
${lines.join("\n")}` });
|
|
494
|
-
}
|
|
495
|
-
return { handled: true };
|
|
539
|
+
case void 0:
|
|
540
|
+
case "manage": {
|
|
541
|
+
return { handled: true, triggerPluginTUI: true };
|
|
496
542
|
}
|
|
497
543
|
case "install": {
|
|
498
544
|
if (!subArgs) {
|
|
@@ -639,7 +685,7 @@ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages
|
|
|
639
685
|
|
|
640
686
|
// src/ui/hooks/useSlashCommands.ts
|
|
641
687
|
var EXIT_DELAY_MS = 500;
|
|
642
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks) {
|
|
688
|
+
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks, setShowPluginTUI) {
|
|
643
689
|
return (0, import_react3.useCallback)(
|
|
644
690
|
async (input) => {
|
|
645
691
|
const parts = input.slice(1).split(/\s+/);
|
|
@@ -659,6 +705,9 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
659
705
|
pendingModelChangeRef.current = result.pendingModelId;
|
|
660
706
|
setPendingModelId(result.pendingModelId);
|
|
661
707
|
}
|
|
708
|
+
if (result.triggerPluginTUI) {
|
|
709
|
+
setShowPluginTUI?.(true);
|
|
710
|
+
}
|
|
662
711
|
if (result.exitRequested) {
|
|
663
712
|
setTimeout(() => exit(), EXIT_DELAY_MS);
|
|
664
713
|
}
|
|
@@ -672,7 +721,8 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
672
721
|
registry,
|
|
673
722
|
pendingModelChangeRef,
|
|
674
723
|
setPendingModelId,
|
|
675
|
-
pluginCallbacks
|
|
724
|
+
pluginCallbacks,
|
|
725
|
+
setShowPluginTUI
|
|
676
726
|
]
|
|
677
727
|
);
|
|
678
728
|
}
|
|
@@ -1056,22 +1106,7 @@ function createBuiltinCommands() {
|
|
|
1056
1106
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
1057
1107
|
{ name: "context", description: "Context window info", source: "builtin" },
|
|
1058
1108
|
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
1059
|
-
{
|
|
1060
|
-
name: "plugin",
|
|
1061
|
-
description: "Manage plugins",
|
|
1062
|
-
source: "builtin",
|
|
1063
|
-
subcommands: [
|
|
1064
|
-
{ name: "install", description: "Install a plugin (name@marketplace)", source: "builtin" },
|
|
1065
|
-
{
|
|
1066
|
-
name: "uninstall",
|
|
1067
|
-
description: "Uninstall a plugin (name@marketplace)",
|
|
1068
|
-
source: "builtin"
|
|
1069
|
-
},
|
|
1070
|
-
{ name: "enable", description: "Enable a plugin (name@marketplace)", source: "builtin" },
|
|
1071
|
-
{ name: "disable", description: "Disable a plugin (name@marketplace)", source: "builtin" },
|
|
1072
|
-
{ name: "marketplace", description: "Manage marketplace sources", source: "builtin" }
|
|
1073
|
-
]
|
|
1074
|
-
},
|
|
1109
|
+
{ name: "plugin", description: "Manage plugins", source: "builtin" },
|
|
1075
1110
|
{ name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
|
|
1076
1111
|
{ name: "reset", description: "Delete settings and exit", source: "builtin" },
|
|
1077
1112
|
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
@@ -1089,7 +1124,7 @@ var BuiltinCommandSource = class {
|
|
|
1089
1124
|
};
|
|
1090
1125
|
|
|
1091
1126
|
// src/commands/skill-source.ts
|
|
1092
|
-
var
|
|
1127
|
+
var import_node_fs3 = require("fs");
|
|
1093
1128
|
var import_node_path2 = require("path");
|
|
1094
1129
|
var import_node_os = require("os");
|
|
1095
1130
|
var BOOLEAN_KEYS = /* @__PURE__ */ new Set(["disable-model-invocation", "user-invocable"]);
|
|
@@ -1138,27 +1173,27 @@ function buildCommand(frontmatter, content, fallbackName) {
|
|
|
1138
1173
|
return cmd;
|
|
1139
1174
|
}
|
|
1140
1175
|
function scanSkillsDir(skillsDir) {
|
|
1141
|
-
if (!(0,
|
|
1176
|
+
if (!(0, import_node_fs3.existsSync)(skillsDir)) return [];
|
|
1142
1177
|
const commands = [];
|
|
1143
|
-
const entries = (0,
|
|
1178
|
+
const entries = (0, import_node_fs3.readdirSync)(skillsDir, { withFileTypes: true });
|
|
1144
1179
|
for (const entry of entries) {
|
|
1145
1180
|
if (!entry.isDirectory()) continue;
|
|
1146
1181
|
const skillFile = (0, import_node_path2.join)(skillsDir, entry.name, "SKILL.md");
|
|
1147
|
-
if (!(0,
|
|
1148
|
-
const content = (0,
|
|
1182
|
+
if (!(0, import_node_fs3.existsSync)(skillFile)) continue;
|
|
1183
|
+
const content = (0, import_node_fs3.readFileSync)(skillFile, "utf-8");
|
|
1149
1184
|
const frontmatter = parseFrontmatter(content);
|
|
1150
1185
|
commands.push(buildCommand(frontmatter, content, entry.name));
|
|
1151
1186
|
}
|
|
1152
1187
|
return commands;
|
|
1153
1188
|
}
|
|
1154
1189
|
function scanCommandsDir(commandsDir) {
|
|
1155
|
-
if (!(0,
|
|
1190
|
+
if (!(0, import_node_fs3.existsSync)(commandsDir)) return [];
|
|
1156
1191
|
const commands = [];
|
|
1157
|
-
const entries = (0,
|
|
1192
|
+
const entries = (0, import_node_fs3.readdirSync)(commandsDir, { withFileTypes: true });
|
|
1158
1193
|
for (const entry of entries) {
|
|
1159
1194
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1160
1195
|
const filePath = (0, import_node_path2.join)(commandsDir, entry.name);
|
|
1161
|
-
const content = (0,
|
|
1196
|
+
const content = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
|
|
1162
1197
|
const frontmatter = parseFrontmatter(content);
|
|
1163
1198
|
const fallbackName = (0, import_node_path2.basename)(entry.name, ".md");
|
|
1164
1199
|
commands.push(buildCommand(frontmatter, content, fallbackName));
|
|
@@ -1338,18 +1373,50 @@ function usePluginCallbacks(cwd) {
|
|
|
1338
1373
|
return {
|
|
1339
1374
|
listInstalled: async () => {
|
|
1340
1375
|
const plugins = await loader.loadAll();
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1376
|
+
const enabledMap = settingsStore.getEnabledPlugins();
|
|
1377
|
+
return plugins.map((p) => {
|
|
1378
|
+
const parts = p.pluginDir.split("/");
|
|
1379
|
+
const cacheIdx = parts.indexOf("cache");
|
|
1380
|
+
const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] : "";
|
|
1381
|
+
const fullId = marketplaceName ? `${p.manifest.name}@${marketplaceName}` : p.manifest.name;
|
|
1382
|
+
return {
|
|
1383
|
+
name: fullId,
|
|
1384
|
+
description: p.manifest.description,
|
|
1385
|
+
enabled: enabledMap[fullId] !== false && enabledMap[p.manifest.name] !== false
|
|
1386
|
+
};
|
|
1387
|
+
});
|
|
1388
|
+
},
|
|
1389
|
+
listAvailablePlugins: async (marketplaceName) => {
|
|
1390
|
+
let manifest;
|
|
1391
|
+
try {
|
|
1392
|
+
manifest = marketplace.fetchManifest(marketplaceName);
|
|
1393
|
+
} catch {
|
|
1394
|
+
return [];
|
|
1395
|
+
}
|
|
1396
|
+
const installed = installer.getInstalledPlugins();
|
|
1397
|
+
const installedNames = new Set(Object.values(installed).map((r) => r.pluginName));
|
|
1398
|
+
return manifest.plugins.map((p) => ({
|
|
1399
|
+
name: p.name,
|
|
1400
|
+
description: p.description,
|
|
1401
|
+
installed: installedNames.has(p.name)
|
|
1345
1402
|
}));
|
|
1346
1403
|
},
|
|
1347
|
-
install: async (pluginId) => {
|
|
1404
|
+
install: async (pluginId, scope) => {
|
|
1348
1405
|
const [name, marketplaceName] = pluginId.split("@");
|
|
1349
1406
|
if (!name || !marketplaceName) {
|
|
1350
1407
|
throw new Error("Plugin ID must be in format: name@marketplace");
|
|
1351
1408
|
}
|
|
1352
|
-
|
|
1409
|
+
if (scope === "project") {
|
|
1410
|
+
const projectPluginsDir = (0, import_node_path4.join)(cwd, ".robota", "plugins");
|
|
1411
|
+
const projectInstaller = new import_agent_sdk4.BundlePluginInstaller({
|
|
1412
|
+
pluginsDir: projectPluginsDir,
|
|
1413
|
+
settingsStore,
|
|
1414
|
+
marketplaceClient: marketplace
|
|
1415
|
+
});
|
|
1416
|
+
await projectInstaller.install(name, marketplaceName);
|
|
1417
|
+
} else {
|
|
1418
|
+
await installer.install(name, marketplaceName);
|
|
1419
|
+
}
|
|
1353
1420
|
},
|
|
1354
1421
|
uninstall: async (pluginId) => {
|
|
1355
1422
|
await installer.uninstall(pluginId);
|
|
@@ -1407,23 +1474,41 @@ function renderMarkdown(md) {
|
|
|
1407
1474
|
// src/ui/DiffBlock.tsx
|
|
1408
1475
|
var import_ink = require("ink");
|
|
1409
1476
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1410
|
-
var MAX_DIFF_LINES =
|
|
1411
|
-
var TRUNCATED_SHOW =
|
|
1477
|
+
var MAX_DIFF_LINES = 12;
|
|
1478
|
+
var TRUNCATED_SHOW = 10;
|
|
1412
1479
|
function DiffBlock({ file, lines }) {
|
|
1413
1480
|
const truncated = lines.length > MAX_DIFF_LINES;
|
|
1414
1481
|
const visible = truncated ? lines.slice(0, TRUNCATED_SHOW) : lines;
|
|
1415
1482
|
const remaining = lines.length - TRUNCATED_SHOW;
|
|
1483
|
+
const maxLineNum = Math.max(...visible.map((l) => l.lineNumber), 0);
|
|
1484
|
+
const numWidth = String(maxLineNum).length;
|
|
1416
1485
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
1417
1486
|
file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1418
1487
|
"\u2502 ",
|
|
1419
1488
|
file
|
|
1420
1489
|
] }),
|
|
1421
|
-
visible.map((line, i) =>
|
|
1422
|
-
"
|
|
1423
|
-
line.type === "
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1490
|
+
visible.map((line, i) => {
|
|
1491
|
+
const lineNum = String(line.lineNumber).padStart(numWidth, " ");
|
|
1492
|
+
if (line.type === "context") {
|
|
1493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1494
|
+
"\u2502 ",
|
|
1495
|
+
lineNum,
|
|
1496
|
+
" ",
|
|
1497
|
+
line.text
|
|
1498
|
+
] }, i);
|
|
1499
|
+
}
|
|
1500
|
+
const prefix = line.type === "remove" ? "-" : "+";
|
|
1501
|
+
const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
|
|
1502
|
+
const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
|
|
1503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: fgColor, backgroundColor: bgColor, children: [
|
|
1504
|
+
"\u2502 ",
|
|
1505
|
+
lineNum,
|
|
1506
|
+
" ",
|
|
1507
|
+
prefix,
|
|
1508
|
+
" ",
|
|
1509
|
+
line.text
|
|
1510
|
+
] }, i);
|
|
1511
|
+
}),
|
|
1427
1512
|
truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
|
|
1428
1513
|
"\u2502 ... and ",
|
|
1429
1514
|
remaining,
|
|
@@ -2076,8 +2161,459 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2076
2161
|
] });
|
|
2077
2162
|
}
|
|
2078
2163
|
|
|
2079
|
-
// src/ui/
|
|
2164
|
+
// src/ui/PluginTUI.tsx
|
|
2165
|
+
var import_react15 = require("react");
|
|
2166
|
+
|
|
2167
|
+
// src/ui/MenuSelect.tsx
|
|
2168
|
+
var import_react13 = require("react");
|
|
2169
|
+
var import_ink11 = require("ink");
|
|
2080
2170
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2171
|
+
function MenuSelect({
|
|
2172
|
+
title,
|
|
2173
|
+
items,
|
|
2174
|
+
onSelect,
|
|
2175
|
+
onBack,
|
|
2176
|
+
loading,
|
|
2177
|
+
error
|
|
2178
|
+
}) {
|
|
2179
|
+
const [selected, setSelected] = (0, import_react13.useState)(0);
|
|
2180
|
+
const selectedRef = (0, import_react13.useRef)(0);
|
|
2181
|
+
const resolvedRef = (0, import_react13.useRef)(false);
|
|
2182
|
+
const doSelect = (0, import_react13.useCallback)(
|
|
2183
|
+
(index) => {
|
|
2184
|
+
if (resolvedRef.current || items.length === 0) return;
|
|
2185
|
+
resolvedRef.current = true;
|
|
2186
|
+
onSelect(items[index].value);
|
|
2187
|
+
},
|
|
2188
|
+
[items, onSelect]
|
|
2189
|
+
);
|
|
2190
|
+
(0, import_ink11.useInput)((input, key) => {
|
|
2191
|
+
if (resolvedRef.current) return;
|
|
2192
|
+
if (key.escape) {
|
|
2193
|
+
resolvedRef.current = true;
|
|
2194
|
+
onBack();
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
if (loading || error || items.length === 0) return;
|
|
2198
|
+
if (key.upArrow) {
|
|
2199
|
+
const next = selectedRef.current > 0 ? selectedRef.current - 1 : selectedRef.current;
|
|
2200
|
+
selectedRef.current = next;
|
|
2201
|
+
setSelected(next);
|
|
2202
|
+
} else if (key.downArrow) {
|
|
2203
|
+
const next = selectedRef.current < items.length - 1 ? selectedRef.current + 1 : selectedRef.current;
|
|
2204
|
+
selectedRef.current = next;
|
|
2205
|
+
setSelected(next);
|
|
2206
|
+
} else if (key.return) {
|
|
2207
|
+
doSelect(selectedRef.current);
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
2210
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "yellow", bold: true, children: title }),
|
|
2212
|
+
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..." }) }),
|
|
2213
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { marginTop: 1, flexDirection: "column", children: [
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "red", children: error }),
|
|
2215
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: "Press Esc to go back" })
|
|
2216
|
+
] }),
|
|
2217
|
+
!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: [
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
2219
|
+
i === selected ? "> " : " ",
|
|
2220
|
+
item.label
|
|
2221
|
+
] }),
|
|
2222
|
+
item.hint && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { dimColor: true, children: [
|
|
2223
|
+
" ",
|
|
2224
|
+
item.hint
|
|
2225
|
+
] })
|
|
2226
|
+
] }, item.value)) }),
|
|
2227
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
|
|
2228
|
+
] });
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
// src/ui/TextPrompt.tsx
|
|
2232
|
+
var import_react14 = require("react");
|
|
2233
|
+
var import_ink12 = require("ink");
|
|
2234
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2235
|
+
function TextPrompt({
|
|
2236
|
+
title,
|
|
2237
|
+
placeholder,
|
|
2238
|
+
onSubmit,
|
|
2239
|
+
onCancel,
|
|
2240
|
+
validate
|
|
2241
|
+
}) {
|
|
2242
|
+
const [value, setValue] = (0, import_react14.useState)("");
|
|
2243
|
+
const [error, setError] = (0, import_react14.useState)();
|
|
2244
|
+
const resolvedRef = (0, import_react14.useRef)(false);
|
|
2245
|
+
const valueRef = (0, import_react14.useRef)("");
|
|
2246
|
+
const handleSubmit = (0, import_react14.useCallback)(() => {
|
|
2247
|
+
if (resolvedRef.current) return;
|
|
2248
|
+
const trimmed = valueRef.current.trim();
|
|
2249
|
+
if (!trimmed) return;
|
|
2250
|
+
if (validate) {
|
|
2251
|
+
const err = validate(trimmed);
|
|
2252
|
+
if (err) {
|
|
2253
|
+
setError(err);
|
|
2254
|
+
return;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
resolvedRef.current = true;
|
|
2258
|
+
onSubmit(trimmed);
|
|
2259
|
+
}, [validate, onSubmit]);
|
|
2260
|
+
(0, import_ink12.useInput)((input, key) => {
|
|
2261
|
+
if (resolvedRef.current) return;
|
|
2262
|
+
if (key.escape) {
|
|
2263
|
+
resolvedRef.current = true;
|
|
2264
|
+
onCancel();
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
if (key.return) {
|
|
2268
|
+
handleSubmit();
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2271
|
+
if (key.backspace || key.delete) {
|
|
2272
|
+
valueRef.current = valueRef.current.slice(0, -1);
|
|
2273
|
+
setValue(valueRef.current);
|
|
2274
|
+
setError(void 0);
|
|
2275
|
+
return;
|
|
2276
|
+
}
|
|
2277
|
+
if (input && !key.ctrl && !key.meta) {
|
|
2278
|
+
valueRef.current = valueRef.current + input;
|
|
2279
|
+
setValue(valueRef.current);
|
|
2280
|
+
setError(void 0);
|
|
2281
|
+
}
|
|
2282
|
+
});
|
|
2283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "yellow", bold: true, children: title }),
|
|
2285
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { marginTop: 1, children: [
|
|
2286
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "> " }),
|
|
2287
|
+
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,
|
|
2288
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "\u2588" })
|
|
2289
|
+
] }),
|
|
2290
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "red", children: error }),
|
|
2291
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { dimColor: true, children: " Enter Submit Esc Cancel" })
|
|
2292
|
+
] });
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
// src/ui/plugin-tui-handlers.ts
|
|
2296
|
+
function handleMainSelect(value, nav) {
|
|
2297
|
+
if (value === "marketplace") {
|
|
2298
|
+
nav.push({ screen: "marketplace-list" });
|
|
2299
|
+
} else if (value === "installed") {
|
|
2300
|
+
nav.push({ screen: "installed-list" });
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
function handleMarketplaceListSelect(value, nav) {
|
|
2304
|
+
if (value === "__add__") {
|
|
2305
|
+
nav.push({ screen: "marketplace-add" });
|
|
2306
|
+
} else {
|
|
2307
|
+
nav.push({ screen: "marketplace-action", context: { marketplace: value } });
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
function handleMarketplaceActionSelect(value, marketplace, callbacks, nav) {
|
|
2311
|
+
if (value === "browse") {
|
|
2312
|
+
nav.push({ screen: "marketplace-browse", context: { marketplace } });
|
|
2313
|
+
} else if (value === "update") {
|
|
2314
|
+
callbacks.marketplaceUpdate(marketplace).then(() => {
|
|
2315
|
+
nav.notify(`Updated marketplace "${marketplace}".`);
|
|
2316
|
+
nav.pop();
|
|
2317
|
+
}).catch((err) => {
|
|
2318
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2319
|
+
});
|
|
2320
|
+
} else if (value === "remove") {
|
|
2321
|
+
nav.setConfirm({
|
|
2322
|
+
message: `Remove marketplace "${marketplace}" and all its plugins?`,
|
|
2323
|
+
onConfirm: () => {
|
|
2324
|
+
nav.setConfirm(void 0);
|
|
2325
|
+
callbacks.marketplaceRemove(marketplace).then(() => {
|
|
2326
|
+
nav.notify(`Removed marketplace "${marketplace}".`);
|
|
2327
|
+
nav.popN(2);
|
|
2328
|
+
}).catch((err) => {
|
|
2329
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2330
|
+
});
|
|
2331
|
+
},
|
|
2332
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
function handleMarketplaceBrowseSelect(value, marketplace, items, nav) {
|
|
2337
|
+
const fullId = `${value}@${marketplace}`;
|
|
2338
|
+
const item = items.find((i) => i.value === value);
|
|
2339
|
+
if (item?.hint === "installed") {
|
|
2340
|
+
nav.push({ screen: "installed-action", context: { pluginId: fullId } });
|
|
2341
|
+
} else {
|
|
2342
|
+
nav.push({ screen: "marketplace-install-scope", context: { marketplace, pluginId: fullId } });
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
function handleInstallScopeSelect(value, pluginId, callbacks, nav) {
|
|
2346
|
+
const scope = value;
|
|
2347
|
+
callbacks.install(pluginId, scope).then(() => {
|
|
2348
|
+
nav.notify(`Installed plugin "${pluginId}" (${scope} scope).`);
|
|
2349
|
+
nav.popN(2);
|
|
2350
|
+
}).catch((err) => {
|
|
2351
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
2354
|
+
function handleInstalledListSelect(value, callbacks, nav) {
|
|
2355
|
+
nav.setConfirm({
|
|
2356
|
+
message: `Uninstall plugin "${value}"?`,
|
|
2357
|
+
onConfirm: () => {
|
|
2358
|
+
nav.setConfirm(void 0);
|
|
2359
|
+
callbacks.uninstall(value).then(() => {
|
|
2360
|
+
nav.notify(`Uninstalled plugin "${value}".`);
|
|
2361
|
+
nav.refresh();
|
|
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
|
+
function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
|
|
2370
|
+
if (value === "uninstall") {
|
|
2371
|
+
nav.setConfirm({
|
|
2372
|
+
message: `Uninstall plugin "${pluginId}"?`,
|
|
2373
|
+
onConfirm: () => {
|
|
2374
|
+
nav.setConfirm(void 0);
|
|
2375
|
+
callbacks.uninstall(pluginId).then(() => {
|
|
2376
|
+
nav.notify(`Uninstalled plugin "${pluginId}".`);
|
|
2377
|
+
nav.popN(2);
|
|
2378
|
+
}).catch((err) => {
|
|
2379
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2380
|
+
});
|
|
2381
|
+
},
|
|
2382
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
// src/ui/PluginTUI.tsx
|
|
2388
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2389
|
+
function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
2390
|
+
const [stack, setStack] = (0, import_react15.useState)([{ screen: "main" }]);
|
|
2391
|
+
const [items, setItems] = (0, import_react15.useState)([]);
|
|
2392
|
+
const [loading, setLoading] = (0, import_react15.useState)(false);
|
|
2393
|
+
const [error, setError] = (0, import_react15.useState)();
|
|
2394
|
+
const [confirm, setConfirm] = (0, import_react15.useState)();
|
|
2395
|
+
const [refreshCounter, setRefreshCounter] = (0, import_react15.useState)(0);
|
|
2396
|
+
const current = stack[stack.length - 1] ?? { screen: "main" };
|
|
2397
|
+
const push = (0, import_react15.useCallback)((state) => {
|
|
2398
|
+
setStack((prev) => [...prev, state]);
|
|
2399
|
+
setItems([]);
|
|
2400
|
+
setError(void 0);
|
|
2401
|
+
}, []);
|
|
2402
|
+
const pop = (0, import_react15.useCallback)(() => {
|
|
2403
|
+
setStack((prev) => {
|
|
2404
|
+
if (prev.length <= 1) {
|
|
2405
|
+
onClose();
|
|
2406
|
+
return prev;
|
|
2407
|
+
}
|
|
2408
|
+
return prev.slice(0, -1);
|
|
2409
|
+
});
|
|
2410
|
+
setItems([]);
|
|
2411
|
+
setError(void 0);
|
|
2412
|
+
}, [onClose]);
|
|
2413
|
+
const popN = (0, import_react15.useCallback)(
|
|
2414
|
+
(n) => {
|
|
2415
|
+
setStack((prev) => {
|
|
2416
|
+
const next = prev.slice(0, Math.max(1, prev.length - n));
|
|
2417
|
+
if (next.length === 0) {
|
|
2418
|
+
onClose();
|
|
2419
|
+
return prev;
|
|
2420
|
+
}
|
|
2421
|
+
return next;
|
|
2422
|
+
});
|
|
2423
|
+
setItems([]);
|
|
2424
|
+
setError(void 0);
|
|
2425
|
+
},
|
|
2426
|
+
[onClose]
|
|
2427
|
+
);
|
|
2428
|
+
const notify = (0, import_react15.useCallback)(
|
|
2429
|
+
(content) => {
|
|
2430
|
+
addMessage?.({ role: "system", content });
|
|
2431
|
+
},
|
|
2432
|
+
[addMessage]
|
|
2433
|
+
);
|
|
2434
|
+
const refresh = (0, import_react15.useCallback)(() => {
|
|
2435
|
+
setItems([]);
|
|
2436
|
+
setRefreshCounter((c) => c + 1);
|
|
2437
|
+
}, []);
|
|
2438
|
+
const nav = { push, pop, popN, notify, setConfirm, refresh };
|
|
2439
|
+
(0, import_react15.useEffect)(() => {
|
|
2440
|
+
const screen2 = current.screen;
|
|
2441
|
+
if (screen2 === "marketplace-list") {
|
|
2442
|
+
setLoading(true);
|
|
2443
|
+
callbacks.marketplaceList().then((sources) => {
|
|
2444
|
+
const baseItems = [{ label: "Add Marketplace", value: "__add__" }];
|
|
2445
|
+
const sourceItems = sources.map((s) => ({
|
|
2446
|
+
label: s.name,
|
|
2447
|
+
value: s.name,
|
|
2448
|
+
hint: s.type
|
|
2449
|
+
}));
|
|
2450
|
+
setItems([...baseItems, ...sourceItems]);
|
|
2451
|
+
setLoading(false);
|
|
2452
|
+
}).catch((err) => {
|
|
2453
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2454
|
+
setLoading(false);
|
|
2455
|
+
});
|
|
2456
|
+
} else if (screen2 === "marketplace-browse") {
|
|
2457
|
+
const marketplace = current.context?.marketplace ?? "";
|
|
2458
|
+
setLoading(true);
|
|
2459
|
+
callbacks.listAvailablePlugins(marketplace).then((plugins) => {
|
|
2460
|
+
setItems(
|
|
2461
|
+
plugins.map((p) => ({
|
|
2462
|
+
label: p.name,
|
|
2463
|
+
value: p.name,
|
|
2464
|
+
hint: p.installed ? "installed" : p.description
|
|
2465
|
+
}))
|
|
2466
|
+
);
|
|
2467
|
+
setLoading(false);
|
|
2468
|
+
}).catch((err) => {
|
|
2469
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2470
|
+
setLoading(false);
|
|
2471
|
+
});
|
|
2472
|
+
} else if (screen2 === "installed-list") {
|
|
2473
|
+
setLoading(true);
|
|
2474
|
+
callbacks.listInstalled().then((plugins) => {
|
|
2475
|
+
setItems(
|
|
2476
|
+
plugins.map((p) => ({
|
|
2477
|
+
label: p.name,
|
|
2478
|
+
value: p.name,
|
|
2479
|
+
hint: p.description
|
|
2480
|
+
}))
|
|
2481
|
+
);
|
|
2482
|
+
setLoading(false);
|
|
2483
|
+
}).catch((err) => {
|
|
2484
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2485
|
+
setLoading(false);
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2488
|
+
}, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
|
|
2489
|
+
const handleSelect = (0, import_react15.useCallback)(
|
|
2490
|
+
(value) => {
|
|
2491
|
+
const screen2 = current.screen;
|
|
2492
|
+
const ctx = current.context;
|
|
2493
|
+
if (screen2 === "main") handleMainSelect(value, nav);
|
|
2494
|
+
else if (screen2 === "marketplace-list") handleMarketplaceListSelect(value, nav);
|
|
2495
|
+
else if (screen2 === "marketplace-action")
|
|
2496
|
+
handleMarketplaceActionSelect(value, ctx?.marketplace ?? "", callbacks, nav);
|
|
2497
|
+
else if (screen2 === "marketplace-browse")
|
|
2498
|
+
handleMarketplaceBrowseSelect(value, ctx?.marketplace ?? "", items, nav);
|
|
2499
|
+
else if (screen2 === "marketplace-install-scope")
|
|
2500
|
+
handleInstallScopeSelect(value, ctx?.pluginId ?? "", callbacks, nav);
|
|
2501
|
+
else if (screen2 === "installed-list") handleInstalledListSelect(value, callbacks, nav);
|
|
2502
|
+
else if (screen2 === "installed-action")
|
|
2503
|
+
handleInstalledActionSelect(value, ctx?.pluginId ?? "", callbacks, nav);
|
|
2504
|
+
},
|
|
2505
|
+
[current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
|
|
2506
|
+
);
|
|
2507
|
+
const handleTextSubmit = (0, import_react15.useCallback)(
|
|
2508
|
+
(value) => {
|
|
2509
|
+
if (current.screen === "marketplace-add") {
|
|
2510
|
+
callbacks.marketplaceAdd(value).then((name) => {
|
|
2511
|
+
notify(`Added marketplace "${name}" from ${value}.`);
|
|
2512
|
+
pop();
|
|
2513
|
+
}).catch((err) => {
|
|
2514
|
+
notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2515
|
+
pop();
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
},
|
|
2519
|
+
[current.screen, callbacks, notify, pop]
|
|
2520
|
+
);
|
|
2521
|
+
if (confirm) {
|
|
2522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2523
|
+
ConfirmPrompt,
|
|
2524
|
+
{
|
|
2525
|
+
message: confirm.message,
|
|
2526
|
+
onSelect: (index) => {
|
|
2527
|
+
if (index === 0) confirm.onConfirm();
|
|
2528
|
+
else confirm.onCancel();
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
const screen = current.screen;
|
|
2534
|
+
if (screen === "marketplace-add") {
|
|
2535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2536
|
+
TextPrompt,
|
|
2537
|
+
{
|
|
2538
|
+
title: "Add Marketplace Source",
|
|
2539
|
+
placeholder: "owner/repo or git URL",
|
|
2540
|
+
onSubmit: handleTextSubmit,
|
|
2541
|
+
onCancel: pop,
|
|
2542
|
+
validate: (v) => !v.includes("/") ? "Must be owner/repo or a git URL" : void 0
|
|
2543
|
+
}
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
if (screen === "marketplace-action") {
|
|
2547
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2548
|
+
MenuSelect,
|
|
2549
|
+
{
|
|
2550
|
+
title: `Marketplace: ${current.context?.marketplace ?? ""}`,
|
|
2551
|
+
items: [
|
|
2552
|
+
{ label: "Browse plugins", value: "browse" },
|
|
2553
|
+
{ label: "Update", value: "update" },
|
|
2554
|
+
{ label: "Remove", value: "remove" }
|
|
2555
|
+
],
|
|
2556
|
+
onSelect: handleSelect,
|
|
2557
|
+
onBack: pop
|
|
2558
|
+
},
|
|
2559
|
+
stack.length
|
|
2560
|
+
);
|
|
2561
|
+
}
|
|
2562
|
+
if (screen === "marketplace-install-scope") {
|
|
2563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2564
|
+
MenuSelect,
|
|
2565
|
+
{
|
|
2566
|
+
title: `Install scope for "${current.context?.pluginId ?? ""}"`,
|
|
2567
|
+
items: [
|
|
2568
|
+
{ label: "User scope", value: "user" },
|
|
2569
|
+
{ label: "Project scope", value: "project" }
|
|
2570
|
+
],
|
|
2571
|
+
onSelect: handleSelect,
|
|
2572
|
+
onBack: pop
|
|
2573
|
+
},
|
|
2574
|
+
stack.length
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
if (screen === "installed-action") {
|
|
2578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2579
|
+
MenuSelect,
|
|
2580
|
+
{
|
|
2581
|
+
title: `Plugin: ${current.context?.pluginId ?? ""}`,
|
|
2582
|
+
items: [{ label: "Uninstall", value: "uninstall" }],
|
|
2583
|
+
onSelect: handleSelect,
|
|
2584
|
+
onBack: pop
|
|
2585
|
+
},
|
|
2586
|
+
stack.length
|
|
2587
|
+
);
|
|
2588
|
+
}
|
|
2589
|
+
const titleMap = {
|
|
2590
|
+
main: "Plugin Management",
|
|
2591
|
+
"marketplace-list": "Marketplace",
|
|
2592
|
+
"marketplace-browse": `Browse: ${current.context?.marketplace ?? ""}`,
|
|
2593
|
+
"installed-list": "Installed Plugins"
|
|
2594
|
+
};
|
|
2595
|
+
const staticItemsMap = {
|
|
2596
|
+
main: [
|
|
2597
|
+
{ label: "Marketplace", value: "marketplace" },
|
|
2598
|
+
{ label: "Installed Plugins", value: "installed" }
|
|
2599
|
+
]
|
|
2600
|
+
};
|
|
2601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2602
|
+
MenuSelect,
|
|
2603
|
+
{
|
|
2604
|
+
title: titleMap[screen] ?? "Plugin Management",
|
|
2605
|
+
items: staticItemsMap[screen] ?? items,
|
|
2606
|
+
onSelect: handleSelect,
|
|
2607
|
+
onBack: pop,
|
|
2608
|
+
loading,
|
|
2609
|
+
error
|
|
2610
|
+
},
|
|
2611
|
+
`${screen}-${stack.length}-${refreshCounter}`
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// src/ui/App.tsx
|
|
2616
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2081
2617
|
var EXIT_DELAY_MS2 = 500;
|
|
2082
2618
|
function mergeHooksIntoConfig(configHooks, pluginHooks) {
|
|
2083
2619
|
const pluginKeys = Object.keys(pluginHooks);
|
|
@@ -2096,7 +2632,7 @@ function mergeHooksIntoConfig(configHooks, pluginHooks) {
|
|
|
2096
2632
|
return merged;
|
|
2097
2633
|
}
|
|
2098
2634
|
function App(props) {
|
|
2099
|
-
const { exit } = (0,
|
|
2635
|
+
const { exit } = (0, import_ink13.useApp)();
|
|
2100
2636
|
const { registry, pluginHooks } = useCommandRegistry(props.cwd ?? process.cwd());
|
|
2101
2637
|
const configWithPluginHooks = {
|
|
2102
2638
|
...props.config,
|
|
@@ -2109,15 +2645,16 @@ function App(props) {
|
|
|
2109
2645
|
{ ...props, config: configWithPluginHooks }
|
|
2110
2646
|
);
|
|
2111
2647
|
const { messages, setMessages, addMessage } = useMessages();
|
|
2112
|
-
const [isThinking, setIsThinking] = (0,
|
|
2648
|
+
const [isThinking, setIsThinking] = (0, import_react16.useState)(false);
|
|
2113
2649
|
const initialCtx = session.getContextState();
|
|
2114
|
-
const [contextState, setContextState] = (0,
|
|
2650
|
+
const [contextState, setContextState] = (0, import_react16.useState)({
|
|
2115
2651
|
percentage: initialCtx.usedPercentage,
|
|
2116
2652
|
usedTokens: initialCtx.usedTokens,
|
|
2117
2653
|
maxTokens: initialCtx.maxTokens
|
|
2118
2654
|
});
|
|
2119
|
-
const pendingModelChangeRef = (0,
|
|
2120
|
-
const [pendingModelId, setPendingModelId] = (0,
|
|
2655
|
+
const pendingModelChangeRef = (0, import_react16.useRef)(null);
|
|
2656
|
+
const [pendingModelId, setPendingModelId] = (0, import_react16.useState)(null);
|
|
2657
|
+
const [showPluginTUI, setShowPluginTUI] = (0, import_react16.useState)(false);
|
|
2121
2658
|
const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
|
|
2122
2659
|
const handleSlashCommand = useSlashCommands(
|
|
2123
2660
|
session,
|
|
@@ -2127,7 +2664,8 @@ function App(props) {
|
|
|
2127
2664
|
registry,
|
|
2128
2665
|
pendingModelChangeRef,
|
|
2129
2666
|
setPendingModelId,
|
|
2130
|
-
pluginCallbacks
|
|
2667
|
+
pluginCallbacks,
|
|
2668
|
+
setShowPluginTUI
|
|
2131
2669
|
);
|
|
2132
2670
|
const handleSubmit = useSubmitHandler(
|
|
2133
2671
|
session,
|
|
@@ -2138,33 +2676,33 @@ function App(props) {
|
|
|
2138
2676
|
setContextState,
|
|
2139
2677
|
registry
|
|
2140
2678
|
);
|
|
2141
|
-
(0,
|
|
2679
|
+
(0, import_ink13.useInput)(
|
|
2142
2680
|
(_input, key) => {
|
|
2143
2681
|
if (key.ctrl && _input === "c") exit();
|
|
2144
2682
|
if (key.escape && isThinking) session.abort();
|
|
2145
2683
|
},
|
|
2146
|
-
{ isActive: !permissionRequest }
|
|
2684
|
+
{ isActive: !permissionRequest && !showPluginTUI }
|
|
2147
2685
|
);
|
|
2148
|
-
return /* @__PURE__ */ (0,
|
|
2149
|
-
/* @__PURE__ */ (0,
|
|
2150
|
-
/* @__PURE__ */ (0,
|
|
2686
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
|
|
2687
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { color: "cyan", bold: true, children: `
|
|
2151
2689
|
____ ___ ____ ___ _____ _
|
|
2152
2690
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
2153
2691
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
2154
2692
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
2155
2693
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
2156
2694
|
` }),
|
|
2157
|
-
/* @__PURE__ */ (0,
|
|
2695
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Text, { dimColor: true, children: [
|
|
2158
2696
|
" v",
|
|
2159
2697
|
props.version ?? "0.0.0"
|
|
2160
2698
|
] })
|
|
2161
2699
|
] }),
|
|
2162
|
-
/* @__PURE__ */ (0,
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2164
|
-
isThinking && /* @__PURE__ */ (0,
|
|
2700
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
2701
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageList, { messages }),
|
|
2702
|
+
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 }) })
|
|
2165
2703
|
] }),
|
|
2166
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
2167
|
-
pendingModelId && /* @__PURE__ */ (0,
|
|
2704
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
2705
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2168
2706
|
ConfirmPrompt,
|
|
2169
2707
|
{
|
|
2170
2708
|
message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
@@ -2192,7 +2730,15 @@ function App(props) {
|
|
|
2192
2730
|
}
|
|
2193
2731
|
}
|
|
2194
2732
|
),
|
|
2195
|
-
/* @__PURE__ */ (0,
|
|
2733
|
+
showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2734
|
+
PluginTUI,
|
|
2735
|
+
{
|
|
2736
|
+
callbacks: pluginCallbacks,
|
|
2737
|
+
onClose: () => setShowPluginTUI(false),
|
|
2738
|
+
addMessage: (msg) => addMessage(msg)
|
|
2739
|
+
}
|
|
2740
|
+
),
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2196
2742
|
StatusBar,
|
|
2197
2743
|
{
|
|
2198
2744
|
permissionMode: session.getPermissionMode(),
|
|
@@ -2205,20 +2751,20 @@ function App(props) {
|
|
|
2205
2751
|
contextMaxTokens: contextState.maxTokens
|
|
2206
2752
|
}
|
|
2207
2753
|
),
|
|
2208
|
-
/* @__PURE__ */ (0,
|
|
2754
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2209
2755
|
InputArea,
|
|
2210
2756
|
{
|
|
2211
2757
|
onSubmit: handleSubmit,
|
|
2212
|
-
isDisabled: isThinking || !!permissionRequest,
|
|
2758
|
+
isDisabled: isThinking || !!permissionRequest || showPluginTUI,
|
|
2213
2759
|
registry
|
|
2214
2760
|
}
|
|
2215
2761
|
),
|
|
2216
|
-
/* @__PURE__ */ (0,
|
|
2762
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { children: " " })
|
|
2217
2763
|
] });
|
|
2218
2764
|
}
|
|
2219
2765
|
|
|
2220
2766
|
// src/ui/render.tsx
|
|
2221
|
-
var
|
|
2767
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2222
2768
|
function renderApp(options) {
|
|
2223
2769
|
process.on("unhandledRejection", (reason) => {
|
|
2224
2770
|
process.stderr.write(`
|
|
@@ -2229,7 +2775,7 @@ function renderApp(options) {
|
|
|
2229
2775
|
`);
|
|
2230
2776
|
}
|
|
2231
2777
|
});
|
|
2232
|
-
const instance = (0,
|
|
2778
|
+
const instance = (0, import_ink14.render)(/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(App, { ...options }), {
|
|
2233
2779
|
exitOnCtrlC: true
|
|
2234
2780
|
});
|
|
2235
2781
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -2244,9 +2790,9 @@ function renderApp(options) {
|
|
|
2244
2790
|
// src/cli.ts
|
|
2245
2791
|
var import_meta = {};
|
|
2246
2792
|
function checkSettingsFile(filePath) {
|
|
2247
|
-
if (!(0,
|
|
2793
|
+
if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
|
|
2248
2794
|
try {
|
|
2249
|
-
const raw = (0,
|
|
2795
|
+
const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8").trim();
|
|
2250
2796
|
if (raw.length === 0) return "incomplete";
|
|
2251
2797
|
const parsed = JSON.parse(raw);
|
|
2252
2798
|
const provider = parsed.provider;
|
|
@@ -2263,7 +2809,7 @@ function readVersion() {
|
|
|
2263
2809
|
const candidates = [(0, import_node_path5.join)(dir, "..", "..", "package.json"), (0, import_node_path5.join)(dir, "..", "package.json")];
|
|
2264
2810
|
for (const pkgPath of candidates) {
|
|
2265
2811
|
try {
|
|
2266
|
-
const raw = (0,
|
|
2812
|
+
const raw = (0, import_node_fs4.readFileSync)(pkgPath, "utf-8");
|
|
2267
2813
|
const pkg = JSON.parse(raw);
|
|
2268
2814
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
2269
2815
|
return pkg.version;
|
|
@@ -2351,7 +2897,7 @@ async function ensureConfig(cwd) {
|
|
|
2351
2897
|
}
|
|
2352
2898
|
const language = await promptInput(" Response language (ko/en/ja/zh, default: en): ");
|
|
2353
2899
|
const settingsDir = (0, import_node_path5.dirname)(userPath);
|
|
2354
|
-
(0,
|
|
2900
|
+
(0, import_node_fs4.mkdirSync)(settingsDir, { recursive: true });
|
|
2355
2901
|
const settings = {
|
|
2356
2902
|
provider: {
|
|
2357
2903
|
name: "anthropic",
|
|
@@ -2362,7 +2908,7 @@ async function ensureConfig(cwd) {
|
|
|
2362
2908
|
if (language) {
|
|
2363
2909
|
settings.language = language;
|
|
2364
2910
|
}
|
|
2365
|
-
(0,
|
|
2911
|
+
(0, import_node_fs4.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
2366
2912
|
process.stdout.write(`
|
|
2367
2913
|
Config saved to ${userPath}
|
|
2368
2914
|
|