@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.
@@ -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 import_node_fs2 = require("fs");
45
- var import_node_path2 = require("path");
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 import_ink9 = require("ink");
52
+ var import_ink10 = require("ink");
53
53
 
54
54
  // src/ui/App.tsx
55
- var import_react5 = require("react");
56
- var import_ink8 = require("ink");
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
- (contextUsedTokens / 1e3).toFixed(1),
301
- "k/",
302
- (contextMaxTokens / 1e3).toFixed(0),
303
- "k)"
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.jsxs)(import_ink5.Box, { children: [
455
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: [
456
- indicator,
457
- prefix,
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/PermissionPrompt.tsx
628
- var import_react4 = __toESM(require("react"), 1);
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] = import_react4.default.useState(0);
639
- const resolvedRef = import_react4.default.useRef(false);
640
- const prevRequestRef = import_react4.default.useRef(request);
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 = import_react4.default.useCallback(
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, import_ink7.useInput)((input, key) => {
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, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
673
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
674
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { children: [
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, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "cyan", bold: true, children: request.toolName })
729
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: request.toolName })
678
730
  ] }),
679
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { dimColor: true, children: [
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, 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: [
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, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
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 import_jsx_runtime8 = require("react/jsx-runtime");
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, import_react5.useState)(null);
715
- const [streamingText, setStreamingText] = (0, import_react5.useState)("");
716
- const permissionQueueRef = (0, import_react5.useRef)([]);
717
- const processingRef = (0, import_react5.useRef)(false);
718
- const processNextPermission = (0, import_react5.useCallback)(() => {
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, import_react5.useRef)(null);
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, import_react5.useCallback)(() => setStreamingText(""), []);
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, import_react5.useState)([]);
768
- const addMessage = (0, import_react5.useCallback)((msg) => {
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 (exists(settingsPath)) {
851
- unlink(settingsPath);
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, import_react5.useCallback)(
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, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
886
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { color: "cyan", bold: true, children: [
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, import_jsx_runtime8.jsx)(import_ink8.Text, { children: " " }),
891
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
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, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", children: "Thinking..." });
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, import_react5.useCallback)(
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, import_react5.useRef)(null);
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, import_ink8.useApp)();
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, import_react5.useState)(false);
1011
- const [contextPercentage, setContextPercentage] = (0, import_react5.useState)(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 handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry);
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, import_ink8.useInput)(
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, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
1031
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
1032
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: `
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, import_jsx_runtime8.jsxs)(import_ink8.Text, { dimColor: true, children: [
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, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
1045
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MessageList, { messages }),
1046
- isThinking && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StreamingIndicator, { text: streamingText }) })
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, import_jsx_runtime8.jsx)(PermissionPrompt, { request: permissionRequest }),
1049
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
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, import_jsx_runtime8.jsx)(
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, import_jsx_runtime8.jsx)(import_ink8.Text, { children: " " })
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 import_jsx_runtime9 = require("react/jsx-runtime");
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, import_ink9.render)(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(App, { ...options }), {
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, import_node_path2.dirname)(thisFile);
1105
- const candidates = [(0, import_node_path2.join)(dir, "..", "..", "package.json"), (0, import_node_path2.join)(dir, "..", "package.json")];
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, import_node_fs2.readFileSync)(pkgPath, "utf-8");
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, import_node_path2.join)(home, ".robota", "settings.json");
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, import_node_path2.join)(cwd, ".robota", "settings.json");
1221
- const localPath = (0, import_node_path2.join)(cwd, ".robota", "settings.local.json");
1222
- if ((0, import_node_fs2.existsSync)(userPath) || (0, import_node_fs2.existsSync)(projectPath) || (0, import_node_fs2.existsSync)(localPath)) {
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, import_node_path2.dirname)(userPath);
1267
- (0, import_node_fs2.mkdirSync)(settingsDir, { recursive: true });
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, import_node_fs2.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
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, import_node_fs2.existsSync)(userPath)) {
1284
- (0, import_node_fs2.unlinkSync)(userPath);
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 {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startCli
3
- } from "./chunk-B423R5N3.js";
3
+ } from "./chunk-OZHWJAII.js";
4
4
 
5
5
  // src/index.ts
6
6
  import { Session, SessionStore, query, TRUST_TO_MODE } from "@robota-sdk/agent-sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-cli",
3
- "version": "3.0.0-beta.15",
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.15",
39
- "@robota-sdk/agent-sdk": "3.0.0-beta.15"
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",