@robota-sdk/agent-cli 3.0.0-beta.34 → 3.0.0-beta.36
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 +634 -119
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-RDPIMQOC.js → chunk-ERF646KY.js} +630 -110
- package/dist/node/index.cjs +634 -119
- package/dist/node/index.js +1 -1
- package/package.json +1 -1
|
@@ -149,9 +149,10 @@ 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
|
+
import { createSystemMessage as createSystemMessage3 } from "@robota-sdk/agent-core";
|
|
155
156
|
|
|
156
157
|
// src/ui/hooks/useSession.ts
|
|
157
158
|
import { useState, useCallback, useRef } from "react";
|
|
@@ -247,6 +248,7 @@ var NOOP_TERMINAL = {
|
|
|
247
248
|
function useSession(props) {
|
|
248
249
|
const [permissionRequest, setPermissionRequest] = useState(null);
|
|
249
250
|
const [streamingText, setStreamingText] = useState("");
|
|
251
|
+
const streamingTextRef = useRef("");
|
|
250
252
|
const [activeTools, setActiveTools] = useState([]);
|
|
251
253
|
const permissionQueueRef = useRef([]);
|
|
252
254
|
const processingRef = useRef(false);
|
|
@@ -278,8 +280,15 @@ function useSession(props) {
|
|
|
278
280
|
processNextPermission();
|
|
279
281
|
});
|
|
280
282
|
};
|
|
283
|
+
let flushTimer = null;
|
|
281
284
|
const onTextDelta = (delta) => {
|
|
282
|
-
|
|
285
|
+
streamingTextRef.current += delta;
|
|
286
|
+
if (!flushTimer) {
|
|
287
|
+
flushTimer = setTimeout(() => {
|
|
288
|
+
setStreamingText(streamingTextRef.current);
|
|
289
|
+
flushTimer = null;
|
|
290
|
+
}, 16);
|
|
291
|
+
}
|
|
283
292
|
};
|
|
284
293
|
const onToolExecution = (event) => {
|
|
285
294
|
if (event.type === "start") {
|
|
@@ -358,6 +367,7 @@ function useSession(props) {
|
|
|
358
367
|
}
|
|
359
368
|
const clearStreamingText = useCallback(() => {
|
|
360
369
|
setStreamingText("");
|
|
370
|
+
streamingTextRef.current = "";
|
|
361
371
|
setActiveTools([]);
|
|
362
372
|
}, []);
|
|
363
373
|
return {
|
|
@@ -372,16 +382,11 @@ function useSession(props) {
|
|
|
372
382
|
// src/ui/hooks/useMessages.ts
|
|
373
383
|
import { useState as useState2, useCallback as useCallback2 } from "react";
|
|
374
384
|
var MAX_RENDERED_MESSAGES = 100;
|
|
375
|
-
var msgIdCounter = 0;
|
|
376
|
-
function nextId() {
|
|
377
|
-
msgIdCounter += 1;
|
|
378
|
-
return `msg_${msgIdCounter}`;
|
|
379
|
-
}
|
|
380
385
|
function useMessages() {
|
|
381
386
|
const [messages, setMessages] = useState2([]);
|
|
382
387
|
const addMessage = useCallback2((msg) => {
|
|
383
388
|
setMessages((prev) => {
|
|
384
|
-
const updated = [...prev,
|
|
389
|
+
const updated = [...prev, msg];
|
|
385
390
|
if (updated.length > MAX_RENDERED_MESSAGES) {
|
|
386
391
|
return updated.slice(-MAX_RENDERED_MESSAGES);
|
|
387
392
|
}
|
|
@@ -393,6 +398,7 @@ function useMessages() {
|
|
|
393
398
|
|
|
394
399
|
// src/ui/hooks/useSlashCommands.ts
|
|
395
400
|
import { useCallback as useCallback3 } from "react";
|
|
401
|
+
import { createSystemMessage } from "@robota-sdk/agent-core";
|
|
396
402
|
|
|
397
403
|
// src/commands/slash-executor.ts
|
|
398
404
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -503,18 +509,9 @@ async function handlePluginCommand(args, addMessage, callbacks) {
|
|
|
503
509
|
try {
|
|
504
510
|
switch (subcommand) {
|
|
505
511
|
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 };
|
|
512
|
+
case void 0:
|
|
513
|
+
case "manage": {
|
|
514
|
+
return { handled: true, triggerPluginTUI: true };
|
|
518
515
|
}
|
|
519
516
|
case "install": {
|
|
520
517
|
if (!subArgs) {
|
|
@@ -661,18 +658,21 @@ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages
|
|
|
661
658
|
|
|
662
659
|
// src/ui/hooks/useSlashCommands.ts
|
|
663
660
|
var EXIT_DELAY_MS = 500;
|
|
664
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks) {
|
|
661
|
+
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId, pluginCallbacks, setShowPluginTUI) {
|
|
665
662
|
return useCallback3(
|
|
666
663
|
async (input) => {
|
|
667
664
|
const parts = input.slice(1).split(/\s+/);
|
|
668
665
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
669
666
|
const args = parts.slice(1).join(" ");
|
|
670
667
|
const clearMessages = () => setMessages([]);
|
|
668
|
+
const slashAddMessage = (msg) => {
|
|
669
|
+
addMessage(createSystemMessage(msg.content));
|
|
670
|
+
};
|
|
671
671
|
const result = await executeSlashCommand(
|
|
672
672
|
cmd,
|
|
673
673
|
args,
|
|
674
674
|
session,
|
|
675
|
-
|
|
675
|
+
slashAddMessage,
|
|
676
676
|
clearMessages,
|
|
677
677
|
registry,
|
|
678
678
|
pluginCallbacks
|
|
@@ -681,6 +681,9 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
681
681
|
pendingModelChangeRef.current = result.pendingModelId;
|
|
682
682
|
setPendingModelId(result.pendingModelId);
|
|
683
683
|
}
|
|
684
|
+
if (result.triggerPluginTUI) {
|
|
685
|
+
setShowPluginTUI?.(true);
|
|
686
|
+
}
|
|
684
687
|
if (result.exitRequested) {
|
|
685
688
|
setTimeout(() => exit(), EXIT_DELAY_MS);
|
|
686
689
|
}
|
|
@@ -694,18 +697,26 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
694
697
|
registry,
|
|
695
698
|
pendingModelChangeRef,
|
|
696
699
|
setPendingModelId,
|
|
697
|
-
pluginCallbacks
|
|
700
|
+
pluginCallbacks,
|
|
701
|
+
setShowPluginTUI
|
|
698
702
|
]
|
|
699
703
|
);
|
|
700
704
|
}
|
|
701
705
|
|
|
702
706
|
// src/ui/hooks/useSubmitHandler.ts
|
|
703
707
|
import { useCallback as useCallback4 } from "react";
|
|
708
|
+
import { randomUUID } from "crypto";
|
|
704
709
|
import {
|
|
705
710
|
createSubagentSession,
|
|
706
711
|
getBuiltInAgent,
|
|
707
712
|
retrieveAgentToolDeps
|
|
708
713
|
} from "@robota-sdk/agent-sdk";
|
|
714
|
+
import {
|
|
715
|
+
createUserMessage,
|
|
716
|
+
createAssistantMessage,
|
|
717
|
+
createSystemMessage as createSystemMessage2,
|
|
718
|
+
createToolMessage
|
|
719
|
+
} from "@robota-sdk/agent-core";
|
|
709
720
|
|
|
710
721
|
// src/utils/tool-call-extractor.ts
|
|
711
722
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -862,21 +873,50 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
862
873
|
historyBefore
|
|
863
874
|
);
|
|
864
875
|
if (toolSummaries.length > 0) {
|
|
865
|
-
addMessage(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
876
|
+
addMessage(
|
|
877
|
+
createToolMessage(JSON.stringify(toolSummaries), {
|
|
878
|
+
toolCallId: randomUUID(),
|
|
879
|
+
name: `${toolSummaries.length} tools`
|
|
880
|
+
})
|
|
881
|
+
);
|
|
870
882
|
}
|
|
871
|
-
addMessage(
|
|
883
|
+
addMessage(createAssistantMessage(response || "(empty response)"));
|
|
872
884
|
syncContextState(session, setContextState);
|
|
873
885
|
} catch (err) {
|
|
874
886
|
clearStreamingText();
|
|
875
|
-
|
|
876
|
-
|
|
887
|
+
const isAbortError = err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
|
|
888
|
+
if (isAbortError) {
|
|
889
|
+
const history = session.getHistory();
|
|
890
|
+
const toolSummaries = extractToolCallsWithDiff(
|
|
891
|
+
history,
|
|
892
|
+
historyBefore
|
|
893
|
+
);
|
|
894
|
+
if (toolSummaries.length > 0) {
|
|
895
|
+
addMessage(
|
|
896
|
+
createToolMessage(JSON.stringify(toolSummaries), {
|
|
897
|
+
toolCallId: randomUUID(),
|
|
898
|
+
name: `${toolSummaries.length} tools`
|
|
899
|
+
})
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
const assistantParts = [];
|
|
903
|
+
let lastAssistantState = "complete";
|
|
904
|
+
for (let i = historyBefore; i < history.length; i++) {
|
|
905
|
+
const msg = history[i];
|
|
906
|
+
if (msg && msg.role === "assistant" && msg.content) {
|
|
907
|
+
assistantParts.push(msg.content);
|
|
908
|
+
if (msg.state === "interrupted") lastAssistantState = "interrupted";
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (assistantParts.length > 0) {
|
|
912
|
+
addMessage(
|
|
913
|
+
createAssistantMessage(assistantParts.join("\n\n"), { state: lastAssistantState })
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
addMessage(createSystemMessage2("Interrupted by user."));
|
|
877
917
|
} else {
|
|
878
918
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
879
|
-
addMessage(
|
|
919
|
+
addMessage(createSystemMessage2(`Error: ${errMsg}`));
|
|
880
920
|
}
|
|
881
921
|
} finally {
|
|
882
922
|
setIsThinking(false);
|
|
@@ -929,7 +969,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
929
969
|
const runInFork = createForkRunner(session);
|
|
930
970
|
const result = await executeSkill(skill, args, { runInFork });
|
|
931
971
|
if (result.mode === "fork") {
|
|
932
|
-
addMessage(
|
|
972
|
+
addMessage(createAssistantMessage(result.result ?? "(empty response)"));
|
|
933
973
|
syncContextState(session, setContextState);
|
|
934
974
|
return;
|
|
935
975
|
}
|
|
@@ -964,7 +1004,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
964
1004
|
hookInput
|
|
965
1005
|
);
|
|
966
1006
|
}
|
|
967
|
-
addMessage(
|
|
1007
|
+
addMessage(createUserMessage(input));
|
|
968
1008
|
return runSessionPrompt(
|
|
969
1009
|
input,
|
|
970
1010
|
session,
|
|
@@ -1082,22 +1122,7 @@ function createBuiltinCommands() {
|
|
|
1082
1122
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
1083
1123
|
{ name: "context", description: "Context window info", source: "builtin" },
|
|
1084
1124
|
{ 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
|
-
},
|
|
1125
|
+
{ name: "plugin", description: "Manage plugins", source: "builtin" },
|
|
1101
1126
|
{ name: "reload-plugins", description: "Reload all plugin resources", source: "builtin" },
|
|
1102
1127
|
{ name: "reset", description: "Delete settings and exit", source: "builtin" },
|
|
1103
1128
|
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
@@ -1369,18 +1394,50 @@ function usePluginCallbacks(cwd) {
|
|
|
1369
1394
|
return {
|
|
1370
1395
|
listInstalled: async () => {
|
|
1371
1396
|
const plugins = await loader.loadAll();
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1397
|
+
const enabledMap = settingsStore.getEnabledPlugins();
|
|
1398
|
+
return plugins.map((p) => {
|
|
1399
|
+
const parts = p.pluginDir.split("/");
|
|
1400
|
+
const cacheIdx = parts.indexOf("cache");
|
|
1401
|
+
const marketplaceName = cacheIdx >= 0 ? parts[cacheIdx + 1] : "";
|
|
1402
|
+
const fullId = marketplaceName ? `${p.manifest.name}@${marketplaceName}` : p.manifest.name;
|
|
1403
|
+
return {
|
|
1404
|
+
name: fullId,
|
|
1405
|
+
description: p.manifest.description,
|
|
1406
|
+
enabled: enabledMap[fullId] !== false && enabledMap[p.manifest.name] !== false
|
|
1407
|
+
};
|
|
1408
|
+
});
|
|
1409
|
+
},
|
|
1410
|
+
listAvailablePlugins: async (marketplaceName) => {
|
|
1411
|
+
let manifest;
|
|
1412
|
+
try {
|
|
1413
|
+
manifest = marketplace.fetchManifest(marketplaceName);
|
|
1414
|
+
} catch {
|
|
1415
|
+
return [];
|
|
1416
|
+
}
|
|
1417
|
+
const installed = installer.getInstalledPlugins();
|
|
1418
|
+
const installedNames = new Set(Object.values(installed).map((r) => r.pluginName));
|
|
1419
|
+
return manifest.plugins.map((p) => ({
|
|
1420
|
+
name: p.name,
|
|
1421
|
+
description: p.description,
|
|
1422
|
+
installed: installedNames.has(p.name)
|
|
1376
1423
|
}));
|
|
1377
1424
|
},
|
|
1378
|
-
install: async (pluginId) => {
|
|
1425
|
+
install: async (pluginId, scope) => {
|
|
1379
1426
|
const [name, marketplaceName] = pluginId.split("@");
|
|
1380
1427
|
if (!name || !marketplaceName) {
|
|
1381
1428
|
throw new Error("Plugin ID must be in format: name@marketplace");
|
|
1382
1429
|
}
|
|
1383
|
-
|
|
1430
|
+
if (scope === "project") {
|
|
1431
|
+
const projectPluginsDir = join4(cwd, ".robota", "plugins");
|
|
1432
|
+
const projectInstaller = new BundlePluginInstaller({
|
|
1433
|
+
pluginsDir: projectPluginsDir,
|
|
1434
|
+
settingsStore,
|
|
1435
|
+
marketplaceClient: marketplace
|
|
1436
|
+
});
|
|
1437
|
+
await projectInstaller.install(name, marketplaceName);
|
|
1438
|
+
} else {
|
|
1439
|
+
await installer.install(name, marketplaceName);
|
|
1440
|
+
}
|
|
1384
1441
|
},
|
|
1385
1442
|
uninstall: async (pluginId) => {
|
|
1386
1443
|
await installer.uninstall(pluginId);
|
|
@@ -1423,6 +1480,7 @@ function usePluginCallbacks(cwd) {
|
|
|
1423
1480
|
// src/ui/MessageList.tsx
|
|
1424
1481
|
import React2 from "react";
|
|
1425
1482
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
1483
|
+
import { isToolMessage, isAssistantMessage } from "@robota-sdk/agent-core";
|
|
1426
1484
|
|
|
1427
1485
|
// src/ui/render-markdown.ts
|
|
1428
1486
|
import { marked } from "marked";
|
|
@@ -1482,7 +1540,7 @@ function DiffBlock({ file, lines }) {
|
|
|
1482
1540
|
}
|
|
1483
1541
|
|
|
1484
1542
|
// src/ui/MessageList.tsx
|
|
1485
|
-
import { jsx, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1543
|
+
import { Fragment, jsx, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1486
1544
|
function RoleLabel({ role }) {
|
|
1487
1545
|
switch (role) {
|
|
1488
1546
|
case "user":
|
|
@@ -1508,9 +1566,14 @@ function RoleLabel({ role }) {
|
|
|
1508
1566
|
}
|
|
1509
1567
|
}
|
|
1510
1568
|
function ToolMessage({ message }) {
|
|
1569
|
+
if (!isToolMessage(message)) {
|
|
1570
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
1571
|
+
}
|
|
1572
|
+
const toolName = message.name;
|
|
1573
|
+
const content = message.content;
|
|
1511
1574
|
let summaries = null;
|
|
1512
1575
|
try {
|
|
1513
|
-
const parsed = JSON.parse(
|
|
1576
|
+
const parsed = JSON.parse(content);
|
|
1514
1577
|
if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0].line === "string") {
|
|
1515
1578
|
summaries = parsed;
|
|
1516
1579
|
}
|
|
@@ -1523,9 +1586,9 @@ function ToolMessage({ message }) {
|
|
|
1523
1586
|
"Tool:",
|
|
1524
1587
|
" "
|
|
1525
1588
|
] }),
|
|
1526
|
-
|
|
1589
|
+
toolName && /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
|
|
1527
1590
|
"[",
|
|
1528
|
-
|
|
1591
|
+
toolName,
|
|
1529
1592
|
"]"
|
|
1530
1593
|
] })
|
|
1531
1594
|
] }),
|
|
@@ -1541,16 +1604,16 @@ function ToolMessage({ message }) {
|
|
|
1541
1604
|
] }, i))
|
|
1542
1605
|
] });
|
|
1543
1606
|
}
|
|
1544
|
-
const lines =
|
|
1607
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
1545
1608
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
1546
1609
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1547
1610
|
/* @__PURE__ */ jsxs2(Text2, { color: "white", bold: true, children: [
|
|
1548
1611
|
"Tool:",
|
|
1549
1612
|
" "
|
|
1550
1613
|
] }),
|
|
1551
|
-
|
|
1614
|
+
toolName && /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
|
|
1552
1615
|
"[",
|
|
1553
|
-
|
|
1616
|
+
toolName,
|
|
1554
1617
|
"]"
|
|
1555
1618
|
] })
|
|
1556
1619
|
] }),
|
|
@@ -1566,21 +1629,15 @@ function ToolMessage({ message }) {
|
|
|
1566
1629
|
var MessageItem = React2.memo(function MessageItem2({
|
|
1567
1630
|
message
|
|
1568
1631
|
}) {
|
|
1569
|
-
if (message
|
|
1632
|
+
if (isToolMessage(message)) {
|
|
1570
1633
|
return /* @__PURE__ */ jsx(ToolMessage, { message });
|
|
1571
1634
|
}
|
|
1635
|
+
const content = message.content ?? "";
|
|
1636
|
+
const isInterrupted = message.state === "interrupted";
|
|
1572
1637
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
1573
|
-
/* @__PURE__ */
|
|
1574
|
-
/* @__PURE__ */ jsx(RoleLabel, { role: message.role }),
|
|
1575
|
-
message.toolName && /* @__PURE__ */ jsxs2(Text2, { color: "magenta", dimColor: true, children: [
|
|
1576
|
-
"[",
|
|
1577
|
-
message.toolName,
|
|
1578
|
-
"]",
|
|
1579
|
-
" "
|
|
1580
|
-
] })
|
|
1581
|
-
] }),
|
|
1638
|
+
/* @__PURE__ */ jsx(Box2, { children: /* @__PURE__ */ jsx(RoleLabel, { role: message.role }) }),
|
|
1582
1639
|
/* @__PURE__ */ jsx(Text2, { children: " " }),
|
|
1583
|
-
/* @__PURE__ */ jsx(Box2, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text2, { wrap: "wrap", children: message
|
|
1640
|
+
/* @__PURE__ */ jsx(Box2, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text2, { wrap: "wrap", children: isAssistantMessage(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
|
|
1584
1641
|
] });
|
|
1585
1642
|
});
|
|
1586
1643
|
function MessageList({ messages }) {
|
|
@@ -1959,7 +2016,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1959
2016
|
isSubcommandMode
|
|
1960
2017
|
}
|
|
1961
2018
|
),
|
|
1962
|
-
/* @__PURE__ */ jsx6(Box5, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response..." }) : /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
2019
|
+
/* @__PURE__ */ jsx6(Box5, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
1963
2020
|
/* @__PURE__ */ jsx6(Text7, { color: "green", bold: true, children: "> " }),
|
|
1964
2021
|
/* @__PURE__ */ jsx6(
|
|
1965
2022
|
CjkTextInput,
|
|
@@ -2084,7 +2141,7 @@ function PermissionPrompt({ request }) {
|
|
|
2084
2141
|
|
|
2085
2142
|
// src/ui/StreamingIndicator.tsx
|
|
2086
2143
|
import { Box as Box8, Text as Text10 } from "ink";
|
|
2087
|
-
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2144
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2088
2145
|
function getToolStyle(t) {
|
|
2089
2146
|
if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
|
|
2090
2147
|
if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
|
|
@@ -2095,7 +2152,7 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2095
2152
|
const hasTools = activeTools.length > 0;
|
|
2096
2153
|
const hasText = text.length > 0;
|
|
2097
2154
|
if (!hasTools && !hasText) {
|
|
2098
|
-
return /* @__PURE__ */ jsx9(
|
|
2155
|
+
return /* @__PURE__ */ jsx9(Fragment2, {});
|
|
2099
2156
|
}
|
|
2100
2157
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2101
2158
|
hasTools && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -2125,8 +2182,459 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2125
2182
|
] });
|
|
2126
2183
|
}
|
|
2127
2184
|
|
|
2128
|
-
// src/ui/
|
|
2185
|
+
// src/ui/PluginTUI.tsx
|
|
2186
|
+
import { useState as useState9, useEffect as useEffect2, useCallback as useCallback9 } from "react";
|
|
2187
|
+
|
|
2188
|
+
// src/ui/MenuSelect.tsx
|
|
2189
|
+
import { useState as useState7, useCallback as useCallback7, useRef as useRef6 } from "react";
|
|
2190
|
+
import { Box as Box9, Text as Text11, useInput as useInput5 } from "ink";
|
|
2129
2191
|
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2192
|
+
function MenuSelect({
|
|
2193
|
+
title,
|
|
2194
|
+
items,
|
|
2195
|
+
onSelect,
|
|
2196
|
+
onBack,
|
|
2197
|
+
loading,
|
|
2198
|
+
error
|
|
2199
|
+
}) {
|
|
2200
|
+
const [selected, setSelected] = useState7(0);
|
|
2201
|
+
const selectedRef = useRef6(0);
|
|
2202
|
+
const resolvedRef = useRef6(false);
|
|
2203
|
+
const doSelect = useCallback7(
|
|
2204
|
+
(index) => {
|
|
2205
|
+
if (resolvedRef.current || items.length === 0) return;
|
|
2206
|
+
resolvedRef.current = true;
|
|
2207
|
+
onSelect(items[index].value);
|
|
2208
|
+
},
|
|
2209
|
+
[items, onSelect]
|
|
2210
|
+
);
|
|
2211
|
+
useInput5((input, key) => {
|
|
2212
|
+
if (resolvedRef.current) return;
|
|
2213
|
+
if (key.escape) {
|
|
2214
|
+
resolvedRef.current = true;
|
|
2215
|
+
onBack();
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
if (loading || error || items.length === 0) return;
|
|
2219
|
+
if (key.upArrow) {
|
|
2220
|
+
const next = selectedRef.current > 0 ? selectedRef.current - 1 : selectedRef.current;
|
|
2221
|
+
selectedRef.current = next;
|
|
2222
|
+
setSelected(next);
|
|
2223
|
+
} else if (key.downArrow) {
|
|
2224
|
+
const next = selectedRef.current < items.length - 1 ? selectedRef.current + 1 : selectedRef.current;
|
|
2225
|
+
selectedRef.current = next;
|
|
2226
|
+
setSelected(next);
|
|
2227
|
+
} else if (key.return) {
|
|
2228
|
+
doSelect(selectedRef.current);
|
|
2229
|
+
}
|
|
2230
|
+
});
|
|
2231
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2232
|
+
/* @__PURE__ */ jsx10(Text11, { color: "yellow", bold: true, children: title }),
|
|
2233
|
+
loading && /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "Loading..." }) }),
|
|
2234
|
+
error && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2235
|
+
/* @__PURE__ */ jsx10(Text11, { color: "red", children: error }),
|
|
2236
|
+
/* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "Press Esc to go back" })
|
|
2237
|
+
] }),
|
|
2238
|
+
!loading && !error && /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2239
|
+
/* @__PURE__ */ jsxs9(Text11, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
2240
|
+
i === selected ? "> " : " ",
|
|
2241
|
+
item.label
|
|
2242
|
+
] }),
|
|
2243
|
+
item.hint && /* @__PURE__ */ jsxs9(Text11, { dimColor: true, children: [
|
|
2244
|
+
" ",
|
|
2245
|
+
item.hint
|
|
2246
|
+
] })
|
|
2247
|
+
] }, item.value)) }),
|
|
2248
|
+
/* @__PURE__ */ jsx10(Text11, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
|
|
2249
|
+
] });
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
// src/ui/TextPrompt.tsx
|
|
2253
|
+
import { useState as useState8, useRef as useRef7, useCallback as useCallback8 } from "react";
|
|
2254
|
+
import { Box as Box10, Text as Text12, useInput as useInput6 } from "ink";
|
|
2255
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2256
|
+
function TextPrompt({
|
|
2257
|
+
title,
|
|
2258
|
+
placeholder,
|
|
2259
|
+
onSubmit,
|
|
2260
|
+
onCancel,
|
|
2261
|
+
validate
|
|
2262
|
+
}) {
|
|
2263
|
+
const [value, setValue] = useState8("");
|
|
2264
|
+
const [error, setError] = useState8();
|
|
2265
|
+
const resolvedRef = useRef7(false);
|
|
2266
|
+
const valueRef = useRef7("");
|
|
2267
|
+
const handleSubmit = useCallback8(() => {
|
|
2268
|
+
if (resolvedRef.current) return;
|
|
2269
|
+
const trimmed = valueRef.current.trim();
|
|
2270
|
+
if (!trimmed) return;
|
|
2271
|
+
if (validate) {
|
|
2272
|
+
const err = validate(trimmed);
|
|
2273
|
+
if (err) {
|
|
2274
|
+
setError(err);
|
|
2275
|
+
return;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
resolvedRef.current = true;
|
|
2279
|
+
onSubmit(trimmed);
|
|
2280
|
+
}, [validate, onSubmit]);
|
|
2281
|
+
useInput6((input, key) => {
|
|
2282
|
+
if (resolvedRef.current) return;
|
|
2283
|
+
if (key.escape) {
|
|
2284
|
+
resolvedRef.current = true;
|
|
2285
|
+
onCancel();
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
if (key.return) {
|
|
2289
|
+
handleSubmit();
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
if (key.backspace || key.delete) {
|
|
2293
|
+
valueRef.current = valueRef.current.slice(0, -1);
|
|
2294
|
+
setValue(valueRef.current);
|
|
2295
|
+
setError(void 0);
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
if (input && !key.ctrl && !key.meta) {
|
|
2299
|
+
valueRef.current = valueRef.current + input;
|
|
2300
|
+
setValue(valueRef.current);
|
|
2301
|
+
setError(void 0);
|
|
2302
|
+
}
|
|
2303
|
+
});
|
|
2304
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2305
|
+
/* @__PURE__ */ jsx11(Text12, { color: "yellow", bold: true, children: title }),
|
|
2306
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2307
|
+
/* @__PURE__ */ jsx11(Text12, { color: "cyan", children: "> " }),
|
|
2308
|
+
value ? /* @__PURE__ */ jsx11(Text12, { children: value }) : placeholder ? /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: placeholder }) : null,
|
|
2309
|
+
/* @__PURE__ */ jsx11(Text12, { color: "cyan", children: "\u2588" })
|
|
2310
|
+
] }),
|
|
2311
|
+
error && /* @__PURE__ */ jsx11(Text12, { color: "red", children: error }),
|
|
2312
|
+
/* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " Enter Submit Esc Cancel" })
|
|
2313
|
+
] });
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
// src/ui/plugin-tui-handlers.ts
|
|
2317
|
+
function handleMainSelect(value, nav) {
|
|
2318
|
+
if (value === "marketplace") {
|
|
2319
|
+
nav.push({ screen: "marketplace-list" });
|
|
2320
|
+
} else if (value === "installed") {
|
|
2321
|
+
nav.push({ screen: "installed-list" });
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
function handleMarketplaceListSelect(value, nav) {
|
|
2325
|
+
if (value === "__add__") {
|
|
2326
|
+
nav.push({ screen: "marketplace-add" });
|
|
2327
|
+
} else {
|
|
2328
|
+
nav.push({ screen: "marketplace-action", context: { marketplace: value } });
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
function handleMarketplaceActionSelect(value, marketplace, callbacks, nav) {
|
|
2332
|
+
if (value === "browse") {
|
|
2333
|
+
nav.push({ screen: "marketplace-browse", context: { marketplace } });
|
|
2334
|
+
} else if (value === "update") {
|
|
2335
|
+
callbacks.marketplaceUpdate(marketplace).then(() => {
|
|
2336
|
+
nav.notify(`Updated marketplace "${marketplace}".`);
|
|
2337
|
+
nav.pop();
|
|
2338
|
+
}).catch((err) => {
|
|
2339
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2340
|
+
});
|
|
2341
|
+
} else if (value === "remove") {
|
|
2342
|
+
nav.setConfirm({
|
|
2343
|
+
message: `Remove marketplace "${marketplace}" and all its plugins?`,
|
|
2344
|
+
onConfirm: () => {
|
|
2345
|
+
nav.setConfirm(void 0);
|
|
2346
|
+
callbacks.marketplaceRemove(marketplace).then(() => {
|
|
2347
|
+
nav.notify(`Removed marketplace "${marketplace}".`);
|
|
2348
|
+
nav.popN(2);
|
|
2349
|
+
}).catch((err) => {
|
|
2350
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2351
|
+
});
|
|
2352
|
+
},
|
|
2353
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
function handleMarketplaceBrowseSelect(value, marketplace, items, nav) {
|
|
2358
|
+
const fullId = `${value}@${marketplace}`;
|
|
2359
|
+
const item = items.find((i) => i.value === value);
|
|
2360
|
+
if (item?.hint === "installed") {
|
|
2361
|
+
nav.push({ screen: "installed-action", context: { pluginId: fullId } });
|
|
2362
|
+
} else {
|
|
2363
|
+
nav.push({ screen: "marketplace-install-scope", context: { marketplace, pluginId: fullId } });
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
function handleInstallScopeSelect(value, pluginId, callbacks, nav) {
|
|
2367
|
+
const scope = value;
|
|
2368
|
+
callbacks.install(pluginId, scope).then(() => {
|
|
2369
|
+
nav.notify(`Installed plugin "${pluginId}" (${scope} scope).`);
|
|
2370
|
+
nav.popN(2);
|
|
2371
|
+
}).catch((err) => {
|
|
2372
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
function handleInstalledListSelect(value, callbacks, nav) {
|
|
2376
|
+
nav.setConfirm({
|
|
2377
|
+
message: `Uninstall plugin "${value}"?`,
|
|
2378
|
+
onConfirm: () => {
|
|
2379
|
+
nav.setConfirm(void 0);
|
|
2380
|
+
callbacks.uninstall(value).then(() => {
|
|
2381
|
+
nav.notify(`Uninstalled plugin "${value}".`);
|
|
2382
|
+
nav.refresh();
|
|
2383
|
+
}).catch((err) => {
|
|
2384
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2385
|
+
});
|
|
2386
|
+
},
|
|
2387
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
|
|
2391
|
+
if (value === "uninstall") {
|
|
2392
|
+
nav.setConfirm({
|
|
2393
|
+
message: `Uninstall plugin "${pluginId}"?`,
|
|
2394
|
+
onConfirm: () => {
|
|
2395
|
+
nav.setConfirm(void 0);
|
|
2396
|
+
callbacks.uninstall(pluginId).then(() => {
|
|
2397
|
+
nav.notify(`Uninstalled plugin "${pluginId}".`);
|
|
2398
|
+
nav.popN(2);
|
|
2399
|
+
}).catch((err) => {
|
|
2400
|
+
nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2401
|
+
});
|
|
2402
|
+
},
|
|
2403
|
+
onCancel: () => nav.setConfirm(void 0)
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
// src/ui/PluginTUI.tsx
|
|
2409
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
2410
|
+
function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
2411
|
+
const [stack, setStack] = useState9([{ screen: "main" }]);
|
|
2412
|
+
const [items, setItems] = useState9([]);
|
|
2413
|
+
const [loading, setLoading] = useState9(false);
|
|
2414
|
+
const [error, setError] = useState9();
|
|
2415
|
+
const [confirm, setConfirm] = useState9();
|
|
2416
|
+
const [refreshCounter, setRefreshCounter] = useState9(0);
|
|
2417
|
+
const current = stack[stack.length - 1] ?? { screen: "main" };
|
|
2418
|
+
const push = useCallback9((state) => {
|
|
2419
|
+
setStack((prev) => [...prev, state]);
|
|
2420
|
+
setItems([]);
|
|
2421
|
+
setError(void 0);
|
|
2422
|
+
}, []);
|
|
2423
|
+
const pop = useCallback9(() => {
|
|
2424
|
+
setStack((prev) => {
|
|
2425
|
+
if (prev.length <= 1) {
|
|
2426
|
+
onClose();
|
|
2427
|
+
return prev;
|
|
2428
|
+
}
|
|
2429
|
+
return prev.slice(0, -1);
|
|
2430
|
+
});
|
|
2431
|
+
setItems([]);
|
|
2432
|
+
setError(void 0);
|
|
2433
|
+
}, [onClose]);
|
|
2434
|
+
const popN = useCallback9(
|
|
2435
|
+
(n) => {
|
|
2436
|
+
setStack((prev) => {
|
|
2437
|
+
const next = prev.slice(0, Math.max(1, prev.length - n));
|
|
2438
|
+
if (next.length === 0) {
|
|
2439
|
+
onClose();
|
|
2440
|
+
return prev;
|
|
2441
|
+
}
|
|
2442
|
+
return next;
|
|
2443
|
+
});
|
|
2444
|
+
setItems([]);
|
|
2445
|
+
setError(void 0);
|
|
2446
|
+
},
|
|
2447
|
+
[onClose]
|
|
2448
|
+
);
|
|
2449
|
+
const notify = useCallback9(
|
|
2450
|
+
(content) => {
|
|
2451
|
+
addMessage?.({ role: "system", content });
|
|
2452
|
+
},
|
|
2453
|
+
[addMessage]
|
|
2454
|
+
);
|
|
2455
|
+
const refresh = useCallback9(() => {
|
|
2456
|
+
setItems([]);
|
|
2457
|
+
setRefreshCounter((c) => c + 1);
|
|
2458
|
+
}, []);
|
|
2459
|
+
const nav = { push, pop, popN, notify, setConfirm, refresh };
|
|
2460
|
+
useEffect2(() => {
|
|
2461
|
+
const screen2 = current.screen;
|
|
2462
|
+
if (screen2 === "marketplace-list") {
|
|
2463
|
+
setLoading(true);
|
|
2464
|
+
callbacks.marketplaceList().then((sources) => {
|
|
2465
|
+
const baseItems = [{ label: "Add Marketplace", value: "__add__" }];
|
|
2466
|
+
const sourceItems = sources.map((s) => ({
|
|
2467
|
+
label: s.name,
|
|
2468
|
+
value: s.name,
|
|
2469
|
+
hint: s.type
|
|
2470
|
+
}));
|
|
2471
|
+
setItems([...baseItems, ...sourceItems]);
|
|
2472
|
+
setLoading(false);
|
|
2473
|
+
}).catch((err) => {
|
|
2474
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2475
|
+
setLoading(false);
|
|
2476
|
+
});
|
|
2477
|
+
} else if (screen2 === "marketplace-browse") {
|
|
2478
|
+
const marketplace = current.context?.marketplace ?? "";
|
|
2479
|
+
setLoading(true);
|
|
2480
|
+
callbacks.listAvailablePlugins(marketplace).then((plugins) => {
|
|
2481
|
+
setItems(
|
|
2482
|
+
plugins.map((p) => ({
|
|
2483
|
+
label: p.name,
|
|
2484
|
+
value: p.name,
|
|
2485
|
+
hint: p.installed ? "installed" : p.description
|
|
2486
|
+
}))
|
|
2487
|
+
);
|
|
2488
|
+
setLoading(false);
|
|
2489
|
+
}).catch((err) => {
|
|
2490
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2491
|
+
setLoading(false);
|
|
2492
|
+
});
|
|
2493
|
+
} else if (screen2 === "installed-list") {
|
|
2494
|
+
setLoading(true);
|
|
2495
|
+
callbacks.listInstalled().then((plugins) => {
|
|
2496
|
+
setItems(
|
|
2497
|
+
plugins.map((p) => ({
|
|
2498
|
+
label: p.name,
|
|
2499
|
+
value: p.name,
|
|
2500
|
+
hint: p.description
|
|
2501
|
+
}))
|
|
2502
|
+
);
|
|
2503
|
+
setLoading(false);
|
|
2504
|
+
}).catch((err) => {
|
|
2505
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2506
|
+
setLoading(false);
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
}, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
|
|
2510
|
+
const handleSelect = useCallback9(
|
|
2511
|
+
(value) => {
|
|
2512
|
+
const screen2 = current.screen;
|
|
2513
|
+
const ctx = current.context;
|
|
2514
|
+
if (screen2 === "main") handleMainSelect(value, nav);
|
|
2515
|
+
else if (screen2 === "marketplace-list") handleMarketplaceListSelect(value, nav);
|
|
2516
|
+
else if (screen2 === "marketplace-action")
|
|
2517
|
+
handleMarketplaceActionSelect(value, ctx?.marketplace ?? "", callbacks, nav);
|
|
2518
|
+
else if (screen2 === "marketplace-browse")
|
|
2519
|
+
handleMarketplaceBrowseSelect(value, ctx?.marketplace ?? "", items, nav);
|
|
2520
|
+
else if (screen2 === "marketplace-install-scope")
|
|
2521
|
+
handleInstallScopeSelect(value, ctx?.pluginId ?? "", callbacks, nav);
|
|
2522
|
+
else if (screen2 === "installed-list") handleInstalledListSelect(value, callbacks, nav);
|
|
2523
|
+
else if (screen2 === "installed-action")
|
|
2524
|
+
handleInstalledActionSelect(value, ctx?.pluginId ?? "", callbacks, nav);
|
|
2525
|
+
},
|
|
2526
|
+
[current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
|
|
2527
|
+
);
|
|
2528
|
+
const handleTextSubmit = useCallback9(
|
|
2529
|
+
(value) => {
|
|
2530
|
+
if (current.screen === "marketplace-add") {
|
|
2531
|
+
callbacks.marketplaceAdd(value).then((name) => {
|
|
2532
|
+
notify(`Added marketplace "${name}" from ${value}.`);
|
|
2533
|
+
pop();
|
|
2534
|
+
}).catch((err) => {
|
|
2535
|
+
notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2536
|
+
pop();
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
},
|
|
2540
|
+
[current.screen, callbacks, notify, pop]
|
|
2541
|
+
);
|
|
2542
|
+
if (confirm) {
|
|
2543
|
+
return /* @__PURE__ */ jsx12(
|
|
2544
|
+
ConfirmPrompt,
|
|
2545
|
+
{
|
|
2546
|
+
message: confirm.message,
|
|
2547
|
+
onSelect: (index) => {
|
|
2548
|
+
if (index === 0) confirm.onConfirm();
|
|
2549
|
+
else confirm.onCancel();
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
);
|
|
2553
|
+
}
|
|
2554
|
+
const screen = current.screen;
|
|
2555
|
+
if (screen === "marketplace-add") {
|
|
2556
|
+
return /* @__PURE__ */ jsx12(
|
|
2557
|
+
TextPrompt,
|
|
2558
|
+
{
|
|
2559
|
+
title: "Add Marketplace Source",
|
|
2560
|
+
placeholder: "owner/repo or git URL",
|
|
2561
|
+
onSubmit: handleTextSubmit,
|
|
2562
|
+
onCancel: pop,
|
|
2563
|
+
validate: (v) => !v.includes("/") ? "Must be owner/repo or a git URL" : void 0
|
|
2564
|
+
}
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
if (screen === "marketplace-action") {
|
|
2568
|
+
return /* @__PURE__ */ jsx12(
|
|
2569
|
+
MenuSelect,
|
|
2570
|
+
{
|
|
2571
|
+
title: `Marketplace: ${current.context?.marketplace ?? ""}`,
|
|
2572
|
+
items: [
|
|
2573
|
+
{ label: "Browse plugins", value: "browse" },
|
|
2574
|
+
{ label: "Update", value: "update" },
|
|
2575
|
+
{ label: "Remove", value: "remove" }
|
|
2576
|
+
],
|
|
2577
|
+
onSelect: handleSelect,
|
|
2578
|
+
onBack: pop
|
|
2579
|
+
},
|
|
2580
|
+
stack.length
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
if (screen === "marketplace-install-scope") {
|
|
2584
|
+
return /* @__PURE__ */ jsx12(
|
|
2585
|
+
MenuSelect,
|
|
2586
|
+
{
|
|
2587
|
+
title: `Install scope for "${current.context?.pluginId ?? ""}"`,
|
|
2588
|
+
items: [
|
|
2589
|
+
{ label: "User scope", value: "user" },
|
|
2590
|
+
{ label: "Project scope", value: "project" }
|
|
2591
|
+
],
|
|
2592
|
+
onSelect: handleSelect,
|
|
2593
|
+
onBack: pop
|
|
2594
|
+
},
|
|
2595
|
+
stack.length
|
|
2596
|
+
);
|
|
2597
|
+
}
|
|
2598
|
+
if (screen === "installed-action") {
|
|
2599
|
+
return /* @__PURE__ */ jsx12(
|
|
2600
|
+
MenuSelect,
|
|
2601
|
+
{
|
|
2602
|
+
title: `Plugin: ${current.context?.pluginId ?? ""}`,
|
|
2603
|
+
items: [{ label: "Uninstall", value: "uninstall" }],
|
|
2604
|
+
onSelect: handleSelect,
|
|
2605
|
+
onBack: pop
|
|
2606
|
+
},
|
|
2607
|
+
stack.length
|
|
2608
|
+
);
|
|
2609
|
+
}
|
|
2610
|
+
const titleMap = {
|
|
2611
|
+
main: "Plugin Management",
|
|
2612
|
+
"marketplace-list": "Marketplace",
|
|
2613
|
+
"marketplace-browse": `Browse: ${current.context?.marketplace ?? ""}`,
|
|
2614
|
+
"installed-list": "Installed Plugins"
|
|
2615
|
+
};
|
|
2616
|
+
const staticItemsMap = {
|
|
2617
|
+
main: [
|
|
2618
|
+
{ label: "Marketplace", value: "marketplace" },
|
|
2619
|
+
{ label: "Installed Plugins", value: "installed" }
|
|
2620
|
+
]
|
|
2621
|
+
};
|
|
2622
|
+
return /* @__PURE__ */ jsx12(
|
|
2623
|
+
MenuSelect,
|
|
2624
|
+
{
|
|
2625
|
+
title: titleMap[screen] ?? "Plugin Management",
|
|
2626
|
+
items: staticItemsMap[screen] ?? items,
|
|
2627
|
+
onSelect: handleSelect,
|
|
2628
|
+
onBack: pop,
|
|
2629
|
+
loading,
|
|
2630
|
+
error
|
|
2631
|
+
},
|
|
2632
|
+
`${screen}-${stack.length}-${refreshCounter}`
|
|
2633
|
+
);
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
// src/ui/App.tsx
|
|
2637
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2130
2638
|
var EXIT_DELAY_MS2 = 500;
|
|
2131
2639
|
function mergeHooksIntoConfig(configHooks, pluginHooks) {
|
|
2132
2640
|
const pluginKeys = Object.keys(pluginHooks);
|
|
@@ -2158,15 +2666,16 @@ function App(props) {
|
|
|
2158
2666
|
{ ...props, config: configWithPluginHooks }
|
|
2159
2667
|
);
|
|
2160
2668
|
const { messages, setMessages, addMessage } = useMessages();
|
|
2161
|
-
const [isThinking, setIsThinking] =
|
|
2669
|
+
const [isThinking, setIsThinking] = useState10(false);
|
|
2162
2670
|
const initialCtx = session.getContextState();
|
|
2163
|
-
const [contextState, setContextState] =
|
|
2671
|
+
const [contextState, setContextState] = useState10({
|
|
2164
2672
|
percentage: initialCtx.usedPercentage,
|
|
2165
2673
|
usedTokens: initialCtx.usedTokens,
|
|
2166
2674
|
maxTokens: initialCtx.maxTokens
|
|
2167
2675
|
});
|
|
2168
|
-
const pendingModelChangeRef =
|
|
2169
|
-
const [pendingModelId, setPendingModelId] =
|
|
2676
|
+
const pendingModelChangeRef = useRef8(null);
|
|
2677
|
+
const [pendingModelId, setPendingModelId] = useState10(null);
|
|
2678
|
+
const [showPluginTUI, setShowPluginTUI] = useState10(false);
|
|
2170
2679
|
const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
|
|
2171
2680
|
const handleSlashCommand = useSlashCommands(
|
|
2172
2681
|
session,
|
|
@@ -2176,7 +2685,8 @@ function App(props) {
|
|
|
2176
2685
|
registry,
|
|
2177
2686
|
pendingModelChangeRef,
|
|
2178
2687
|
setPendingModelId,
|
|
2179
|
-
pluginCallbacks
|
|
2688
|
+
pluginCallbacks,
|
|
2689
|
+
setShowPluginTUI
|
|
2180
2690
|
);
|
|
2181
2691
|
const handleSubmit = useSubmitHandler(
|
|
2182
2692
|
session,
|
|
@@ -2187,33 +2697,33 @@ function App(props) {
|
|
|
2187
2697
|
setContextState,
|
|
2188
2698
|
registry
|
|
2189
2699
|
);
|
|
2190
|
-
|
|
2700
|
+
useInput7(
|
|
2191
2701
|
(_input, key) => {
|
|
2192
2702
|
if (key.ctrl && _input === "c") exit();
|
|
2193
2703
|
if (key.escape && isThinking) session.abort();
|
|
2194
2704
|
},
|
|
2195
|
-
{ isActive: !permissionRequest }
|
|
2705
|
+
{ isActive: !permissionRequest && !showPluginTUI }
|
|
2196
2706
|
);
|
|
2197
|
-
return /* @__PURE__ */
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
2707
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
2708
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2709
|
+
/* @__PURE__ */ jsx13(Text13, { color: "cyan", bold: true, children: `
|
|
2200
2710
|
____ ___ ____ ___ _____ _
|
|
2201
2711
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
2202
2712
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
2203
2713
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
2204
2714
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
2205
2715
|
` }),
|
|
2206
|
-
/* @__PURE__ */
|
|
2716
|
+
/* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
|
|
2207
2717
|
" v",
|
|
2208
2718
|
props.version ?? "0.0.0"
|
|
2209
2719
|
] })
|
|
2210
2720
|
] }),
|
|
2211
|
-
/* @__PURE__ */
|
|
2212
|
-
/* @__PURE__ */
|
|
2213
|
-
isThinking && /* @__PURE__ */
|
|
2721
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
2722
|
+
/* @__PURE__ */ jsx13(MessageList, { messages }),
|
|
2723
|
+
isThinking && /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx13(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
2214
2724
|
] }),
|
|
2215
|
-
permissionRequest && /* @__PURE__ */
|
|
2216
|
-
pendingModelId && /* @__PURE__ */
|
|
2725
|
+
permissionRequest && /* @__PURE__ */ jsx13(PermissionPrompt, { request: permissionRequest }),
|
|
2726
|
+
pendingModelId && /* @__PURE__ */ jsx13(
|
|
2217
2727
|
ConfirmPrompt,
|
|
2218
2728
|
{
|
|
2219
2729
|
message: `Change model to ${getModelName(pendingModelId)}? This will restart the session.`,
|
|
@@ -2224,24 +2734,34 @@ function App(props) {
|
|
|
2224
2734
|
try {
|
|
2225
2735
|
const settingsPath = getUserSettingsPath();
|
|
2226
2736
|
updateModelInSettings(settingsPath, pendingModelId);
|
|
2227
|
-
addMessage(
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2737
|
+
addMessage(
|
|
2738
|
+
createSystemMessage3(
|
|
2739
|
+
`Model changed to ${getModelName(pendingModelId)}. Restarting...`
|
|
2740
|
+
)
|
|
2741
|
+
);
|
|
2231
2742
|
setTimeout(() => exit(), EXIT_DELAY_MS2);
|
|
2232
2743
|
} catch (err) {
|
|
2233
|
-
addMessage(
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2744
|
+
addMessage(
|
|
2745
|
+
createSystemMessage3(
|
|
2746
|
+
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2747
|
+
)
|
|
2748
|
+
);
|
|
2237
2749
|
}
|
|
2238
2750
|
} else {
|
|
2239
|
-
addMessage(
|
|
2751
|
+
addMessage(createSystemMessage3("Model change cancelled."));
|
|
2240
2752
|
}
|
|
2241
2753
|
}
|
|
2242
2754
|
}
|
|
2243
2755
|
),
|
|
2244
|
-
/* @__PURE__ */
|
|
2756
|
+
showPluginTUI && /* @__PURE__ */ jsx13(
|
|
2757
|
+
PluginTUI,
|
|
2758
|
+
{
|
|
2759
|
+
callbacks: pluginCallbacks,
|
|
2760
|
+
onClose: () => setShowPluginTUI(false),
|
|
2761
|
+
addMessage: (msg) => addMessage(createSystemMessage3(msg.content))
|
|
2762
|
+
}
|
|
2763
|
+
),
|
|
2764
|
+
/* @__PURE__ */ jsx13(
|
|
2245
2765
|
StatusBar,
|
|
2246
2766
|
{
|
|
2247
2767
|
permissionMode: session.getPermissionMode(),
|
|
@@ -2254,20 +2774,20 @@ function App(props) {
|
|
|
2254
2774
|
contextMaxTokens: contextState.maxTokens
|
|
2255
2775
|
}
|
|
2256
2776
|
),
|
|
2257
|
-
/* @__PURE__ */
|
|
2777
|
+
/* @__PURE__ */ jsx13(
|
|
2258
2778
|
InputArea,
|
|
2259
2779
|
{
|
|
2260
2780
|
onSubmit: handleSubmit,
|
|
2261
|
-
isDisabled: isThinking || !!permissionRequest,
|
|
2781
|
+
isDisabled: isThinking || !!permissionRequest || showPluginTUI,
|
|
2262
2782
|
registry
|
|
2263
2783
|
}
|
|
2264
2784
|
),
|
|
2265
|
-
/* @__PURE__ */
|
|
2785
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " })
|
|
2266
2786
|
] });
|
|
2267
2787
|
}
|
|
2268
2788
|
|
|
2269
2789
|
// src/ui/render.tsx
|
|
2270
|
-
import { jsx as
|
|
2790
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
2271
2791
|
function renderApp(options) {
|
|
2272
2792
|
process.on("unhandledRejection", (reason) => {
|
|
2273
2793
|
process.stderr.write(`
|
|
@@ -2278,7 +2798,7 @@ function renderApp(options) {
|
|
|
2278
2798
|
`);
|
|
2279
2799
|
}
|
|
2280
2800
|
});
|
|
2281
|
-
const instance = render(/* @__PURE__ */
|
|
2801
|
+
const instance = render(/* @__PURE__ */ jsx14(App, { ...options }), {
|
|
2282
2802
|
exitOnCtrlC: true
|
|
2283
2803
|
});
|
|
2284
2804
|
instance.waitUntilExit().catch((err) => {
|