@robota-sdk/agent-cli 3.0.0-beta.51 → 3.0.0-beta.53

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.
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(index_exports);
38
38
  var import_node_fs3 = require("fs");
39
39
  var import_node_path5 = require("path");
40
40
  var import_node_url = require("url");
41
- var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
41
+ var import_agent_sdk4 = require("@robota-sdk/agent-sdk");
42
42
  var import_agent_sessions = require("@robota-sdk/agent-sessions");
43
43
 
44
44
  // src/utils/cli-args.ts
@@ -111,7 +111,14 @@ function getUserSettingsPath() {
111
111
  }
112
112
  function readSettings(path) {
113
113
  if (!(0, import_node_fs.existsSync)(path)) return {};
114
- return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
114
+ const raw = (0, import_node_fs.readFileSync)(path, "utf8");
115
+ try {
116
+ return JSON.parse(raw);
117
+ } catch {
118
+ process.stderr.write(`Warning: corrupt settings file at ${path}, resetting to defaults
119
+ `);
120
+ return {};
121
+ }
115
122
  }
116
123
  function writeSettings(path, settings) {
117
124
  (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(path), { recursive: true });
@@ -180,20 +187,18 @@ function createProviderFromSettings(cwd, modelOverride) {
180
187
  var import_agent_transport_headless = require("@robota-sdk/agent-transport-headless");
181
188
 
182
189
  // src/ui/render.tsx
183
- var import_ink15 = require("ink");
190
+ var import_ink17 = require("ink");
184
191
 
185
192
  // src/ui/App.tsx
186
- var import_react13 = require("react");
187
- var import_ink14 = require("ink");
188
- var import_agent_core4 = require("@robota-sdk/agent-core");
193
+ var import_react17 = require("react");
194
+ var import_ink16 = require("ink");
195
+ var import_agent_core5 = require("@robota-sdk/agent-core");
189
196
 
190
197
  // src/ui/hooks/useInteractiveSession.ts
191
- var import_react = require("react");
198
+ var import_react2 = require("react");
192
199
  var import_node_os2 = require("os");
193
200
  var import_node_path3 = require("path");
194
- var import_agent_sdk = require("@robota-sdk/agent-sdk");
195
- var import_agent_core = require("@robota-sdk/agent-core");
196
- var import_node_crypto = require("crypto");
201
+ var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
197
202
 
198
203
  // src/ui/tui-state-manager.ts
199
204
  var MAX_RENDERED_MESSAGES = 100;
@@ -321,9 +326,97 @@ var TuiStateManager = class {
321
326
  }
322
327
  };
323
328
 
329
+ // src/ui/hooks/useSlashRouting.ts
330
+ var import_react = require("react");
331
+ var import_node_crypto = require("crypto");
332
+ var import_agent_sdk = require("@robota-sdk/agent-sdk");
333
+ var import_agent_core = require("@robota-sdk/agent-core");
334
+ function useSlashRouting(interactiveSession, registry, manager) {
335
+ return (0, import_react.useCallback)(
336
+ async (input) => {
337
+ if (!input.startsWith("/")) {
338
+ await interactiveSession.submit(input);
339
+ manager.setPendingPrompt(interactiveSession.getPendingPrompt());
340
+ return;
341
+ }
342
+ const parts = input.slice(1).split(/\s+/);
343
+ const cmd = parts[0]?.toLowerCase() ?? "";
344
+ const args = parts.slice(1).join(" ");
345
+ const result = await interactiveSession.executeCommand(cmd, args);
346
+ if (result) {
347
+ manager.addEntry((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createSystemMessage)(result.message)));
348
+ const effects = interactiveSession;
349
+ if (result.data?.modelId) {
350
+ effects._pendingModelId = result.data.modelId;
351
+ return;
352
+ }
353
+ if (result.data?.language) {
354
+ effects._pendingLanguage = result.data.language;
355
+ return;
356
+ }
357
+ if (result.data?.resetRequested) {
358
+ effects._resetRequested = true;
359
+ return;
360
+ }
361
+ if (result.data?.triggerResumePicker) {
362
+ effects._triggerResumePicker = true;
363
+ return;
364
+ }
365
+ if (result.data?.name) {
366
+ effects._sessionName = result.data.name;
367
+ return;
368
+ }
369
+ const ctx = interactiveSession.getContextState();
370
+ manager.setContextState({
371
+ percentage: ctx.usedPercentage,
372
+ usedTokens: ctx.usedTokens,
373
+ maxTokens: ctx.maxTokens
374
+ });
375
+ return;
376
+ }
377
+ const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
378
+ if (skillCmd) {
379
+ manager.addEntry({
380
+ id: (0, import_node_crypto.randomUUID)(),
381
+ timestamp: /* @__PURE__ */ new Date(),
382
+ category: "event",
383
+ type: "skill-invocation",
384
+ data: {
385
+ skillName: cmd,
386
+ source: skillCmd.source,
387
+ message: `Invoking ${skillCmd.source}: ${cmd}`
388
+ }
389
+ });
390
+ const prompt = await (0, import_agent_sdk.buildSkillPrompt)(input, registry);
391
+ if (prompt) {
392
+ const qualifiedName = registry.resolveQualifiedName(cmd);
393
+ const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmd.length)}` : input;
394
+ await interactiveSession.submit(prompt, input, hookInput);
395
+ manager.setPendingPrompt(interactiveSession.getPendingPrompt());
396
+ return;
397
+ }
398
+ }
399
+ if (cmd === "exit") {
400
+ interactiveSession._exitRequested = true;
401
+ return;
402
+ }
403
+ if (cmd === "plugin") {
404
+ interactiveSession._triggerPluginTUI = true;
405
+ return;
406
+ }
407
+ manager.addEntry(
408
+ (0, import_agent_core.messageToHistoryEntry)(
409
+ (0, import_agent_core.createSystemMessage)(`Unknown command "/${cmd}". Type /help for help.`)
410
+ )
411
+ );
412
+ },
413
+ [interactiveSession, registry, manager]
414
+ );
415
+ }
416
+
324
417
  // src/ui/hooks/useInteractiveSession.ts
325
418
  function initializeSession(props, permissionHandler) {
326
- const interactiveSession = new import_agent_sdk.InteractiveSession({
419
+ const interactiveSession = new import_agent_sdk2.InteractiveSession({
327
420
  cwd: props.cwd,
328
421
  provider: props.provider,
329
422
  permissionMode: props.permissionMode,
@@ -334,15 +427,15 @@ function initializeSession(props, permissionHandler) {
334
427
  forkSession: props.forkSession,
335
428
  sessionName: props.sessionName
336
429
  });
337
- const registry = new import_agent_sdk.CommandRegistry();
338
- registry.addSource(new import_agent_sdk.BuiltinCommandSource());
339
- registry.addSource(new import_agent_sdk.SkillCommandSource(props.cwd));
430
+ const registry = new import_agent_sdk2.CommandRegistry();
431
+ registry.addSource(new import_agent_sdk2.BuiltinCommandSource());
432
+ registry.addSource(new import_agent_sdk2.SkillCommandSource(props.cwd));
340
433
  const pluginsDir = (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".robota", "plugins");
341
- const loader = new import_agent_sdk.BundlePluginLoader(pluginsDir);
434
+ const loader = new import_agent_sdk2.BundlePluginLoader(pluginsDir);
342
435
  try {
343
436
  const plugins = loader.loadPluginsSync();
344
437
  if (plugins.length > 0) {
345
- registry.addSource(new import_agent_sdk.PluginCommandSource(plugins));
438
+ registry.addSource(new import_agent_sdk2.PluginCommandSource(plugins));
346
439
  }
347
440
  } catch {
348
441
  }
@@ -350,11 +443,11 @@ function initializeSession(props, permissionHandler) {
350
443
  return { interactiveSession, registry, manager };
351
444
  }
352
445
  function useInteractiveSession(props) {
353
- const [, forceRender] = (0, import_react.useState)(0);
354
- const [permissionRequest, setPermissionRequest] = (0, import_react.useState)(null);
355
- const permissionQueueRef = (0, import_react.useRef)([]);
356
- const processingRef = (0, import_react.useRef)(false);
357
- const processNextPermission = (0, import_react.useCallback)(() => {
446
+ const [, forceRender] = (0, import_react2.useState)(0);
447
+ const [permissionRequest, setPermissionRequest] = (0, import_react2.useState)(null);
448
+ const permissionQueueRef = (0, import_react2.useRef)([]);
449
+ const processingRef = (0, import_react2.useRef)(false);
450
+ const processNextPermission = (0, import_react2.useCallback)(() => {
358
451
  if (processingRef.current) return;
359
452
  const next = permissionQueueRef.current[0];
360
453
  if (!next) {
@@ -374,14 +467,14 @@ function useInteractiveSession(props) {
374
467
  }
375
468
  });
376
469
  }, []);
377
- const permissionHandler = (0, import_react.useCallback)(
470
+ const permissionHandler = (0, import_react2.useCallback)(
378
471
  (toolName, toolArgs) => new Promise((resolve) => {
379
472
  permissionQueueRef.current.push({ toolName, toolArgs, resolve });
380
473
  processNextPermission();
381
474
  }),
382
475
  [processNextPermission]
383
476
  );
384
- const stateRef = (0, import_react.useRef)(null);
477
+ const stateRef = (0, import_react2.useRef)(null);
385
478
  if (stateRef.current === null) {
386
479
  stateRef.current = initializeSession(props, permissionHandler);
387
480
  }
@@ -393,7 +486,7 @@ function useInteractiveSession(props) {
393
486
  manager.syncHistory(restored);
394
487
  }
395
488
  }
396
- (0, import_react.useEffect)(() => {
489
+ (0, import_react2.useEffect)(() => {
397
490
  interactiveSession.on("text_delta", manager.onTextDelta);
398
491
  interactiveSession.on("tool_start", manager.onToolStart);
399
492
  interactiveSession.on("tool_end", manager.onToolEnd);
@@ -428,97 +521,18 @@ function useInteractiveSession(props) {
428
521
  interactiveSession.off("error", manager.onError);
429
522
  };
430
523
  }, [interactiveSession, manager]);
431
- (0, import_react.useEffect)(() => {
524
+ (0, import_react2.useEffect)(() => {
432
525
  manager.syncHistory(interactiveSession.getFullHistory());
433
526
  if (!manager.isThinking) {
434
527
  manager.setPendingPrompt(interactiveSession.getPendingPrompt());
435
528
  }
436
529
  }, [manager.isThinking, interactiveSession, manager]);
437
- const handleSubmit = (0, import_react.useCallback)(
438
- async (input) => {
439
- if (input.startsWith("/")) {
440
- const parts = input.slice(1).split(/\s+/);
441
- const cmd = parts[0]?.toLowerCase() ?? "";
442
- const args = parts.slice(1).join(" ");
443
- const result = await interactiveSession.executeCommand(cmd, args);
444
- if (result) {
445
- manager.addEntry((0, import_agent_core.messageToHistoryEntry)((0, import_agent_core.createSystemMessage)(result.message)));
446
- const effects = interactiveSession;
447
- if (result.data?.modelId) {
448
- effects._pendingModelId = result.data.modelId;
449
- return;
450
- }
451
- if (result.data?.language) {
452
- effects._pendingLanguage = result.data.language;
453
- return;
454
- }
455
- if (result.data?.resetRequested) {
456
- effects._resetRequested = true;
457
- return;
458
- }
459
- if (result.data?.triggerResumePicker) {
460
- effects._triggerResumePicker = true;
461
- return;
462
- }
463
- if (result.data?.name) {
464
- effects._sessionName = result.data.name;
465
- return;
466
- }
467
- const ctx = interactiveSession.getContextState();
468
- manager.setContextState({
469
- percentage: ctx.usedPercentage,
470
- usedTokens: ctx.usedTokens,
471
- maxTokens: ctx.maxTokens
472
- });
473
- return;
474
- }
475
- const skillCmd = registry.getCommands().find((c) => c.name === cmd && (c.source === "skill" || c.source === "plugin"));
476
- if (skillCmd) {
477
- manager.addEntry({
478
- id: (0, import_node_crypto.randomUUID)(),
479
- timestamp: /* @__PURE__ */ new Date(),
480
- category: "event",
481
- type: "skill-invocation",
482
- data: {
483
- skillName: cmd,
484
- source: skillCmd.source,
485
- message: `Invoking ${skillCmd.source}: ${cmd}`
486
- }
487
- });
488
- const prompt = await (0, import_agent_sdk.buildSkillPrompt)(input, registry);
489
- if (prompt) {
490
- const qualifiedName = registry.resolveQualifiedName(cmd);
491
- const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmd.length)}` : input;
492
- await interactiveSession.submit(prompt, input, hookInput);
493
- manager.setPendingPrompt(interactiveSession.getPendingPrompt());
494
- return;
495
- }
496
- }
497
- if (cmd === "exit") {
498
- interactiveSession._exitRequested = true;
499
- return;
500
- }
501
- if (cmd === "plugin") {
502
- interactiveSession._triggerPluginTUI = true;
503
- return;
504
- }
505
- manager.addEntry(
506
- (0, import_agent_core.messageToHistoryEntry)(
507
- (0, import_agent_core.createSystemMessage)(`Unknown command "/${cmd}". Type /help for help.`)
508
- )
509
- );
510
- return;
511
- }
512
- await interactiveSession.submit(input);
513
- manager.setPendingPrompt(interactiveSession.getPendingPrompt());
514
- },
515
- [interactiveSession, registry, manager]
516
- );
517
- const handleAbort = (0, import_react.useCallback)(() => {
530
+ const handleSubmit = useSlashRouting(interactiveSession, registry, manager);
531
+ const handleAbort = (0, import_react2.useCallback)(() => {
518
532
  manager.setAborting(true);
519
533
  interactiveSession.abort();
520
534
  }, [interactiveSession, manager]);
521
- const handleCancelQueue = (0, import_react.useCallback)(() => {
535
+ const handleCancelQueue = (0, import_react2.useCallback)(() => {
522
536
  interactiveSession.cancelQueue();
523
537
  manager.setPendingPrompt(null);
524
538
  }, [interactiveSession, manager]);
@@ -541,23 +555,23 @@ function useInteractiveSession(props) {
541
555
  }
542
556
 
543
557
  // src/ui/hooks/usePluginCallbacks.ts
544
- var import_react2 = require("react");
558
+ var import_react3 = require("react");
545
559
  var import_node_os3 = require("os");
546
560
  var import_node_path4 = require("path");
547
- var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
561
+ var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
548
562
  function usePluginCallbacks(cwd) {
549
- return (0, import_react2.useMemo)(() => {
563
+ return (0, import_react3.useMemo)(() => {
550
564
  const home = (0, import_node_os3.homedir)();
551
565
  const pluginsDir = (0, import_node_path4.join)(home, ".robota", "plugins");
552
566
  const userSettingsPath = (0, import_node_path4.join)(home, ".robota", "settings.json");
553
- const settingsStore = new import_agent_sdk2.PluginSettingsStore(userSettingsPath);
554
- const marketplace = new import_agent_sdk2.MarketplaceClient({ pluginsDir });
555
- const installer = new import_agent_sdk2.BundlePluginInstaller({
567
+ const settingsStore = new import_agent_sdk3.PluginSettingsStore(userSettingsPath);
568
+ const marketplace = new import_agent_sdk3.MarketplaceClient({ pluginsDir });
569
+ const installer = new import_agent_sdk3.BundlePluginInstaller({
556
570
  pluginsDir,
557
571
  settingsStore,
558
572
  marketplaceClient: marketplace
559
573
  });
560
- const loader = new import_agent_sdk2.BundlePluginLoader(pluginsDir);
574
+ const loader = new import_agent_sdk3.BundlePluginLoader(pluginsDir);
561
575
  return {
562
576
  listInstalled: async () => {
563
577
  const plugins = await loader.loadAll();
@@ -596,7 +610,7 @@ function usePluginCallbacks(cwd) {
596
610
  }
597
611
  if (scope === "project") {
598
612
  const projectPluginsDir = (0, import_node_path4.join)(cwd, ".robota", "plugins");
599
- const projectInstaller = new import_agent_sdk2.BundlePluginInstaller({
613
+ const projectInstaller = new import_agent_sdk3.BundlePluginInstaller({
600
614
  pluginsDir: projectPluginsDir,
601
615
  settingsStore,
602
616
  marketplaceClient: marketplace
@@ -644,10 +658,128 @@ function usePluginCallbacks(cwd) {
644
658
  }, [cwd]);
645
659
  }
646
660
 
647
- // src/ui/MessageList.tsx
648
- var import_react3 = __toESM(require("react"), 1);
649
- var import_ink2 = require("ink");
661
+ // src/ui/hooks/useSideEffects.ts
662
+ var import_react4 = require("react");
663
+ var import_ink = require("ink");
650
664
  var import_agent_core2 = require("@robota-sdk/agent-core");
665
+ var EXIT_DELAY_MS = 500;
666
+ function useSideEffects({
667
+ interactiveSession,
668
+ addEntry,
669
+ baseHandleSubmit,
670
+ setSessionName
671
+ }) {
672
+ const { exit } = (0, import_ink.useApp)();
673
+ const [pendingModelId, setPendingModelId] = (0, import_react4.useState)(null);
674
+ const pendingModelChangeRef = (0, import_react4.useRef)(null);
675
+ const [showPluginTUI, setShowPluginTUI] = (0, import_react4.useState)(false);
676
+ const [showSessionPicker, setShowSessionPicker] = (0, import_react4.useState)(false);
677
+ const handleSubmit = (0, import_react4.useCallback)(
678
+ async (input) => {
679
+ await baseHandleSubmit(input);
680
+ const sideEffects = interactiveSession;
681
+ if (sideEffects._pendingModelId) {
682
+ const modelId = sideEffects._pendingModelId;
683
+ delete sideEffects._pendingModelId;
684
+ pendingModelChangeRef.current = modelId;
685
+ setPendingModelId(modelId);
686
+ return;
687
+ }
688
+ if (sideEffects._pendingLanguage) {
689
+ const lang = sideEffects._pendingLanguage;
690
+ delete sideEffects._pendingLanguage;
691
+ const settingsPath = getUserSettingsPath();
692
+ const settings = readSettings(settingsPath);
693
+ settings.language = lang;
694
+ writeSettings(settingsPath, settings);
695
+ addEntry(
696
+ (0, import_agent_core2.messageToHistoryEntry)((0, import_agent_core2.createSystemMessage)(`Language set to "${lang}". Restarting...`))
697
+ );
698
+ setTimeout(() => exit(), EXIT_DELAY_MS);
699
+ return;
700
+ }
701
+ if (sideEffects._resetRequested) {
702
+ delete sideEffects._resetRequested;
703
+ const settingsPath = getUserSettingsPath();
704
+ if (deleteSettings(settingsPath)) {
705
+ addEntry(
706
+ (0, import_agent_core2.messageToHistoryEntry)((0, import_agent_core2.createSystemMessage)(`Deleted ${settingsPath}. Exiting...`))
707
+ );
708
+ } else {
709
+ addEntry((0, import_agent_core2.messageToHistoryEntry)((0, import_agent_core2.createSystemMessage)("No user settings found.")));
710
+ }
711
+ setTimeout(() => exit(), EXIT_DELAY_MS);
712
+ return;
713
+ }
714
+ if (sideEffects._exitRequested) {
715
+ delete sideEffects._exitRequested;
716
+ setTimeout(() => exit(), EXIT_DELAY_MS);
717
+ return;
718
+ }
719
+ if (sideEffects._triggerPluginTUI) {
720
+ delete sideEffects._triggerPluginTUI;
721
+ setShowPluginTUI(true);
722
+ return;
723
+ }
724
+ if (sideEffects._triggerResumePicker) {
725
+ delete sideEffects._triggerResumePicker;
726
+ setShowSessionPicker(true);
727
+ return;
728
+ }
729
+ if (sideEffects._sessionName) {
730
+ const name = sideEffects._sessionName;
731
+ delete sideEffects._sessionName;
732
+ interactiveSession.setName(name);
733
+ setSessionName(name);
734
+ return;
735
+ }
736
+ },
737
+ [interactiveSession, baseHandleSubmit, addEntry, exit, setSessionName]
738
+ );
739
+ const handleModelConfirm = (0, import_react4.useCallback)(
740
+ (index) => {
741
+ const modelId = pendingModelChangeRef.current;
742
+ setPendingModelId(null);
743
+ pendingModelChangeRef.current = null;
744
+ if (index === 0 && modelId) {
745
+ try {
746
+ const settingsPath = getUserSettingsPath();
747
+ updateModelInSettings(settingsPath, modelId);
748
+ addEntry(
749
+ (0, import_agent_core2.messageToHistoryEntry)(
750
+ (0, import_agent_core2.createSystemMessage)(`Model changed to ${(0, import_agent_core2.getModelName)(modelId)}. Restarting...`)
751
+ )
752
+ );
753
+ setTimeout(() => exit(), EXIT_DELAY_MS);
754
+ } catch (err) {
755
+ addEntry(
756
+ (0, import_agent_core2.messageToHistoryEntry)(
757
+ (0, import_agent_core2.createSystemMessage)(`Failed: ${err instanceof Error ? err.message : String(err)}`)
758
+ )
759
+ );
760
+ }
761
+ } else {
762
+ addEntry((0, import_agent_core2.messageToHistoryEntry)((0, import_agent_core2.createSystemMessage)("Model change cancelled.")));
763
+ }
764
+ },
765
+ [addEntry, exit]
766
+ );
767
+ return {
768
+ handleSubmit,
769
+ pendingModelId,
770
+ showPluginTUI,
771
+ showSessionPicker,
772
+ setPendingModelId,
773
+ setShowPluginTUI,
774
+ setShowSessionPicker,
775
+ handleModelConfirm
776
+ };
777
+ }
778
+
779
+ // src/ui/MessageList.tsx
780
+ var import_react5 = __toESM(require("react"), 1);
781
+ var import_ink3 = require("ink");
782
+ var import_agent_core3 = require("@robota-sdk/agent-core");
651
783
 
652
784
  // src/ui/render-markdown.ts
653
785
  var import_marked = require("marked");
@@ -661,7 +793,7 @@ function renderMarkdown(md) {
661
793
  }
662
794
 
663
795
  // src/ui/DiffBlock.tsx
664
- var import_ink = require("ink");
796
+ var import_ink2 = require("ink");
665
797
  var import_jsx_runtime = require("react/jsx-runtime");
666
798
  var MAX_DIFF_LINES = 12;
667
799
  var TRUNCATED_SHOW = 10;
@@ -671,15 +803,15 @@ function DiffBlock({ file, lines }) {
671
803
  const remaining = lines.length - TRUNCATED_SHOW;
672
804
  const maxLineNum = Math.max(...visible.map((l) => l.lineNumber), 0);
673
805
  const numWidth = String(maxLineNum).length;
674
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginLeft: 4, children: [
675
- file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
806
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Box, { flexDirection: "column", marginLeft: 4, children: [
807
+ file && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
676
808
  "\u2502 ",
677
809
  file
678
810
  ] }),
679
811
  visible.map((line, i) => {
680
812
  const lineNum = String(line.lineNumber).padStart(numWidth, " ");
681
813
  if (line.type === "context") {
682
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
814
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
683
815
  "\u2502 ",
684
816
  lineNum,
685
817
  " ",
@@ -689,7 +821,7 @@ function DiffBlock({ file, lines }) {
689
821
  const prefix = line.type === "remove" ? "-" : "+";
690
822
  const bgColor = line.type === "remove" ? "#5c1a1a" : "#1a3d1a";
691
823
  const fgColor = line.type === "remove" ? "#ff9999" : "#99ff99";
692
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: fgColor, backgroundColor: bgColor, children: [
824
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: fgColor, backgroundColor: bgColor, children: [
693
825
  "\u2502 ",
694
826
  lineNum,
695
827
  " ",
@@ -698,7 +830,7 @@ function DiffBlock({ file, lines }) {
698
830
  line.text
699
831
  ] }, i);
700
832
  }),
701
- truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
833
+ truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
702
834
  "\u2502 ... and ",
703
835
  remaining,
704
836
  " more lines"
@@ -711,29 +843,29 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
711
843
  function RoleLabel({ role }) {
712
844
  switch (role) {
713
845
  case "user":
714
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "green", bold: true, children: [
846
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "green", bold: true, children: [
715
847
  "You:",
716
848
  " "
717
849
  ] });
718
850
  case "assistant":
719
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "cyan", bold: true, children: [
851
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "cyan", bold: true, children: [
720
852
  "Robota:",
721
853
  " "
722
854
  ] });
723
855
  case "system":
724
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "yellow", bold: true, children: [
856
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "yellow", bold: true, children: [
725
857
  "System:",
726
858
  " "
727
859
  ] });
728
860
  case "tool":
729
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
861
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", bold: true, children: [
730
862
  "Tool:",
731
863
  " "
732
864
  ] });
733
865
  }
734
866
  }
735
867
  function ToolMessage({ message }) {
736
- if (!(0, import_agent_core2.isToolMessage)(message)) {
868
+ if (!(0, import_agent_core3.isToolMessage)(message)) {
737
869
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
738
870
  }
739
871
  const toolName = message.name;
@@ -747,21 +879,21 @@ function ToolMessage({ message }) {
747
879
  } catch {
748
880
  }
749
881
  if (summaries) {
750
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
751
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
752
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
882
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: [
883
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", bold: true, children: [
753
885
  "Tool:",
754
886
  " "
755
887
  ] }),
756
- toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
888
+ toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", dimColor: true, children: [
757
889
  "[",
758
890
  toolName,
759
891
  "]"
760
892
  ] })
761
893
  ] }),
762
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
763
- summaries.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", children: [
764
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "green", children: [
894
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: " " }),
895
+ summaries.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", children: [
896
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "green", children: [
765
897
  " ",
766
898
  "\u2713",
767
899
  " ",
@@ -772,20 +904,20 @@ function ToolMessage({ message }) {
772
904
  ] });
773
905
  }
774
906
  const lines = content.split("\n").filter((l) => l.trim());
775
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
776
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
777
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
907
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", bold: true, children: [
778
910
  "Tool:",
779
911
  " "
780
912
  ] }),
781
- toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
913
+ toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", dimColor: true, children: [
782
914
  "[",
783
915
  toolName,
784
916
  "]"
785
917
  ] })
