@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.
@@ -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 useState7, useRef as useRef6 } from "react";
153
- import { Box as Box9, Text as Text11, useApp, useInput as useInput5 } from "ink";
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
- const plugins = await callbacks.listInstalled();
508
- if (plugins.length === 0) {
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
- return plugins.map((p) => ({
1373
- name: p.manifest.name,
1374
- description: p.manifest.description,
1375
- enabled: true
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
- await installer.install(name, marketplaceName);
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/App.tsx
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] = useState7(false);
2624
+ const [isThinking, setIsThinking] = useState10(false);
2162
2625
  const initialCtx = session.getContextState();
2163
- const [contextState, setContextState] = useState7({
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 = useRef6(null);
2169
- const [pendingModelId, setPendingModelId] = useState7(null);
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
- useInput5(
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__ */ jsxs9(Box9, { flexDirection: "column", children: [
2198
- /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2199
- /* @__PURE__ */ jsx10(Text11, { color: "cyan", bold: true, children: `
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__ */ jsxs9(Text11, { dimColor: true, children: [
2671
+ /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
2207
2672
  " v",
2208
2673
  props.version ?? "0.0.0"
2209
2674
  ] })
2210
2675
  ] }),
2211
- /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2212
- /* @__PURE__ */ jsx10(MessageList, { messages }),
2213
- isThinking && /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx10(StreamingIndicator, { text: streamingText, activeTools }) })
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__ */ jsx10(PermissionPrompt, { request: permissionRequest }),
2216
- pendingModelId && /* @__PURE__ */ jsx10(
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__ */ jsx10(
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__ */ jsx10(
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__ */ jsx10(Text11, { children: " " })
2738
+ /* @__PURE__ */ jsx13(Text13, { children: " " })
2266
2739
  ] });
2267
2740
  }
2268
2741
 
2269
2742
  // src/ui/render.tsx
2270
- import { jsx as jsx11 } from "react/jsx-runtime";
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__ */ jsx11(App, { ...options }), {
2754
+ const instance = render(/* @__PURE__ */ jsx14(App, { ...options }), {
2282
2755
  exitOnCtrlC: true
2283
2756
  });
2284
2757
  instance.waitUntilExit().catch((err) => {