@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/README.md
CHANGED
|
@@ -75,9 +75,14 @@ robota -r <session-id> # Resume session by ID
|
|
|
75
75
|
robota --model <model> # Model override (e.g., claude-sonnet-4-6)
|
|
76
76
|
robota --permission-mode <mode> # plan | default | acceptEdits | bypassPermissions
|
|
77
77
|
robota --max-turns <n> # Limit agentic turns per interaction
|
|
78
|
+
robota --reset # Delete user settings and exit
|
|
78
79
|
robota --version # Show version
|
|
79
80
|
```
|
|
80
81
|
|
|
82
|
+
## First-Run Setup
|
|
83
|
+
|
|
84
|
+
When no settings file exists, the CLI prompts for an Anthropic API key (input masked with asterisks) and creates `~/.robota/settings.json`. Use `robota --reset` to return to first-run state.
|
|
85
|
+
|
|
81
86
|
## Built-in Tools
|
|
82
87
|
|
|
83
88
|
The CLI provides 6 tools that the AI agent can invoke:
|
|
@@ -177,9 +182,11 @@ Configure in `.robota/settings.json` or `.robota/settings.local.json`:
|
|
|
177
182
|
| `/help` | Show help |
|
|
178
183
|
| `/clear` | Clear conversation history |
|
|
179
184
|
| `/mode [mode]` | Show or change permission mode |
|
|
180
|
-
| `/
|
|
181
|
-
| `/
|
|
182
|
-
| `/
|
|
185
|
+
| `/model [model]`| Select AI model (confirmation + restart) |
|
|
186
|
+
| `/compact [instructions]` | Compress context window |
|
|
187
|
+
| `/cost` | Show session info |
|
|
188
|
+
| `/context` | Context window details |
|
|
189
|
+
| `/permissions` | Show permission rules |
|
|
183
190
|
| `/exit` | Exit CLI |
|
|
184
191
|
|
|
185
192
|
## Configuration
|
package/dist/node/bin.cjs
CHANGED
|
@@ -25,20 +25,23 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
27
|
var import_node_util = require("util");
|
|
28
|
-
var
|
|
29
|
-
var
|
|
28
|
+
var import_node_fs3 = require("fs");
|
|
29
|
+
var import_node_path3 = require("path");
|
|
30
30
|
var import_node_url = require("url");
|
|
31
31
|
var readline = __toESM(require("readline"), 1);
|
|
32
32
|
var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
|
|
33
33
|
var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
|
|
34
34
|
|
|
35
35
|
// src/ui/render.tsx
|
|
36
|
-
var
|
|
36
|
+
var import_ink10 = require("ink");
|
|
37
37
|
|
|
38
38
|
// src/ui/App.tsx
|
|
39
|
-
var
|
|
40
|
-
var
|
|
39
|
+
var import_react6 = require("react");
|
|
40
|
+
var import_ink9 = require("ink");
|
|
41
|
+
var import_node_fs2 = require("fs");
|
|
42
|
+
var import_node_path2 = require("path");
|
|
41
43
|
var import_agent_sdk = require("@robota-sdk/agent-sdk");
|
|
44
|
+
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
42
45
|
|
|
43
46
|
// src/commands/command-registry.ts
|
|
44
47
|
var CommandRegistry = class {
|
|
@@ -71,6 +74,21 @@ var CommandRegistry = class {
|
|
|
71
74
|
};
|
|
72
75
|
|
|
73
76
|
// src/commands/builtin-source.ts
|
|
77
|
+
var import_agent_core = require("@robota-sdk/agent-core");
|
|
78
|
+
function buildModelSubcommands() {
|
|
79
|
+
const seen = /* @__PURE__ */ new Set();
|
|
80
|
+
const commands = [];
|
|
81
|
+
for (const model of Object.values(import_agent_core.CLAUDE_MODELS)) {
|
|
82
|
+
if (seen.has(model.name)) continue;
|
|
83
|
+
seen.add(model.name);
|
|
84
|
+
commands.push({
|
|
85
|
+
name: model.id,
|
|
86
|
+
description: `${model.name} (${(0, import_agent_core.formatTokenCount)(model.contextWindow).toUpperCase()})`,
|
|
87
|
+
source: "builtin"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return commands;
|
|
91
|
+
}
|
|
74
92
|
function createBuiltinCommands() {
|
|
75
93
|
return [
|
|
76
94
|
{ name: "help", description: "Show available commands", source: "builtin" },
|
|
@@ -90,11 +108,7 @@ function createBuiltinCommands() {
|
|
|
90
108
|
name: "model",
|
|
91
109
|
description: "Select AI model",
|
|
92
110
|
source: "builtin",
|
|
93
|
-
subcommands:
|
|
94
|
-
{ name: "claude-opus-4-6", description: "Opus 4.6 (highest quality)", source: "builtin" },
|
|
95
|
-
{ name: "claude-sonnet-4-6", description: "Sonnet 4.6 (balanced)", source: "builtin" },
|
|
96
|
-
{ name: "claude-haiku-4-5", description: "Haiku 4.5 (fastest)", source: "builtin" }
|
|
97
|
-
]
|
|
111
|
+
subcommands: buildModelSubcommands()
|
|
98
112
|
},
|
|
99
113
|
{ name: "compact", description: "Compress context window", source: "builtin" },
|
|
100
114
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
@@ -242,6 +256,7 @@ function MessageList({ messages }) {
|
|
|
242
256
|
|
|
243
257
|
// src/ui/StatusBar.tsx
|
|
244
258
|
var import_ink2 = require("ink");
|
|
259
|
+
var import_agent_core2 = require("@robota-sdk/agent-core");
|
|
245
260
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
246
261
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
247
262
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
@@ -281,10 +296,10 @@ function StatusBar({
|
|
|
281
296
|
"Context: ",
|
|
282
297
|
Math.round(contextPercentage),
|
|
283
298
|
"% (",
|
|
284
|
-
(
|
|
285
|
-
"
|
|
286
|
-
(
|
|
287
|
-
"
|
|
299
|
+
(0, import_agent_core2.formatTokenCount)(contextUsedTokens),
|
|
300
|
+
"/",
|
|
301
|
+
(0, import_agent_core2.formatTokenCount)(contextMaxTokens),
|
|
302
|
+
")"
|
|
288
303
|
] })
|
|
289
304
|
] }),
|
|
290
305
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { children: [
|
|
@@ -431,19 +446,13 @@ var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
|
431
446
|
var MAX_VISIBLE = 8;
|
|
432
447
|
function CommandRow(props) {
|
|
433
448
|
const { cmd, isSelected, showSlash } = props;
|
|
434
|
-
const prefix = showSlash ? "/" : "";
|
|
435
449
|
const indicator = isSelected ? "\u25B8 " : " ";
|
|
436
450
|
const nameColor = isSelected ? "cyan" : void 0;
|
|
437
451
|
const dimmed = !isSelected;
|
|
438
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
cmd.name
|
|
443
|
-
] }),
|
|
444
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { dimColor: dimmed, children: " " }),
|
|
445
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: cmd.description })
|
|
446
|
-
] });
|
|
452
|
+
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: [
|
|
453
|
+
indicator,
|
|
454
|
+
showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
|
|
455
|
+
] }) });
|
|
447
456
|
}
|
|
448
457
|
function SlashAutocomplete({
|
|
449
458
|
commands,
|
|
@@ -608,10 +617,53 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
608
617
|
] });
|
|
609
618
|
}
|
|
610
619
|
|
|
611
|
-
// src/ui/
|
|
612
|
-
var import_react4 =
|
|
620
|
+
// src/ui/ConfirmPrompt.tsx
|
|
621
|
+
var import_react4 = require("react");
|
|
613
622
|
var import_ink7 = require("ink");
|
|
614
623
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
624
|
+
function ConfirmPrompt({
|
|
625
|
+
message,
|
|
626
|
+
options = ["Yes", "No"],
|
|
627
|
+
onSelect
|
|
628
|
+
}) {
|
|
629
|
+
const [selected, setSelected] = (0, import_react4.useState)(0);
|
|
630
|
+
const resolvedRef = (0, import_react4.useRef)(false);
|
|
631
|
+
const doSelect = (0, import_react4.useCallback)(
|
|
632
|
+
(index) => {
|
|
633
|
+
if (resolvedRef.current) return;
|
|
634
|
+
resolvedRef.current = true;
|
|
635
|
+
onSelect(index);
|
|
636
|
+
},
|
|
637
|
+
[onSelect]
|
|
638
|
+
);
|
|
639
|
+
(0, import_ink7.useInput)((input, key) => {
|
|
640
|
+
if (resolvedRef.current) return;
|
|
641
|
+
if (key.leftArrow || key.upArrow) {
|
|
642
|
+
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
643
|
+
} else if (key.rightArrow || key.downArrow) {
|
|
644
|
+
setSelected((prev) => prev < options.length - 1 ? prev + 1 : prev);
|
|
645
|
+
} else if (key.return) {
|
|
646
|
+
doSelect(selected);
|
|
647
|
+
} else if (input === "y" && options.length === 2) {
|
|
648
|
+
doSelect(0);
|
|
649
|
+
} else if (input === "n" && options.length === 2) {
|
|
650
|
+
doSelect(1);
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: message }),
|
|
655
|
+
/* @__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: [
|
|
656
|
+
i === selected ? "> " : " ",
|
|
657
|
+
opt
|
|
658
|
+
] }) }, opt)) }),
|
|
659
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
|
|
660
|
+
] });
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/ui/PermissionPrompt.tsx
|
|
664
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
665
|
+
var import_ink8 = require("ink");
|
|
666
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
615
667
|
var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
|
|
616
668
|
function formatArgs(args) {
|
|
617
669
|
const entries = Object.entries(args);
|
|
@@ -619,15 +671,15 @@ function formatArgs(args) {
|
|
|
619
671
|
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
620
672
|
}
|
|
621
673
|
function PermissionPrompt({ request }) {
|
|
622
|
-
const [selected, setSelected] =
|
|
623
|
-
const resolvedRef =
|
|
624
|
-
const prevRequestRef =
|
|
674
|
+
const [selected, setSelected] = import_react5.default.useState(0);
|
|
675
|
+
const resolvedRef = import_react5.default.useRef(false);
|
|
676
|
+
const prevRequestRef = import_react5.default.useRef(request);
|
|
625
677
|
if (prevRequestRef.current !== request) {
|
|
626
678
|
prevRequestRef.current = request;
|
|
627
679
|
resolvedRef.current = false;
|
|
628
680
|
setSelected(0);
|
|
629
681
|
}
|
|
630
|
-
const doResolve =
|
|
682
|
+
const doResolve = import_react5.default.useCallback(
|
|
631
683
|
(index) => {
|
|
632
684
|
if (resolvedRef.current) return;
|
|
633
685
|
resolvedRef.current = true;
|
|
@@ -637,7 +689,7 @@ function PermissionPrompt({ request }) {
|
|
|
637
689
|
},
|
|
638
690
|
[request]
|
|
639
691
|
);
|
|
640
|
-
(0,
|
|
692
|
+
(0, import_ink8.useInput)((input, key) => {
|
|
641
693
|
if (resolvedRef.current) return;
|
|
642
694
|
if (key.upArrow || key.leftArrow) {
|
|
643
695
|
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
@@ -653,27 +705,27 @@ function PermissionPrompt({ request }) {
|
|
|
653
705
|
doResolve(2);
|
|
654
706
|
}
|
|
655
707
|
});
|
|
656
|
-
return /* @__PURE__ */ (0,
|
|
657
|
-
/* @__PURE__ */ (0,
|
|
658
|
-
/* @__PURE__ */ (0,
|
|
708
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
709
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
|
|
710
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { children: [
|
|
659
711
|
"Tool:",
|
|
660
712
|
" ",
|
|
661
|
-
/* @__PURE__ */ (0,
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: request.toolName })
|
|
662
714
|
] }),
|
|
663
|
-
/* @__PURE__ */ (0,
|
|
715
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { dimColor: true, children: [
|
|
664
716
|
" ",
|
|
665
717
|
formatArgs(request.toolArgs)
|
|
666
718
|
] }),
|
|
667
|
-
/* @__PURE__ */ (0,
|
|
719
|
+
/* @__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: [
|
|
668
720
|
i === selected ? "> " : " ",
|
|
669
721
|
opt
|
|
670
722
|
] }) }, opt)) }),
|
|
671
|
-
/* @__PURE__ */ (0,
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
|
|
672
724
|
] });
|
|
673
725
|
}
|
|
674
726
|
|
|
675
727
|
// src/ui/App.tsx
|
|
676
|
-
var
|
|
728
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
677
729
|
var msgIdCounter = 0;
|
|
678
730
|
function nextId() {
|
|
679
731
|
msgIdCounter += 1;
|
|
@@ -695,11 +747,11 @@ var NOOP_TERMINAL = {
|
|
|
695
747
|
} })
|
|
696
748
|
};
|
|
697
749
|
function useSession(props) {
|
|
698
|
-
const [permissionRequest, setPermissionRequest] = (0,
|
|
699
|
-
const [streamingText, setStreamingText] = (0,
|
|
700
|
-
const permissionQueueRef = (0,
|
|
701
|
-
const processingRef = (0,
|
|
702
|
-
const processNextPermission = (0,
|
|
750
|
+
const [permissionRequest, setPermissionRequest] = (0, import_react6.useState)(null);
|
|
751
|
+
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
752
|
+
const permissionQueueRef = (0, import_react6.useRef)([]);
|
|
753
|
+
const processingRef = (0, import_react6.useRef)(false);
|
|
754
|
+
const processNextPermission = (0, import_react6.useCallback)(() => {
|
|
703
755
|
if (processingRef.current) return;
|
|
704
756
|
const next = permissionQueueRef.current[0];
|
|
705
757
|
if (!next) {
|
|
@@ -719,7 +771,7 @@ function useSession(props) {
|
|
|
719
771
|
}
|
|
720
772
|
});
|
|
721
773
|
}, []);
|
|
722
|
-
const sessionRef = (0,
|
|
774
|
+
const sessionRef = (0, import_react6.useRef)(null);
|
|
723
775
|
if (sessionRef.current === null) {
|
|
724
776
|
const permissionHandler = (toolName, toolArgs) => {
|
|
725
777
|
return new Promise((resolve) => {
|
|
@@ -744,12 +796,12 @@ function useSession(props) {
|
|
|
744
796
|
onTextDelta
|
|
745
797
|
});
|
|
746
798
|
}
|
|
747
|
-
const clearStreamingText = (0,
|
|
799
|
+
const clearStreamingText = (0, import_react6.useCallback)(() => setStreamingText(""), []);
|
|
748
800
|
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText };
|
|
749
801
|
}
|
|
750
802
|
function useMessages() {
|
|
751
|
-
const [messages, setMessages] = (0,
|
|
752
|
-
const addMessage = (0,
|
|
803
|
+
const [messages, setMessages] = (0, import_react6.useState)([]);
|
|
804
|
+
const addMessage = (0, import_react6.useCallback)((msg) => {
|
|
753
805
|
setMessages((prev) => [...prev, { ...msg, id: nextId(), timestamp: /* @__PURE__ */ new Date() }]);
|
|
754
806
|
}, []);
|
|
755
807
|
return { messages, setMessages, addMessage };
|
|
@@ -776,7 +828,7 @@ function handleModeCommand(arg, session, addMessage) {
|
|
|
776
828
|
}
|
|
777
829
|
return true;
|
|
778
830
|
}
|
|
779
|
-
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry) {
|
|
831
|
+
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
|
|
780
832
|
switch (cmd) {
|
|
781
833
|
case "help":
|
|
782
834
|
addMessage({ role: "system", content: HELP_TEXT });
|
|
@@ -800,6 +852,16 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
|
|
|
800
852
|
}
|
|
801
853
|
case "mode":
|
|
802
854
|
return handleModeCommand(parts[1], session, addMessage);
|
|
855
|
+
case "model": {
|
|
856
|
+
const modelId = parts[1];
|
|
857
|
+
if (!modelId) {
|
|
858
|
+
addMessage({ role: "system", content: "Select a model from the /model submenu." });
|
|
859
|
+
return true;
|
|
860
|
+
}
|
|
861
|
+
pendingModelChangeRef.current = modelId;
|
|
862
|
+
setPendingModelId(modelId);
|
|
863
|
+
return true;
|
|
864
|
+
}
|
|
803
865
|
case "cost":
|
|
804
866
|
addMessage({
|
|
805
867
|
role: "system",
|
|
@@ -828,11 +890,10 @@ Messages: ${session.getMessageCount()}`
|
|
|
828
890
|
return true;
|
|
829
891
|
}
|
|
830
892
|
case "reset": {
|
|
831
|
-
const { existsSync: exists, unlinkSync: unlink } = await import("fs");
|
|
832
893
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
833
894
|
const settingsPath = `${home}/.robota/settings.json`;
|
|
834
|
-
if (
|
|
835
|
-
|
|
895
|
+
if ((0, import_node_fs2.existsSync)(settingsPath)) {
|
|
896
|
+
(0, import_node_fs2.unlinkSync)(settingsPath);
|
|
836
897
|
addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
|
|
837
898
|
} else {
|
|
838
899
|
addMessage({ role: "system", content: "No user settings found." });
|
|
@@ -854,28 +915,28 @@ Messages: ${session.getMessageCount()}`
|
|
|
854
915
|
}
|
|
855
916
|
}
|
|
856
917
|
}
|
|
857
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry) {
|
|
858
|
-
return (0,
|
|
918
|
+
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
|
|
919
|
+
return (0, import_react6.useCallback)(
|
|
859
920
|
async (input) => {
|
|
860
921
|
const parts = input.slice(1).split(/\s+/);
|
|
861
922
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
862
|
-
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry);
|
|
923
|
+
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
|
|
863
924
|
},
|
|
864
|
-
[session, addMessage, setMessages, exit, registry]
|
|
925
|
+
[session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
|
|
865
926
|
);
|
|
866
927
|
}
|
|
867
928
|
function StreamingIndicator({ text }) {
|
|
868
929
|
if (text) {
|
|
869
|
-
return /* @__PURE__ */ (0,
|
|
870
|
-
/* @__PURE__ */ (0,
|
|
930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: "cyan", bold: true, children: [
|
|
871
932
|
"Robota:",
|
|
872
933
|
" "
|
|
873
934
|
] }),
|
|
874
|
-
/* @__PURE__ */ (0,
|
|
875
|
-
/* @__PURE__ */ (0,
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
936
|
+
/* @__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) }) })
|
|
876
937
|
] });
|
|
877
938
|
}
|
|
878
|
-
return /* @__PURE__ */ (0,
|
|
939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
|
|
879
940
|
}
|
|
880
941
|
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
|
|
881
942
|
setIsThinking(true);
|
|
@@ -937,7 +998,7 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
937
998
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
938
999
|
}
|
|
939
1000
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
|
|
940
|
-
return (0,
|
|
1001
|
+
return (0, import_react6.useCallback)(
|
|
941
1002
|
async (input) => {
|
|
942
1003
|
if (input.startsWith("/")) {
|
|
943
1004
|
const handled = await handleSlashCommand(input);
|
|
@@ -978,7 +1039,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
978
1039
|
);
|
|
979
1040
|
}
|
|
980
1041
|
function useCommandRegistry(cwd) {
|
|
981
|
-
const registryRef = (0,
|
|
1042
|
+
const registryRef = (0, import_react6.useRef)(null);
|
|
982
1043
|
if (registryRef.current === null) {
|
|
983
1044
|
const registry = new CommandRegistry();
|
|
984
1045
|
registry.addSource(new BuiltinCommandSource());
|
|
@@ -988,13 +1049,15 @@ function useCommandRegistry(cwd) {
|
|
|
988
1049
|
return registryRef.current;
|
|
989
1050
|
}
|
|
990
1051
|
function App(props) {
|
|
991
|
-
const { exit } = (0,
|
|
1052
|
+
const { exit } = (0, import_ink9.useApp)();
|
|
992
1053
|
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
993
1054
|
const { messages, setMessages, addMessage } = useMessages();
|
|
994
|
-
const [isThinking, setIsThinking] = (0,
|
|
995
|
-
const [contextPercentage, setContextPercentage] = (0,
|
|
1055
|
+
const [isThinking, setIsThinking] = (0, import_react6.useState)(false);
|
|
1056
|
+
const [contextPercentage, setContextPercentage] = (0, import_react6.useState)(0);
|
|
996
1057
|
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
997
|
-
const
|
|
1058
|
+
const pendingModelChangeRef = (0, import_react6.useRef)(null);
|
|
1059
|
+
const [pendingModelId, setPendingModelId] = (0, import_react6.useState)(null);
|
|
1060
|
+
const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
|
|
998
1061
|
const handleSubmit = useSubmitHandler(
|
|
999
1062
|
session,
|
|
1000
1063
|
addMessage,
|
|
@@ -1004,37 +1067,68 @@ function App(props) {
|
|
|
1004
1067
|
setContextPercentage,
|
|
1005
1068
|
registry
|
|
1006
1069
|
);
|
|
1007
|
-
(0,
|
|
1070
|
+
(0, import_ink9.useInput)(
|
|
1008
1071
|
(_input, key) => {
|
|
1009
1072
|
if (key.ctrl && _input === "c") exit();
|
|
1010
1073
|
if (key.escape && isThinking) session.abort();
|
|
1011
1074
|
},
|
|
1012
1075
|
{ isActive: !permissionRequest }
|
|
1013
1076
|
);
|
|
1014
|
-
return /* @__PURE__ */ (0,
|
|
1015
|
-
/* @__PURE__ */ (0,
|
|
1016
|
-
/* @__PURE__ */ (0,
|
|
1077
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: `
|
|
1017
1080
|
____ ___ ____ ___ _____ _
|
|
1018
1081
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1019
1082
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1020
1083
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1021
1084
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1022
1085
|
` }),
|
|
1023
|
-
/* @__PURE__ */ (0,
|
|
1086
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { dimColor: true, children: [
|
|
1024
1087
|
" v",
|
|
1025
1088
|
props.version ?? "0.0.0"
|
|
1026
1089
|
] })
|
|
1027
1090
|
] }),
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1029
|
-
/* @__PURE__ */ (0,
|
|
1030
|
-
isThinking && /* @__PURE__ */ (0,
|
|
1091
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1092
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageList, { messages }),
|
|
1093
|
+
isThinking && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StreamingIndicator, { text: streamingText }) })
|
|
1031
1094
|
] }),
|
|
1032
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1095
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
1096
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1097
|
+
ConfirmPrompt,
|
|
1098
|
+
{
|
|
1099
|
+
message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
1100
|
+
onSelect: (index) => {
|
|
1101
|
+
setPendingModelId(null);
|
|
1102
|
+
pendingModelChangeRef.current = null;
|
|
1103
|
+
if (index === 0) {
|
|
1104
|
+
try {
|
|
1105
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1106
|
+
const settingsPath = (0, import_node_path2.join)(home, ".robota", "settings.json");
|
|
1107
|
+
let settings = {};
|
|
1108
|
+
if ((0, import_node_fs2.existsSync)(settingsPath)) {
|
|
1109
|
+
settings = JSON.parse((0, import_node_fs2.readFileSync)(settingsPath, "utf8"));
|
|
1110
|
+
}
|
|
1111
|
+
const provider = settings.provider ?? {};
|
|
1112
|
+
provider.model = pendingModelId;
|
|
1113
|
+
settings.provider = provider;
|
|
1114
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path2.join)(home, ".robota"), { recursive: true });
|
|
1115
|
+
(0, import_node_fs2.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1116
|
+
addMessage({ role: "system", content: `Model changed to ${(0, import_agent_core3.getModelName)(pendingModelId)}. Restarting...` });
|
|
1117
|
+
setTimeout(() => exit(), 500);
|
|
1118
|
+
} catch (err) {
|
|
1119
|
+
addMessage({ role: "system", content: `Failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
1120
|
+
}
|
|
1121
|
+
} else {
|
|
1122
|
+
addMessage({ role: "system", content: "Model change cancelled." });
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
),
|
|
1127
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1034
1128
|
StatusBar,
|
|
1035
1129
|
{
|
|
1036
1130
|
permissionMode: session.getPermissionMode(),
|
|
1037
|
-
modelName: props.config.provider.model,
|
|
1131
|
+
modelName: (0, import_agent_core3.getModelName)(props.config.provider.model),
|
|
1038
1132
|
sessionId: session.getSessionId(),
|
|
1039
1133
|
messageCount: messages.length,
|
|
1040
1134
|
isThinking,
|
|
@@ -1043,7 +1137,7 @@ function App(props) {
|
|
|
1043
1137
|
contextMaxTokens: session.getContextState().maxTokens
|
|
1044
1138
|
}
|
|
1045
1139
|
),
|
|
1046
|
-
/* @__PURE__ */ (0,
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1047
1141
|
InputArea,
|
|
1048
1142
|
{
|
|
1049
1143
|
onSubmit: handleSubmit,
|
|
@@ -1051,12 +1145,12 @@ function App(props) {
|
|
|
1051
1145
|
registry
|
|
1052
1146
|
}
|
|
1053
1147
|
),
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1148
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " })
|
|
1055
1149
|
] });
|
|
1056
1150
|
}
|
|
1057
1151
|
|
|
1058
1152
|
// src/ui/render.tsx
|
|
1059
|
-
var
|
|
1153
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1060
1154
|
function renderApp(options) {
|
|
1061
1155
|
process.on("unhandledRejection", (reason) => {
|
|
1062
1156
|
process.stderr.write(`
|
|
@@ -1067,7 +1161,7 @@ function renderApp(options) {
|
|
|
1067
1161
|
`);
|
|
1068
1162
|
}
|
|
1069
1163
|
});
|
|
1070
|
-
const instance = (0,
|
|
1164
|
+
const instance = (0, import_ink10.render)(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(App, { ...options }), {
|
|
1071
1165
|
exitOnCtrlC: true
|
|
1072
1166
|
});
|
|
1073
1167
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -1085,11 +1179,11 @@ var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
|
1085
1179
|
function readVersion() {
|
|
1086
1180
|
try {
|
|
1087
1181
|
const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
1088
|
-
const dir = (0,
|
|
1089
|
-
const candidates = [(0,
|
|
1182
|
+
const dir = (0, import_node_path3.dirname)(thisFile);
|
|
1183
|
+
const candidates = [(0, import_node_path3.join)(dir, "..", "..", "package.json"), (0, import_node_path3.join)(dir, "..", "package.json")];
|
|
1090
1184
|
for (const pkgPath of candidates) {
|
|
1091
1185
|
try {
|
|
1092
|
-
const raw = (0,
|
|
1186
|
+
const raw = (0, import_node_fs3.readFileSync)(pkgPath, "utf-8");
|
|
1093
1187
|
const pkg = JSON.parse(raw);
|
|
1094
1188
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
1095
1189
|
return pkg.version;
|
|
@@ -1197,13 +1291,13 @@ var PrintTerminal = class {
|
|
|
1197
1291
|
};
|
|
1198
1292
|
function getUserSettingsPath() {
|
|
1199
1293
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1200
|
-
return (0,
|
|
1294
|
+
return (0, import_node_path3.join)(home, ".robota", "settings.json");
|
|
1201
1295
|
}
|
|
1202
1296
|
async function ensureConfig(cwd) {
|
|
1203
1297
|
const userPath = getUserSettingsPath();
|
|
1204
|
-
const projectPath = (0,
|
|
1205
|
-
const localPath = (0,
|
|
1206
|
-
if ((0,
|
|
1298
|
+
const projectPath = (0, import_node_path3.join)(cwd, ".robota", "settings.json");
|
|
1299
|
+
const localPath = (0, import_node_path3.join)(cwd, ".robota", "settings.local.json");
|
|
1300
|
+
if ((0, import_node_fs3.existsSync)(userPath) || (0, import_node_fs3.existsSync)(projectPath) || (0, import_node_fs3.existsSync)(localPath)) {
|
|
1207
1301
|
return;
|
|
1208
1302
|
}
|
|
1209
1303
|
process.stdout.write("\n");
|
|
@@ -1247,8 +1341,8 @@ async function ensureConfig(cwd) {
|
|
|
1247
1341
|
process.stderr.write("\n No API key provided. Exiting.\n");
|
|
1248
1342
|
process.exit(1);
|
|
1249
1343
|
}
|
|
1250
|
-
const settingsDir = (0,
|
|
1251
|
-
(0,
|
|
1344
|
+
const settingsDir = (0, import_node_path3.dirname)(userPath);
|
|
1345
|
+
(0, import_node_fs3.mkdirSync)(settingsDir, { recursive: true });
|
|
1252
1346
|
const settings = {
|
|
1253
1347
|
provider: {
|
|
1254
1348
|
name: "anthropic",
|
|
@@ -1256,7 +1350,7 @@ async function ensureConfig(cwd) {
|
|
|
1256
1350
|
apiKey
|
|
1257
1351
|
}
|
|
1258
1352
|
};
|
|
1259
|
-
(0,
|
|
1353
|
+
(0, import_node_fs3.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1260
1354
|
process.stdout.write(`
|
|
1261
1355
|
Config saved to ${userPath}
|
|
1262
1356
|
|
|
@@ -1264,8 +1358,8 @@ async function ensureConfig(cwd) {
|
|
|
1264
1358
|
}
|
|
1265
1359
|
function resetConfig() {
|
|
1266
1360
|
const userPath = getUserSettingsPath();
|
|
1267
|
-
if ((0,
|
|
1268
|
-
(0,
|
|
1361
|
+
if ((0, import_node_fs3.existsSync)(userPath)) {
|
|
1362
|
+
(0, import_node_fs3.unlinkSync)(userPath);
|
|
1269
1363
|
process.stdout.write(`Deleted ${userPath}
|
|
1270
1364
|
`);
|
|
1271
1365
|
} else {
|