786
918
  ] }),
787
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
788
- lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "green", children: [
919
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: " " }),
920
+ lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "green", children: [
789
921
  " ",
790
922
  "\u2713",
791
923
  " ",
@@ -793,30 +925,30 @@ function ToolMessage({ message }) {
793
925
  ] }, i))
794
926
  ] });
795
927
  }
796
- var MessageItem = import_react3.default.memo(function MessageItem2({
928
+ var MessageItem = import_react5.default.memo(function MessageItem2({
797
929
  message
798
930
  }) {
799
- if ((0, import_agent_core2.isToolMessage)(message)) {
931
+ if ((0, import_agent_core3.isToolMessage)(message)) {
800
932
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToolMessage, { message });
801
933
  }
802
934
  const content = message.content ?? "";
803
935
  const isInterrupted = message.state === "interrupted";
804
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
805
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }) }),
806
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
807
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: (0, import_agent_core2.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
936
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: [
937
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }) }),
938
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: " " }),
939
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { wrap: "wrap", children: (0, import_agent_core3.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
808
940
  ] });
809
941
  });
810
942
  function ToolSummaryEntry({ entry }) {
811
943
  const data = entry.data;
812
944
  const lines = data?.summary?.split("\n") ?? [];
813
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
945
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: [
946
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "white", bold: true, children: [
815
947
  "Tool:",
816
948
  " "
817
949
  ] }) }),
