@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/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
|
|
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
|
|
166
|
+
var import_ink14 = require("ink");
|
|
167
167
|
|
|
168
168
|
// src/ui/App.tsx
|
|
169
|
-
var
|
|
170
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
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 (
|
|
185
|
-
lines.push({ type: "add", text:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
470
|
-
|
|
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
|
|
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,
|
|
1160
|
+
if (!(0, import_node_fs3.existsSync)(skillsDir)) return [];
|
|
1126
1161
|
const commands = [];
|
|
1127
|
-
const entries = (0,
|
|
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,
|
|
1132
|
-
const content = (0,
|
|
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,
|
|
1174
|
+
if (!(0, import_node_fs3.existsSync)(commandsDir)) return [];
|
|
1140
1175
|
const commands = [];
|
|
1141
|
-
const entries = (0,
|
|
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,
|
|
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
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
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
|
-
|
|
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 =
|
|
1395
|
-
var TRUNCATED_SHOW =
|
|
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) =>
|
|
1406
|
-
"
|
|
1407
|
-
line.type === "
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
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/
|
|
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,
|
|
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,
|
|
2632
|
+
const [isThinking, setIsThinking] = (0, import_react16.useState)(false);
|
|
2097
2633
|
const initialCtx = session.getContextState();
|
|
2098
|
-
const [contextState, setContextState] = (0,
|
|
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,
|
|
2104
|
-
const [pendingModelId, setPendingModelId] = (0,
|
|
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,
|
|
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,
|
|
2133
|
-
/* @__PURE__ */ (0,
|
|
2134
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2147
|
-
/* @__PURE__ */ (0,
|
|
2148
|
-
isThinking && /* @__PURE__ */ (0,
|
|
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,
|
|
2151
|
-
pendingModelId && /* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
2777
|
+
if (!(0, import_node_fs4.existsSync)(filePath)) return "missing";
|
|
2232
2778
|
try {
|
|
2233
|
-
const raw = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|