@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.
@@ -1,7 +1,7 @@
1
1
  // src/cli.ts
2
2
  import { parseArgs } from "util";
3
- import { readFileSync as readFileSync2, existsSync as existsSync2, mkdirSync, writeFileSync, unlinkSync } from "fs";
4
- import { join as join2, dirname } from "path";
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 useState4, useCallback as useCallback2, useRef as useRef2 } from "react";
23
- import { Box as Box6, Text as Text8, useApp, useInput as useInput4 } from "ink";
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 / 1e3).toFixed(1),
268
- "k/",
269
- (contextMaxTokens / 1e3).toFixed(0),
270
- "k)"
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__ */ jsxs3(Box3, { children: [
422
- /* @__PURE__ */ jsxs3(Text5, { color: nameColor, dimColor: dimmed, children: [
423
- indicator,
424
- prefix,
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/PermissionPrompt.tsx
595
- import React4 from "react";
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] = React4.useState(0);
606
- const resolvedRef = React4.useRef(false);
607
- const prevRequestRef = React4.useRef(request);
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 = React4.useCallback(
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
- useInput3((input, key) => {
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__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
640
- /* @__PURE__ */ jsx7(Text7, { color: "yellow", bold: true, children: "[Permission Required]" }),
641
- /* @__PURE__ */ jsxs5(Text7, { children: [
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__ */ jsx7(Text7, { color: "cyan", bold: true, children: request.toolName })
696
+ /* @__PURE__ */ jsx8(Text8, { color: "cyan", bold: true, children: request.toolName })
645
697
  ] }),
646
- /* @__PURE__ */ jsxs5(Text7, { dimColor: true, children: [
698
+ /* @__PURE__ */ jsxs6(Text8, { dimColor: true, children: [
647
699
  " ",
648
700
  formatArgs(request.toolArgs)
649
701
  ] }),
650
- /* @__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: [
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__ */ jsx7(Text7, { dimColor: true, children: " left/right to select, Enter to confirm" })
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 jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
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] = useState4(null);
682
- const [streamingText, setStreamingText] = useState4("");
683
- const permissionQueueRef = useRef2([]);
684
- const processingRef = useRef2(false);
685
- const processNextPermission = useCallback2(() => {
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 = useRef2(null);
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 = useCallback2(() => setStreamingText(""), []);
782
+ const clearStreamingText = useCallback3(() => setStreamingText(""), []);
731
783
  return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText };
732
784
  }
733
785
  function useMessages() {
734
- const [messages, setMessages] = useState4([]);
735
- const addMessage = useCallback2((msg) => {
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 (exists(settingsPath)) {
818
- unlink(settingsPath);
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 useCallback2(
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__ */ jsxs6(Box6, { flexDirection: "column", children: [
853
- /* @__PURE__ */ jsxs6(Text8, { color: "cyan", bold: true, children: [
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__ */ jsx8(Text8, { children: " " }),
858
- /* @__PURE__ */ jsx8(Box6, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { wrap: "wrap", children: renderMarkdown(text) }) })
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__ */ jsx8(Text8, { color: "yellow", children: "Thinking..." });
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 useCallback2(
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 = useRef2(null);
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] = useState4(false);
978
- const [contextPercentage, setContextPercentage] = useState4(0);
1038
+ const [isThinking, setIsThinking] = useState5(false);
1039
+ const [contextPercentage, setContextPercentage] = useState5(0);
979
1040
  const registry = useCommandRegistry(props.cwd ?? process.cwd());
980
- const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry);
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
- useInput4(
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__ */ jsxs6(Box6, { flexDirection: "column", children: [
998
- /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
999
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", bold: true, children: `
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__ */ jsxs6(Text8, { dimColor: true, children: [
1069
+ /* @__PURE__ */ jsxs7(Text9, { dimColor: true, children: [
1007
1070
  " v",
1008
1071
  props.version ?? "0.0.0"
1009
1072
  ] })
1010
1073
  ] }),
1011
- /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
1012
- /* @__PURE__ */ jsx8(MessageList, { messages }),
1013
- isThinking && /* @__PURE__ */ jsx8(Box6, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx8(StreamingIndicator, { text: streamingText }) })
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__ */ jsx8(PermissionPrompt, { request: permissionRequest }),
1016
- /* @__PURE__ */ jsx8(
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__ */ jsx8(
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__ */ jsx8(Text8, { children: " " })
1131
+ /* @__PURE__ */ jsx9(Text9, { children: " " })
1038
1132
  ] });
1039
1133
  }
1040
1134
 
1041
1135
  // src/ui/render.tsx
1042
- import { jsx as jsx9 } from "react/jsx-runtime";
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__ */ jsx9(App, { ...options }), {
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 = [join2(dir, "..", "..", "package.json"), join2(dir, "..", "package.json")];
1165
+ const candidates = [join3(dir, "..", "..", "package.json"), join3(dir, "..", "package.json")];
1072
1166
  for (const pkgPath of candidates) {
1073
1167
  try {
1074
- const raw = readFileSync2(pkgPath, "utf-8");
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 join2(home, ".robota", "settings.json");
1276
+ return join3(home, ".robota", "settings.json");
1183
1277
  }
1184
1278
  async function ensureConfig(cwd) {
1185
1279
  const userPath = getUserSettingsPath();
1186
- const projectPath = join2(cwd, ".robota", "settings.json");
1187
- const localPath = join2(cwd, ".robota", "settings.local.json");
1188
- if (existsSync2(userPath) || existsSync2(projectPath) || existsSync2(localPath)) {
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
- mkdirSync(settingsDir, { recursive: true });
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
- writeFileSync(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
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 (existsSync2(userPath)) {
1250
- unlinkSync(userPath);
1343
+ if (existsSync3(userPath)) {
1344
+ unlinkSync2(userPath);
1251
1345
  process.stdout.write(`Deleted ${userPath}
1252
1346
  `);
1253
1347
  } else {