818
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
819
- lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "green", children: [
950
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: " " }),
951
+ lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "green", children: [
820
952
  " ",
821
953
  line
822
954
  ] }, i))
@@ -825,13 +957,13 @@ function ToolSummaryEntry({ entry }) {
825
957
  function EventEntry({ entry }) {
826
958
  const eventData = entry.data;
827
959
  const eventMessage = typeof eventData?.message === "string" ? eventData.message : typeof eventData?.content === "string" ? eventData.content : entry.type;
828
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
829
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "yellow", bold: true, children: [
960
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: [
961
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { color: "yellow", bold: true, children: [
830
962
  "System:",
831
963
  " "
832
964
  ] }) }),
833
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
834
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: eventMessage }) })
965
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: " " }),
966
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { wrap: "wrap", children: eventMessage }) })
835
967
  ] });
836
968
  }
837
969
  function EntryItem({ entry }) {
@@ -848,12 +980,12 @@ function EntryItem({ entry }) {
848
980
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EventEntry, { entry });
849
981
  }
850
982
  function MessageList({ history }) {
851
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { flexDirection: "column", children: history.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EntryItem, { entry }, entry.id)) });
983
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { flexDirection: "column", children: history.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EntryItem, { entry }, entry.id)) });
852
984
  }
853
985
 
854
986
  // src/ui/StatusBar.tsx
855
- var import_ink3 = require("ink");
856
- var import_agent_core3 = require("@robota-sdk/agent-core");
987
+ var import_ink4 = require("ink");
988
+ var import_agent_core4 = require("@robota-sdk/agent-core");
857
989
  var import_jsx_runtime3 = require("react/jsx-runtime");
858
990
  var CONTEXT_YELLOW_THRESHOLD = 70;
859
991
  var CONTEXT_RED_THRESHOLD = 90;
@@ -875,7 +1007,7 @@ function StatusBar({
875
1007
  }) {
876
1008
  const contextColor = getContextColor(contextPercentage);
877
1009
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
878
- import_ink3.Box,
1010
+ import_ink4.Box,
879
1011
  {
880
1012
  borderStyle: "single",
881
1013
  borderColor: "gray",
@@ -883,30 +1015,30 @@ function StatusBar({
883
1015
  paddingRight: 1,
884
1016
  justifyContent: "space-between",
885
1017
  children: [
886
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink3.Text, { children: [
887
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { color: "cyan", bold: true, children: "Mode:" }),
1018
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink4.Text, { children: [
1019
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { color: "cyan", bold: true, children: "Mode:" }),
888
1020
  " ",
889
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { children: permissionMode }),
1021
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { children: permissionMode }),
890
1022
  sessionName && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
891
1023
  " | ",
892
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { color: "magenta", children: sessionName })
1024
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { color: "magenta", children: sessionName })
893
1025
  ] }),
894
1026
  " | ",
895
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { dimColor: true, children: modelName }),
1027
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { dimColor: true, children: modelName }),
896
1028
  " | ",
897
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink3.Text, { color: contextColor, children: [
1029
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink4.Text, { color: contextColor, children: [
898
1030
  "Context: ",
899
1031
  Math.round(contextPercentage),
900
1032
  "% (",
901
- (0, import_agent_core3.formatTokenCount)(contextUsedTokens),
1033
+ (0, import_agent_core4.formatTokenCount)(contextUsedTokens),
902
1034
  "/",
903
- (0, import_agent_core3.formatTokenCount)(contextMaxTokens),
1035
+ (0, import_agent_core4.formatTokenCount)(contextMaxTokens),
904
1036
  ")"
905
1037
  ] })
906
1038
  ] }),
