@robota-sdk/agent-cli 3.0.0-beta.34 → 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 +536 -63
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-RDPIMQOC.js → chunk-27OPEZHA.js} +534 -61
- package/dist/node/index.cjs +536 -63
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
|
@@ -149,8 +149,8 @@ var PrintTerminal = class {
|
|
|
149
149
|
import { render } from "ink";
|
|
150
150
|
|
|
151
151
|
// src/ui/App.tsx
|
|
152
|
-
import { useState as
|
|
153
|
-
import { Box as
|
|
152
|
+
import { useState as useState10, useRef as useRef8 } from "react";
|
|
153
|
+
import { Box as Box11, Text as Text13, useApp, useInput as useInput7 } from "ink";
|
|
154
154
|
import { getModelName } from "@robota-sdk/agent-core";
|
|
155
155
|
|
|
156
156
|
// src/ui/hooks/useSession.ts
|
|
@@ -503,18 +503,9 @@ async function handlePluginCommand(args, addMessage, callbacks) {
|
|
|
503
503
|
try {
|
|
504
504
|
switch (subcommand) {
|
|
505
505
|
case "":
|
|
506
|
-
case void 0:
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
addMessage({ role: "system", content: "No plugins installed." });
|
|
510
|
-
} else {
|
|
511
|
-
const lines = plugins.map(
|
|
512
|
-
(p) => ` ${p.name} \u2014 ${p.description} [${p.enabled ? "enabled" : "disabled"}]`
|
|
513
|
-
);
|
|
514
|
-
addMessage({ role: "system", content: `Installed plugins:
|
|
515
|
-
${lines.join("\n")}` });
|
|
516
|
-
}
|
|
517
|
-
return { handled: true };
|
|
506
|
+
case void 0:
|
|
507
|
+
case "manage": {
|
|
508
|
+
return { handled: true, triggerPluginTUI: true };
|
|
518
509
|
}
|
|
519
510
|
case "install": {
|
|
520
511
|
if (!subArgs) {
|
|
@@ -661,7 +652,7 @@ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages
|
|
|
661
652
|
|
|
662
653
|
// src/ui/hooks/useSlashCommands.ts
|
|
663
654
|
var EXIT_DELAY_MS = 500;
|
|
664
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks) {
|
|
655
|
+
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks, setShowPluginTUI) {
|
|
665
656
|
return useCallback3(
|
|
666
657
|
async (input) => {
|
|
667
658
|
const parts = input.slice(1).split(/\s+/);
|
|
@@ -681,6 +672,9 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
681
672
|
pendingModelChangeRef.current = result.pendingModelId;
|
|
682
673
|
setPendingModelId(result.pendingModelId);
|
|
683
674
|
}
|
|
675
|
+
if (result.triggerPluginTUI) {
|
|
676
|
+
setShowPluginTUI?.(true);
|
|
677
|
+
}
|
|
684
678
|
if (result.exitRequested) {
|
|
685
679
|
setTimeout(() => exit(), EXIT_DELAY_MS);
|
|
686
680
|
}
|
|
@@ -694,7 +688,8 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
694
688
|
registry,
|
|
695
689
|
pendingModelChangeRef,
|
|
696
690
|
setPendingModelId,
|
|
697
|
-
pluginCallbacks
|
|
691
|
+
pluginCallbacks,
|
|
692
|
+
setShowPluginTUI
|
|
698
693
|
]
|
|
699
694
|
);
|
|
700
695
|
}
|
|
@@ -1082,22 +1077,7 @@ function createBuiltinCommands() {
|
|
|
1082
1077
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
1083
1078
|
{ name: "context", description: "Context window info", source: "builtin" },
|
|
1084
1079
|
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
1085
|
-
{
|
|
1086
|
-
name: "plugin",
|
|
1087
|
-
description: "Manage plugins",
|
|
1088
|
-
source: "builtin",
|
|
1089
|
-
subcommands: [
|
|
1090
|
-
{ name: "install", description: "Install a plugin (name@marketplace)", source: "builtin" },
|
|
1091
|
-
{
|
|
1092
|
-
name: "uninstall",
|
|
1093
|
-
description: "Uninstall a plugin (name@marketplace)",
|
|
1094
|
-
source: "builtin"
|
|
1095
|
-
},
|
|
1096
|
-
{ name: "enable", description: "Enable a plugin (name@marketplace)", source: "builtin" },
|
|
1097
|
-
{ name: "disable", description: "Disable a plugin (name@marketplace)", source: "builtin" },
|
|
1098
|
-
{ name: "marketplace", description: "Manage marketplace sources", source: "builtin" }
|
|
1099
|
-
]
|
|
1100
|
-
},
|
|
1080
|
+
{ name: "plugin", description: "Manage plugins", source: "builtin" },
|
|
1101
1081
|
{ name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
|
|
1102
1082
|
{ name: "reset", description: "Delete settings and exit", source: "builtin" },
|
|
1103
1083
|
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
@@ -1369,18 +1349,50 @@ function usePluginCallbacks(cwd) {
|
|
|
1369
1349
|
return {
|
|
1370
1350
|
listInstalled: async () => {
|
|
1371
1351
|
const plugins = await loader.loadAll();
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1352
|
+
const enabledMap = settingsStore.getEnabledPlugins();
|
|
1353
|
+
return plugins.map((p) => {
|
|
1354
|
+
const parts = p.pluginDir.split("/");
|
|
1355
|
+
const cacheIdx = parts.indexOf("cache");
|
|
1356
|
+
const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] : "";
|
|
1357
|
+
const fullId = marketplaceName ? `${p.manifest.name}@${marketplaceName}` : p.manifest.name;
|
|
1358
|
+
return {
|
|
1359
|
+
name: fullId,
|
|
1360
|
+
description: p.manifest.description,
|
|
1361
|
+
enabled: enabledMap[fullId] !== false && enabledMap[p.manifest.name] !== false
|
|
1362
|
+
};
|
|
1363
|
+
});
|
|
1364
|
+
},
|
|
1365
|
+
listAvailablePlugins: async (marketplaceName) => {
|
|
1366
|
+
let manifest;
|
|
1367
|
+
try {
|
|
1368
|
+
manifest = marketplace.fetchManifest(marketplaceName);
|
|
1369
|
+
} catch {
|
|
1370
|
+
return [];
|
|
1371
|
+
}
|
|
1372
|
+
const installed = installer.getInstalledPlugins();
|
|
1373
|
+
const installedNames = new Set(Object.values(installed).map((r) => r.pluginName));
|
|
1374
|
+
return manifest.plugins.map((p) => ({
|
|
1375
|
+
name: p.name,
|
|
1376
|
+
description: p.description,
|
|
1377
|
+
installed: installedNames.has(p.name)
|
|
1376
1378
|
}));
|
|
1377
1379
|
},
|
|
1378
|
-
install: async (pluginId) => {
|
|
1380
|
+
install: async (pluginId, scope) => {
|
|
1379
1381
|
const [name, marketplaceName] = pluginId.split("@");
|
|
1380
1382
|
if (!name || !marketplaceName) {
|
|
1381
1383
|
throw new Error("Plugin ID must be in format: name@marketplace");
|
|
1382
1384
|
}
|
|
1383
|
-
|
|
1385
|
+
if (scope === "project") {
|
|
1386
|
+
const projectPluginsDir = join4(cwd, ".robota", "plugins");
|
|
1387
|
+
const projectInstaller = new BundlePluginInstaller({
|
|
1388
|
+
pluginsDir: projectPluginsDir,
|
|
1389
|
+
settingsStore,
|
|
1390
|
+
marketplaceClient: marketplace
|
|
1391
|
+
});
|
|
1392
|
+
await projectInstaller.install(name, marketplaceName);
|
|
1393
|
+
} else {
|
|
1394
|
+
await installer.install(name, marketplaceName);
|
|
1395
|
+
}
|
|
1384
1396
|
},
|
|
1385
1397
|
uninstall: async (pluginId) => {
|
|
1386
1398
|
await installer.uninstall(pluginId);
|
|
@@ -2125,8 +2137,459 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2125
2137
|
] });
|
|
2126
2138
|
}
|
|
2127
2139
|
|
|
2128
|
-
// src/ui/
|
|
2140
|
+
// src/ui/PluginTUI.tsx
|
|
2141
|
+
import { useState as useState9, useEffect as useEffect2, useCallback as useCallback9 } from "react";
|
|
2142
|
+
|
|
2143
|
+
// src/ui/MenuSelect.tsx
|
|
2144
|
+
import { useState as useState7, useCallback as useCallback7, useRef as useRef6 } from "react";
|
|
2145
|
+
import { Box as Box9, Text as Text11, useInput as useInput5 } from "ink";
|
|
2129
2146
|
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2147
|
+
function MenuSelect({
|
|
2148
|
+
title,
|
|
2149
|
+
items,
|
|
2150
|
+
onSelect,
|
|
2151
|
+
onBack,
|
|
2152
|
+
loading,
|
|
2153
|
+
error
|
|
2154
|
+
}) {
|
|
2155
|
+
const [selected, setSelected] = useState7(0);
|
|
2156
|
+
const selectedRef = useRef6(0);
|
|
2157
|
+
const resolvedRef = useRef6(false);
|
|
2158
|
+
const doSelect = useCallback7(
|
|
2159
|
+
(index) => {
|
|
2160
|
+
if (resolvedRef.current || items.length === 0) return;
|
|
2161
|
+
resolvedRef.current = true;
|
|
2162
|
+
onSelect(items[index].value);
|
|
2163
|
+
},
|
|
2164
|
+
[items, onSelect]
|
|
2165
|
+
);
|
|
2166
|
+
useInput5((input, key) => {
|
|
2167
|
+
if (resolvedRef.current) return;
|
|
2168
|
+
if (key.escape) {
|
|
2169
|
+
resolvedRef.current = true;
|
|
2170
|
+
onBack();
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
if (loading || error || items.length === 0) return;
|
|
2174
|
+
if (key.upArrow) {
|
|
2175
|
+
const next = selectedRef.current > 0 ? selectedRef.current - 1 : selectedRef.current;
|
|
2176
|
+
selectedRef.current = next;
|
|
2177
|
+
setSelected(next);
|
|
2178
|
+
} else if (key.downArrow) {
|
|
2179
|
+
const next = selectedRef.current < items.length - 1 ? selectedRef.current + 1 : selectedRef.current;
|
|
2180
|
+
selectedRef.current = next;
|
|
2181
|
+
setSelected(next);
|
|
2182
|
+
} else if (key.return) {
|
|
2183
|
+
doSelect(selectedRef.current);
|
|
2184
|
+
}
|
|
2185
|
+
});
|
|
2186
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2187
|
+
/* @__PURE__ */ jsx10(Text11, { color: "yellow", bold: true, children: title }),
|
|
2188
|
+
loading && /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "Loading..." }) }),
|
|
2189
|
+
error && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2190
|
+
/* @__PURE__ */ jsx10(Text11, { color: "red", children: error }),
|
|
2191
|
+
/* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "Press Esc to go back" })
|
|
2192
|
+
] }),
|
|
2193
|
+
!loading && !error && /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2194
|
+
/* @__PURE__ */ jsxs9(Text11, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
2195
|
+
i === selected ? "> " : " ",
|
|
2196
|
+
item.label
|
|
2197
|
+
] }),
|
|
2198
|
+
item.hint && /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
|
|
2199
|
+
" ",
|
|
2200
|
+
item.hint
|
|
2201
|
+
] })
|
|
2202
|
+
] }, item.value)) }),
|
|
2203
|
+
/* @__PURE__ */ jsx10(Text11, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
|
|
2204
|
+
] });
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
// src/ui/TextPrompt.tsx
|
|
2208
|
+
import { useState as useState8, useRef as useRef7, useCallback as useCallback8 } from "react";
|
|
2209
|
+
import { Box as Box10, Text as Text12, useInput as useInput6 } from "ink";
|
|
2210
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2211
|
+
function TextPrompt({
|
|
2212
|
+
title,
|
|
2213
|
+
placeholder,
|
|
2214
|
+
onSubmit,
|
|
2215
|
+
onCancel,
|
|
2216
|
+
validate
|
|
2217
|
+
}) {
|
|
2218
|
+
const [value, setValue] = useState8("");
|
|
2219
|
+
const [error, setError] = useState8();
|
|
2220
|
+
const resolvedRef = useRef7(false);
|
|
2221
|
+
const valueRef = useRef7("");
|
|
2222
|
+
const handleSubmit = useCallback8(() => {
|
|
2223
|
+
if (resolvedRef.current) return;
|
|
2224
|
+
const trimmed = valueRef.current.trim();
|
|
2225
|
+
if (!trimmed) return;
|
|
2226
|
+
if (validate) {
|
|
2227
|
+
const err = validate(trimmed);
|
|
2228
|
+
if (err) {
|
|
2229
|
+
setError(err);
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
resolvedRef.current = true;
|
|
2234
|
+
onSubmit(trimmed);
|
|
2235
|
+
}, [validate, onSubmit]);
|
|
2236
|
+
useInput6((input, key) => {
|
|
2237
|
+
if (resolvedRef.current) return;
|
|
2238
|
+
if (key.escape) {
|
|
2239
|
+
resolvedRef.current = true;
|
|
2240
|
+
onCancel();
|
|
2241
|
+
return;
|
|
2242
|
+
}
|
|
2243
|
+
if (key.return) {
|
|
2244
|
+
handleSubmit();
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
if (key.backspace || key.delete) {
|
|
2248
|
+
valueRef.current = valueRef.current.slice(0, -1);
|
|
2249
|
+
setValue(valueRef.current);
|
|
2250
|
+
setError(void 0);
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
2253
|
+
if (input && !key.ctrl && !key.meta) {
|
|
2254
|
+
valueRef.current = valueRef.current + input;
|
|
2255
|
+
setValue(valueRef.current);
|
|
2256
|
+
setError(void 0);
|
|
2257
|
+
}
|
|
2258
|
+
});
|
|
2259
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2260
|
+
/* @__PURE__ */ jsx11(Text12, { color: "yellow", bold: true, children: title }),
|
|
2261
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2262
|
+
/* @__PURE__ */ jsx11(Text12, { color: "cyan", children: "> " }),
|
|
2263
|
+
value ? /* @__PURE__ */ jsx11(Text12, { children: value }) : placeholder ? /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: placeholder }) : null,
|
|
2264
|
+
/* @__PURE__ */ jsx11(Text12, { color: "cyan", children: "\u2588" })
|
|
2265
|
+
] }),
|
|
2266
|
+
error && /* @__PURE__ */ jsx11(Text12, { color: "red", children: error }),
|
|
2267
|
+
/* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " Enter Submit Esc Cancel" })
|
|
2268
|
+
] });
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
// src/ui/plugin-tui-handlers.ts
|
|
2272
|
+
function handleMainSelect(value, nav) {
|
|
2273
|
+
if (value === "marketplace") {
|
|
2274
|
+
nav.push({ screen: "marketplace-list" });
|
|
2275
|
+
} else if (value === "installed") {
|
|
2276
|
+
nav.push({ screen: "installed-list" });
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
function handleMarketplaceListSelect(value, nav) {
|
|
2280
|
+
if (value === "__add__") {
|
|
2281
|
+
nav.push({ screen: "marketplace-add" });
|
|
2282
|
+
} else {
|
|
2283
|
+
nav.push({ screen: "marketplace-action", context: { marketplace: value } });
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
function handleMarketplaceActionSelect(value, marketplace, callbacks, nav) {
|
|
2287
|
+
if (value === "browse") {
|
|
2288
|
+
nav.push({ screen: "marketplace-browse", context: { marketplace } });
|
|
2289
|
+
} else if (value === "update") {
|
|
2290
|
+
callbacks.marketplaceUpdate(marketplace).then(() => {
|
|
2291
|
+
nav.notify(`Updated marketplace "${marketplace}".`);
|
|
2292
|
+
nav.pop();
|
|
2293
|
+
}).catch((err) => {
|
|
2294
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2295
|
+
});
|
|
2296
|
+
} else if (value === "remove") {
|
|
2297
|
+
nav.setConfirm({
|
|
2298
|
+
message: `Remove marketplace "${marketplace}" and all its plugins?`,
|
|
2299
|
+
onConfirm: () => {
|
|
2300
|
+
nav.setConfirm(void 0);
|
|
2301
|
+
callbacks.marketplaceRemove(marketplace).then(() => {
|
|
2302
|
+
nav.notify(`Removed marketplace "${marketplace}".`);
|
|
2303
|
+
nav.popN(2);
|
|
2304
|
+
}).catch((err) => {
|
|
2305
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2306
|
+
});
|
|
2307
|
+
},
|
|
2308
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
function handleMarketplaceBrowseSelect(value, marketplace, items, nav) {
|
|
2313
|
+
const fullId = `${value}@${marketplace}`;
|
|
2314
|
+
const item = items.find((i) => i.value === value);
|
|
2315
|
+
if (item?.hint === "installed") {
|
|
2316
|
+
nav.push({ screen: "installed-action", context: { pluginId: fullId } });
|
|
2317
|
+
} else {
|
|
2318
|
+
nav.push({ screen: "marketplace-install-scope", context: { marketplace, pluginId: fullId } });
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
function handleInstallScopeSelect(value, pluginId, callbacks, nav) {
|
|
2322
|
+
const scope = value;
|
|
2323
|
+
callbacks.install(pluginId, scope).then(() => {
|
|
2324
|
+
nav.notify(`Installed plugin "${pluginId}" (${scope} scope).`);
|
|
2325
|
+
nav.popN(2);
|
|
2326
|
+
}).catch((err) => {
|
|
2327
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
function handleInstalledListSelect(value, callbacks, nav) {
|
|
2331
|
+
nav.setConfirm({
|
|
2332
|
+
message: `Uninstall plugin "${value}"?`,
|
|
2333
|
+
onConfirm: () => {
|
|
2334
|
+
nav.setConfirm(void 0);
|
|
2335
|
+
callbacks.uninstall(value).then(() => {
|
|
2336
|
+
nav.notify(`Uninstalled plugin "${value}".`);
|
|
2337
|
+
nav.refresh();
|
|
2338
|
+
}).catch((err) => {
|
|
2339
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2340
|
+
});
|
|
2341
|
+
},
|
|
2342
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2343
|
+
});
|
|
2344
|
+
}
|
|
2345
|
+
function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
|
|
2346
|
+
if (value === "uninstall") {
|
|
2347
|
+
nav.setConfirm({
|
|
2348
|
+
message: `Uninstall plugin "${pluginId}"?`,
|
|
2349
|
+
onConfirm: () => {
|
|
2350
|
+
nav.setConfirm(void 0);
|
|
2351
|
+
callbacks.uninstall(pluginId).then(() => {
|
|
2352
|
+
nav.notify(`Uninstalled plugin "${pluginId}".`);
|
|
2353
|
+
nav.popN(2);
|
|
2354
|
+
}).catch((err) => {
|
|
2355
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2356
|
+
});
|
|
2357
|
+
},
|
|
2358
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
// src/ui/PluginTUI.tsx
|
|
2364
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
2365
|
+
function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
2366
|
+
const [stack, setStack] = useState9([{ screen: "main" }]);
|
|
2367
|
+
const [items, setItems] = useState9([]);
|
|
2368
|
+
const [loading, setLoading] = useState9(false);
|
|
2369
|
+
const [error, setError] = useState9();
|
|
2370
|
+
const [confirm, setConfirm] = useState9();
|
|
2371
|
+
const [refreshCounter, setRefreshCounter] = useState9(0);
|
|
2372
|
+
const current = stack[stack.length - 1] ?? { screen: "main" };
|
|
2373
|
+
const push = useCallback9((state) => {
|
|
2374
|
+
setStack((prev) => [...prev, state]);
|
|
2375
|
+
setItems([]);
|
|
2376
|
+
setError(void 0);
|
|
2377
|
+
}, []);
|
|
2378
|
+
const pop = useCallback9(() => {
|
|
2379
|
+
setStack((prev) => {
|
|
2380
|
+
if (prev.length <= 1) {
|
|
2381
|
+
onClose();
|
|
2382
|
+
return prev;
|
|
2383
|
+
}
|
|
2384
|
+
return prev.slice(0, -1);
|
|
2385
|
+
});
|
|
2386
|
+
setItems([]);
|
|
2387
|
+
setError(void 0);
|
|
2388
|
+
}, [onClose]);
|
|
2389
|
+
const popN = useCallback9(
|
|
2390
|
+
(n) => {
|
|
2391
|
+
setStack((prev) => {
|
|
2392
|
+
const next = prev.slice(0, Math.max(1, prev.length - n));
|
|
2393
|
+
if (next.length === 0) {
|
|
2394
|
+
onClose();
|
|
2395
|
+
return prev;
|
|
2396
|
+
}
|
|
2397
|
+
return next;
|
|
2398
|
+
});
|
|
2399
|
+
setItems([]);
|
|
2400
|
+
setError(void 0);
|
|
2401
|
+
},
|
|
2402
|
+
[onClose]
|
|
2403
|
+
);
|
|
2404
|
+
const notify = useCallback9(
|
|
2405
|
+
(content) => {
|
|
2406
|
+
addMessage?.({ role: "system", content });
|
|
2407
|
+
},
|
|
2408
|
+
[addMessage]
|
|
2409
|
+
);
|
|
2410
|
+
const refresh = useCallback9(() => {
|
|
2411
|
+
setItems([]);
|
|
2412
|
+
setRefreshCounter((c) => c + 1);
|
|
2413
|
+
}, []);
|
|
2414
|
+
const nav = { push, pop, popN, notify, setConfirm, refresh };
|
|
2415
|
+
useEffect2(() => {
|
|
2416
|
+
const screen2 = current.screen;
|
|
2417
|
+
if (screen2 === "marketplace-list") {
|
|
2418
|
+
setLoading(true);
|
|
2419
|
+
callbacks.marketplaceList().then((sources) => {
|
|
2420
|
+
const baseItems = [{ label: "Add Marketplace", value: "__add__" }];
|
|
2421
|
+
const sourceItems = sources.map((s) => ({
|
|
2422
|
+
label: s.name,
|
|
2423
|
+
value: s.name,
|
|
2424
|
+
hint: s.type
|
|
2425
|
+
}));
|
|
2426
|
+
setItems([...baseItems, ...sourceItems]);
|
|
2427
|
+
setLoading(false);
|
|
2428
|
+
}).catch((err) => {
|
|
2429
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2430
|
+
setLoading(false);
|
|
2431
|
+
});
|
|
2432
|
+
} else if (screen2 === "marketplace-browse") {
|
|
2433
|
+
const marketplace = current.context?.marketplace ?? "";
|
|
2434
|
+
setLoading(true);
|
|
2435
|
+
callbacks.listAvailablePlugins(marketplace).then((plugins) => {
|
|
2436
|
+
setItems(
|
|
2437
|
+
plugins.map((p) => ({
|
|
2438
|
+
label: p.name,
|
|
2439
|
+
value: p.name,
|
|
2440
|
+
hint: p.installed ? "installed" : p.description
|
|
2441
|
+
}))
|
|
2442
|
+
);
|
|
2443
|
+
setLoading(false);
|
|
2444
|
+
}).catch((err) => {
|
|
2445
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2446
|
+
setLoading(false);
|
|
2447
|
+
});
|
|
2448
|
+
} else if (screen2 === "installed-list") {
|
|
2449
|
+
setLoading(true);
|
|
2450
|
+
callbacks.listInstalled().then((plugins) => {
|
|
2451
|
+
setItems(
|
|
2452
|
+
plugins.map((p) => ({
|
|
2453
|
+
label: p.name,
|
|
2454
|
+
value: p.name,
|
|
2455
|
+
hint: p.description
|
|
2456
|
+
}))
|
|
2457
|
+
);
|
|
2458
|
+
setLoading(false);
|
|
2459
|
+
}).catch((err) => {
|
|
2460
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2461
|
+
setLoading(false);
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
}, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
|
|
2465
|
+
const handleSelect = useCallback9(
|
|
2466
|
+
(value) => {
|
|
2467
|
+
const screen2 = current.screen;
|
|
2468
|
+
const ctx = current.context;
|
|
2469
|
+
if (screen2 === "main") handleMainSelect(value, nav);
|
|
2470
|
+
else if (screen2 === "marketplace-list") handleMarketplaceListSelect(value, nav);
|
|
2471
|
+
else if (screen2 === "marketplace-action")
|
|
2472
|
+
handleMarketplaceActionSelect(value, ctx?.marketplace ?? "", callbacks, nav);
|
|
2473
|
+
else if (screen2 === "marketplace-browse")
|
|
2474
|
+
handleMarketplaceBrowseSelect(value, ctx?.marketplace ?? "", items, nav);
|
|
2475
|
+
else if (screen2 === "marketplace-install-scope")
|
|
2476
|
+
handleInstallScopeSelect(value, ctx?.pluginId ?? "", callbacks, nav);
|
|
2477
|
+
else if (screen2 === "installed-list") handleInstalledListSelect(value, callbacks, nav);
|
|
2478
|
+
else if (screen2 === "installed-action")
|
|
2479
|
+
handleInstalledActionSelect(value, ctx?.pluginId ?? "", callbacks, nav);
|
|
2480
|
+
},
|
|
2481
|
+
[current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
|
|
2482
|
+
);
|
|
2483
|
+
const handleTextSubmit = useCallback9(
|
|
2484
|
+
(value) => {
|
|
2485
|
+
if (current.screen === "marketplace-add") {
|
|
2486
|
+
callbacks.marketplaceAdd(value).then((name) => {
|
|
2487
|
+
notify(`Added marketplace "${name}" from ${value}.`);
|
|
2488
|
+
pop();
|
|
2489
|
+
}).catch((err) => {
|
|
2490
|
+
notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2491
|
+
pop();
|
|
2492
|
+
});
|
|
2493
|
+
}
|
|
2494
|
+
},
|
|
2495
|
+
[current.screen, callbacks, notify, pop]
|
|
2496
|
+
);
|
|
2497
|
+
if (confirm) {
|
|
2498
|
+
return /* @__PURE__ */ jsx12(
|
|
2499
|
+
ConfirmPrompt,
|
|
2500
|
+
{
|
|
2501
|
+
message: confirm.message,
|
|
2502
|
+
onSelect: (index) => {
|
|
2503
|
+
if (index === 0) confirm.onConfirm();
|
|
2504
|
+
else confirm.onCancel();
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
);
|
|
2508
|
+
}
|
|
2509
|
+
const screen = current.screen;
|
|
2510
|
+
if (screen === "marketplace-add") {
|
|
2511
|
+
return /* @__PURE__ */ jsx12(
|
|
2512
|
+
TextPrompt,
|
|
2513
|
+
{
|
|
2514
|
+
title: "Add Marketplace Source",
|
|
2515
|
+
placeholder: "owner/repo or git URL",
|
|
2516
|
+
onSubmit: handleTextSubmit,
|
|
2517
|
+
onCancel: pop,
|
|
2518
|
+
validate: (v) => !v.includes("/") ? "Must be owner/repo or a git URL" : void 0
|
|
2519
|
+
}
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
if (screen === "marketplace-action") {
|
|
2523
|
+
return /* @__PURE__ */ jsx12(
|
|
2524
|
+
MenuSelect,
|
|
2525
|
+
{
|
|
2526
|
+
title: `Marketplace: ${current.context?.marketplace ?? ""}`,
|
|
2527
|
+
items: [
|
|
2528
|
+
{ label: "Browse plugins", value: "browse" },
|
|
2529
|
+
{ label: "Update", value: "update" },
|
|
2530
|
+
{ label: "Remove", value: "remove" }
|
|
2531
|
+
],
|
|
2532
|
+
onSelect: handleSelect,
|
|
2533
|
+
onBack: pop
|
|
2534
|
+
},
|
|
2535
|
+
stack.length
|
|
2536
|
+
);
|
|
2537
|
+
}
|
|
2538
|
+
if (screen === "marketplace-install-scope") {
|
|
2539
|
+
return /* @__PURE__ */ jsx12(
|
|
2540
|
+
MenuSelect,
|
|
2541
|
+
{
|
|
2542
|
+
title: `Install scope for "${current.context?.pluginId ?? ""}"`,
|
|
2543
|
+
items: [
|
|
2544
|
+
{ label: "User scope", value: "user" },
|
|
2545
|
+
{ label: "Project scope", value: "project" }
|
|
2546
|
+
],
|
|
2547
|
+
onSelect: handleSelect,
|
|
2548
|
+
onBack: pop
|
|
2549
|
+
},
|
|
2550
|
+
stack.length
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
if (screen === "installed-action") {
|
|
2554
|
+
return /* @__PURE__ */ jsx12(
|
|
2555
|
+
MenuSelect,
|
|
2556
|
+
{
|
|
2557
|
+
title: `Plugin: ${current.context?.pluginId ?? ""}`,
|
|
2558
|
+
items: [{ label: "Uninstall", value: "uninstall" }],
|
|
2559
|
+
onSelect: handleSelect,
|
|
2560
|
+
onBack: pop
|
|
2561
|
+
},
|
|
2562
|
+
stack.length
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
const titleMap = {
|
|
2566
|
+
main: "Plugin Management",
|
|
2567
|
+
"marketplace-list": "Marketplace",
|
|
2568
|
+
"marketplace-browse": `Browse: ${current.context?.marketplace ?? ""}`,
|
|
2569
|
+
"installed-list": "Installed Plugins"
|
|
2570
|
+
};
|
|
2571
|
+
const staticItemsMap = {
|
|
2572
|
+
main: [
|
|
2573
|
+
{ label: "Marketplace", value: "marketplace" },
|
|
2574
|
+
{ label: "Installed Plugins", value: "installed" }
|
|
2575
|
+
]
|
|
2576
|
+
};
|
|
2577
|
+
return /* @__PURE__ */ jsx12(
|
|
2578
|
+
MenuSelect,
|
|
2579
|
+
{
|
|
2580
|
+
title: titleMap[screen] ?? "Plugin Management",
|
|
2581
|
+
items: staticItemsMap[screen] ?? items,
|
|
2582
|
+
onSelect: handleSelect,
|
|
2583
|
+
onBack: pop,
|
|
2584
|
+
loading,
|
|
2585
|
+
error
|
|
2586
|
+
},
|
|
2587
|
+
`${screen}-${stack.length}-${refreshCounter}`
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
// src/ui/App.tsx
|
|
2592
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2130
2593
|
var EXIT_DELAY_MS2 = 500;
|
|
2131
2594
|
function mergeHooksIntoConfig(configHooks, pluginHooks) {
|
|
2132
2595
|
const pluginKeys = Object.keys(pluginHooks);
|
|
@@ -2158,15 +2621,16 @@ function App(props) {
|
|
|
2158
2621
|
{ ...props, config: configWithPluginHooks }
|
|
2159
2622
|
);
|
|
2160
2623
|
const { messages, setMessages, addMessage } = useMessages();
|
|
2161
|
-
const [isThinking, setIsThinking] =
|
|
2624
|
+
const [isThinking, setIsThinking] = useState10(false);
|
|
2162
2625
|
const initialCtx = session.getContextState();
|
|
2163
|
-
const [contextState, setContextState] =
|
|
2626
|
+
const [contextState, setContextState] = useState10({
|
|
2164
2627
|
percentage: initialCtx.usedPercentage,
|
|
2165
2628
|
usedTokens: initialCtx.usedTokens,
|
|
2166
2629
|
maxTokens: initialCtx.maxTokens
|
|
2167
2630
|
});
|
|
2168
|
-
const pendingModelChangeRef =
|
|
2169
|
-
const [pendingModelId, setPendingModelId] =
|
|
2631
|
+
const pendingModelChangeRef = useRef8(null);
|
|
2632
|
+
const [pendingModelId, setPendingModelId] = useState10(null);
|
|
2633
|
+
const [showPluginTUI, setShowPluginTUI] = useState10(false);
|
|
2170
2634
|
const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
|
|
2171
2635
|
const handleSlashCommand = useSlashCommands(
|
|
2172
2636
|
session,
|
|
@@ -2176,7 +2640,8 @@ function App(props) {
|
|
|
2176
2640
|
registry,
|
|
2177
2641
|
pendingModelChangeRef,
|
|
2178
2642
|
setPendingModelId,
|
|
2179
|
-
pluginCallbacks
|
|
2643
|
+
pluginCallbacks,
|
|
2644
|
+
setShowPluginTUI
|
|
2180
2645
|
);
|
|
2181
2646
|
const handleSubmit = useSubmitHandler(
|
|
2182
2647
|
session,
|
|
@@ -2187,33 +2652,33 @@ function App(props) {
|
|
|
2187
2652
|
setContextState,
|
|
2188
2653
|
registry
|
|
2189
2654
|
);
|
|
2190
|
-
|
|
2655
|
+
useInput7(
|
|
2191
2656
|
(_input, key) => {
|
|
2192
2657
|
if (key.ctrl && _input === "c") exit();
|
|
2193
2658
|
if (key.escape && isThinking) session.abort();
|
|
2194
2659
|
},
|
|
2195
|
-
{ isActive: !permissionRequest }
|
|
2660
|
+
{ isActive: !permissionRequest && !showPluginTUI }
|
|
2196
2661
|
);
|
|
2197
|
-
return /* @__PURE__ */
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
2662
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
2663
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2664
|
+
/* @__PURE__ */ jsx13(Text13, { color: "cyan", bold: true, children: `
|
|
2200
2665
|
____ ___ ____ ___ _____ _
|
|
2201
2666
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
2202
2667
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
2203
2668
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
2204
2669
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
2205
2670
|
` }),
|
|
2206
|
-
/* @__PURE__ */
|
|
2671
|
+
/* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
|
|
2207
2672
|
" v",
|
|
2208
2673
|
props.version ?? "0.0.0"
|
|
2209
2674
|
] })
|
|
2210
2675
|
] }),
|
|
2211
|
-
/* @__PURE__ */
|
|
2212
|
-
/* @__PURE__ */
|
|
2213
|
-
isThinking && /* @__PURE__ */
|
|
2676
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
2677
|
+
/* @__PURE__ */ jsx13(MessageList, { messages }),
|
|
2678
|
+
isThinking && /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx13(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
2214
2679
|
] }),
|
|
2215
|
-
permissionRequest && /* @__PURE__ */
|
|
2216
|
-
pendingModelId && /* @__PURE__ */
|
|
2680
|
+
permissionRequest && /* @__PURE__ */ jsx13(PermissionPrompt, { request: permissionRequest }),
|
|
2681
|
+
pendingModelId && /* @__PURE__ */ jsx13(
|
|
2217
2682
|
ConfirmPrompt,
|
|
2218
2683
|
{
|
|
2219
2684
|
message: `Change model to ${getModelName(pendingModelId)}? This will restart the session.`,
|
|
@@ -2241,7 +2706,15 @@ function App(props) {
|
|
|
2241
2706
|
}
|
|
2242
2707
|
}
|
|
2243
2708
|
),
|
|
2244
|
-
/* @__PURE__ */
|
|
2709
|
+
showPluginTUI && /* @__PURE__ */ jsx13(
|
|
2710
|
+
PluginTUI,
|
|
2711
|
+
{
|
|
2712
|
+
callbacks: pluginCallbacks,
|
|
2713
|
+
onClose: () => setShowPluginTUI(false),
|
|
2714
|
+
addMessage: (msg) => addMessage(msg)
|
|
2715
|
+
}
|
|
2716
|
+
),
|
|
2717
|
+
/* @__PURE__ */ jsx13(
|
|
2245
2718
|
StatusBar,
|
|
2246
2719
|
{
|
|
2247
2720
|
permissionMode: session.getPermissionMode(),
|
|
@@ -2254,20 +2727,20 @@ function App(props) {
|
|
|
2254
2727
|
contextMaxTokens: contextState.maxTokens
|
|
2255
2728
|
}
|
|
2256
2729
|
),
|
|
2257
|
-
/* @__PURE__ */
|
|
2730
|
+
/* @__PURE__ */ jsx13(
|
|
2258
2731
|
InputArea,
|
|
2259
2732
|
{
|
|
2260
2733
|
onSubmit: handleSubmit,
|
|
2261
|
-
isDisabled: isThinking || !!permissionRequest,
|
|
2734
|
+
isDisabled: isThinking || !!permissionRequest || showPluginTUI,
|
|
2262
2735
|
registry
|
|
2263
2736
|
}
|
|
2264
2737
|
),
|
|
2265
|
-
/* @__PURE__ */
|
|
2738
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " })
|
|
2266
2739
|
] });
|
|
2267
2740
|
}
|
|
2268
2741
|
|
|
2269
2742
|
// src/ui/render.tsx
|
|
2270
|
-
import { jsx as
|
|
2743
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
2271
2744
|
function renderApp(options) {
|
|
2272
2745
|
process.on("unhandledRejection", (reason) => {
|
|
2273
2746
|
process.stderr.write(`
|
|
@@ -2278,7 +2751,7 @@ function renderApp(options) {
|
|
|
2278
2751
|
`);
|
|
2279
2752
|
}
|
|
2280
2753
|
});
|
|
2281
|
-
const instance = render(/* @__PURE__ */
|
|
2754
|
+
const instance = render(/* @__PURE__ */ jsx14(App, { ...options }), {
|
|
2282
2755
|
exitOnCtrlC: true
|
|
2283
2756
|
});
|
|
2284
2757
|
instance.waitUntilExit().catch((err) => {
|