@robota-sdk/agent-cli 3.0.0-beta.15 → 3.0.0-beta.16
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/README.md +10 -3
- package/dist/node/bin.cjs +188 -94
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-B423R5N3.js → chunk-OZHWJAII.js} +184 -90
- package/dist/node/index.cjs +188 -94
- package/dist/node/index.js +1 -1
- package/package.json +4 -3
package/dist/node/index.cjs
CHANGED
|
@@ -41,20 +41,23 @@ var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
|
|
|
41
41
|
|
|
42
42
|
// src/cli.ts
|
|
43
43
|
var import_node_util = require("util");
|
|
44
|
-
var
|
|
45
|
-
var
|
|
44
|
+
var import_node_fs3 = require("fs");
|
|
45
|
+
var import_node_path3 = require("path");
|
|
46
46
|
var import_node_url = require("url");
|
|
47
47
|
var readline = __toESM(require("readline"), 1);
|
|
48
48
|
var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
|
|
49
49
|
var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
|
|
50
50
|
|
|
51
51
|
// src/ui/render.tsx
|
|
52
|
-
var
|
|
52
|
+
var import_ink10 = require("ink");
|
|
53
53
|
|
|
54
54
|
// src/ui/App.tsx
|
|
55
|
-
var
|
|
56
|
-
var
|
|
55
|
+
var import_react6 = require("react");
|
|
56
|
+
var import_ink9 = require("ink");
|
|
57
|
+
var import_node_fs2 = require("fs");
|
|
58
|
+
var import_node_path2 = require("path");
|
|
57
59
|
var import_agent_sdk = require("@robota-sdk/agent-sdk");
|
|
60
|
+
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
58
61
|
|
|
59
62
|
// src/commands/command-registry.ts
|
|
60
63
|
var CommandRegistry = class {
|
|
@@ -87,6 +90,21 @@ var CommandRegistry = class {
|
|
|
87
90
|
};
|
|
88
91
|
|
|
89
92
|
// src/commands/builtin-source.ts
|
|
93
|
+
var import_agent_core = require("@robota-sdk/agent-core");
|
|
94
|
+
function buildModelSubcommands() {
|
|
95
|
+
const seen = /* @__PURE__ */ new Set();
|
|
96
|
+
const commands = [];
|
|
97
|
+
for (const model of Object.values(import_agent_core.CLAUDE_MODELS)) {
|
|
98
|
+
if (seen.has(model.name)) continue;
|
|
99
|
+
seen.add(model.name);
|
|
100
|
+
commands.push({
|
|
101
|
+
name: model.id,
|
|
102
|
+
description: `${model.name} (${(0, import_agent_core.formatTokenCount)(model.contextWindow).toUpperCase()})`,
|
|
103
|
+
source: "builtin"
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return commands;
|
|
107
|
+
}
|
|
90
108
|
function createBuiltinCommands() {
|
|
91
109
|
return [
|
|
92
110
|
{ name: "help", description: "Show available commands", source: "builtin" },
|
|
@@ -106,11 +124,7 @@ function createBuiltinCommands() {
|
|
|
106
124
|
name: "model",
|
|
107
125
|
description: "Select AI model",
|
|
108
126
|
source: "builtin",
|
|
109
|
-
subcommands:
|
|
110
|
-
{ name: "claude-opus-4-6", description: "Opus 4.6 (highest quality)", source: "builtin" },
|
|
111
|
-
{ name: "claude-sonnet-4-6", description: "Sonnet 4.6 (balanced)", source: "builtin" },
|
|
112
|
-
{ name: "claude-haiku-4-5", description: "Haiku 4.5 (fastest)", source: "builtin" }
|
|
113
|
-
]
|
|
127
|
+
subcommands: buildModelSubcommands()
|
|
114
128
|
},
|
|
115
129
|
{ name: "compact", description: "Compress context window", source: "builtin" },
|
|
116
130
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
@@ -258,6 +272,7 @@ function MessageList({ messages }) {
|
|
|
258
272
|
|
|
259
273
|
// src/ui/StatusBar.tsx
|
|
260
274
|
var import_ink2 = require("ink");
|
|
275
|
+
var import_agent_core2 = require("@robota-sdk/agent-core");
|
|
261
276
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
262
277
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
263
278
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
@@ -297,10 +312,10 @@ function StatusBar({
|
|
|
297
312
|
"Context: ",
|
|
298
313
|
Math.round(contextPercentage),
|
|
299
314
|
"% (",
|
|
300
|
-
(
|
|
301
|
-
"
|
|
302
|
-
(
|
|
303
|
-
"
|
|
315
|
+
(0, import_agent_core2.formatTokenCount)(contextUsedTokens),
|
|
316
|
+
"/",
|
|
317
|
+
(0, import_agent_core2.formatTokenCount)(contextMaxTokens),
|
|
318
|
+
")"
|
|
304
319
|
] })
|
|
305
320
|
] }),
|
|
306
321
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { children: [
|
|
@@ -447,19 +462,13 @@ var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
|
447
462
|
var MAX_VISIBLE = 8;
|
|
448
463
|
function CommandRow(props) {
|
|
449
464
|
const { cmd, isSelected, showSlash } = props;
|
|
450
|
-
const prefix = showSlash ? "/" : "";
|
|
451
465
|
const indicator = isSelected ? "\u25B8 " : " ";
|
|
452
466
|
const nameColor = isSelected ? "cyan" : void 0;
|
|
453
467
|
const dimmed = !isSelected;
|
|
454
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
cmd.name
|
|
459
|
-
] }),
|
|
460
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { dimColor: dimmed, children: " " }),
|
|
461
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: cmd.description })
|
|
462
|
-
] });
|
|
468
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: [
|
|
469
|
+
indicator,
|
|
470
|
+
showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
|
|
471
|
+
] }) });
|
|
463
472
|
}
|
|
464
473
|
function SlashAutocomplete({
|
|
465
474
|
commands,
|
|
@@ -624,10 +633,53 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
624
633
|
] });
|
|
625
634
|
}
|
|
626
635
|
|
|
627
|
-
// src/ui/
|
|
628
|
-
var import_react4 =
|
|
636
|
+
// src/ui/ConfirmPrompt.tsx
|
|
637
|
+
var import_react4 = require("react");
|
|
629
638
|
var import_ink7 = require("ink");
|
|
630
639
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
640
|
+
function ConfirmPrompt({
|
|
641
|
+
message,
|
|
642
|
+
options = ["Yes", "No"],
|
|
643
|
+
onSelect
|
|
644
|
+
}) {
|
|
645
|
+
const [selected, setSelected] = (0, import_react4.useState)(0);
|
|
646
|
+
const resolvedRef = (0, import_react4.useRef)(false);
|
|
647
|
+
const doSelect = (0, import_react4.useCallback)(
|
|
648
|
+
(index) => {
|
|
649
|
+
if (resolvedRef.current) return;
|
|
650
|
+
resolvedRef.current = true;
|
|
651
|
+
onSelect(index);
|
|
652
|
+
},
|
|
653
|
+
[onSelect]
|
|
654
|
+
);
|
|
655
|
+
(0, import_ink7.useInput)((input, key) => {
|
|
656
|
+
if (resolvedRef.current) return;
|
|
657
|
+
if (key.leftArrow || key.upArrow) {
|
|
658
|
+
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
659
|
+
} else if (key.rightArrow || key.downArrow) {
|
|
660
|
+
setSelected((prev) => prev < options.length - 1 ? prev + 1 : prev);
|
|
661
|
+
} else if (key.return) {
|
|
662
|
+
doSelect(selected);
|
|
663
|
+
} else if (input === "y" && options.length === 2) {
|
|
664
|
+
doSelect(0);
|
|
665
|
+
} else if (input === "n" && options.length === 2) {
|
|
666
|
+
doSelect(1);
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
670
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: message }),
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
672
|
+
i === selected ? "> " : " ",
|
|
673
|
+
opt
|
|
674
|
+
] }) }, opt)) }),
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
|
|
676
|
+
] });
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// src/ui/PermissionPrompt.tsx
|
|
680
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
681
|
+
var import_ink8 = require("ink");
|
|
682
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
631
683
|
var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
|
|
632
684
|
function formatArgs(args) {
|
|
633
685
|
const entries = Object.entries(args);
|
|
@@ -635,15 +687,15 @@ function formatArgs(args) {
|
|
|
635
687
|
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
636
688
|
}
|
|
637
689
|
function PermissionPrompt({ request }) {
|
|
638
|
-
const [selected, setSelected] =
|
|
639
|
-
const resolvedRef =
|
|
640
|
-
const prevRequestRef =
|
|
690
|
+
const [selected, setSelected] = import_react5.default.useState(0);
|
|
691
|
+
const resolvedRef = import_react5.default.useRef(false);
|
|
692
|
+
const prevRequestRef = import_react5.default.useRef(request);
|
|
641
693
|
if (prevRequestRef.current !== request) {
|
|
642
694
|
prevRequestRef.current = request;
|
|
643
695
|
resolvedRef.current = false;
|
|
644
696
|
setSelected(0);
|
|
645
697
|
}
|
|
646
|
-
const doResolve =
|
|
698
|
+
const doResolve = import_react5.default.useCallback(
|
|
647
699
|
(index) => {
|
|
648
700
|
if (resolvedRef.current) return;
|
|
649
701
|
resolvedRef.current = true;
|
|
@@ -653,7 +705,7 @@ function PermissionPrompt({ request }) {
|
|
|
653
705
|
},
|
|
654
706
|
[request]
|
|
655
707
|
);
|
|
656
|
-
(0,
|
|
708
|
+
(0, import_ink8.useInput)((input, key) => {
|
|
657
709
|
if (resolvedRef.current) return;
|
|
658
710
|
if (key.upArrow || key.leftArrow) {
|
|
659
711
|
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
@@ -669,27 +721,27 @@ function PermissionPrompt({ request }) {
|
|
|
669
721
|
doResolve(2);
|
|
670
722
|
}
|
|
671
723
|
});
|
|
672
|
-
return /* @__PURE__ */ (0,
|
|
673
|
-
/* @__PURE__ */ (0,
|
|
674
|
-
/* @__PURE__ */ (0,
|
|
724
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { children: [
|
|
675
727
|
"Tool:",
|
|
676
728
|
" ",
|
|
677
|
-
/* @__PURE__ */ (0,
|
|
729
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: request.toolName })
|
|
678
730
|
] }),
|
|
679
|
-
/* @__PURE__ */ (0,
|
|
731
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { dimColor: true, children: [
|
|
680
732
|
" ",
|
|
681
733
|
formatArgs(request.toolArgs)
|
|
682
734
|
] }),
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
684
736
|
i === selected ? "> " : " ",
|
|
685
737
|
opt
|
|
686
738
|
] }) }, opt)) }),
|
|
687
|
-
/* @__PURE__ */ (0,
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
|
|
688
740
|
] });
|
|
689
741
|
}
|
|
690
742
|
|
|
691
743
|
// src/ui/App.tsx
|
|
692
|
-
var
|
|
744
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
693
745
|
var msgIdCounter = 0;
|
|
694
746
|
function nextId() {
|
|
695
747
|
msgIdCounter += 1;
|
|
@@ -711,11 +763,11 @@ var NOOP_TERMINAL = {
|
|
|
711
763
|
} })
|
|
712
764
|
};
|
|
713
765
|
function useSession(props) {
|
|
714
|
-
const [permissionRequest, setPermissionRequest] = (0,
|
|
715
|
-
const [streamingText, setStreamingText] = (0,
|
|
716
|
-
const permissionQueueRef = (0,
|
|
717
|
-
const processingRef = (0,
|
|
718
|
-
const processNextPermission = (0,
|
|
766
|
+
const [permissionRequest, setPermissionRequest] = (0, import_react6.useState)(null);
|
|
767
|
+
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
768
|
+
const permissionQueueRef = (0, import_react6.useRef)([]);
|
|
769
|
+
const processingRef = (0, import_react6.useRef)(false);
|
|
770
|
+
const processNextPermission = (0, import_react6.useCallback)(() => {
|
|
719
771
|
if (processingRef.current) return;
|
|
720
772
|
const next = permissionQueueRef.current[0];
|
|
721
773
|
if (!next) {
|
|
@@ -735,7 +787,7 @@ function useSession(props) {
|
|
|
735
787
|
}
|
|
736
788
|
});
|
|
737
789
|
}, []);
|
|
738
|
-
const sessionRef = (0,
|
|
790
|
+
const sessionRef = (0, import_react6.useRef)(null);
|
|
739
791
|
if (sessionRef.current === null) {
|
|
740
792
|
const permissionHandler = (toolName, toolArgs) => {
|
|
741
793
|
return new Promise((resolve) => {
|
|
@@ -760,12 +812,12 @@ function useSession(props) {
|
|
|
760
812
|
onTextDelta
|
|
761
813
|
});
|
|
762
814
|
}
|
|
763
|
-
const clearStreamingText = (0,
|
|
815
|
+
const clearStreamingText = (0, import_react6.useCallback)(() => setStreamingText(""), []);
|
|
764
816
|
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText };
|
|
765
817
|
}
|
|
766
818
|
function useMessages() {
|
|
767
|
-
const [messages, setMessages] = (0,
|
|
768
|
-
const addMessage = (0,
|
|
819
|
+
const [messages, setMessages] = (0, import_react6.useState)([]);
|
|
820
|
+
const addMessage = (0, import_react6.useCallback)((msg) => {
|
|
769
821
|
setMessages((prev) => [...prev, { ...msg, id: nextId(), timestamp: /* @__PURE__ */ new Date() }]);
|
|
770
822
|
}, []);
|
|
771
823
|
return { messages, setMessages, addMessage };
|
|
@@ -792,7 +844,7 @@ function handleModeCommand(arg, session, addMessage) {
|
|
|
792
844
|
}
|
|
793
845
|
return true;
|
|
794
846
|
}
|
|
795
|
-
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry) {
|
|
847
|
+
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
|
|
796
848
|
switch (cmd) {
|
|
797
849
|
case "help":
|
|
798
850
|
addMessage({ role: "system", content: HELP_TEXT });
|
|
@@ -816,6 +868,16 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
|
|
|
816
868
|
}
|
|
817
869
|
case "mode":
|
|
818
870
|
return handleModeCommand(parts[1], session, addMessage);
|
|
871
|
+
case "model": {
|
|
872
|
+
const modelId = parts[1];
|
|
873
|
+
if (!modelId) {
|
|
874
|
+
addMessage({ role: "system", content: "Select a model from the /model submenu." });
|
|
875
|
+
return true;
|
|
876
|
+
}
|
|
877
|
+
pendingModelChangeRef.current = modelId;
|
|
878
|
+
setPendingModelId(modelId);
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
819
881
|
case "cost":
|
|
820
882
|
addMessage({
|
|
821
883
|
role: "system",
|
|
@@ -844,11 +906,10 @@ Messages: ${session.getMessageCount()}`
|
|
|
844
906
|
return true;
|
|
845
907
|
}
|
|
846
908
|
case "reset": {
|
|
847
|
-
const { existsSync: exists, unlinkSync: unlink } = await import("fs");
|
|
848
909
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
849
910
|
const settingsPath = `${home}/.robota/settings.json`;
|
|
850
|
-
if (
|
|
851
|
-
|
|
911
|
+
if ((0, import_node_fs2.existsSync)(settingsPath)) {
|
|
912
|
+
(0, import_node_fs2.unlinkSync)(settingsPath);
|
|
852
913
|
addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
|
|
853
914
|
} else {
|
|
854
915
|
addMessage({ role: "system", content: "No user settings found." });
|
|
@@ -870,28 +931,28 @@ Messages: ${session.getMessageCount()}`
|
|
|
870
931
|
}
|
|
871
932
|
}
|
|
872
933
|
}
|
|
873
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry) {
|
|
874
|
-
return (0,
|
|
934
|
+
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
|
|
935
|
+
return (0, import_react6.useCallback)(
|
|
875
936
|
async (input) => {
|
|
876
937
|
const parts = input.slice(1).split(/\s+/);
|
|
877
938
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
878
|
-
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry);
|
|
939
|
+
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
|
|
879
940
|
},
|
|
880
|
-
[session, addMessage, setMessages, exit, registry]
|
|
941
|
+
[session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
|
|
881
942
|
);
|
|
882
943
|
}
|
|
883
944
|
function StreamingIndicator({ text }) {
|
|
884
945
|
if (text) {
|
|
885
|
-
return /* @__PURE__ */ (0,
|
|
886
|
-
/* @__PURE__ */ (0,
|
|
946
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: "cyan", bold: true, children: [
|
|
887
948
|
"Robota:",
|
|
888
949
|
" "
|
|
889
950
|
] }),
|
|
890
|
-
/* @__PURE__ */ (0,
|
|
891
|
-
/* @__PURE__ */ (0,
|
|
951
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
892
953
|
] });
|
|
893
954
|
}
|
|
894
|
-
return /* @__PURE__ */ (0,
|
|
955
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
|
|
895
956
|
}
|
|
896
957
|
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
|
|
897
958
|
setIsThinking(true);
|
|
@@ -953,7 +1014,7 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
953
1014
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
954
1015
|
}
|
|
955
1016
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
|
|
956
|
-
return (0,
|
|
1017
|
+
return (0, import_react6.useCallback)(
|
|
957
1018
|
async (input) => {
|
|
958
1019
|
if (input.startsWith("/")) {
|
|
959
1020
|
const handled = await handleSlashCommand(input);
|
|
@@ -994,7 +1055,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
994
1055
|
);
|
|
995
1056
|
}
|
|
996
1057
|
function useCommandRegistry(cwd) {
|
|
997
|
-
const registryRef = (0,
|
|
1058
|
+
const registryRef = (0, import_react6.useRef)(null);
|
|
998
1059
|
if (registryRef.current === null) {
|
|
999
1060
|
const registry = new CommandRegistry();
|
|
1000
1061
|
registry.addSource(new BuiltinCommandSource());
|
|
@@ -1004,13 +1065,15 @@ function useCommandRegistry(cwd) {
|
|
|
1004
1065
|
return registryRef.current;
|
|
1005
1066
|
}
|
|
1006
1067
|
function App(props) {
|
|
1007
|
-
const { exit } = (0,
|
|
1068
|
+
const { exit } = (0, import_ink9.useApp)();
|
|
1008
1069
|
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
1009
1070
|
const { messages, setMessages, addMessage } = useMessages();
|
|
1010
|
-
const [isThinking, setIsThinking] = (0,
|
|
1011
|
-
const [contextPercentage, setContextPercentage] = (0,
|
|
1071
|
+
const [isThinking, setIsThinking] = (0, import_react6.useState)(false);
|
|
1072
|
+
const [contextPercentage, setContextPercentage] = (0, import_react6.useState)(0);
|
|
1012
1073
|
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
1013
|
-
const
|
|
1074
|
+
const pendingModelChangeRef = (0, import_react6.useRef)(null);
|
|
1075
|
+
const [pendingModelId, setPendingModelId] = (0, import_react6.useState)(null);
|
|
1076
|
+
const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
|
|
1014
1077
|
const handleSubmit = useSubmitHandler(
|
|
1015
1078
|
session,
|
|
1016
1079
|
addMessage,
|
|
@@ -1020,37 +1083,68 @@ function App(props) {
|
|
|
1020
1083
|
setContextPercentage,
|
|
1021
1084
|
registry
|
|
1022
1085
|
);
|
|
1023
|
-
(0,
|
|
1086
|
+
(0, import_ink9.useInput)(
|
|
1024
1087
|
(_input, key) => {
|
|
1025
1088
|
if (key.ctrl && _input === "c") exit();
|
|
1026
1089
|
if (key.escape && isThinking) session.abort();
|
|
1027
1090
|
},
|
|
1028
1091
|
{ isActive: !permissionRequest }
|
|
1029
1092
|
);
|
|
1030
|
-
return /* @__PURE__ */ (0,
|
|
1031
|
-
/* @__PURE__ */ (0,
|
|
1032
|
-
/* @__PURE__ */ (0,
|
|
1093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: `
|
|
1033
1096
|
____ ___ ____ ___ _____ _
|
|
1034
1097
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1035
1098
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1036
1099
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1037
1100
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1038
1101
|
` }),
|
|
1039
|
-
/* @__PURE__ */ (0,
|
|
1102
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { dimColor: true, children: [
|
|
1040
1103
|
" v",
|
|
1041
1104
|
props.version ?? "0.0.0"
|
|
1042
1105
|
] })
|
|
1043
1106
|
] }),
|
|
1044
|
-
/* @__PURE__ */ (0,
|
|
1045
|
-
/* @__PURE__ */ (0,
|
|
1046
|
-
isThinking && /* @__PURE__ */ (0,
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageList, { messages }),
|
|
1109
|
+
isThinking && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StreamingIndicator, { text: streamingText }) })
|
|
1047
1110
|
] }),
|
|
1048
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
1049
|
-
/* @__PURE__ */ (0,
|
|
1111
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
1112
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1113
|
+
ConfirmPrompt,
|
|
1114
|
+
{
|
|
1115
|
+
message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
1116
|
+
onSelect: (index) => {
|
|
1117
|
+
setPendingModelId(null);
|
|
1118
|
+
pendingModelChangeRef.current = null;
|
|
1119
|
+
if (index === 0) {
|
|
1120
|
+
try {
|
|
1121
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1122
|
+
const settingsPath = (0, import_node_path2.join)(home, ".robota", "settings.json");
|
|
1123
|
+
let settings = {};
|
|
1124
|
+
if ((0, import_node_fs2.existsSync)(settingsPath)) {
|
|
1125
|
+
settings = JSON.parse((0, import_node_fs2.readFileSync)(settingsPath, "utf8"));
|
|
1126
|
+
}
|
|
1127
|
+
const provider = settings.provider ?? {};
|
|
1128
|
+
provider.model = pendingModelId;
|
|
1129
|
+
settings.provider = provider;
|
|
1130
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path2.join)(home, ".robota"), { recursive: true });
|
|
1131
|
+
(0, import_node_fs2.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1132
|
+
addMessage({ role: "system", content: `Model changed to ${(0, import_agent_core3.getModelName)(pendingModelId)}. Restarting...` });
|
|
1133
|
+
setTimeout(() => exit(), 500);
|
|
1134
|
+
} catch (err) {
|
|
1135
|
+
addMessage({ role: "system", content: `Failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
1136
|
+
}
|
|
1137
|
+
} else {
|
|
1138
|
+
addMessage({ role: "system", content: "Model change cancelled." });
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
),
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1050
1144
|
StatusBar,
|
|
1051
1145
|
{
|
|
1052
1146
|
permissionMode: session.getPermissionMode(),
|
|
1053
|
-
modelName: props.config.provider.model,
|
|
1147
|
+
modelName: (0, import_agent_core3.getModelName)(props.config.provider.model),
|
|
1054
1148
|
sessionId: session.getSessionId(),
|
|
1055
1149
|
messageCount: messages.length,
|
|
1056
1150
|
isThinking,
|
|
@@ -1059,7 +1153,7 @@ function App(props) {
|
|
|
1059
1153
|
contextMaxTokens: session.getContextState().maxTokens
|
|
1060
1154
|
}
|
|
1061
1155
|
),
|
|
1062
|
-
/* @__PURE__ */ (0,
|
|
1156
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1063
1157
|
InputArea,
|
|
1064
1158
|
{
|
|
1065
1159
|
onSubmit: handleSubmit,
|
|
@@ -1067,12 +1161,12 @@ function App(props) {
|
|
|
1067
1161
|
registry
|
|
1068
1162
|
}
|
|
1069
1163
|
),
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1164
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " })
|
|
1071
1165
|
] });
|
|
1072
1166
|
}
|
|
1073
1167
|
|
|
1074
1168
|
// src/ui/render.tsx
|
|
1075
|
-
var
|
|
1169
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1076
1170
|
function renderApp(options) {
|
|
1077
1171
|
process.on("unhandledRejection", (reason) => {
|
|
1078
1172
|
process.stderr.write(`
|
|
@@ -1083,7 +1177,7 @@ function renderApp(options) {
|
|
|
1083
1177
|
`);
|
|
1084
1178
|
}
|
|
1085
1179
|
});
|
|
1086
|
-
const instance = (0,
|
|
1180
|
+
const instance = (0, import_ink10.render)(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(App, { ...options }), {
|
|
1087
1181
|
exitOnCtrlC: true
|
|
1088
1182
|
});
|
|
1089
1183
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -1101,11 +1195,11 @@ var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
|
1101
1195
|
function readVersion() {
|
|
1102
1196
|
try {
|
|
1103
1197
|
const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
1104
|
-
const dir = (0,
|
|
1105
|
-
const candidates = [(0,
|
|
1198
|
+
const dir = (0, import_node_path3.dirname)(thisFile);
|
|
1199
|
+
const candidates = [(0, import_node_path3.join)(dir, "..", "..", "package.json"), (0, import_node_path3.join)(dir, "..", "package.json")];
|
|
1106
1200
|
for (const pkgPath of candidates) {
|
|
1107
1201
|
try {
|
|
1108
|
-
const raw = (0,
|
|
1202
|
+
const raw = (0, import_node_fs3.readFileSync)(pkgPath, "utf-8");
|
|
1109
1203
|
const pkg = JSON.parse(raw);
|
|
1110
1204
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
1111
1205
|
return pkg.version;
|
|
@@ -1213,13 +1307,13 @@ var PrintTerminal = class {
|
|
|
1213
1307
|
};
|
|
1214
1308
|
function getUserSettingsPath() {
|
|
1215
1309
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1216
|
-
return (0,
|
|
1310
|
+
return (0, import_node_path3.join)(home, ".robota", "settings.json");
|
|
1217
1311
|
}
|
|
1218
1312
|
async function ensureConfig(cwd) {
|
|
1219
1313
|
const userPath = getUserSettingsPath();
|
|
1220
|
-
const projectPath = (0,
|
|
1221
|
-
const localPath = (0,
|
|
1222
|
-
if ((0,
|
|
1314
|
+
const projectPath = (0, import_node_path3.join)(cwd, ".robota", "settings.json");
|
|
1315
|
+
const localPath = (0, import_node_path3.join)(cwd, ".robota", "settings.local.json");
|
|
1316
|
+
if ((0, import_node_fs3.existsSync)(userPath) || (0, import_node_fs3.existsSync)(projectPath) || (0, import_node_fs3.existsSync)(localPath)) {
|
|
1223
1317
|
return;
|
|
1224
1318
|
}
|
|
1225
1319
|
process.stdout.write("\n");
|
|
@@ -1263,8 +1357,8 @@ async function ensureConfig(cwd) {
|
|
|
1263
1357
|
process.stderr.write("\n No API key provided. Exiting.\n");
|
|
1264
1358
|
process.exit(1);
|
|
1265
1359
|
}
|
|
1266
|
-
const settingsDir = (0,
|
|
1267
|
-
(0,
|
|
1360
|
+
const settingsDir = (0, import_node_path3.dirname)(userPath);
|
|
1361
|
+
(0, import_node_fs3.mkdirSync)(settingsDir, { recursive: true });
|
|
1268
1362
|
const settings = {
|
|
1269
1363
|
provider: {
|
|
1270
1364
|
name: "anthropic",
|
|
@@ -1272,7 +1366,7 @@ async function ensureConfig(cwd) {
|
|
|
1272
1366
|
apiKey
|
|
1273
1367
|
}
|
|
1274
1368
|
};
|
|
1275
|
-
(0,
|
|
1369
|
+
(0, import_node_fs3.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1276
1370
|
process.stdout.write(`
|
|
1277
1371
|
Config saved to ${userPath}
|
|
1278
1372
|
|
|
@@ -1280,8 +1374,8 @@ async function ensureConfig(cwd) {
|
|
|
1280
1374
|
}
|
|
1281
1375
|
function resetConfig() {
|
|
1282
1376
|
const userPath = getUserSettingsPath();
|
|
1283
|
-
if ((0,
|
|
1284
|
-
(0,
|
|
1377
|
+
if ((0, import_node_fs3.existsSync)(userPath)) {
|
|
1378
|
+
(0, import_node_fs3.unlinkSync)(userPath);
|
|
1285
1379
|
process.stdout.write(`Deleted ${userPath}
|
|
1286
1380
|
`);
|
|
1287
1381
|
} else {
|
package/dist/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-cli",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.16",
|
|
4
4
|
"description": "AI coding assistant CLI built on Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,12 +35,13 @@
|
|
|
35
35
|
"marked-terminal": "^7.3.0",
|
|
36
36
|
"react": "19.2.4",
|
|
37
37
|
"string-width": "^8.2.0",
|
|
38
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
39
|
-
"@robota-sdk/agent-sdk": "3.0.0-beta.
|
|
38
|
+
"@robota-sdk/agent-core": "3.0.0-beta.16",
|
|
39
|
+
"@robota-sdk/agent-sdk": "3.0.0-beta.16"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/marked": "^6.0.0",
|
|
43
43
|
"@types/react": "^19.2.14",
|
|
44
|
+
"ink-testing-library": "^4.0.0",
|
|
44
45
|
"rimraf": "^5.0.5",
|
|
45
46
|
"tsup": "^8.0.1",
|
|
46
47
|
"tsx": "^4.7.0",
|