907
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink3.Text, { children: [
908
- isThinking && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { color: "yellow", children: "Thinking... " }),
909
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink3.Text, { dimColor: true, children: [
1039
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink4.Text, { children: [
1040
+ isThinking && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { color: "yellow", children: "Thinking... " }),
1041
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_ink4.Text, { dimColor: true, children: [
910
1042
  "msgs: ",
911
1043
  messageCount
912
1044
  ] })
@@ -917,12 +1049,12 @@ function StatusBar({
917
1049
  }
918
1050
 
919
1051
  // src/ui/InputArea.tsx
920
- var import_react6 = __toESM(require("react"), 1);
921
- var import_ink7 = require("ink");
1052
+ var import_react9 = require("react");
1053
+ var import_ink8 = require("ink");
922
1054
 
923
1055
  // src/ui/CjkTextInput.tsx
924
- var import_react4 = require("react");
925
- var import_ink4 = require("ink");
1056
+ var import_react6 = require("react");
1057
+ var import_ink5 = require("ink");
926
1058
  var import_chalk = __toESM(require("chalk"), 1);
927
1059
  var import_string_width = __toESM(require("string-width"), 1);
928
1060
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -965,18 +1097,19 @@ function CjkTextInput({
965
1097
  placeholder = "",
966
1098
  focus = true,
967
1099
  showCursor = true,
968
- availableWidth
1100
+ availableWidth,
1101
+ cursorHint = null
969
1102
  }) {
970
- const valueRef = (0, import_react4.useRef)(value);
971
- const cursorRef = (0, import_react4.useRef)(value.length);
972
- const [, forceRender] = (0, import_react4.useState)(0);
973
- const isPastingRef = (0, import_react4.useRef)(false);
974
- const pasteBufferRef = (0, import_react4.useRef)("");
1103
+ const valueRef = (0, import_react6.useRef)(value);
1104
+ const cursorRef = (0, import_react6.useRef)(value.length);
1105
+ const [, forceRender] = (0, import_react6.useState)(0);
1106
+ const isPastingRef = (0, import_react6.useRef)(false);
1107
+ const pasteBufferRef = (0, import_react6.useRef)("");
975
1108
  if (value !== valueRef.current) {
976
1109
  valueRef.current = value;
977
- cursorRef.current = value.length;
1110
+ cursorRef.current = cursorHint != null ? Math.min(cursorHint, value.length) : value.length;
978
1111
  }
979
- (0, import_ink4.useInput)(
1112
+ (0, import_ink5.useInput)(
980
1113
  (input, key) => {
981
1114
  try {
982
1115
  if (input === PASTE_START || input.startsWith(PASTE_START)) {
@@ -996,7 +1129,7 @@ function CjkTextInput({
996
1129
  isPastingRef.current = false;
997
1130
  if (text.length > 0) {
998
1131
  if (text.includes("\n") && onPaste) {
999
- onPaste(text);
1132
+ onPaste(text, cursorRef.current);
1000
1133
  } else {
1001
1134
  const printable2 = filterPrintable(text);
1002
1135
  if (printable2.length > 0) {
@@ -1035,7 +1168,7 @@ function CjkTextInput({
1035
1168
  return;
1036
1169
  }
1037
1170
  if (input.length > 1 && (input.includes("\n") || input.includes("\r")) && onPaste) {
1038
- onPaste(input.replace(/\r\n?/g, "\n"));
1171
+ onPaste(input.replace(/\r\n?/g, "\n"), cursorRef.current);
1039
1172
  return;
1040
1173
  }
1041
1174
  if (key.leftArrow) {
@@ -1073,7 +1206,7 @@ function CjkTextInput({
1073
1206
  },
1074
1207
  { isActive: focus }
1075
1208
  );
1076
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink4.Text, { children: renderWithCursor(valueRef.current, cursorRef.current, placeholder, showCursor && focus) });
1209
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: renderWithCursor(valueRef.current, cursorRef.current, placeholder, showCursor && focus) });
1077
1210
  }
1078
1211
  function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
1079
1212
  if (!showCursor) {
@@ -1098,30 +1231,30 @@ function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
1098
1231
  }
1099
1232
 
1100
1233
  // src/ui/WaveText.tsx
1101
- var import_react5 = require("react");
1102
- var import_ink5 = require("ink");
1234
+ var import_react7 = require("react");
1235
+ var import_ink6 = require("ink");
1103
1236
  var import_jsx_runtime5 = require("react/jsx-runtime");
1104
1237
  var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
1105
1238
  var INTERVAL_MS = 400;
1106
1239
  var CHARS_PER_GROUP = 4;
1107
1240
  function WaveText({ text }) {
1108
- const [tick, setTick] = (0, import_react5.useState)(0);
1109
- (0, import_react5.useEffect)(() => {
1241
+ const [tick, setTick] = (0, import_react7.useState)(0);
1242
+ (0, import_react7.useEffect)(() => {
1110
1243
  const timer = setInterval(() => {
1111
1244
  setTick((prev) => prev + 1);
1112
1245
  }, INTERVAL_MS);
1113
1246
  return () => clearInterval(timer);
1114
1247
  }, []);
1115
1248
  const chars = [...text];
1116
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { children: chars.map((char, i) => {
1249
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { children: chars.map((char, i) => {
1117
1250
  const group = Math.floor(i / CHARS_PER_GROUP);
1118
1251
  const colorIndex = (tick + group) % WAVE_COLORS.length;
1119
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { color: WAVE_COLORS[colorIndex], children: char }, i);
1252
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { color: WAVE_COLORS[colorIndex], children: char }, i);
1120
1253
  }) });
1121
1254
  }
1122
1255
 
1123
1256
  // src/ui/SlashAutocomplete.tsx
1124
- var import_ink6 = require("ink");
1257
+ var import_ink7 = require("ink");
1125
1258
  var import_jsx_runtime6 = require("react/jsx-runtime");
1126
1259
  var MAX_VISIBLE = 8;
1127
1260
  function CommandRow(props) {
@@ -1129,7 +1262,7 @@ function CommandRow(props) {
1129
1262
  const indicator = isSelected ? "\u25B8 " : " ";
1130
1263
  const nameColor = isSelected ? "cyan" : void 0;
1131
1264
  const dimmed = !isSelected;
1132
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink6.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_ink6.Text, { color: nameColor, dimColor: dimmed, children: [
1265
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink7.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_ink7.Text, { color: nameColor, dimColor: dimmed, children: [
1133
1266
  indicator,
1134
1267
  showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
1135
1268
  ] }) });
@@ -1143,7 +1276,7 @@ function SlashAutocomplete({
1143
1276
  if (!visible || commands.length === 0) return null;
1144
1277
  const scrollOffset = computeScrollOffset(selectedIndex, commands.length);
1145
1278
  const visibleCommands = commands.slice(scrollOffset, scrollOffset + MAX_VISIBLE);
1146
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink6.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: visibleCommands.map((cmd, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1279
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: visibleCommands.map((cmd, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1147
1280
  CommandRow,
1148
1281
  {
1149
1282
  cmd,
@@ -1166,8 +1299,8 @@ function expandPasteLabels(text, store) {
1166
1299
  return text.replace(PASTE_LABEL_RE, (_, id) => store.get(Number(id)) ?? "");
1167
1300
  }
1168
1301
 
1169
- // src/ui/InputArea.tsx
1170
- var import_jsx_runtime7 = require("react/jsx-runtime");
1302
+ // src/ui/hooks/useAutocomplete.ts
1303
+ var import_react8 = __toESM(require("react"), 1);
1171
1304
  function parseSlashInput(value) {
1172
1305
  if (!value.startsWith("/")) return { isSlash: false, parentCommand: "", filter: "" };
1173
1306
  const afterSlash = value.slice(1);
@@ -1178,16 +1311,16 @@ function parseSlashInput(value) {
1178
1311
  return { isSlash: true, parentCommand: parent, filter: rest };
1179
1312
  }
1180
1313
  function useAutocomplete(value, registry) {
1181
- const [selectedIndex, setSelectedIndex] = (0, import_react6.useState)(0);
1182
- const [dismissed, setDismissed] = (0, import_react6.useState)(false);
1183
- const prevValueRef = import_react6.default.useRef(value);
1314
+ const [selectedIndex, setSelectedIndex] = (0, import_react8.useState)(0);
1315
+ const [dismissed, setDismissed] = (0, import_react8.useState)(false);
1316
+ const prevValueRef = import_react8.default.useRef(value);
1184
1317
  if (prevValueRef.current !== value) {
1185
1318
  prevValueRef.current = value;
1186
1319
  if (dismissed) setDismissed(false);
1187
1320
  }
1188
1321
  const parsed = parseSlashInput(value);
1189
1322
  const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
1190
- const filteredCommands = (0, import_react6.useMemo)(() => {
1323
+ const filteredCommands = (0, import_react8.useMemo)(() => {
1191
1324
  if (!registry || !parsed.isSlash || dismissed) return [];
1192
1325
  if (isSubcommandMode) {
1193
1326
  const subs = registry.getSubcommands(parsed.parentCommand);
@@ -1220,6 +1353,9 @@ function useAutocomplete(value, registry) {
1220
1353
  }
1221
1354
  };
1222
1355
  }
1356
+
1357
+ // src/ui/InputArea.tsx
1358
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1223
1359
  var BORDER_HORIZONTAL = 2;
1224
1360
  var PADDING_LEFT = 1;
1225
1361
  var PROMPT_WIDTH = 2;
@@ -1233,12 +1369,13 @@ function InputArea({
1233
1369
  registry,
1234
1370
  sessionName
1235
1371
  }) {
1236
- const [value, setValue] = (0, import_react6.useState)("");
1237
- const pasteStore = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
1238
- const { stdout } = (0, import_ink7.useStdout)();
1372
+ const [value, setValue] = (0, import_react9.useState)("");
1373
+ const [cursorHint, setCursorHint] = (0, import_react9.useState)(null);
1374
+ const pasteStore = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
1375
+ const { stdout } = (0, import_ink8.useStdout)();
1239
1376
  const terminalColumns = stdout?.columns ?? 80;
1240
1377
  const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
1241
- const pasteIdRef = (0, import_react6.useRef)(0);
1378
+ const pasteIdRef = (0, import_react9.useRef)(0);
1242
1379
  const {
1243
1380
  showPopup,
1244
1381
  filteredCommands,
@@ -1247,15 +1384,17 @@ function InputArea({
1247
1384
  isSubcommandMode,
1248
1385
  setShowPopup
1249
1386
  } = useAutocomplete(value, registry);
1250
- const handlePaste = (0, import_react6.useCallback)((text) => {
1387
+ const handlePaste = (0, import_react9.useCallback)((text, cursorPosition) => {
1251
1388
  pasteIdRef.current += 1;
1252
1389
  const id = pasteIdRef.current;
1253
1390
  pasteStore.current.set(id, text);
1254
1391
  const lineCount = text.split("\n").length;
1255
1392
  const label = `[Pasted text #${id} +${lineCount} lines]`;
1256
- setValue((prev) => prev ? `${prev} ${label}` : label);
1393
+ const newCursorPos = cursorPosition + label.length;
1394
+ setCursorHint(newCursorPos);
1395
+ setValue((prev) => prev.slice(0, cursorPosition) + label + prev.slice(cursorPosition));
1257
1396
  }, []);
1258
- const tabCompleteCommand = (0, import_react6.useCallback)(
1397
+ const tabCompleteCommand = (0, import_react9.useCallback)(
1259
1398
  (cmd) => {
1260
1399
  const parsed = parseSlashInput(value);
1261
1400
  if (parsed.parentCommand) {
@@ -1271,7 +1410,7 @@ function InputArea({
1271
1410
  },
1272
1411
  [value, setSelectedIndex]
1273
1412
  );
1274
- const enterSelectCommand = (0, import_react6.useCallback)(
1413
+ const enterSelectCommand = (0, import_react9.useCallback)(
1275
1414
  (cmd) => {
1276
1415
  const parsed = parseSlashInput(value);
1277
1416
  if (parsed.parentCommand) {
@@ -1290,7 +1429,7 @@ function InputArea({
1290
1429
  },
1291
1430
  [value, onSubmit, setSelectedIndex]
1292
1431
  );
1293
- const handleSubmit = (0, import_react6.useCallback)(
1432
+ const handleSubmit = (0, import_react9.useCallback)(
1294
1433
  (text) => {
1295
1434
  const trimmed = text.trim();
1296
1435
  if (trimmed.length === 0) return;
@@ -1306,7 +1445,7 @@ function InputArea({
1306
1445
  },
1307
1446
  [showPopup, filteredCommands, selectedIndex, onSubmit, enterSelectCommand]
1308
1447
  );
1309
- (0, import_ink7.useInput)(
1448
+ (0, import_ink8.useInput)(
1310
1449
  (_input, key) => {
1311
1450
  if (!showPopup) return;
1312
1451
  if (key.upArrow) {
@@ -1322,7 +1461,7 @@ function InputArea({
1322
1461
  },
1323
1462
  { isActive: showPopup && !isDisabled }
1324
1463
  );
1325
- (0, import_ink7.useInput)(
1464
+ (0, import_ink8.useInput)(
1326
1465
  (_input, key) => {
1327
1466
  if ((key.backspace || key.delete) && pendingPrompt) {
1328
1467
  onCancelQueue?.();
@@ -1341,7 +1480,7 @@ function InputArea({
1341
1480
  }
1342
1481
  return { left: "\u250C" + "\u2500".repeat(innerWidth), label: "", right: "\u2510" };
1343
1482
  })();
1344
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", children: [
1483
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
1345
1484
  showPopup && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1346
1485
  SlashAutocomplete,
1347
1486
  {
@@ -1351,28 +1490,32 @@ function InputArea({
1351
1490
  isSubcommandMode
1352
1491
  }
1353
1492
  ),
1354
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: borderColor, children: [
1493
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink8.Text, { color: borderColor, children: [
1355
1494
  topBorder.left,
1356
- topBorder.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { backgroundColor: borderColor, color: "black", bold: true, children: topBorder.label }) : null,
1495
+ topBorder.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink8.Text, { backgroundColor: borderColor, color: "black", bold: true, children: topBorder.label }) : null,
1357
1496
  topBorder.right
1358
1497
  ] }),
1359
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { borderStyle: "single", borderTop: false, borderColor, paddingLeft: 1, children: isAborting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: "cyan", children: [
1498
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink8.Box, { borderStyle: "single", borderTop: false, borderColor, paddingLeft: 1, children: isAborting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink8.Text, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink8.Text, { color: "cyan", children: [
1360
1499
  " ",
1361
1500
  "Queued: ",
1362
1501
  pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
1363
1502
  " ",
1364
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: "(Backspace to cancel)" })
1365
- ] }) : isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
1366
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "green", bold: true, children: "> " }),
1503
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink8.Text, { dimColor: true, children: "(Backspace to cancel)" })
1504
+ ] }) : isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink8.Box, { children: [
1505
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink8.Text, { color: "green", bold: true, children: "> " }),
1367
1506
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1368
1507
  CjkTextInput,
1369
1508
  {
1370
1509
  value,
1371
- onChange: setValue,
1510
+ onChange: (v) => {
1511
+ setValue(v);
1512
+ setCursorHint(null);
1513
+ },
1372
1514
  onSubmit: handleSubmit,
1373
1515
  onPaste: handlePaste,
1374
1516
  placeholder: "Type a message or /help",
1375
- availableWidth
1517
+ availableWidth,
1518
+ cursorHint
1376
1519
  }
1377
1520
  )
1378
1521
  ] }) })
@@ -1380,17 +1523,17 @@ function InputArea({
1380
1523
  }
1381
1524
 
1382
1525
  // src/ui/ConfirmPrompt.tsx
1383
- var import_react7 = require("react");
1384
- var import_ink8 = require("ink");
1526
+ var import_react10 = require("react");
1527
+ var import_ink9 = require("ink");
1385
1528
  var import_jsx_runtime8 = require("react/jsx-runtime");
1386
1529
  function ConfirmPrompt({
1387
1530
  message,
1388
1531
  options = ["Yes", "No"],
1389
1532
  onSelect
1390
1533
  }) {
1391
- const [selected, setSelected] = (0, import_react7.useState)(0);
1392
- const resolvedRef = (0, import_react7.useRef)(false);
1393
- const doSelect = (0, import_react7.useCallback)(
1534
+ const [selected, setSelected] = (0, import_react10.useState)(0);
1535
+ const resolvedRef = (0, import_react10.useRef)(false);
1536
+ const doSelect = (0, import_react10.useCallback)(
1394
1537
  (index) => {
1395
1538
  if (resolvedRef.current) return;
1396
1539
  resolvedRef.current = true;
@@ -1398,7 +1541,7 @@ function ConfirmPrompt({
1398
1541
  },
1399
1542
  [onSelect]
1400
1543
  );
1401
- (0, import_ink8.useInput)((input, key) => {
1544
+ (0, import_ink9.useInput)((input, key) => {
1402
1545
  if (resolvedRef.current) return;
1403
1546
  if (key.leftArrow || key.upArrow) {
1404
1547
  setSelected((prev) => prev > 0 ? prev - 1 : prev);
@@ -1412,19 +1555,19 @@ function ConfirmPrompt({
1412
1555
  doSelect(1);
1413
1556
  }
1414
1557
  });
1415
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1416
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", children: message }),
1417
- /* @__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: [
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink9.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1559
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink9.Text, { color: "yellow", children: message }),
1560
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink9.Box, { marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink9.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink9.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
1418
1561
  i === selected ? "> " : " ",
1419
1562
  opt
1420
1563
  ] }) }, opt)) }),
1421
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
1564
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink9.Text, { dimColor: true, children: " arrow keys to select, Enter to confirm" })
1422
1565
  ] });
1423
1566
  }
1424
1567
 
1425
1568
  // src/ui/PermissionPrompt.tsx
1426
- var import_react8 = __toESM(require("react"), 1);
1427
- var import_ink9 = require("ink");
1569
+ var import_react11 = __toESM(require("react"), 1);
1570
+ var import_ink10 = require("ink");
1428
1571
  var import_jsx_runtime9 = require("react/jsx-runtime");
1429
1572
  var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
1430
1573
  function formatArgs(args) {
@@ -1433,15 +1576,15 @@ function formatArgs(args) {
1433
1576
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
1434
1577
  }
1435
1578
  function PermissionPrompt({ request }) {
1436
- const [selected, setSelected] = import_react8.default.useState(0);
1437
- const resolvedRef = import_react8.default.useRef(false);
1438
- const prevRequestRef = import_react8.default.useRef(request);
1579
+ const [selected, setSelected] = import_react11.default.useState(0);
1580
+ const resolvedRef = import_react11.default.useRef(false);
1581
+ const prevRequestRef = import_react11.default.useRef(request);
1439
1582
  if (prevRequestRef.current !== request) {
1440
1583
  prevRequestRef.current = request;
1441
1584
  resolvedRef.current = false;
1442
1585
  setSelected(0);
1443
1586
  }
1444
- const doResolve = import_react8.default.useCallback(
1587
+ const doResolve = import_react11.default.useCallback(
1445
1588
  (index) => {
1446
1589
  if (resolvedRef.current) return;
1447
1590
  resolvedRef.current = true;
@@ -1451,7 +1594,7 @@ function PermissionPrompt({ request }) {
1451
1594
  },
1452
1595
  [request]
1453
1596
  );
1454
- (0, import_ink9.useInput)((input, key) => {
1597
+ (0, import_ink10.useInput)((input, key) => {
1455
1598
  if (resolvedRef.current) return;
1456
1599
  if (key.upArrow || key.leftArrow) {
1457
1600
  setSelected((prev) => prev > 0 ? prev - 1 : prev);
@@ -1467,27 +1610,27 @@ function PermissionPrompt({ request }) {
1467
1610
  doResolve(2);
1468
1611
  }
1469
1612
  });
1470
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1471
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
1472
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { children: [
1613
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink10.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1614
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink10.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
1615
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink10.Text, { children: [
1473
1616
  "Tool:",
1474
1617
  " ",
1475
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: request.toolName })
1618
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink10.Text, { color: "cyan", bold: true, children: request.toolName })
1476
1619
  ] }),
1477
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { dimColor: true, children: [
1620
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink10.Text, { dimColor: true, children: [
1478
1621
  " ",
1479
1622
  formatArgs(request.toolArgs)
1480
1623
  ] }),
1481
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink10.Box, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink10.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink10.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
1482
1625
  i === selected ? "> " : " ",
1483
1626
  opt
1484
1627
  ] }) }, opt)) }),
1485
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
1628
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink10.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
1486
1629
  ] });
1487
1630
  }
1488
1631
 
1489
1632
  // src/ui/StreamingIndicator.tsx
1490
- var import_ink10 = require("ink");
1633
+ var import_ink11 = require("ink");
1491
1634
  var import_jsx_runtime10 = require("react/jsx-runtime");
1492
1635
  function getToolStyle(t) {
1493
1636
  if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
@@ -1501,14 +1644,14 @@ function StreamingIndicator({ text, activeTools }) {
1501
1644
  if (!hasTools && !hasText) {
1502
1645
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
1503
1646
  }
1504
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
1505
- hasTools && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: [
1506
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "white", bold: true, children: "Tools:" }),
1507
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { children: " " }),
1647
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink11.Box, { flexDirection: "column", children: [
1648
+ hasTools && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink11.Box, { flexDirection: "column", marginBottom: 1, children: [
1649
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink11.Text, { color: "white", bold: true, children: "Tools:" }),
1650
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink11.Text, { children: " " }),
1508
1651
  activeTools.map((t, i) => {
1509
1652
  const { color, icon, strikethrough } = getToolStyle(t);
1510
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
1511
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { color, strikethrough, children: [
1653
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink11.Box, { flexDirection: "column", children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink11.Text, { color, strikethrough, children: [
1512
1655
  " ",
1513
1656
  icon,
1514
1657
  " ",
@@ -1521,20 +1664,20 @@ function StreamingIndicator({ text, activeTools }) {
1521
1664
  ] }, `${t.toolName}-${i}`);
1522
1665
  })
1523
1666
  ] }),
1524
- hasText && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: [
1525
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "cyan", bold: true, children: "Robota:" }),
1526
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { children: " " }),
1527
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
1667
+ hasText && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink11.Box, { flexDirection: "column", marginBottom: 1, children: [
1668
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink11.Text, { color: "cyan", bold: true, children: "Robota:" }),
1669
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink11.Text, { children: " " }),
1670
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink11.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink11.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
1528
1671
  ] })
1529
1672
  ] });
1530
1673
  }
1531
1674
 
1532
1675
  // src/ui/PluginTUI.tsx
1533
- var import_react11 = require("react");
1676
+ var import_react15 = require("react");
1534
1677
 
1535
1678
  // src/ui/MenuSelect.tsx
1536
- var import_react9 = require("react");
1537
- var import_ink11 = require("ink");
1679
+ var import_react12 = require("react");
1680
+ var import_ink12 = require("ink");
1538
1681
  var import_jsx_runtime11 = require("react/jsx-runtime");
1539
1682
  function MenuSelect({
1540
1683
  title,
@@ -1544,10 +1687,10 @@ function MenuSelect({
1544
1687
  loading,
1545
1688
  error
1546
1689
  }) {
1547
- const [selected, setSelected] = (0, import_react9.useState)(0);
1548
- const selectedRef = (0, import_react9.useRef)(0);
1549
- const resolvedRef = (0, import_react9.useRef)(false);
1550
- const doSelect = (0, import_react9.useCallback)(
1690
+ const [selected, setSelected] = (0, import_react12.useState)(0);
1691
+ const selectedRef = (0, import_react12.useRef)(0);
1692
+ const resolvedRef = (0, import_react12.useRef)(false);
1693
+ const doSelect = (0, import_react12.useCallback)(
1551
1694
  (index) => {
1552
1695
  if (resolvedRef.current || items.length === 0) return;
1553
1696
  resolvedRef.current = true;
@@ -1555,7 +1698,7 @@ function MenuSelect({
1555
1698
  },
1556
1699
  [items, onSelect]
1557
1700
  );
1558
- (0, import_ink11.useInput)((input, key) => {
1701
+ (0, import_ink12.useInput)((input, key) => {
1559
1702
  if (resolvedRef.current) return;
1560
1703
  if (key.escape) {
1561
1704
  resolvedRef.current = true;
@@ -1575,30 +1718,30 @@ function MenuSelect({
1575
1718
  doSelect(selectedRef.current);
1576
1719
  }
1577
1720
  });
1578
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1579
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "yellow", bold: true, children: title }),
1580
- loading && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: "Loading..." }) }),
1581
- error && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { marginTop: 1, flexDirection: "column", children: [
1582
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "red", children: error }),
1583
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: "Press Esc to go back" })
1721
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink12.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1722
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Text, { color: "yellow", bold: true, children: title }),
1723
+ loading && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Text, { dimColor: true, children: "Loading..." }) }),
1724
+ error && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink12.Box, { marginTop: 1, flexDirection: "column", children: [
1725
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Text, { color: "red", children: error }),
1726
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Text, { dimColor: true, children: "Press Esc to go back" })
1584
1727
  ] }),
1585
- !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { children: [
1586
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
1728
+ !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Box, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink12.Box, { children: [
1729
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink12.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
1587
1730
  i === selected ? "> " : " ",
1588
1731
  item.label
1589
1732
  ] }),
1590
- item.hint && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { dimColor: true, children: [
1733
+ item.hint && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink12.Text, { dimColor: true, children: [
1591
1734
  " ",
1592
1735
  item.hint
1593
1736
  ] })
1594
1737
  ] }, item.value)) }),
1595
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
1738
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink12.Text, { dimColor: true, children: loading || error ? "" : " \u2191\u2193 Navigate Enter Select Esc Back" })
1596
1739
  ] });
1597
1740
  }
1598
1741
 
1599
1742
  // src/ui/TextPrompt.tsx
1600
- var import_react10 = require("react");
1601
- var import_ink12 = require("ink");
1743
+ var import_react13 = require("react");
1744
+ var import_ink13 = require("ink");
1602
1745
  var import_jsx_runtime12 = require("react/jsx-runtime");
1603
1746
  function TextPrompt({
1604
1747
  title,
@@ -1607,11 +1750,11 @@ function TextPrompt({
1607
1750
  onCancel,
1608
1751
  validate
1609
1752
  }) {
1610
- const [value, setValue] = (0, import_react10.useState)("");
1611
- const [error, setError] = (0, import_react10.useState)();
1612
- const resolvedRef = (0, import_react10.useRef)(false);
1613
- const valueRef = (0, import_react10.useRef)("");
1614
- const handleSubmit = (0, import_react10.useCallback)(() => {
1753
+ const [value, setValue] = (0, import_react13.useState)("");
1754
+ const [error, setError] = (0, import_react13.useState)();
1755
+ const resolvedRef = (0, import_react13.useRef)(false);
1756
+ const valueRef = (0, import_react13.useRef)("");
1757
+ const handleSubmit = (0, import_react13.useCallback)(() => {
1615
1758
  if (resolvedRef.current) return;
1616
1759
  const trimmed = valueRef.current.trim();
1617
1760
  if (!trimmed) return;
@@ -1625,7 +1768,7 @@ function TextPrompt({
1625
1768
  resolvedRef.current = true;
1626
1769
  onSubmit(trimmed);
1627
1770
  }, [validate, onSubmit]);
1628
- (0, import_ink12.useInput)((input, key) => {
1771
+ (0, import_ink13.useInput)((input, key) => {
1629
1772
  if (resolvedRef.current) return;
1630
1773
  if (key.escape) {
1631
1774
  resolvedRef.current = true;
@@ -1648,15 +1791,15 @@ function TextPrompt({
1648
1791
  setError(void 0);
1649
1792
  }
1650
1793
  });
1651
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1652
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "yellow", bold: true, children: title }),
1653
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { marginTop: 1, children: [
1654
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "> " }),
1655
- value ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { children: value }) : placeholder ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { dimColor: true, children: placeholder }) : null,
1656
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "\u2588" })
1794
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink13.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1795
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { color: "yellow", bold: true, children: title }),
1796
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink13.Box, { marginTop: 1, children: [
1797
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { color: "cyan", children: "> " }),
1798
+ value ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { children: value }) : placeholder ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { dimColor: true, children: placeholder }) : null,
1799
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { color: "cyan", children: "\u2588" })
1657
1800
  ] }),
1658
- error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "red", children: error }),
1659
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { dimColor: true, children: " Enter Submit Esc Cancel" })
1801
+ error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { color: "red", children: error }),
1802
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { dimColor: true, children: " Enter Submit Esc Cancel" })
1660
1803
  ] });
1661
1804
  }
1662
1805
 
@@ -1752,61 +1895,16 @@ function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
1752
1895
  }
1753
1896
  }
1754
1897
 
1755
- // src/ui/PluginTUI.tsx
1756
- var import_jsx_runtime13 = require("react/jsx-runtime");
1757
- function PluginTUI({ callbacks, onClose, addMessage }) {
1758
- const [stack, setStack] = (0, import_react11.useState)([{ screen: "main" }]);
1759
- const [items, setItems] = (0, import_react11.useState)([]);
1760
- const [loading, setLoading] = (0, import_react11.useState)(false);
1761
- const [error, setError] = (0, import_react11.useState)();
1762
- const [confirm, setConfirm] = (0, import_react11.useState)();
1763
- const [refreshCounter, setRefreshCounter] = (0, import_react11.useState)(0);
1764
- const current = stack[stack.length - 1] ?? { screen: "main" };
1765
- const push = (0, import_react11.useCallback)((state) => {
1766
- setStack((prev) => [...prev, state]);
1898
+ // src/ui/hooks/usePluginScreenData.ts
1899
+ var import_react14 = require("react");
1900
+ function usePluginScreenData(screen, marketplace, callbacks, refreshCounter, stackLength) {
1901
+ const [items, setItems] = (0, import_react14.useState)([]);
1902
+ const [loading, setLoading] = (0, import_react14.useState)(false);
1903
+ const [error, setError] = (0, import_react14.useState)();
1904
+ (0, import_react14.useEffect)(() => {
1767
1905
  setItems([]);
1768
1906
  setError(void 0);
1769
- }, []);
1770
- const pop = (0, import_react11.useCallback)(() => {
1771
- setStack((prev) => {
1772
- if (prev.length <= 1) {
1773
- onClose();
1774
- return prev;
1775
- }
1776
- return prev.slice(0, -1);
1777
- });
1778
- setItems([]);
1779
- setError(void 0);
1780
- }, [onClose]);
1781
- const popN = (0, import_react11.useCallback)(
1782
- (n) => {
1783
- setStack((prev) => {
1784
- const next = prev.slice(0, Math.max(1, prev.length - n));
1785
- if (next.length === 0) {
1786
- onClose();
1787
- return prev;
1788
- }
1789
- return next;
1790
- });
1791
- setItems([]);
1792
- setError(void 0);
1793
- },
1794
- [onClose]
1795
- );
1796
- const notify = (0, import_react11.useCallback)(
1797
- (content) => {
1798
- addMessage?.({ role: "system", content });
1799
- },
1800
- [addMessage]
1801
- );
1802
- const refresh = (0, import_react11.useCallback)(() => {
1803
- setItems([]);
1804
- setRefreshCounter((c) => c + 1);
1805
- }, []);
1806
- const nav = { push, pop, popN, notify, setConfirm, refresh };
1807
- (0, import_react11.useEffect)(() => {
1808
- const screen2 = current.screen;
1809
- if (screen2 === "marketplace-list") {
1907
+ if (screen === "marketplace-list") {
1810
1908
  setLoading(true);
1811
1909
  callbacks.marketplaceList().then((sources) => {
1812
1910
  const baseItems = [{ label: "Add Marketplace", value: "__add__" }];
@@ -1821,10 +1919,10 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1821
1919
  setError(err instanceof Error ? err.message : String(err));
1822
1920
  setLoading(false);
1823
1921
  });
1824
- } else if (screen2 === "marketplace-browse") {
1825
- const marketplace = current.context?.marketplace ?? "";
1922
+ } else if (screen === "marketplace-browse") {
1923
+ const mp = marketplace ?? "";
1826
1924
  setLoading(true);
1827
- callbacks.listAvailablePlugins(marketplace).then((plugins) => {
1925
+ callbacks.listAvailablePlugins(mp).then((plugins) => {
1828
1926
  setItems(
1829
1927
  plugins.map((p) => ({
1830
1928
  label: p.name,
@@ -1837,7 +1935,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1837
1935
  setError(err instanceof Error ? err.message : String(err));
1838
1936
  setLoading(false);
1839
1937
  });
1840
- } else if (screen2 === "installed-list") {
1938
+ } else if (screen === "installed-list") {
1841
1939
  setLoading(true);
1842
1940
  callbacks.listInstalled().then((plugins) => {
1843
1941
  setItems(
@@ -1853,8 +1951,60 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1853
1951
  setLoading(false);
1854
1952
  });
1855
1953
  }
1856
- }, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
1857
- const handleSelect = (0, import_react11.useCallback)(
1954
+ }, [stackLength, screen, marketplace, callbacks, refreshCounter]);
1955
+ return { items, loading, error };
1956
+ }
1957
+
1958
+ // src/ui/PluginTUI.tsx
1959
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1960
+ function PluginTUI({ callbacks, onClose, addMessage }) {
1961
+ const [stack, setStack] = (0, import_react15.useState)([{ screen: "main" }]);
1962
+ const [confirm, setConfirm] = (0, import_react15.useState)();
1963
+ const [refreshCounter, setRefreshCounter] = (0, import_react15.useState)(0);
1964
+ const current = stack[stack.length - 1] ?? { screen: "main" };
1965
+ const push = (0, import_react15.useCallback)((state) => {
1966
+ setStack((prev) => [...prev, state]);
1967
+ }, []);
1968
+ const pop = (0, import_react15.useCallback)(() => {
1969
+ setStack((prev) => {
1970
+ if (prev.length <= 1) {
1971
+ onClose();
1972
+ return prev;
1973
+ }
1974
+ return prev.slice(0, -1);
1975
+ });
1976
+ }, [onClose]);
1977
+ const popN = (0, import_react15.useCallback)(
1978
+ (n) => {
1979
+ setStack((prev) => {
1980
+ const next = prev.slice(0, Math.max(1, prev.length - n));
1981
+ if (next.length === 0) {
1982
+ onClose();
1983
+ return prev;
1984
+ }
1985
+ return next;
1986
+ });
1987
+ },
1988
+ [onClose]
1989
+ );
1990
+ const notify = (0, import_react15.useCallback)(
1991
+ (content) => {
1992
+ addMessage?.({ role: "system", content });
1993
+ },
1994
+ [addMessage]
1995
+ );
1996
+ const refresh = (0, import_react15.useCallback)(() => {
1997
+ setRefreshCounter((c) => c + 1);
1998
+ }, []);
1999
+ const nav = { push, pop, popN, notify, setConfirm, refresh };
2000
+ const { items, loading, error } = usePluginScreenData(
2001
+ current.screen,
2002
+ current.context?.marketplace,
2003
+ callbacks,
2004
+ refreshCounter,
2005
+ stack.length
2006
+ );
2007
+ const handleSelect = (0, import_react15.useCallback)(
1858
2008
  (value) => {
1859
2009
  const screen2 = current.screen;
1860
2010
  const ctx = current.context;
@@ -1872,7 +2022,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1872
2022
  },
1873
2023
  [current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
1874
2024
  );
1875
- const handleTextSubmit = (0, import_react11.useCallback)(
2025
+ const handleTextSubmit = (0, import_react15.useCallback)(
1876
2026
  (value) => {
1877
2027
  if (current.screen === "marketplace-add") {
1878
2028
  callbacks.marketplaceAdd(value).then((name) => {
@@ -1980,9 +2130,12 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1980
2130
  );
1981
2131
  }
1982
2132
 
2133
+ // src/ui/SessionPicker.tsx
2134
+ var import_ink15 = require("ink");
2135
+
1983
2136
  // src/ui/ListPicker.tsx
1984
- var import_react12 = require("react");
1985
- var import_ink13 = require("ink");
2137
+ var import_react16 = require("react");
2138
+ var import_ink14 = require("ink");
1986
2139
  var import_jsx_runtime14 = require("react/jsx-runtime");
1987
2140
  var DEFAULT_MAX_VISIBLE = 3;
1988
2141
  function ListPicker({
@@ -1992,11 +2145,11 @@ function ListPicker({
1992
2145
  onCancel,
1993
2146
  maxVisible = DEFAULT_MAX_VISIBLE
1994
2147
  }) {
1995
- const [selectedIndex, setSelectedIndex] = (0, import_react12.useState)(0);
1996
- const [scrollOffset, setScrollOffset] = (0, import_react12.useState)(0);
1997
- const selectedRef = (0, import_react12.useRef)(0);
1998
- const resolvedRef = (0, import_react12.useRef)(false);
1999
- (0, import_ink13.useInput)((_input, key) => {
2148
+ const [selectedIndex, setSelectedIndex] = (0, import_react16.useState)(0);
2149
+ const [scrollOffset, setScrollOffset] = (0, import_react16.useState)(0);
2150
+ const selectedRef = (0, import_react16.useRef)(0);
2151
+ const resolvedRef = (0, import_react16.useRef)(false);
2152
+ (0, import_ink14.useInput)((_input, key) => {
2000
2153
  if (resolvedRef.current) return;
2001
2154
  if (key.escape) {
2002
2155
  resolvedRef.current = true;
@@ -2027,19 +2180,19 @@ function ListPicker({
2027
2180
  }
2028
2181
  });
2029
2182
  if (items.length === 0) {
2030
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, {});
2183
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink14.Box, {});
2031
2184
  }
2032
2185
  const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
2033
2186
  const hasMore = scrollOffset + maxVisible < items.length;
2034
2187
  const hasLess = scrollOffset > 0;
2035
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2036
- hasLess && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Text, { dimColor: true, children: [
2188
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink14.Box, { flexDirection: "column", children: [
2189
+ hasLess && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink14.Text, { dimColor: true, children: [
2037
2190
  " \u2191 ",
2038
2191
  scrollOffset,
2039
2192
  " more above"
2040
2193
  ] }),
2041
- visibleItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
2042
- hasMore && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Text, { dimColor: true, children: [
2194
+ visibleItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink14.Box, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
2195
+ hasMore && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink14.Text, { dimColor: true, children: [
2043
2196
  " \u2193 ",
2044
2197
  items.length - scrollOffset - maxVisible,
2045
2198
  " more below"
@@ -2047,13 +2200,62 @@ function ListPicker({
2047
2200
  ] });
2048
2201
  }
2049
2202
 
2050
- // src/ui/App.tsx
2203
+ // src/ui/SessionPicker.tsx
2051
2204
  var import_jsx_runtime15 = require("react/jsx-runtime");
2052
- var EXIT_DELAY_MS = 500;
2053
2205
  var SESSION_ID_DISPLAY_LENGTH = 8;
2206
+ function SessionPicker({
2207
+ sessionStore,
2208
+ cwd,
2209
+ onSelect,
2210
+ onCancel
2211
+ }) {
2212
+ const sessions = (sessionStore?.list() ?? []).filter((s) => s.cwd === cwd);
2213
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink15.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2214
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
2215
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2216
+ ListPicker,
2217
+ {
2218
+ items: sessions,
2219
+ renderItem: (session, isSelected) => {
2220
+ const lastMsg = session.messages.slice().reverse().find((m) => {
2221
+ const msg = m;
2222
+ return msg.role === "assistant" && msg.content;
2223
+ });
2224
+ const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
2225
+ const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
2226
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink15.Text, { children: [
2227
+ isSelected ? "> " : " ",
2228
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
2229
+ " ",
2230
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { dimColor: true, children: new Date(session.updatedAt).toLocaleString(void 0, {
2231
+ month: "short",
2232
+ day: "numeric",
2233
+ hour: "2-digit",
2234
+ minute: "2-digit"
2235
+ }) }),
2236
+ " ",
2237
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink15.Text, { dimColor: true, children: [
2238
+ "msgs: ",
2239
+ session.messages.length
2240
+ ] }),
2241
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2242
+ "\n ",
2243
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink15.Text, { color: "gray", children: preview })
2244
+ ] }) : null
2245
+ ] });
2246
+ },
2247
+ onSelect: (session) => onSelect(session.id),
2248
+ onCancel
2249
+ }
2250
+ )
2251
+ ] });
2252
+ }
2253
+
2254
+ // src/ui/App.tsx
2255
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2054
2256
  function App(props) {
2055
- const [activeSessionId, setActiveSessionId] = (0, import_react13.useState)(props.resumeSessionId);
2056
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2257
+ const [activeSessionId, setActiveSessionId] = (0, import_react17.useState)(props.resumeSessionId);
2258
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2057
2259
  AppInner,
2058
2260
  {
2059
2261
  ...props,
@@ -2064,7 +2266,6 @@ function App(props) {
2064
2266
  );
2065
2267
  }
2066
2268
  function AppInner(props) {
2067
- const { exit } = (0, import_ink14.useApp)();
2068
2269
  const cwd = props.cwd;
2069
2270
  const {
2070
2271
  interactiveSession,
@@ -2092,83 +2293,32 @@ function AppInner(props) {
2092
2293
  sessionName: props.sessionName
2093
2294
  });
2094
2295
  const pluginCallbacks = usePluginCallbacks(cwd);
2095
- const [pendingModelId, setPendingModelId] = (0, import_react13.useState)(null);
2096
- const pendingModelChangeRef = (0, import_react13.useRef)(null);
2097
- const [showPluginTUI, setShowPluginTUI] = (0, import_react13.useState)(false);
2098
- const [showSessionPicker, setShowSessionPicker] = (0, import_react13.useState)(
2099
- props.resumeSessionId === "__picker__"
2100
- );
2101
- const [sessionName, setSessionName] = (0, import_react13.useState)(props.sessionName);
2102
- (0, import_react13.useEffect)(() => {
2296
+ const [sessionName, setSessionName] = (0, import_react17.useState)(props.sessionName);
2297
+ const {
2298
+ handleSubmit,
2299
+ pendingModelId,
2300
+ showPluginTUI,
2301
+ showSessionPicker,
2302
+ setShowPluginTUI,
2303
+ setShowSessionPicker,
2304
+ handleModelConfirm
2305
+ } = useSideEffects({
2306
+ interactiveSession,
2307
+ addEntry,
2308
+ baseHandleSubmit,
2309
+ setSessionName
2310
+ });
2311
+ (0, import_react17.useEffect)(() => {
2103
2312
  const name = interactiveSession?.getName?.();
2104
2313
  if (name && !sessionName) setSessionName(name);
2105
2314
  }, [interactiveSession, sessionName]);
2106
- (0, import_react13.useEffect)(() => {
2315
+ (0, import_react17.useEffect)(() => {
2107
2316
  const title = sessionName ? `Robota \u2014 ${sessionName}` : "Robota";
2108
2317
  process.stdout.write(`\x1B]0;${title}\x07`);
2109
2318
  }, [sessionName]);
2110
- const handleSubmit = async (input) => {
2111
- await baseHandleSubmit(input);
2112
- const sideEffects = interactiveSession;
2113
- if (sideEffects._pendingModelId) {
2114
- const modelId = sideEffects._pendingModelId;
2115
- delete sideEffects._pendingModelId;
2116
- pendingModelChangeRef.current = modelId;
2117
- setPendingModelId(modelId);
2118
- return;
2119
- }
2120
- if (sideEffects._pendingLanguage) {
2121
- const lang = sideEffects._pendingLanguage;
2122
- delete sideEffects._pendingLanguage;
2123
- const settingsPath = getUserSettingsPath();
2124
- const settings = readSettings(settingsPath);
2125
- settings.language = lang;
2126
- writeSettings(settingsPath, settings);
2127
- addEntry(
2128
- (0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Language set to "${lang}". Restarting...`))
2129
- );
2130
- setTimeout(() => exit(), EXIT_DELAY_MS);
2131
- return;
2132
- }
2133
- if (sideEffects._resetRequested) {
2134
- delete sideEffects._resetRequested;
2135
- const settingsPath = getUserSettingsPath();
2136
- if (deleteSettings(settingsPath)) {
2137
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Deleted ${settingsPath}. Exiting...`)));
2138
- } else {
2139
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("No user settings found.")));
2140
- }
2141
- setTimeout(() => exit(), EXIT_DELAY_MS);
2142
- return;
2143
- }
2144
- if (sideEffects._exitRequested) {
2145
- delete sideEffects._exitRequested;
2146
- setTimeout(() => exit(), EXIT_DELAY_MS);
2147
- return;
2148
- }
2149
- if (sideEffects._triggerPluginTUI) {
2150
- delete sideEffects._triggerPluginTUI;
2151
- setShowPluginTUI(true);
2152
- return;
2153
- }
2154
- if (sideEffects._triggerResumePicker) {
2155
- delete sideEffects._triggerResumePicker;
2156
- setShowSessionPicker(true);
2157
- return;
2158
- }
2159
- if (sideEffects._sessionName) {
2160
- const name = sideEffects._sessionName;
2161
- delete sideEffects._sessionName;
2162
- interactiveSession.setName(name);
2163
- setSessionName(name);
2164
- return;
2165
- }
2166
- };
2167
- (0, import_ink14.useInput)(
2319
+ (0, import_ink16.useInput)(
2168
2320
  (_input, key) => {
2169
- if (key.escape && isThinking) {
2170
- handleAbort();
2171
- }
2321
+ if (key.escape && isThinking) handleAbort();
2172
2322
  },
2173
2323
  { isActive: !permissionRequest && !showPluginTUI && !showSessionPicker }
2174
2324
  );
@@ -2180,117 +2330,60 @@ function AppInner(props) {
2180
2330
  sessionId = session.getSessionId();
2181
2331
  } catch {
2182
2332
  }
2183
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", children: [
2184
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2185
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "cyan", bold: true, children: `
2333
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", children: [
2334
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2335
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { color: "cyan", bold: true, children: `
2186
2336
  ____ ___ ____ ___ _____ _
2187
2337
  | _ \\ / _ \\| __ ) / _ \\_ _|/ \\
2188
2338
  | |_) | | | | _ \\| | | || | / _ \\
2189
2339
  | _ <| |_| | |_) | |_| || |/ ___ \\
2190
2340
  |_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
2191
2341
  ` }),
2192
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
2342
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Text, { dimColor: true, children: [
2193
2343
  " v",
2194
2344
  props.version ?? "0.0.0"
2195
2345
  ] })
2196
2346
  ] }),
2197
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2198
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageList, { history }),
2199
- (isThinking || activeTools.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
2347
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_ink16.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2348
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MessageList, { history }),
2349
+ (isThinking || activeTools.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
2200
2350
  ] }),
2201
- permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PermissionPrompt, { request: permissionRequest }),
2202
- pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2351
+ permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PermissionPrompt, { request: permissionRequest }),
2352
+ pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2203
2353
  ConfirmPrompt,
2204
2354
  {
2205
- message: `Change model to ${(0, import_agent_core4.getModelName)(pendingModelId)}? This will restart the session.`,
2206
- onSelect: (index) => {
2207
- setPendingModelId(null);
2208
- pendingModelChangeRef.current = null;
2209
- if (index === 0) {
2210
- try {
2211
- const settingsPath = getUserSettingsPath();
2212
- updateModelInSettings(settingsPath, pendingModelId);
2213
- addEntry(
2214
- (0, import_agent_core4.messageToHistoryEntry)(
2215
- (0, import_agent_core4.createSystemMessage)(
2216
- `Model changed to ${(0, import_agent_core4.getModelName)(pendingModelId)}. Restarting...`
2217
- )
2218
- )
2219
- );
2220
- setTimeout(() => exit(), EXIT_DELAY_MS);
2221
- } catch (err) {
2222
- addEntry(
2223
- (0, import_agent_core4.messageToHistoryEntry)(
2224
- (0, import_agent_core4.createSystemMessage)(
2225
- `Failed: ${err instanceof Error ? err.message : String(err)}`
2226
- )
2227
- )
2228
- );
2229
- }
2230
- } else {
2231
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Model change cancelled.")));
2232
- }
2233
- }
2355
+ message: `Change model to ${(0, import_agent_core5.getModelName)(pendingModelId)}? This will restart the session.`,
2356
+ onSelect: handleModelConfirm
2234
2357
  }
2235
2358
  ),
2236
- showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2359
+ showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2237
2360
  PluginTUI,
2238
2361
  {
2239
2362
  callbacks: pluginCallbacks,
2240
2363
  onClose: () => setShowPluginTUI(false),
2241
- addMessage: (msg) => addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(msg.content)))
2364
+ addMessage: (msg) => addEntry((0, import_agent_core5.messageToHistoryEntry)((0, import_agent_core5.createSystemMessage)(msg.content)))
2242
2365
  }
2243
2366
  ),
2244
- showSessionPicker && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2245
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
2246
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2247
- ListPicker,
2248
- {
2249
- items: (props.sessionStore?.list() ?? []).filter((s) => s.cwd === props.cwd),
2250
- renderItem: (session, isSelected) => {
2251
- const lastMsg = session.messages.slice().reverse().find((m) => {
2252
- const msg = m;
2253
- return msg.role === "assistant" && msg.content;
2254
- });
2255
- const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
2256
- const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
2257
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { children: [
2258
- isSelected ? "> " : " ",
2259
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
2260
- " ",
2261
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { dimColor: true, children: new Date(session.updatedAt).toLocaleString(void 0, {
2262
- month: "short",
2263
- day: "numeric",
2264
- hour: "2-digit",
2265
- minute: "2-digit"
2266
- }) }),
2267
- " ",
2268
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
2269
- "msgs: ",
2270
- session.messages.length
2271
- ] }),
2272
- preview ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2273
- "\n ",
2274
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "gray", children: preview })
2275
- ] }) : null
2276
- ] });
2277
- },
2278
- onSelect: (session) => {
2279
- setShowSessionPicker(false);
2280
- props.onSessionSwitch(session.id);
2281
- },
2282
- onCancel: () => {
2283
- setShowSessionPicker(false);
2284
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Session resume cancelled.")));
2285
- }
2367
+ showSessionPicker && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2368
+ SessionPicker,
2369
+ {
2370
+ sessionStore: props.sessionStore,
2371
+ cwd: props.cwd,
2372
+ onSelect: (id) => {
2373
+ setShowSessionPicker(false);
2374
+ props.onSessionSwitch(id);
2375
+ },
2376
+ onCancel: () => {
2377
+ setShowSessionPicker(false);
2378
+ addEntry((0, import_agent_core5.messageToHistoryEntry)((0, import_agent_core5.createSystemMessage)("Session resume cancelled.")));
2286
2379
  }
2287
- )
2288
- ] }),
2289
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2380
+ }
2381
+ ),
2382
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2290
2383
  StatusBar,
2291
2384
  {
2292
2385
  permissionMode,
2293
- modelName: props.modelId ? (0, import_agent_core4.getModelName)(props.modelId) : "",
2386
+ modelName: props.modelId ? (0, import_agent_core5.getModelName)(props.modelId) : "",
2294
2387
  sessionId,
2295
2388
  messageCount: history.length,
2296
2389
  isThinking,
@@ -2300,7 +2393,7 @@ function AppInner(props) {
2300
2393
  sessionName
2301
2394
  }
2302
2395
  ),
2303
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2396
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2304
2397
  InputArea,
2305
2398
  {
2306
2399
  onSubmit: handleSubmit,
@@ -2312,12 +2405,12 @@ function AppInner(props) {
2312
2405
  sessionName
2313
2406
  }
2314
2407
  ),
2315
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: " " })
2408
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { children: " " })
2316
2409
  ] });
2317
2410
  }
2318
2411
 
2319
2412
  // src/ui/render.tsx
2320
- var import_jsx_runtime16 = require("react/jsx-runtime");
2413
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2321
2414
  function renderApp(options) {
2322
2415
  process.on("unhandledRejection", (reason) => {
2323
2416
  process.stderr.write(`
@@ -2331,7 +2424,7 @@ function renderApp(options) {
2331
2424
  if (process.stdin.isTTY && process.stdout.isTTY) {
2332
2425
  process.stdout.write("\x1B[?2004h");
2333
2426
  }
2334
- const instance = (0, import_ink15.render)(/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(App, { ...options }), {
2427
+ const instance = (0, import_ink17.render)(/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(App, { ...options }), {
2335
2428
  exitOnCtrlC: true
2336
2429
  });
2337
2430
  instance.waitUntilExit().then(() => {
@@ -2536,7 +2629,7 @@ async function startCli() {
2536
2629
  process.stderr.write("Print mode (-p) requires a prompt argument.\n");
2537
2630
  process.exit(1);
2538
2631
  }
2539
- const session = new import_agent_sdk3.InteractiveSession({
2632
+ const session = new import_agent_sdk4.InteractiveSession({
2540
2633
  cwd,
2541
2634
  provider,
2542
2635
  permissionMode: args.permissionMode ?? "bypassPermissions",