@robota-sdk/agent-cli 3.0.0-beta.15 → 3.0.0-beta.17

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/dist/node/bin.cjs CHANGED
@@ -24,21 +24,275 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/cli.ts
27
- var import_node_util = require("util");
28
- var import_node_fs2 = require("fs");
29
- var import_node_path2 = require("path");
27
+ var import_node_fs3 = require("fs");
28
+ var import_node_path3 = require("path");
30
29
  var import_node_url = require("url");
31
- var readline = __toESM(require("readline"), 1);
32
30
  var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
33
31
  var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
34
32
 
33
+ // src/utils/cli-args.ts
34
+ var import_node_util = require("util");
35
+ var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
36
+ function parsePermissionMode(raw) {
37
+ if (raw === void 0) return void 0;
38
+ if (!VALID_MODES.includes(raw)) {
39
+ process.stderr.write(`Invalid --permission-mode "${raw}". Valid: ${VALID_MODES.join(" | ")}
40
+ `);
41
+ process.exit(1);
42
+ }
43
+ return raw;
44
+ }
45
+ function parseMaxTurns(raw) {
46
+ if (raw === void 0) return void 0;
47
+ const n = parseInt(raw, 10);
48
+ if (isNaN(n) || n <= 0) {
49
+ process.stderr.write(`Invalid --max-turns "${raw}". Must be a positive integer.
50
+ `);
51
+ process.exit(1);
52
+ }
53
+ return n;
54
+ }
55
+ function parseCliArgs() {
56
+ const { values, positionals } = (0, import_node_util.parseArgs)({
57
+ allowPositionals: true,
58
+ options: {
59
+ p: { type: "boolean", short: "p", default: false },
60
+ c: { type: "boolean", short: "c", default: false },
61
+ r: { type: "string", short: "r" },
62
+ model: { type: "string" },
63
+ "permission-mode": { type: "string" },
64
+ "max-turns": { type: "string" },
65
+ version: { type: "boolean", default: false },
66
+ reset: { type: "boolean", default: false }
67
+ }
68
+ });
69
+ return {
70
+ positional: positionals,
71
+ printMode: values["p"] ?? false,
72
+ continueMode: values["c"] ?? false,
73
+ resumeId: values["r"],
74
+ model: values["model"],
75
+ permissionMode: parsePermissionMode(values["permission-mode"]),
76
+ maxTurns: parseMaxTurns(values["max-turns"]),
77
+ version: values["version"] ?? false,
78
+ reset: values["reset"] ?? false
79
+ };
80
+ }
81
+
82
+ // src/utils/settings-io.ts
83
+ var import_node_fs = require("fs");
84
+ var import_node_path = require("path");
85
+ function getUserSettingsPath() {
86
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
87
+ return (0, import_node_path.join)(home, ".robota", "settings.json");
88
+ }
89
+ function readSettings(path) {
90
+ if (!(0, import_node_fs.existsSync)(path)) return {};
91
+ return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
92
+ }
93
+ function writeSettings(path, settings) {
94
+ (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(path), { recursive: true });
95
+ (0, import_node_fs.writeFileSync)(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
96
+ }
97
+ function updateModelInSettings(settingsPath, modelId) {
98
+ const settings = readSettings(settingsPath);
99
+ const provider = settings.provider ?? {};
100
+ provider.model = modelId;
101
+ settings.provider = provider;
102
+ writeSettings(settingsPath, settings);
103
+ }
104
+ function deleteSettings(path) {
105
+ if ((0, import_node_fs.existsSync)(path)) {
106
+ (0, import_node_fs.unlinkSync)(path);
107
+ return true;
108
+ }
109
+ return false;
110
+ }
111
+
112
+ // src/print-terminal.ts
113
+ var readline = __toESM(require("readline"), 1);
114
+ var PrintTerminal = class {
115
+ write(text) {
116
+ process.stdout.write(text);
117
+ }
118
+ writeLine(text) {
119
+ process.stdout.write(text + "\n");
120
+ }
121
+ writeMarkdown(md) {
122
+ process.stdout.write(md);
123
+ }
124
+ writeError(text) {
125
+ process.stderr.write(text + "\n");
126
+ }
127
+ prompt(question) {
128
+ return new Promise((resolve) => {
129
+ const rl = readline.createInterface({
130
+ input: process.stdin,
131
+ output: process.stdout,
132
+ terminal: false,
133
+ historySize: 0
134
+ });
135
+ rl.question(question, (answer) => {
136
+ rl.close();
137
+ resolve(answer);
138
+ });
139
+ });
140
+ }
141
+ async select(options, initialIndex = 0) {
142
+ for (let i = 0; i < options.length; i++) {
143
+ const marker = i === initialIndex ? ">" : " ";
144
+ process.stdout.write(` ${marker} ${i + 1}) ${options[i]}
145
+ `);
146
+ }
147
+ const answer = await this.prompt(
148
+ ` Choose [1-${options.length}] (default: ${options[initialIndex]}): `
149
+ );
150
+ const trimmed = answer.trim().toLowerCase();
151
+ if (trimmed === "") return initialIndex;
152
+ const num = parseInt(trimmed, 10);
153
+ if (!isNaN(num) && num >= 1 && num <= options.length) return num - 1;
154
+ return initialIndex;
155
+ }
156
+ spinner(_message) {
157
+ return { stop() {
158
+ }, update() {
159
+ } };
160
+ }
161
+ };
162
+
35
163
  // src/ui/render.tsx
164
+ var import_ink10 = require("ink");
165
+
166
+ // src/ui/App.tsx
167
+ var import_react6 = require("react");
36
168
  var import_ink9 = require("ink");
37
169
 
170
+ // src/commands/slash-executor.ts
171
+ var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
172
+ var HELP_TEXT = [
173
+ "Available commands:",
174
+ " /help \u2014 Show this help",
175
+ " /clear \u2014 Clear conversation",
176
+ " /compact [instr] \u2014 Compact context (optional focus instructions)",
177
+ " /mode [m] \u2014 Show/change permission mode",
178
+ " /cost \u2014 Show session info",
179
+ " /reset \u2014 Delete settings and exit",
180
+ " /exit \u2014 Exit CLI"
181
+ ].join("\n");
182
+ function handleHelp(addMessage) {
183
+ addMessage({ role: "system", content: HELP_TEXT });
184
+ return { handled: true };
185
+ }
186
+ function handleClear(addMessage, clearMessages, session) {
187
+ clearMessages();
188
+ session.clearHistory();
189
+ addMessage({ role: "system", content: "Conversation cleared." });
190
+ return { handled: true };
191
+ }
192
+ async function handleCompact(args, session, addMessage) {
193
+ const instructions = args.trim() || void 0;
194
+ const before = session.getContextState().usedPercentage;
195
+ addMessage({ role: "system", content: "Compacting context..." });
196
+ await session.compact(instructions);
197
+ const after = session.getContextState().usedPercentage;
198
+ addMessage({
199
+ role: "system",
200
+ content: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`
201
+ });
202
+ return { handled: true };
203
+ }
204
+ function handleMode(arg, session, addMessage) {
205
+ if (!arg) {
206
+ addMessage({ role: "system", content: `Current mode: ${session.getPermissionMode()}` });
207
+ } else if (VALID_MODES2.includes(arg)) {
208
+ session.setPermissionMode(arg);
209
+ addMessage({ role: "system", content: `Permission mode set to: ${arg}` });
210
+ } else {
211
+ addMessage({ role: "system", content: `Invalid mode. Valid: ${VALID_MODES2.join(" | ")}` });
212
+ }
213
+ return { handled: true };
214
+ }
215
+ function handleModel(modelId, addMessage) {
216
+ if (!modelId) {
217
+ addMessage({ role: "system", content: "Select a model from the /model submenu." });
218
+ return { handled: true };
219
+ }
220
+ return { handled: true, pendingModelId: modelId };
221
+ }
222
+ function handleCost(session, addMessage) {
223
+ addMessage({
224
+ role: "system",
225
+ content: `Session: ${session.getSessionId()}
226
+ Messages: ${session.getMessageCount()}`
227
+ });
228
+ return { handled: true };
229
+ }
230
+ function handlePermissions(session, addMessage) {
231
+ const mode = session.getPermissionMode();
232
+ const sessionAllowed = session.getSessionAllowedTools();
233
+ const lines = [`Permission mode: ${mode}`];
234
+ if (sessionAllowed.length > 0) {
235
+ lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
236
+ } else {
237
+ lines.push("No session-approved tools.");
238
+ }
239
+ addMessage({ role: "system", content: lines.join("\n") });
240
+ return { handled: true };
241
+ }
242
+ function handleContext(session, addMessage) {
243
+ const ctx = session.getContextState();
244
+ addMessage({
245
+ role: "system",
246
+ content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
247
+ });
248
+ return { handled: true };
249
+ }
250
+ function handleReset(addMessage) {
251
+ const settingsPath = getUserSettingsPath();
252
+ if (deleteSettings(settingsPath)) {
253
+ addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
254
+ } else {
255
+ addMessage({ role: "system", content: "No user settings found." });
256
+ }
257
+ return { handled: true, exitRequested: true };
258
+ }
259
+ async function executeSlashCommand(cmd, args, session, addMessage, clearMessages, registry) {
260
+ switch (cmd) {
261
+ case "help":
262
+ return handleHelp(addMessage);
263
+ case "clear":
264
+ return handleClear(addMessage, clearMessages, session);
265
+ case "compact":
266
+ return handleCompact(args, session, addMessage);
267
+ case "mode":
268
+ return handleMode(args.split(/\s+/)[0] || void 0, session, addMessage);
269
+ case "model":
270
+ return handleModel(args.split(/\s+/)[0] || void 0, addMessage);
271
+ case "cost":
272
+ return handleCost(session, addMessage);
273
+ case "permissions":
274
+ return handlePermissions(session, addMessage);
275
+ case "context":
276
+ return handleContext(session, addMessage);
277
+ case "reset":
278
+ return handleReset(addMessage);
279
+ case "exit":
280
+ return { handled: true, exitRequested: true };
281
+ default: {
282
+ const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
283
+ if (skillCmd) {
284
+ addMessage({ role: "system", content: `Invoking skill: ${cmd}` });
285
+ return { handled: false };
286
+ }
287
+ addMessage({ role: "system", content: `Unknown command "/${cmd}". Type /help for help.` });
288
+ return { handled: true };
289
+ }
290
+ }
291
+ }
292
+
38
293
  // src/ui/App.tsx
39
- var import_react5 = require("react");
40
- var import_ink8 = require("ink");
41
294
  var import_agent_sdk = require("@robota-sdk/agent-sdk");
295
+ var import_agent_core3 = require("@robota-sdk/agent-core");
42
296
 
43
297
  // src/commands/command-registry.ts
44
298
  var CommandRegistry = class {
@@ -71,6 +325,21 @@ var CommandRegistry = class {
71
325
  };
72
326
 
73
327
  // src/commands/builtin-source.ts
328
+ var import_agent_core = require("@robota-sdk/agent-core");
329
+ function buildModelSubcommands() {
330
+ const seen = /* @__PURE__ */ new Set();
331
+ const commands = [];
332
+ for (const model of Object.values(import_agent_core.CLAUDE_MODELS)) {
333
+ if (seen.has(model.name)) continue;
334
+ seen.add(model.name);
335
+ commands.push({
336
+ name: model.id,
337
+ description: `${model.name} (${(0, import_agent_core.formatTokenCount)(model.contextWindow).toUpperCase()})`,
338
+ source: "builtin"
339
+ });
340
+ }
341
+ return commands;
342
+ }
74
343
  function createBuiltinCommands() {
75
344
  return [
76
345
  { name: "help", description: "Show available commands", source: "builtin" },
@@ -90,11 +359,7 @@ function createBuiltinCommands() {
90
359
  name: "model",
91
360
  description: "Select AI model",
92
361
  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
- ]
362
+ subcommands: buildModelSubcommands()
98
363
  },
99
364
  { name: "compact", description: "Compress context window", source: "builtin" },
100
365
  { name: "cost", description: "Show session info", source: "builtin" },
@@ -116,8 +381,8 @@ var BuiltinCommandSource = class {
116
381
  };
117
382
 
118
383
  // src/commands/skill-source.ts
119
- var import_node_fs = require("fs");
120
- var import_node_path = require("path");
384
+ var import_node_fs2 = require("fs");
385
+ var import_node_path2 = require("path");
121
386
  var import_node_os = require("os");
122
387
  function parseFrontmatter(content) {
123
388
  const lines = content.split("\n");
@@ -140,14 +405,14 @@ function parseFrontmatter(content) {
140
405
  return name ? { name, description } : null;
141
406
  }
142
407
  function scanSkillsDir(skillsDir) {
143
- if (!(0, import_node_fs.existsSync)(skillsDir)) return [];
408
+ if (!(0, import_node_fs2.existsSync)(skillsDir)) return [];
144
409
  const commands = [];
145
- const entries = (0, import_node_fs.readdirSync)(skillsDir, { withFileTypes: true });
410
+ const entries = (0, import_node_fs2.readdirSync)(skillsDir, { withFileTypes: true });
146
411
  for (const entry of entries) {
147
412
  if (!entry.isDirectory()) continue;
148
- const skillFile = (0, import_node_path.join)(skillsDir, entry.name, "SKILL.md");
149
- if (!(0, import_node_fs.existsSync)(skillFile)) continue;
150
- const content = (0, import_node_fs.readFileSync)(skillFile, "utf-8");
413
+ const skillFile = (0, import_node_path2.join)(skillsDir, entry.name, "SKILL.md");
414
+ if (!(0, import_node_fs2.existsSync)(skillFile)) continue;
415
+ const content = (0, import_node_fs2.readFileSync)(skillFile, "utf-8");
151
416
  const frontmatter = parseFrontmatter(content);
152
417
  commands.push({
153
418
  name: frontmatter?.name ?? entry.name,
@@ -167,8 +432,8 @@ var SkillCommandSource = class {
167
432
  }
168
433
  getCommands() {
169
434
  if (this.cachedCommands) return this.cachedCommands;
170
- const projectSkills = scanSkillsDir((0, import_node_path.join)(this.cwd, ".agents", "skills"));
171
- const userSkills = scanSkillsDir((0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills"));
435
+ const projectSkills = scanSkillsDir((0, import_node_path2.join)(this.cwd, ".agents", "skills"));
436
+ const userSkills = scanSkillsDir((0, import_node_path2.join)((0, import_node_os.homedir)(), ".claude", "skills"));
172
437
  const seen = new Set(projectSkills.map((cmd) => cmd.name));
173
438
  const merged = [...projectSkills];
174
439
  for (const cmd of userSkills) {
@@ -242,6 +507,7 @@ function MessageList({ messages }) {
242
507
 
243
508
  // src/ui/StatusBar.tsx
244
509
  var import_ink2 = require("ink");
510
+ var import_agent_core2 = require("@robota-sdk/agent-core");
245
511
  var import_jsx_runtime2 = require("react/jsx-runtime");
246
512
  var CONTEXT_YELLOW_THRESHOLD = 70;
247
513
  var CONTEXT_RED_THRESHOLD = 90;
@@ -281,10 +547,10 @@ function StatusBar({
281
547
  "Context: ",
282
548
  Math.round(contextPercentage),
283
549
  "% (",
284
- (contextUsedTokens / 1e3).toFixed(1),
285
- "k/",
286
- (contextMaxTokens / 1e3).toFixed(0),
287
- "k)"
550
+ (0, import_agent_core2.formatTokenCount)(contextUsedTokens),
551
+ "/",
552
+ (0, import_agent_core2.formatTokenCount)(contextMaxTokens),
553
+ ")"
288
554
  ] })
289
555
  ] }),
290
556
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { children: [
@@ -431,19 +697,13 @@ var import_jsx_runtime5 = require("react/jsx-runtime");
431
697
  var MAX_VISIBLE = 8;
432
698
  function CommandRow(props) {
433
699
  const { cmd, isSelected, showSlash } = props;
434
- const prefix = showSlash ? "/" : "";
435
700
  const indicator = isSelected ? "\u25B8 " : " ";
436
701
  const nameColor = isSelected ? "cyan" : void 0;
437
702
  const dimmed = !isSelected;
438
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink5.Box, { children: [
439
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: [
440
- indicator,
441
- prefix,
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
- ] });
703
+ 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: [
704
+ indicator,
705
+ showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
706
+ ] }) });
447
707
  }
448
708
  function SlashAutocomplete({
449
709
  commands,
@@ -608,10 +868,53 @@ function InputArea({ onSubmit, isDisabled, registry }) {
608
868
  ] });
609
869
  }
610
870
 
611
- // src/ui/PermissionPrompt.tsx
612
- var import_react4 = __toESM(require("react"), 1);
871
+ // src/ui/ConfirmPrompt.tsx
872
+ var import_react4 = require("react");
613
873
  var import_ink7 = require("ink");
614
874
  var import_jsx_runtime7 = require("react/jsx-runtime");
875
+ function ConfirmPrompt({
876
+ message,
877
+ options = ["Yes", "No"],
878
+ onSelect
879
+ }) {
880
+ const [selected, setSelected] = (0, import_react4.useState)(0);
881
+ const resolvedRef = (0, import_react4.useRef)(false);
882
+ const doSelect = (0, import_react4.useCallback)(
883
+ (index) => {
884
+ if (resolvedRef.current) return;
885
+ resolvedRef.current = true;
886
+ onSelect(index);
887
+ },
888
+ [onSelect]
889
+ );
890
+ (0, import_ink7.useInput)((input, key) => {
891
+ if (resolvedRef.current) return;
892
+ if (key.leftArrow || key.upArrow) {
893
+ setSelected((prev) => prev > 0 ? prev - 1 : prev);
894
+ } else if (key.rightArrow || key.downArrow) {
895
+ setSelected((prev) => prev < options.length - 1 ? prev + 1 : prev);
896
+ } else if (key.return) {
897
+ doSelect(selected);
898
+ } else if (input === "y" && options.length === 2) {
899
+ doSelect(0);
900
+ } else if (input === "n" && options.length === 2) {
901
+ doSelect(1);
902
+ }
903
+ });
904
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: message }),
906
+ /* @__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: [
907
+ i === selected ? "> " : " ",
908
+ opt
909
+ ] }) }, opt)) }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
911
+ ] });
912
+ }
913
+
914
+ // src/ui/PermissionPrompt.tsx
915
+ var import_react5 = __toESM(require("react"), 1);
916
+ var import_ink8 = require("ink");
917
+ var import_jsx_runtime8 = require("react/jsx-runtime");
615
918
  var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
616
919
  function formatArgs(args) {
617
920
  const entries = Object.entries(args);
@@ -619,15 +922,15 @@ function formatArgs(args) {
619
922
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
620
923
  }
621
924
  function PermissionPrompt({ request }) {
622
- const [selected, setSelected] = import_react4.default.useState(0);
623
- const resolvedRef = import_react4.default.useRef(false);
624
- const prevRequestRef = import_react4.default.useRef(request);
925
+ const [selected, setSelected] = import_react5.default.useState(0);
926
+ const resolvedRef = import_react5.default.useRef(false);
927
+ const prevRequestRef = import_react5.default.useRef(request);
625
928
  if (prevRequestRef.current !== request) {
626
929
  prevRequestRef.current = request;
627
930
  resolvedRef.current = false;
628
931
  setSelected(0);
629
932
  }
630
- const doResolve = import_react4.default.useCallback(
933
+ const doResolve = import_react5.default.useCallback(
631
934
  (index) => {
632
935
  if (resolvedRef.current) return;
633
936
  resolvedRef.current = true;
@@ -637,7 +940,7 @@ function PermissionPrompt({ request }) {
637
940
  },
638
941
  [request]
639
942
  );
640
- (0, import_ink7.useInput)((input, key) => {
943
+ (0, import_ink8.useInput)((input, key) => {
641
944
  if (resolvedRef.current) return;
642
945
  if (key.upArrow || key.leftArrow) {
643
946
  setSelected((prev) => prev > 0 ? prev - 1 : prev);
@@ -653,27 +956,54 @@ function PermissionPrompt({ request }) {
653
956
  doResolve(2);
654
957
  }
655
958
  });
656
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
657
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
658
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { children: [
959
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
960
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { children: [
659
962
  "Tool:",
660
963
  " ",
661
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "cyan", bold: true, children: request.toolName })
964
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: request.toolName })
662
965
  ] }),
663
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { dimColor: true, children: [
966
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { dimColor: true, children: [
664
967
  " ",
665
968
  formatArgs(request.toolArgs)
666
969
  ] }),
667
- /* @__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: [
970
+ /* @__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
971
  i === selected ? "> " : " ",
669
972
  opt
670
973
  ] }) }, opt)) }),
671
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
974
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
672
975
  ] });
673
976
  }
674
977
 
978
+ // src/utils/tool-call-extractor.ts
979
+ var TOOL_ARG_MAX_LENGTH = 80;
980
+ var TOOL_ARG_TRUNCATE_LENGTH = 77;
981
+ function extractToolCalls(history, startIndex) {
982
+ const lines = [];
983
+ for (let i = startIndex; i < history.length; i++) {
984
+ const msg = history[i];
985
+ if (msg.role === "assistant" && msg.toolCalls) {
986
+ for (const tc of msg.toolCalls) {
987
+ const value = parseFirstArgValue(tc.function.arguments);
988
+ const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_TRUNCATE_LENGTH) + "..." : value;
989
+ lines.push(`${tc.function.name}(${truncated})`);
990
+ }
991
+ }
992
+ }
993
+ return lines;
994
+ }
995
+ function parseFirstArgValue(argsJson) {
996
+ try {
997
+ const parsed = JSON.parse(argsJson);
998
+ const firstVal = Object.values(parsed)[0];
999
+ return typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal);
1000
+ } catch {
1001
+ return argsJson;
1002
+ }
1003
+ }
1004
+
675
1005
  // src/ui/App.tsx
676
- var import_jsx_runtime8 = require("react/jsx-runtime");
1006
+ var import_jsx_runtime9 = require("react/jsx-runtime");
677
1007
  var msgIdCounter = 0;
678
1008
  function nextId() {
679
1009
  msgIdCounter += 1;
@@ -695,11 +1025,11 @@ var NOOP_TERMINAL = {
695
1025
  } })
696
1026
  };
697
1027
  function useSession(props) {
698
- const [permissionRequest, setPermissionRequest] = (0, import_react5.useState)(null);
699
- const [streamingText, setStreamingText] = (0, import_react5.useState)("");
700
- const permissionQueueRef = (0, import_react5.useRef)([]);
701
- const processingRef = (0, import_react5.useRef)(false);
702
- const processNextPermission = (0, import_react5.useCallback)(() => {
1028
+ const [permissionRequest, setPermissionRequest] = (0, import_react6.useState)(null);
1029
+ const [streamingText, setStreamingText] = (0, import_react6.useState)("");
1030
+ const permissionQueueRef = (0, import_react6.useRef)([]);
1031
+ const processingRef = (0, import_react6.useRef)(false);
1032
+ const processNextPermission = (0, import_react6.useCallback)(() => {
703
1033
  if (processingRef.current) return;
704
1034
  const next = permissionQueueRef.current[0];
705
1035
  if (!next) {
@@ -719,7 +1049,7 @@ function useSession(props) {
719
1049
  }
720
1050
  });
721
1051
  }, []);
722
- const sessionRef = (0, import_react5.useRef)(null);
1052
+ const sessionRef = (0, import_react6.useRef)(null);
723
1053
  if (sessionRef.current === null) {
724
1054
  const permissionHandler = (toolName, toolArgs) => {
725
1055
  return new Promise((resolve) => {
@@ -744,138 +1074,49 @@ function useSession(props) {
744
1074
  onTextDelta
745
1075
  });
746
1076
  }
747
- const clearStreamingText = (0, import_react5.useCallback)(() => setStreamingText(""), []);
1077
+ const clearStreamingText = (0, import_react6.useCallback)(() => setStreamingText(""), []);
748
1078
  return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText };
749
1079
  }
750
1080
  function useMessages() {
751
- const [messages, setMessages] = (0, import_react5.useState)([]);
752
- const addMessage = (0, import_react5.useCallback)((msg) => {
1081
+ const [messages, setMessages] = (0, import_react6.useState)([]);
1082
+ const addMessage = (0, import_react6.useCallback)((msg) => {
753
1083
  setMessages((prev) => [...prev, { ...msg, id: nextId(), timestamp: /* @__PURE__ */ new Date() }]);
754
1084
  }, []);
755
1085
  return { messages, setMessages, addMessage };
756
1086
  }
757
- var HELP_TEXT = [
758
- "Available commands:",
759
- " /help \u2014 Show this help",
760
- " /clear \u2014 Clear conversation",
761
- " /compact [instr] \u2014 Compact context (optional focus instructions)",
762
- " /mode [m] \u2014 Show/change permission mode",
763
- " /cost \u2014 Show session info",
764
- " /reset \u2014 Delete settings and exit",
765
- " /exit \u2014 Exit CLI"
766
- ].join("\n");
767
- function handleModeCommand(arg, session, addMessage) {
768
- const validModes = ["plan", "default", "acceptEdits", "bypassPermissions"];
769
- if (!arg) {
770
- addMessage({ role: "system", content: `Current mode: ${session.getPermissionMode()}` });
771
- } else if (validModes.includes(arg)) {
772
- session.setPermissionMode(arg);
773
- addMessage({ role: "system", content: `Permission mode set to: ${arg}` });
774
- } else {
775
- addMessage({ role: "system", content: `Invalid mode. Valid: ${validModes.join(" | ")}` });
776
- }
777
- return true;
778
- }
779
- async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry) {
780
- switch (cmd) {
781
- case "help":
782
- addMessage({ role: "system", content: HELP_TEXT });
783
- return true;
784
- case "clear":
785
- setMessages([]);
786
- session.clearHistory();
787
- addMessage({ role: "system", content: "Conversation cleared." });
788
- return true;
789
- case "compact": {
790
- const instructions = parts.slice(1).join(" ").trim() || void 0;
791
- const before = session.getContextState().usedPercentage;
792
- addMessage({ role: "system", content: "Compacting context..." });
793
- await session.compact(instructions);
794
- const after = session.getContextState().usedPercentage;
795
- addMessage({
796
- role: "system",
797
- content: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`
798
- });
799
- return true;
800
- }
801
- case "mode":
802
- return handleModeCommand(parts[1], session, addMessage);
803
- case "cost":
804
- addMessage({
805
- role: "system",
806
- content: `Session: ${session.getSessionId()}
807
- Messages: ${session.getMessageCount()}`
808
- });
809
- return true;
810
- case "permissions": {
811
- const mode = session.getPermissionMode();
812
- const sessionAllowed = session.getSessionAllowedTools();
813
- const lines = [`Permission mode: ${mode}`];
814
- if (sessionAllowed.length > 0) {
815
- lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
816
- } else {
817
- lines.push("No session-approved tools.");
818
- }
819
- addMessage({ role: "system", content: lines.join("\n") });
820
- return true;
821
- }
822
- case "context": {
823
- const ctx = session.getContextState();
824
- addMessage({
825
- role: "system",
826
- content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
827
- });
828
- return true;
829
- }
830
- case "reset": {
831
- const { existsSync: exists, unlinkSync: unlink } = await import("fs");
832
- const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
833
- const settingsPath = `${home}/.robota/settings.json`;
834
- if (exists(settingsPath)) {
835
- unlink(settingsPath);
836
- addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
837
- } else {
838
- addMessage({ role: "system", content: "No user settings found." });
839
- }
840
- setTimeout(() => exit(), 500);
841
- return true;
842
- }
843
- case "exit":
844
- exit();
845
- return true;
846
- default: {
847
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
848
- if (skillCmd) {
849
- addMessage({ role: "system", content: `Invoking skill: ${cmd}` });
850
- return false;
851
- }
852
- addMessage({ role: "system", content: `Unknown command "/${cmd}". Type /help for help.` });
853
- return true;
854
- }
855
- }
856
- }
857
- function useSlashCommands(session, addMessage, setMessages, exit, registry) {
858
- return (0, import_react5.useCallback)(
1087
+ var EXIT_DELAY_MS = 500;
1088
+ function useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId) {
1089
+ return (0, import_react6.useCallback)(
859
1090
  async (input) => {
860
1091
  const parts = input.slice(1).split(/\s+/);
861
1092
  const cmd = parts[0]?.toLowerCase() ?? "";
862
- return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry);
1093
+ const args = parts.slice(1).join(" ");
1094
+ const clearMessages = () => setMessages([]);
1095
+ const result = await executeSlashCommand(cmd, args, session, addMessage, clearMessages, registry);
1096
+ if (result.pendingModelId) {
1097
+ pendingModelChangeRef.current = result.pendingModelId;
1098
+ setPendingModelId(result.pendingModelId);
1099
+ }
1100
+ if (result.exitRequested) {
1101
+ setTimeout(() => exit(), EXIT_DELAY_MS);
1102
+ }
1103
+ return result.handled;
863
1104
  },
864
- [session, addMessage, setMessages, exit, registry]
1105
+ [session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
865
1106
  );
866
1107
  }
867
1108
  function StreamingIndicator({ text }) {
868
1109
  if (text) {
869
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
870
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { color: "cyan", bold: true, children: [
1110
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
1111
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: "cyan", bold: true, children: [
871
1112
  "Robota:",
872
1113
  " "
873
1114
  ] }),
874
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { children: " " }),
875
- /* @__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) }) })
1115
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
1116
+ /* @__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
1117
  ] });
877
1118
  }
878
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", children: "Thinking..." });
1119
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
879
1120
  }
880
1121
  async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
881
1122
  setIsThinking(true);
@@ -885,24 +1126,10 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
885
1126
  const response = await session.run(prompt);
886
1127
  clearStreamingText();
887
1128
  const history = session.getHistory();
888
- const toolLines = [];
889
- for (let i = historyBefore; i < history.length; i++) {
890
- const msg = history[i];
891
- if (msg.role === "assistant" && msg.toolCalls) {
892
- for (const tc of msg.toolCalls) {
893
- let value = "";
894
- try {
895
- const parsed = JSON.parse(tc.function.arguments);
896
- const firstVal = Object.values(parsed)[0];
897
- value = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal);
898
- } catch {
899
- value = tc.function.arguments;
900
- }
901
- const truncated = value.length > 80 ? value.slice(0, 77) + "..." : value;
902
- toolLines.push(`${tc.function.name}(${truncated})`);
903
- }
904
- }
905
- }
1129
+ const toolLines = extractToolCalls(
1130
+ history,
1131
+ historyBefore
1132
+ );
906
1133
  if (toolLines.length > 0) {
907
1134
  addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
908
1135
  }
@@ -937,7 +1164,7 @@ Execute the "${cmd}" skill: ${userInstruction}`;
937
1164
  return `Use the "${cmd}" skill: ${userInstruction}`;
938
1165
  }
939
1166
  function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
940
- return (0, import_react5.useCallback)(
1167
+ return (0, import_react6.useCallback)(
941
1168
  async (input) => {
942
1169
  if (input.startsWith("/")) {
943
1170
  const handled = await handleSlashCommand(input);
@@ -978,7 +1205,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
978
1205
  );
979
1206
  }
980
1207
  function useCommandRegistry(cwd) {
981
- const registryRef = (0, import_react5.useRef)(null);
1208
+ const registryRef = (0, import_react6.useRef)(null);
982
1209
  if (registryRef.current === null) {
983
1210
  const registry = new CommandRegistry();
984
1211
  registry.addSource(new BuiltinCommandSource());
@@ -988,13 +1215,15 @@ function useCommandRegistry(cwd) {
988
1215
  return registryRef.current;
989
1216
  }
990
1217
  function App(props) {
991
- const { exit } = (0, import_ink8.useApp)();
1218
+ const { exit } = (0, import_ink9.useApp)();
992
1219
  const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
993
1220
  const { messages, setMessages, addMessage } = useMessages();
994
- const [isThinking, setIsThinking] = (0, import_react5.useState)(false);
995
- const [contextPercentage, setContextPercentage] = (0, import_react5.useState)(0);
1221
+ const [isThinking, setIsThinking] = (0, import_react6.useState)(false);
1222
+ const [contextPercentage, setContextPercentage] = (0, import_react6.useState)(0);
996
1223
  const registry = useCommandRegistry(props.cwd ?? process.cwd());
997
- const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry);
1224
+ const pendingModelChangeRef = (0, import_react6.useRef)(null);
1225
+ const [pendingModelId, setPendingModelId] = (0, import_react6.useState)(null);
1226
+ const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId);
998
1227
  const handleSubmit = useSubmitHandler(
999
1228
  session,
1000
1229
  addMessage,
@@ -1004,37 +1233,59 @@ function App(props) {
1004
1233
  setContextPercentage,
1005
1234
  registry
1006
1235
  );
1007
- (0, import_ink8.useInput)(
1236
+ (0, import_ink9.useInput)(
1008
1237
  (_input, key) => {
1009
1238
  if (key.ctrl && _input === "c") exit();
1010
1239
  if (key.escape && isThinking) session.abort();
1011
1240
  },
1012
1241
  { isActive: !permissionRequest }
1013
1242
  );
1014
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
1015
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
1016
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: `
1243
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
1244
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
1245
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: `
1017
1246
  ____ ___ ____ ___ _____ _
1018
1247
  | _ \\ / _ \\| __ ) / _ \\_ _|/ \\
1019
1248
  | |_) | | | | _ \\| | | || | / _ \\
1020
1249
  | _ <| |_| | |_) | |_| || |/ ___ \\
1021
1250
  |_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
1022
1251
  ` }),
1023
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { dimColor: true, children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { dimColor: true, children: [
1024
1253
  " v",
1025
1254
  props.version ?? "0.0.0"
1026
1255
  ] })
1027
1256
  ] }),
1028
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
1029
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MessageList, { messages }),
1030
- isThinking && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StreamingIndicator, { text: streamingText }) })
1257
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
1258
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageList, { messages }),
1259
+ 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
1260
  ] }),
1032
- permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PermissionPrompt, { request: permissionRequest }),
1033
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1261
+ permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PermissionPrompt, { request: permissionRequest }),
1262
+ pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1263
+ ConfirmPrompt,
1264
+ {
1265
+ message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
1266
+ onSelect: (index) => {
1267
+ setPendingModelId(null);
1268
+ pendingModelChangeRef.current = null;
1269
+ if (index === 0) {
1270
+ try {
1271
+ const settingsPath = getUserSettingsPath();
1272
+ updateModelInSettings(settingsPath, pendingModelId);
1273
+ addMessage({ role: "system", content: `Model changed to ${(0, import_agent_core3.getModelName)(pendingModelId)}. Restarting...` });
1274
+ setTimeout(() => exit(), 500);
1275
+ } catch (err) {
1276
+ addMessage({ role: "system", content: `Failed: ${err instanceof Error ? err.message : String(err)}` });
1277
+ }
1278
+ } else {
1279
+ addMessage({ role: "system", content: "Model change cancelled." });
1280
+ }
1281
+ }
1282
+ }
1283
+ ),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1034
1285
  StatusBar,
1035
1286
  {
1036
1287
  permissionMode: session.getPermissionMode(),
1037
- modelName: props.config.provider.model,
1288
+ modelName: (0, import_agent_core3.getModelName)(props.config.provider.model),
1038
1289
  sessionId: session.getSessionId(),
1039
1290
  messageCount: messages.length,
1040
1291
  isThinking,
@@ -1043,7 +1294,7 @@ function App(props) {
1043
1294
  contextMaxTokens: session.getContextState().maxTokens
1044
1295
  }
1045
1296
  ),
1046
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1297
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1047
1298
  InputArea,
1048
1299
  {
1049
1300
  onSubmit: handleSubmit,
@@ -1051,12 +1302,12 @@ function App(props) {
1051
1302
  registry
1052
1303
  }
1053
1304
  ),
1054
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { children: " " })
1305
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " })
1055
1306
  ] });
1056
1307
  }
1057
1308
 
1058
1309
  // src/ui/render.tsx
1059
- var import_jsx_runtime9 = require("react/jsx-runtime");
1310
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1060
1311
  function renderApp(options) {
1061
1312
  process.on("unhandledRejection", (reason) => {
1062
1313
  process.stderr.write(`
@@ -1067,7 +1318,7 @@ function renderApp(options) {
1067
1318
  `);
1068
1319
  }
1069
1320
  });
1070
- const instance = (0, import_ink9.render)(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(App, { ...options }), {
1321
+ const instance = (0, import_ink10.render)(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(App, { ...options }), {
1071
1322
  exitOnCtrlC: true
1072
1323
  });
1073
1324
  instance.waitUntilExit().catch((err) => {
@@ -1081,15 +1332,14 @@ function renderApp(options) {
1081
1332
 
1082
1333
  // src/cli.ts
1083
1334
  var import_meta = {};
1084
- var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
1085
1335
  function readVersion() {
1086
1336
  try {
1087
1337
  const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
1088
- const dir = (0, import_node_path2.dirname)(thisFile);
1089
- const candidates = [(0, import_node_path2.join)(dir, "..", "..", "package.json"), (0, import_node_path2.join)(dir, "..", "package.json")];
1338
+ const dir = (0, import_node_path3.dirname)(thisFile);
1339
+ const candidates = [(0, import_node_path3.join)(dir, "..", "..", "package.json"), (0, import_node_path3.join)(dir, "..", "package.json")];
1090
1340
  for (const pkgPath of candidates) {
1091
1341
  try {
1092
- const raw = (0, import_node_fs2.readFileSync)(pkgPath, "utf-8");
1342
+ const raw = (0, import_node_fs3.readFileSync)(pkgPath, "utf-8");
1093
1343
  const pkg = JSON.parse(raw);
1094
1344
  if (pkg.version !== void 0 && pkg.name !== void 0) {
1095
1345
  return pkg.version;
@@ -1102,108 +1352,11 @@ function readVersion() {
1102
1352
  return "0.0.0";
1103
1353
  }
1104
1354
  }
1105
- function parsePermissionMode(raw) {
1106
- if (raw === void 0) return void 0;
1107
- if (!VALID_MODES.includes(raw)) {
1108
- process.stderr.write(`Invalid --permission-mode "${raw}". Valid: ${VALID_MODES.join(" | ")}
1109
- `);
1110
- process.exit(1);
1111
- }
1112
- return raw;
1113
- }
1114
- function parseMaxTurns(raw) {
1115
- if (raw === void 0) return void 0;
1116
- const n = parseInt(raw, 10);
1117
- if (isNaN(n) || n <= 0) {
1118
- process.stderr.write(`Invalid --max-turns "${raw}". Must be a positive integer.
1119
- `);
1120
- process.exit(1);
1121
- }
1122
- return n;
1123
- }
1124
- function parseCliArgs() {
1125
- const { values, positionals } = (0, import_node_util.parseArgs)({
1126
- allowPositionals: true,
1127
- options: {
1128
- p: { type: "boolean", short: "p", default: false },
1129
- c: { type: "boolean", short: "c", default: false },
1130
- r: { type: "string", short: "r" },
1131
- model: { type: "string" },
1132
- "permission-mode": { type: "string" },
1133
- "max-turns": { type: "string" },
1134
- version: { type: "boolean", default: false },
1135
- reset: { type: "boolean", default: false }
1136
- }
1137
- });
1138
- return {
1139
- positional: positionals,
1140
- printMode: values["p"] ?? false,
1141
- continueMode: values["c"] ?? false,
1142
- resumeId: values["r"],
1143
- model: values["model"],
1144
- permissionMode: parsePermissionMode(values["permission-mode"]),
1145
- maxTurns: parseMaxTurns(values["max-turns"]),
1146
- version: values["version"] ?? false,
1147
- reset: values["reset"] ?? false
1148
- };
1149
- }
1150
- var PrintTerminal = class {
1151
- write(text) {
1152
- process.stdout.write(text);
1153
- }
1154
- writeLine(text) {
1155
- process.stdout.write(text + "\n");
1156
- }
1157
- writeMarkdown(md) {
1158
- process.stdout.write(md);
1159
- }
1160
- writeError(text) {
1161
- process.stderr.write(text + "\n");
1162
- }
1163
- prompt(question) {
1164
- return new Promise((resolve) => {
1165
- const rl = readline.createInterface({
1166
- input: process.stdin,
1167
- output: process.stdout,
1168
- terminal: false,
1169
- historySize: 0
1170
- });
1171
- rl.question(question, (answer) => {
1172
- rl.close();
1173
- resolve(answer);
1174
- });
1175
- });
1176
- }
1177
- async select(options, initialIndex = 0) {
1178
- for (let i = 0; i < options.length; i++) {
1179
- const marker = i === initialIndex ? ">" : " ";
1180
- process.stdout.write(` ${marker} ${i + 1}) ${options[i]}
1181
- `);
1182
- }
1183
- const answer = await this.prompt(
1184
- ` Choose [1-${options.length}] (default: ${options[initialIndex]}): `
1185
- );
1186
- const trimmed = answer.trim().toLowerCase();
1187
- if (trimmed === "") return initialIndex;
1188
- const num = parseInt(trimmed, 10);
1189
- if (!isNaN(num) && num >= 1 && num <= options.length) return num - 1;
1190
- return initialIndex;
1191
- }
1192
- spinner(_message) {
1193
- return { stop() {
1194
- }, update() {
1195
- } };
1196
- }
1197
- };
1198
- function getUserSettingsPath() {
1199
- const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
1200
- return (0, import_node_path2.join)(home, ".robota", "settings.json");
1201
- }
1202
1355
  async function ensureConfig(cwd) {
1203
1356
  const userPath = getUserSettingsPath();
1204
- const projectPath = (0, import_node_path2.join)(cwd, ".robota", "settings.json");
1205
- const localPath = (0, import_node_path2.join)(cwd, ".robota", "settings.local.json");
1206
- if ((0, import_node_fs2.existsSync)(userPath) || (0, import_node_fs2.existsSync)(projectPath) || (0, import_node_fs2.existsSync)(localPath)) {
1357
+ const projectPath = (0, import_node_path3.join)(cwd, ".robota", "settings.json");
1358
+ const localPath = (0, import_node_path3.join)(cwd, ".robota", "settings.local.json");
1359
+ if ((0, import_node_fs3.existsSync)(userPath) || (0, import_node_fs3.existsSync)(projectPath) || (0, import_node_fs3.existsSync)(localPath)) {
1207
1360
  return;
1208
1361
  }
1209
1362
  process.stdout.write("\n");
@@ -1247,8 +1400,8 @@ async function ensureConfig(cwd) {
1247
1400
  process.stderr.write("\n No API key provided. Exiting.\n");
1248
1401
  process.exit(1);
1249
1402
  }
1250
- const settingsDir = (0, import_node_path2.dirname)(userPath);
1251
- (0, import_node_fs2.mkdirSync)(settingsDir, { recursive: true });
1403
+ const settingsDir = (0, import_node_path3.dirname)(userPath);
1404
+ (0, import_node_fs3.mkdirSync)(settingsDir, { recursive: true });
1252
1405
  const settings = {
1253
1406
  provider: {
1254
1407
  name: "anthropic",
@@ -1256,7 +1409,7 @@ async function ensureConfig(cwd) {
1256
1409
  apiKey
1257
1410
  }
1258
1411
  };
1259
- (0, import_node_fs2.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
1412
+ (0, import_node_fs3.writeFileSync)(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
1260
1413
  process.stdout.write(`
1261
1414
  Config saved to ${userPath}
1262
1415
 
@@ -1264,8 +1417,7 @@ async function ensureConfig(cwd) {
1264
1417
  }
1265
1418
  function resetConfig() {
1266
1419
  const userPath = getUserSettingsPath();
1267
- if ((0, import_node_fs2.existsSync)(userPath)) {
1268
- (0, import_node_fs2.unlinkSync)(userPath);
1420
+ if (deleteSettings(userPath)) {
1269
1421
  process.stdout.write(`Deleted ${userPath}
1270
1422
  `);
1271
1423
  } else {