@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
2
|
import { parseArgs } from "util";
|
|
3
|
-
import { readFileSync as
|
|
4
|
-
import { join as
|
|
3
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
4
|
+
import { join as join3, dirname } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import * as readline from "readline";
|
|
7
7
|
import {
|
|
@@ -19,9 +19,12 @@ import { promptForApproval } from "@robota-sdk/agent-sdk";
|
|
|
19
19
|
import { render } from "ink";
|
|
20
20
|
|
|
21
21
|
// src/ui/App.tsx
|
|
22
|
-
import { useState as
|
|
23
|
-
import { Box as
|
|
22
|
+
import { useState as useState5, useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
23
|
+
import { Box as Box7, Text as Text9, useApp, useInput as useInput5 } from "ink";
|
|
24
|
+
import { existsSync as existsSync2, unlinkSync, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
25
|
+
import { join as join2 } from "path";
|
|
24
26
|
import { createSession, FileSessionLogger, projectPaths } from "@robota-sdk/agent-sdk";
|
|
27
|
+
import { getModelName } from "@robota-sdk/agent-core";
|
|
25
28
|
|
|
26
29
|
// src/commands/command-registry.ts
|
|
27
30
|
var CommandRegistry = class {
|
|
@@ -54,6 +57,21 @@ var CommandRegistry = class {
|
|
|
54
57
|
};
|
|
55
58
|
|
|
56
59
|
// src/commands/builtin-source.ts
|
|
60
|
+
import { CLAUDE_MODELS, formatTokenCount } from "@robota-sdk/agent-core";
|
|
61
|
+
function buildModelSubcommands() {
|
|
62
|
+
const seen = /* @__PURE__ */ new Set();
|
|
63
|
+
const commands = [];
|
|
64
|
+
for (const model of Object.values(CLAUDE_MODELS)) {
|
|
65
|
+
if (seen.has(model.name)) continue;
|
|
66
|
+
seen.add(model.name);
|
|
67
|
+
commands.push({
|
|
68
|
+
name: model.id,
|
|
69
|
+
description: `${model.name} (${formatTokenCount(model.contextWindow).toUpperCase()})`,
|
|
70
|
+
source: "builtin"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return commands;
|
|
74
|
+
}
|
|
57
75
|
function createBuiltinCommands() {
|
|
58
76
|
return [
|
|
59
77
|
{ name: "help", description: "Show available commands", source: "builtin" },
|
|
@@ -73,11 +91,7 @@ function createBuiltinCommands() {
|
|
|
73
91
|
name: "model",
|
|
74
92
|
description: "Select AI model",
|
|
75
93
|
source: "builtin",
|
|
76
|
-
subcommands:
|
|
77
|
-
{ name: "claude-opus-4-6", description: "Opus 4.6 (highest quality)", source: "builtin" },
|
|
78
|
-
{ name: "claude-sonnet-4-6", description: "Sonnet 4.6 (balanced)", source: "builtin" },
|
|
79
|
-
{ name: "claude-haiku-4-5", description: "Haiku 4.5 (fastest)", source: "builtin" }
|
|
80
|
-
]
|
|
94
|
+
subcommands: buildModelSubcommands()
|
|
81
95
|
},
|
|
82
96
|
{ name: "compact", description: "Compress context window", source: "builtin" },
|
|
83
97
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
@@ -225,6 +239,7 @@ function MessageList({ messages }) {
|
|
|
225
239
|
|
|
226
240
|
// src/ui/StatusBar.tsx
|
|
227
241
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
242
|
+
import { formatTokenCount as formatTokenCount2 } from "@robota-sdk/agent-core";
|
|
228
243
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
229
244
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
230
245
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
@@ -264,10 +279,10 @@ function StatusBar({
|
|
|
264
279
|
"Context: ",
|
|
265
280
|
Math.round(contextPercentage),
|
|
266
281
|
"% (",
|
|
267
|
-
(contextUsedTokens
|
|
268
|
-
"
|
|
269
|
-
(contextMaxTokens
|
|
270
|
-
"
|
|
282
|
+
formatTokenCount2(contextUsedTokens),
|
|
283
|
+
"/",
|
|
284
|
+
formatTokenCount2(contextMaxTokens),
|
|
285
|
+
")"
|
|
271
286
|
] })
|
|
272
287
|
] }),
|
|
273
288
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
@@ -414,19 +429,13 @@ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
|
414
429
|
var MAX_VISIBLE = 8;
|
|
415
430
|
function CommandRow(props) {
|
|
416
431
|
const { cmd, isSelected, showSlash } = props;
|
|
417
|
-
const prefix = showSlash ? "/" : "";
|
|
418
432
|
const indicator = isSelected ? "\u25B8 " : " ";
|
|
419
433
|
const nameColor = isSelected ? "cyan" : void 0;
|
|
420
434
|
const dimmed = !isSelected;
|
|
421
|
-
return /* @__PURE__ */
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
cmd.name
|
|
426
|
-
] }),
|
|
427
|
-
/* @__PURE__ */ jsx5(Text5, { dimColor: dimmed, children: " " }),
|
|
428
|
-
/* @__PURE__ */ jsx5(Text5, { color: nameColor, dimColor: dimmed, children: cmd.description })
|
|
429
|
-
] });
|
|
435
|
+
return /* @__PURE__ */ jsx5(Box3, { children: /* @__PURE__ */ jsxs3(Text5, { color: nameColor, dimColor: dimmed, children: [
|
|
436
|
+
indicator,
|
|
437
|
+
showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
|
|
438
|
+
] }) });
|
|
430
439
|
}
|
|
431
440
|
function SlashAutocomplete({
|
|
432
441
|
commands,
|
|
@@ -591,10 +600,53 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
591
600
|
] });
|
|
592
601
|
}
|
|
593
602
|
|
|
594
|
-
// src/ui/
|
|
595
|
-
import
|
|
603
|
+
// src/ui/ConfirmPrompt.tsx
|
|
604
|
+
import { useState as useState4, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
596
605
|
import { Box as Box5, Text as Text7, useInput as useInput3 } from "ink";
|
|
597
606
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
607
|
+
function ConfirmPrompt({
|
|
608
|
+
message,
|
|
609
|
+
options = ["Yes", "No"],
|
|
610
|
+
onSelect
|
|
611
|
+
}) {
|
|
612
|
+
const [selected, setSelected] = useState4(0);
|
|
613
|
+
const resolvedRef = useRef2(false);
|
|
614
|
+
const doSelect = useCallback2(
|
|
615
|
+
(index) => {
|
|
616
|
+
if (resolvedRef.current) return;
|
|
617
|
+
resolvedRef.current = true;
|
|
618
|
+
onSelect(index);
|
|
619
|
+
},
|
|
620
|
+
[onSelect]
|
|
621
|
+
);
|
|
622
|
+
useInput3((input, key) => {
|
|
623
|
+
if (resolvedRef.current) return;
|
|
624
|
+
if (key.leftArrow || key.upArrow) {
|
|
625
|
+
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
626
|
+
} else if (key.rightArrow || key.downArrow) {
|
|
627
|
+
setSelected((prev) => prev < options.length - 1 ? prev + 1 : prev);
|
|
628
|
+
} else if (key.return) {
|
|
629
|
+
doSelect(selected);
|
|
630
|
+
} else if (input === "y" && options.length === 2) {
|
|
631
|
+
doSelect(0);
|
|
632
|
+
} else if (input === "n" && options.length === 2) {
|
|
633
|
+
doSelect(1);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
637
|
+
/* @__PURE__ */ jsx7(Text7, { color: "yellow", children: message }),
|
|
638
|
+
/* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ jsx7(Box5, { marginRight: 2, children: /* @__PURE__ */ jsxs5(Text7, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
639
|
+
i === selected ? "> " : " ",
|
|
640
|
+
opt
|
|
641
|
+
] }) }, opt)) }),
|
|
642
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
|
|
643
|
+
] });
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/ui/PermissionPrompt.tsx
|
|
647
|
+
import React5 from "react";
|
|
648
|
+
import { Box as Box6, Text as Text8, useInput as useInput4 } from "ink";
|
|
649
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
598
650
|
var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
|
|
599
651
|
function formatArgs(args) {
|
|
600
652
|
const entries = Object.entries(args);
|
|
@@ -602,15 +654,15 @@ function formatArgs(args) {
|
|
|
602
654
|
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
603
655
|
}
|
|
604
656
|
function PermissionPrompt({ request }) {
|
|
605
|
-
const [selected, setSelected] =
|
|
606
|
-
const resolvedRef =
|
|
607
|
-
const prevRequestRef =
|
|
657
|
+
const [selected, setSelected] = React5.useState(0);
|
|
658
|
+
const resolvedRef = React5.useRef(false);
|
|
659
|
+
const prevRequestRef = React5.useRef(request);
|
|
608
660
|
if (prevRequestRef.current !== request) {
|
|
609
661
|
prevRequestRef.current = request;
|
|
610
662
|
resolvedRef.current = false;
|
|
611
663
|
setSelected(0);
|
|
612
664
|
}
|
|
613
|
-
const doResolve =
|
|
665
|
+
const doResolve = React5.useCallback(
|
|
614
666
|
(index) => {
|
|
615
667
|
if (resolvedRef.current) return;
|
|
616
668
|
resolvedRef.current = true;
|
|
@@ -620,7 +672,7 @@ function PermissionPrompt({ request }) {
|
|
|
620
672
|
},
|
|
621
673
|
[request]
|
|
622
674
|
);
|
|
623
|
-
|
|
675
|
+
useInput4((input, key) => {
|
|
624
676
|
if (resolvedRef.current) return;
|
|
625
677
|
if (key.upArrow || key.leftArrow) {
|
|
626
678
|
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
@@ -636,27 +688,27 @@ function PermissionPrompt({ request }) {
|
|
|
636
688
|
doResolve(2);
|
|
637
689
|
}
|
|
638
690
|
});
|
|
639
|
-
return /* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
641
|
-
/* @__PURE__ */
|
|
691
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
692
|
+
/* @__PURE__ */ jsx8(Text8, { color: "yellow", bold: true, children: "[Permission Required]" }),
|
|
693
|
+
/* @__PURE__ */ jsxs6(Text8, { children: [
|
|
642
694
|
"Tool:",
|
|
643
695
|
" ",
|
|
644
|
-
/* @__PURE__ */
|
|
696
|
+
/* @__PURE__ */ jsx8(Text8, { color: "cyan", bold: true, children: request.toolName })
|
|
645
697
|
] }),
|
|
646
|
-
/* @__PURE__ */
|
|
698
|
+
/* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
|
|
647
699
|
" ",
|
|
648
700
|
formatArgs(request.toolArgs)
|
|
649
701
|
] }),
|
|
650
|
-
/* @__PURE__ */
|
|
702
|
+
/* @__PURE__ */ jsx8(Box6, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsx8(Box6, { marginRight: 2, children: /* @__PURE__ */ jsxs6(Text8, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
651
703
|
i === selected ? "> " : " ",
|
|
652
704
|
opt
|
|
653
705
|
] }) }, opt)) }),
|
|
654
|
-
/* @__PURE__ */
|
|
706
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " left/right to select, Enter to confirm" })
|
|
655
707
|
] });
|
|
656
708
|
}
|
|
657
709
|
|
|
658
710
|
// src/ui/App.tsx
|
|
659
|
-
import { jsx as
|
|
711
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
660
712
|
var msgIdCounter = 0;
|
|
661
713
|
function nextId() {
|
|
662
714
|
msgIdCounter += 1;
|
|
@@ -678,11 +730,11 @@ var NOOP_TERMINAL = {
|
|
|
678
730
|
} })
|
|
679
731
|
};
|
|
680
732
|
function useSession(props) {
|
|
681
|
-
const [permissionRequest, setPermissionRequest] =
|
|
682
|
-
const [streamingText, setStreamingText] =
|
|
683
|
-
const permissionQueueRef =
|
|
684
|
-
const processingRef =
|
|
685
|
-
const processNextPermission =
|
|
733
|
+
const [permissionRequest, setPermissionRequest] = useState5(null);
|
|
734
|
+
const [streamingText, setStreamingText] = useState5("");
|
|
735
|
+
const permissionQueueRef = useRef3([]);
|
|
736
|
+
const processingRef = useRef3(false);
|
|
737
|
+
const processNextPermission = useCallback3(() => {
|
|
686
738
|
if (processingRef.current) return;
|
|
687
739
|
const next = permissionQueueRef.current[0];
|
|
688
740
|
if (!next) {
|
|
@@ -702,7 +754,7 @@ function useSession(props) {
|
|
|
702
754
|
}
|
|
703
755
|
});
|
|
704
756
|
}, []);
|
|
705
|
-
const sessionRef =
|
|
757
|
+
const sessionRef = useRef3(null);
|
|
706
758
|
if (sessionRef.current === null) {
|
|
707
759
|
const permissionHandler = (toolName, toolArgs) => {
|
|
708
760
|
return new Promise((resolve) => {
|
|
@@ -727,12 +779,12 @@ function useSession(props) {
|
|
|
727
779
|
onTextDelta
|
|
728
780
|
});
|
|
729
781
|
}
|
|
730
|
-
const clearStreamingText =
|
|
782
|
+
const clearStreamingText = useCallback3(() => setStreamingText(""), []);
|
|
731
783
|
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText };
|
|
732
784
|
}
|
|
733
785
|
function useMessages() {
|
|
734
|
-
const [messages, setMessages] =
|
|
735
|
-
const addMessage =
|
|
786
|
+
const [messages, setMessages] = useState5([]);
|
|
787
|
+
const addMessage = useCallback3((msg) => {
|
|
736
788
|
setMessages((prev) => [...prev, { ...msg, id: nextId(), timestamp: /* @__PURE__ */ new Date() }]);
|
|
737
789
|
}, []);
|
|
738
790
|
return { messages, setMessages, addMessage };
|
|
@@ -759,7 +811,7 @@ function handleModeCommand(arg, session, addMessage) {
|
|
|
759
811
|
}
|
|
760
812
|
return true;
|
|
761
813
|
}
|
|
762
|
-
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry) {
|
|
814
|
+
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
|
|
763
815
|
switch (cmd) {
|
|
764
816
|
case "help":
|
|
765
817
|
addMessage({ role: "system", content: HELP_TEXT });
|
|
@@ -783,6 +835,16 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
|
|
|
783
835
|
}
|
|
784
836
|
case "mode":
|
|
785
837
|
return handleModeCommand(parts[1], session, addMessage);
|
|
838
|
+
case "model": {
|
|
839
|
+
const modelId = parts[1];
|
|
840
|
+
if (!modelId) {
|
|
841
|
+
addMessage({ role: "system", content: "Select a model from the /model submenu." });
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
844
|
+
pendingModelChangeRef.current = modelId;
|
|
845
|
+
setPendingModelId(modelId);
|
|
846
|
+
return true;
|
|
847
|
+
}
|
|
786
848
|
case "cost":
|
|
787
849
|
addMessage({
|
|
788
850
|
role: "system",
|
|
@@ -811,11 +873,10 @@ Messages: ${session.getMessageCount()}`
|
|
|
811
873
|
return true;
|
|
812
874
|
}
|
|
813
875
|
case "reset": {
|
|
814
|
-
const { existsSync: exists, unlinkSync: unlink } = await import("fs");
|
|
815
876
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
816
877
|
const settingsPath = `${home}/.robota/settings.json`;
|
|
817
|
-
if (
|
|
818
|
-
|
|
878
|
+
if (existsSync2(settingsPath)) {
|
|
879
|
+
unlinkSync(settingsPath);
|
|
819
880
|
addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
|
|
820
881
|
} else {
|
|
821
882
|
addMessage({ role: "system", content: "No user settings found." });
|
|
@@ -837,28 +898,28 @@ Messages: ${session.getMessageCount()}`
|
|
|
837
898
|
}
|
|
838
899
|
}
|
|
839
900
|
}
|
|
840
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry) {
|
|
841
|
-
return
|
|
901
|
+
function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
|
|
902
|
+
return useCallback3(
|
|
842
903
|
async (input) => {
|
|
843
904
|
const parts = input.slice(1).split(/\s+/);
|
|
844
905
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
845
|
-
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry);
|
|
906
|
+
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
|
|
846
907
|
},
|
|
847
|
-
[session, addMessage, setMessages, exit, registry]
|
|
908
|
+
[session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
|
|
848
909
|
);
|
|
849
910
|
}
|
|
850
911
|
function StreamingIndicator({ text }) {
|
|
851
912
|
if (text) {
|
|
852
|
-
return /* @__PURE__ */
|
|
853
|
-
/* @__PURE__ */
|
|
913
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
914
|
+
/* @__PURE__ */ jsxs7(Text9, { color: "cyan", bold: true, children: [
|
|
854
915
|
"Robota:",
|
|
855
916
|
" "
|
|
856
917
|
] }),
|
|
857
|
-
/* @__PURE__ */
|
|
858
|
-
/* @__PURE__ */
|
|
918
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
919
|
+
/* @__PURE__ */ jsx9(Box7, { marginLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
859
920
|
] });
|
|
860
921
|
}
|
|
861
|
-
return /* @__PURE__ */
|
|
922
|
+
return /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "Thinking..." });
|
|
862
923
|
}
|
|
863
924
|
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
|
|
864
925
|
setIsThinking(true);
|
|
@@ -920,7 +981,7 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
920
981
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
921
982
|
}
|
|
922
983
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
|
|
923
|
-
return
|
|
984
|
+
return useCallback3(
|
|
924
985
|
async (input) => {
|
|
925
986
|
if (input.startsWith("/")) {
|
|
926
987
|
const handled = await handleSlashCommand(input);
|
|
@@ -961,7 +1022,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
961
1022
|
);
|
|
962
1023
|
}
|
|
963
1024
|
function useCommandRegistry(cwd) {
|
|
964
|
-
const registryRef =
|
|
1025
|
+
const registryRef = useRef3(null);
|
|
965
1026
|
if (registryRef.current === null) {
|
|
966
1027
|
const registry = new CommandRegistry();
|
|
967
1028
|
registry.addSource(new BuiltinCommandSource());
|
|
@@ -974,10 +1035,12 @@ function App(props) {
|
|
|
974
1035
|
const { exit } = useApp();
|
|
975
1036
|
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
976
1037
|
const { messages, setMessages, addMessage } = useMessages();
|
|
977
|
-
const [isThinking, setIsThinking] =
|
|
978
|
-
const [contextPercentage, setContextPercentage] =
|
|
1038
|
+
const [isThinking, setIsThinking] = useState5(false);
|
|
1039
|
+
const [contextPercentage, setContextPercentage] = useState5(0);
|
|
979
1040
|
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
980
|
-
const
|
|
1041
|
+
const pendingModelChangeRef = useRef3(null);
|
|
1042
|
+
const [pendingModelId, setPendingModelId] = useState5(null);
|
|
1043
|
+
const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
|
|
981
1044
|
const handleSubmit = useSubmitHandler(
|
|
982
1045
|
session,
|
|
983
1046
|
addMessage,
|
|
@@ -987,37 +1050,68 @@ function App(props) {
|
|
|
987
1050
|
setContextPercentage,
|
|
988
1051
|
registry
|
|
989
1052
|
);
|
|
990
|
-
|
|
1053
|
+
useInput5(
|
|
991
1054
|
(_input, key) => {
|
|
992
1055
|
if (key.ctrl && _input === "c") exit();
|
|
993
1056
|
if (key.escape && isThinking) session.abort();
|
|
994
1057
|
},
|
|
995
1058
|
{ isActive: !permissionRequest }
|
|
996
1059
|
);
|
|
997
|
-
return /* @__PURE__ */
|
|
998
|
-
/* @__PURE__ */
|
|
999
|
-
/* @__PURE__ */
|
|
1060
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
1061
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1062
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: `
|
|
1000
1063
|
____ ___ ____ ___ _____ _
|
|
1001
1064
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1002
1065
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1003
1066
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1004
1067
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1005
1068
|
` }),
|
|
1006
|
-
/* @__PURE__ */
|
|
1069
|
+
/* @__PURE__ */ jsxs7(Text9, { dimColor: true, children: [
|
|
1007
1070
|
" v",
|
|
1008
1071
|
props.version ?? "0.0.0"
|
|
1009
1072
|
] })
|
|
1010
1073
|
] }),
|
|
1011
|
-
/* @__PURE__ */
|
|
1012
|
-
/* @__PURE__ */
|
|
1013
|
-
isThinking && /* @__PURE__ */
|
|
1074
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1075
|
+
/* @__PURE__ */ jsx9(MessageList, { messages }),
|
|
1076
|
+
isThinking && /* @__PURE__ */ jsx9(Box7, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx9(StreamingIndicator, { text: streamingText }) })
|
|
1014
1077
|
] }),
|
|
1015
|
-
permissionRequest && /* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
1078
|
+
permissionRequest && /* @__PURE__ */ jsx9(PermissionPrompt, { request: permissionRequest }),
|
|
1079
|
+
pendingModelId && /* @__PURE__ */ jsx9(
|
|
1080
|
+
ConfirmPrompt,
|
|
1081
|
+
{
|
|
1082
|
+
message: `Change model to ${getModelName(pendingModelId)}? This will restart the session.`,
|
|
1083
|
+
onSelect: (index) => {
|
|
1084
|
+
setPendingModelId(null);
|
|
1085
|
+
pendingModelChangeRef.current = null;
|
|
1086
|
+
if (index === 0) {
|
|
1087
|
+
try {
|
|
1088
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1089
|
+
const settingsPath = join2(home, ".robota", "settings.json");
|
|
1090
|
+
let settings = {};
|
|
1091
|
+
if (existsSync2(settingsPath)) {
|
|
1092
|
+
settings = JSON.parse(readFileSync2(settingsPath, "utf8"));
|
|
1093
|
+
}
|
|
1094
|
+
const provider = settings.provider ?? {};
|
|
1095
|
+
provider.model = pendingModelId;
|
|
1096
|
+
settings.provider = provider;
|
|
1097
|
+
mkdirSync(join2(home, ".robota"), { recursive: true });
|
|
1098
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1099
|
+
addMessage({ role: "system", content: `Model changed to ${getModelName(pendingModelId)}. Restarting...` });
|
|
1100
|
+
setTimeout(() => exit(), 500);
|
|
1101
|
+
} catch (err) {
|
|
1102
|
+
addMessage({ role: "system", content: `Failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
1103
|
+
}
|
|
1104
|
+
} else {
|
|
1105
|
+
addMessage({ role: "system", content: "Model change cancelled." });
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
),
|
|
1110
|
+
/* @__PURE__ */ jsx9(
|
|
1017
1111
|
StatusBar,
|
|
1018
1112
|
{
|
|
1019
1113
|
permissionMode: session.getPermissionMode(),
|
|
1020
|
-
modelName: props.config.provider.model,
|
|
1114
|
+
modelName: getModelName(props.config.provider.model),
|
|
1021
1115
|
sessionId: session.getSessionId(),
|
|
1022
1116
|
messageCount: messages.length,
|
|
1023
1117
|
isThinking,
|
|
@@ -1026,7 +1120,7 @@ function App(props) {
|
|
|
1026
1120
|
contextMaxTokens: session.getContextState().maxTokens
|
|
1027
1121
|
}
|
|
1028
1122
|
),
|
|
1029
|
-
/* @__PURE__ */
|
|
1123
|
+
/* @__PURE__ */ jsx9(
|
|
1030
1124
|
InputArea,
|
|
1031
1125
|
{
|
|
1032
1126
|
onSubmit: handleSubmit,
|
|
@@ -1034,12 +1128,12 @@ function App(props) {
|
|
|
1034
1128
|
registry
|
|
1035
1129
|
}
|
|
1036
1130
|
),
|
|
1037
|
-
/* @__PURE__ */
|
|
1131
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " })
|
|
1038
1132
|
] });
|
|
1039
1133
|
}
|
|
1040
1134
|
|
|
1041
1135
|
// src/ui/render.tsx
|
|
1042
|
-
import { jsx as
|
|
1136
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1043
1137
|
function renderApp(options) {
|
|
1044
1138
|
process.on("unhandledRejection", (reason) => {
|
|
1045
1139
|
process.stderr.write(`
|
|
@@ -1050,7 +1144,7 @@ function renderApp(options) {
|
|
|
1050
1144
|
`);
|
|
1051
1145
|
}
|
|
1052
1146
|
});
|
|
1053
|
-
const instance = render(/* @__PURE__ */
|
|
1147
|
+
const instance = render(/* @__PURE__ */ jsx10(App, { ...options }), {
|
|
1054
1148
|
exitOnCtrlC: true
|
|
1055
1149
|
});
|
|
1056
1150
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -1068,10 +1162,10 @@ function readVersion() {
|
|
|
1068
1162
|
try {
|
|
1069
1163
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1070
1164
|
const dir = dirname(thisFile);
|
|
1071
|
-
const candidates = [
|
|
1165
|
+
const candidates = [join3(dir, "..", "..", "package.json"), join3(dir, "..", "package.json")];
|
|
1072
1166
|
for (const pkgPath of candidates) {
|
|
1073
1167
|
try {
|
|
1074
|
-
const raw =
|
|
1168
|
+
const raw = readFileSync3(pkgPath, "utf-8");
|
|
1075
1169
|
const pkg = JSON.parse(raw);
|
|
1076
1170
|
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
1077
1171
|
return pkg.version;
|
|
@@ -1179,13 +1273,13 @@ var PrintTerminal = class {
|
|
|
1179
1273
|
};
|
|
1180
1274
|
function getUserSettingsPath() {
|
|
1181
1275
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1182
|
-
return
|
|
1276
|
+
return join3(home, ".robota", "settings.json");
|
|
1183
1277
|
}
|
|
1184
1278
|
async function ensureConfig(cwd) {
|
|
1185
1279
|
const userPath = getUserSettingsPath();
|
|
1186
|
-
const projectPath =
|
|
1187
|
-
const localPath =
|
|
1188
|
-
if (
|
|
1280
|
+
const projectPath = join3(cwd, ".robota", "settings.json");
|
|
1281
|
+
const localPath = join3(cwd, ".robota", "settings.local.json");
|
|
1282
|
+
if (existsSync3(userPath) || existsSync3(projectPath) || existsSync3(localPath)) {
|
|
1189
1283
|
return;
|
|
1190
1284
|
}
|
|
1191
1285
|
process.stdout.write("\n");
|
|
@@ -1230,7 +1324,7 @@ async function ensureConfig(cwd) {
|
|
|
1230
1324
|
process.exit(1);
|
|
1231
1325
|
}
|
|
1232
1326
|
const settingsDir = dirname(userPath);
|
|
1233
|
-
|
|
1327
|
+
mkdirSync2(settingsDir, { recursive: true });
|
|
1234
1328
|
const settings = {
|
|
1235
1329
|
provider: {
|
|
1236
1330
|
name: "anthropic",
|
|
@@ -1238,7 +1332,7 @@ async function ensureConfig(cwd) {
|
|
|
1238
1332
|
apiKey
|
|
1239
1333
|
}
|
|
1240
1334
|
};
|
|
1241
|
-
|
|
1335
|
+
writeFileSync2(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1242
1336
|
process.stdout.write(`
|
|
1243
1337
|
Config saved to ${userPath}
|
|
1244
1338
|
|
|
@@ -1246,8 +1340,8 @@ async function ensureConfig(cwd) {
|
|
|
1246
1340
|
}
|
|
1247
1341
|
function resetConfig() {
|
|
1248
1342
|
const userPath = getUserSettingsPath();
|
|
1249
|
-
if (
|
|
1250
|
-
|
|
1343
|
+
if (existsSync3(userPath)) {
|
|
1344
|
+
unlinkSync2(userPath);
|
|
1251
1345
|
process.stdout.write(`Deleted ${userPath}
|
|
1252
1346
|
`);
|
|
1253
1347
|
} else {
|