@robota-sdk/agent-cli 3.0.0-beta.52 → 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");
@@ -968,16 +1100,16 @@ function CjkTextInput({
968
1100
  availableWidth,
969
1101
  cursorHint = null
970
1102
  }) {
971
- const valueRef = (0, import_react4.useRef)(value);
972
- const cursorRef = (0, import_react4.useRef)(value.length);
973
- const [, forceRender] = (0, import_react4.useState)(0);
974
- const isPastingRef = (0, import_react4.useRef)(false);
975
- 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)("");
976
1108
  if (value !== valueRef.current) {
977
1109
  valueRef.current = value;
978
1110
  cursorRef.current = cursorHint != null ? Math.min(cursorHint, value.length) : value.length;
979
1111
  }
980
- (0, import_ink4.useInput)(
1112
+ (0, import_ink5.useInput)(
981
1113
  (input, key) => {
982
1114
  try {
983
1115
  if (input === PASTE_START || input.startsWith(PASTE_START)) {
@@ -1074,7 +1206,7 @@ function CjkTextInput({
1074
1206
  },
1075
1207
  { isActive: focus }
1076
1208
  );
1077
- 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) });
1078
1210
  }
1079
1211
  function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
1080
1212
  if (!showCursor) {
@@ -1099,30 +1231,30 @@ function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
1099
1231
  }
1100
1232
 
1101
1233
  // src/ui/WaveText.tsx
1102
- var import_react5 = require("react");
1103
- var import_ink5 = require("ink");
1234
+ var import_react7 = require("react");
1235
+ var import_ink6 = require("ink");
1104
1236
  var import_jsx_runtime5 = require("react/jsx-runtime");
1105
1237
  var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
1106
1238
  var INTERVAL_MS = 400;
1107
1239
  var CHARS_PER_GROUP = 4;
1108
1240
  function WaveText({ text }) {
1109
- const [tick, setTick] = (0, import_react5.useState)(0);
1110
- (0, import_react5.useEffect)(() => {
1241
+ const [tick, setTick] = (0, import_react7.useState)(0);
1242
+ (0, import_react7.useEffect)(() => {
1111
1243
  const timer = setInterval(() => {
1112
1244
  setTick((prev) => prev + 1);
1113
1245
  }, INTERVAL_MS);
1114
1246
  return () => clearInterval(timer);
1115
1247
  }, []);
1116
1248
  const chars = [...text];
1117
- 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) => {
1118
1250
  const group = Math.floor(i / CHARS_PER_GROUP);
1119
1251
  const colorIndex = (tick + group) % WAVE_COLORS.length;
1120
- 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);
1121
1253
  }) });
1122
1254
  }
1123
1255
 
1124
1256
  // src/ui/SlashAutocomplete.tsx
1125
- var import_ink6 = require("ink");
1257
+ var import_ink7 = require("ink");
1126
1258
  var import_jsx_runtime6 = require("react/jsx-runtime");
1127
1259
  var MAX_VISIBLE = 8;
1128
1260
  function CommandRow(props) {
@@ -1130,7 +1262,7 @@ function CommandRow(props) {
1130
1262
  const indicator = isSelected ? "\u25B8 " : " ";
1131
1263
  const nameColor = isSelected ? "cyan" : void 0;
1132
1264
  const dimmed = !isSelected;
1133
- 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: [
1134
1266
  indicator,
1135
1267
  showSlash ? `/${cmd.name} ${cmd.description}` : cmd.description
1136
1268
  ] }) });
@@ -1144,7 +1276,7 @@ function SlashAutocomplete({
1144
1276
  if (!visible || commands.length === 0) return null;
1145
1277
  const scrollOffset = computeScrollOffset(selectedIndex, commands.length);
1146
1278
  const visibleCommands = commands.slice(scrollOffset, scrollOffset + MAX_VISIBLE);
1147
- 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)(
1148
1280
  CommandRow,
1149
1281
  {
1150
1282
  cmd,
@@ -1167,8 +1299,8 @@ function expandPasteLabels(text, store) {
1167
1299
  return text.replace(PASTE_LABEL_RE, (_, id) => store.get(Number(id)) ?? "");
1168
1300
  }
1169
1301
 
1170
- // src/ui/InputArea.tsx
1171
- var import_jsx_runtime7 = require("react/jsx-runtime");
1302
+ // src/ui/hooks/useAutocomplete.ts
1303
+ var import_react8 = __toESM(require("react"), 1);
1172
1304
  function parseSlashInput(value) {
1173
1305
  if (!value.startsWith("/")) return { isSlash: false, parentCommand: "", filter: "" };
1174
1306
  const afterSlash = value.slice(1);
@@ -1179,16 +1311,16 @@ function parseSlashInput(value) {
1179
1311
  return { isSlash: true, parentCommand: parent, filter: rest };
1180
1312
  }
1181
1313
  function useAutocomplete(value, registry) {
1182
- const [selectedIndex, setSelectedIndex] = (0, import_react6.useState)(0);
1183
- const [dismissed, setDismissed] = (0, import_react6.useState)(false);
1184
- 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);
1185
1317
  if (prevValueRef.current !== value) {
1186
1318
  prevValueRef.current = value;
1187
1319
  if (dismissed) setDismissed(false);
1188
1320
  }
1189
1321
  const parsed = parseSlashInput(value);
1190
1322
  const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
1191
- const filteredCommands = (0, import_react6.useMemo)(() => {
1323
+ const filteredCommands = (0, import_react8.useMemo)(() => {
1192
1324
  if (!registry || !parsed.isSlash || dismissed) return [];
1193
1325
  if (isSubcommandMode) {
1194
1326
  const subs = registry.getSubcommands(parsed.parentCommand);
@@ -1221,6 +1353,9 @@ function useAutocomplete(value, registry) {
1221
1353
  }
1222
1354
  };
1223
1355
  }
1356
+
1357
+ // src/ui/InputArea.tsx
1358
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1224
1359
  var BORDER_HORIZONTAL = 2;
1225
1360
  var PADDING_LEFT = 1;
1226
1361
  var PROMPT_WIDTH = 2;
@@ -1234,13 +1369,13 @@ function InputArea({
1234
1369
  registry,
1235
1370
  sessionName
1236
1371
  }) {
1237
- const [value, setValue] = (0, import_react6.useState)("");
1238
- const [cursorHint, setCursorHint] = (0, import_react6.useState)(null);
1239
- const pasteStore = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
1240
- 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)();
1241
1376
  const terminalColumns = stdout?.columns ?? 80;
1242
1377
  const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
1243
- const pasteIdRef = (0, import_react6.useRef)(0);
1378
+ const pasteIdRef = (0, import_react9.useRef)(0);
1244
1379
  const {
1245
1380
  showPopup,
1246
1381
  filteredCommands,
@@ -1249,7 +1384,7 @@ function InputArea({
1249
1384
  isSubcommandMode,
1250
1385
  setShowPopup
1251
1386
  } = useAutocomplete(value, registry);
1252
- const handlePaste = (0, import_react6.useCallback)((text, cursorPosition) => {
1387
+ const handlePaste = (0, import_react9.useCallback)((text, cursorPosition) => {
1253
1388
  pasteIdRef.current += 1;
1254
1389
  const id = pasteIdRef.current;
1255
1390
  pasteStore.current.set(id, text);
@@ -1259,7 +1394,7 @@ function InputArea({
1259
1394
  setCursorHint(newCursorPos);
1260
1395
  setValue((prev) => prev.slice(0, cursorPosition) + label + prev.slice(cursorPosition));
1261
1396
  }, []);
1262
- const tabCompleteCommand = (0, import_react6.useCallback)(
1397
+ const tabCompleteCommand = (0, import_react9.useCallback)(
1263
1398
  (cmd) => {
1264
1399
  const parsed = parseSlashInput(value);
1265
1400
  if (parsed.parentCommand) {
@@ -1275,7 +1410,7 @@ function InputArea({
1275
1410
  },
1276
1411
  [value, setSelectedIndex]
1277
1412
  );
1278
- const enterSelectCommand = (0, import_react6.useCallback)(
1413
+ const enterSelectCommand = (0, import_react9.useCallback)(
1279
1414
  (cmd) => {
1280
1415
  const parsed = parseSlashInput(value);
1281
1416
  if (parsed.parentCommand) {
@@ -1294,7 +1429,7 @@ function InputArea({
1294
1429
  },
1295
1430
  [value, onSubmit, setSelectedIndex]
1296
1431
  );
1297
- const handleSubmit = (0, import_react6.useCallback)(
1432
+ const handleSubmit = (0, import_react9.useCallback)(
1298
1433
  (text) => {
1299
1434
  const trimmed = text.trim();
1300
1435
  if (trimmed.length === 0) return;
@@ -1310,7 +1445,7 @@ function InputArea({
1310
1445
  },
1311
1446
  [showPopup, filteredCommands, selectedIndex, onSubmit, enterSelectCommand]
1312
1447
  );
1313
- (0, import_ink7.useInput)(
1448
+ (0, import_ink8.useInput)(
1314
1449
  (_input, key) => {
1315
1450
  if (!showPopup) return;
1316
1451
  if (key.upArrow) {
@@ -1326,7 +1461,7 @@ function InputArea({
1326
1461
  },
1327
1462
  { isActive: showPopup && !isDisabled }
1328
1463
  );
1329
- (0, import_ink7.useInput)(
1464
+ (0, import_ink8.useInput)(
1330
1465
  (_input, key) => {
1331
1466
  if ((key.backspace || key.delete) && pendingPrompt) {
1332
1467
  onCancelQueue?.();
@@ -1345,7 +1480,7 @@ function InputArea({
1345
1480
  }
1346
1481
  return { left: "\u250C" + "\u2500".repeat(innerWidth), label: "", right: "\u2510" };
1347
1482
  })();
1348
- 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: [
1349
1484
  showPopup && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1350
1485
  SlashAutocomplete,
1351
1486
  {
@@ -1355,19 +1490,19 @@ function InputArea({
1355
1490
  isSubcommandMode
1356
1491
  }
1357
1492
  ),
1358
- /* @__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: [
1359
1494
  topBorder.left,
1360
- 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,
1361
1496
  topBorder.right
1362
1497
  ] }),
1363
- /* @__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: [
1364
1499
  " ",
1365
1500
  "Queued: ",
1366
1501
  pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
1367
1502
  " ",
1368
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: "(Backspace to cancel)" })
1369
- ] }) : 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: [
1370
- /* @__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: "> " }),
1371
1506
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1372
1507
  CjkTextInput,
1373
1508
  {
@@ -1388,17 +1523,17 @@ function InputArea({
1388
1523
  }
1389
1524
 
1390
1525
  // src/ui/ConfirmPrompt.tsx
1391
- var import_react7 = require("react");
1392
- var import_ink8 = require("ink");
1526
+ var import_react10 = require("react");
1527
+ var import_ink9 = require("ink");
1393
1528
  var import_jsx_runtime8 = require("react/jsx-runtime");
1394
1529
  function ConfirmPrompt({
1395
1530
  message,
1396
1531
  options = ["Yes", "No"],
1397
1532
  onSelect
1398
1533
  }) {
1399
- const [selected, setSelected] = (0, import_react7.useState)(0);
1400
- const resolvedRef = (0, import_react7.useRef)(false);
1401
- 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)(
1402
1537
  (index) => {
1403
1538
  if (resolvedRef.current) return;
1404
1539
  resolvedRef.current = true;
@@ -1406,7 +1541,7 @@ function ConfirmPrompt({
1406
1541
  },
1407
1542
  [onSelect]
1408
1543
  );
1409
- (0, import_ink8.useInput)((input, key) => {
1544
+ (0, import_ink9.useInput)((input, key) => {
1410
1545
  if (resolvedRef.current) return;
1411
1546
  if (key.leftArrow || key.upArrow) {
1412
1547
  setSelected((prev) => prev > 0 ? prev - 1 : prev);
@@ -1420,19 +1555,19 @@ function ConfirmPrompt({
1420
1555
  doSelect(1);
1421
1556
  }
1422
1557
  });
1423
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1424
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", children: message }),
1425
- /* @__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: [
1426
1561
  i === selected ? "> " : " ",
1427
1562
  opt
1428
1563
  ] }) }, opt)) }),
1429
- /* @__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" })
1430
1565
  ] });
1431
1566
  }
1432
1567
 
1433
1568
  // src/ui/PermissionPrompt.tsx
1434
- var import_react8 = __toESM(require("react"), 1);
1435
- var import_ink9 = require("ink");
1569
+ var import_react11 = __toESM(require("react"), 1);
1570
+ var import_ink10 = require("ink");
1436
1571
  var import_jsx_runtime9 = require("react/jsx-runtime");
1437
1572
  var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
1438
1573
  function formatArgs(args) {
@@ -1441,15 +1576,15 @@ function formatArgs(args) {
1441
1576
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
1442
1577
  }
1443
1578
  function PermissionPrompt({ request }) {
1444
- const [selected, setSelected] = import_react8.default.useState(0);
1445
- const resolvedRef = import_react8.default.useRef(false);
1446
- 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);
1447
1582
  if (prevRequestRef.current !== request) {
1448
1583
  prevRequestRef.current = request;
1449
1584
  resolvedRef.current = false;
1450
1585
  setSelected(0);
1451
1586
  }
1452
- const doResolve = import_react8.default.useCallback(
1587
+ const doResolve = import_react11.default.useCallback(
1453
1588
  (index) => {
1454
1589
  if (resolvedRef.current) return;
1455
1590
  resolvedRef.current = true;
@@ -1459,7 +1594,7 @@ function PermissionPrompt({ request }) {
1459
1594
  },
1460
1595
  [request]
1461
1596
  );
1462
- (0, import_ink9.useInput)((input, key) => {
1597
+ (0, import_ink10.useInput)((input, key) => {
1463
1598
  if (resolvedRef.current) return;
1464
1599
  if (key.upArrow || key.leftArrow) {
1465
1600
  setSelected((prev) => prev > 0 ? prev - 1 : prev);
@@ -1475,27 +1610,27 @@ function PermissionPrompt({ request }) {
1475
1610
  doResolve(2);
1476
1611
  }
1477
1612
  });
1478
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1479
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
1480
- /* @__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: [
1481
1616
  "Tool:",
1482
1617
  " ",
1483
- /* @__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 })
1484
1619
  ] }),
1485
- /* @__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: [
1486
1621
  " ",
1487
1622
  formatArgs(request.toolArgs)
1488
1623
  ] }),
1489
- /* @__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: [
1490
1625
  i === selected ? "> " : " ",
1491
1626
  opt
1492
1627
  ] }) }, opt)) }),
1493
- /* @__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" })
1494
1629
  ] });
1495
1630
  }
1496
1631
 
1497
1632
  // src/ui/StreamingIndicator.tsx
1498
- var import_ink10 = require("ink");
1633
+ var import_ink11 = require("ink");
1499
1634
  var import_jsx_runtime10 = require("react/jsx-runtime");
1500
1635
  function getToolStyle(t) {
1501
1636
  if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
@@ -1509,14 +1644,14 @@ function StreamingIndicator({ text, activeTools }) {
1509
1644
  if (!hasTools && !hasText) {
1510
1645
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
1511
1646
  }
1512
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
1513
- hasTools && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: [
1514
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "white", bold: true, children: "Tools:" }),
1515
- /* @__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: " " }),
1516
1651
  activeTools.map((t, i) => {
1517
1652
  const { color, icon, strikethrough } = getToolStyle(t);
1518
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
1519
- /* @__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: [
1520
1655
  " ",
1521
1656
  icon,
1522
1657
  " ",
@@ -1529,20 +1664,20 @@ function StreamingIndicator({ text, activeTools }) {
1529
1664
  ] }, `${t.toolName}-${i}`);
1530
1665
  })
1531
1666
  ] }),
1532
- hasText && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: [
1533
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "cyan", bold: true, children: "Robota:" }),
1534
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { children: " " }),
1535
- /* @__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) }) })
1536
1671
  ] })
1537
1672
  ] });
1538
1673
  }
1539
1674
 
1540
1675
  // src/ui/PluginTUI.tsx
1541
- var import_react11 = require("react");
1676
+ var import_react15 = require("react");
1542
1677
 
1543
1678
  // src/ui/MenuSelect.tsx
1544
- var import_react9 = require("react");
1545
- var import_ink11 = require("ink");
1679
+ var import_react12 = require("react");
1680
+ var import_ink12 = require("ink");
1546
1681
  var import_jsx_runtime11 = require("react/jsx-runtime");
1547
1682
  function MenuSelect({
1548
1683
  title,
@@ -1552,10 +1687,10 @@ function MenuSelect({
1552
1687
  loading,
1553
1688
  error
1554
1689
  }) {
1555
- const [selected, setSelected] = (0, import_react9.useState)(0);
1556
- const selectedRef = (0, import_react9.useRef)(0);
1557
- const resolvedRef = (0, import_react9.useRef)(false);
1558
- 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)(
1559
1694
  (index) => {
1560
1695
  if (resolvedRef.current || items.length === 0) return;
1561
1696
  resolvedRef.current = true;
@@ -1563,7 +1698,7 @@ function MenuSelect({
1563
1698
  },
1564
1699
  [items, onSelect]
1565
1700
  );
1566
- (0, import_ink11.useInput)((input, key) => {
1701
+ (0, import_ink12.useInput)((input, key) => {
1567
1702
  if (resolvedRef.current) return;
1568
1703
  if (key.escape) {
1569
1704
  resolvedRef.current = true;
@@ -1583,30 +1718,30 @@ function MenuSelect({
1583
1718
  doSelect(selectedRef.current);
1584
1719
  }
1585
1720
  });
1586
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1587
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "yellow", bold: true, children: title }),
1588
- 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..." }) }),
1589
- error && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Box, { marginTop: 1, flexDirection: "column", children: [
1590
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { color: "red", children: error }),
1591
- /* @__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" })
1592
1727
  ] }),
1593
- !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: [
1594
- /* @__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: [
1595
1730
  i === selected ? "> " : " ",
1596
1731
  item.label
1597
1732
  ] }),
1598
- 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: [
1599
1734
  " ",
1600
1735
  item.hint
1601
1736
  ] })
1602
1737
  ] }, item.value)) }),
1603
- /* @__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" })
1604
1739
  ] });
1605
1740
  }
1606
1741
 
1607
1742
  // src/ui/TextPrompt.tsx
1608
- var import_react10 = require("react");
1609
- var import_ink12 = require("ink");
1743
+ var import_react13 = require("react");
1744
+ var import_ink13 = require("ink");
1610
1745
  var import_jsx_runtime12 = require("react/jsx-runtime");
1611
1746
  function TextPrompt({
1612
1747
  title,
@@ -1615,11 +1750,11 @@ function TextPrompt({
1615
1750
  onCancel,
1616
1751
  validate
1617
1752
  }) {
1618
- const [value, setValue] = (0, import_react10.useState)("");
1619
- const [error, setError] = (0, import_react10.useState)();
1620
- const resolvedRef = (0, import_react10.useRef)(false);
1621
- const valueRef = (0, import_react10.useRef)("");
1622
- 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)(() => {
1623
1758
  if (resolvedRef.current) return;
1624
1759
  const trimmed = valueRef.current.trim();
1625
1760
  if (!trimmed) return;
@@ -1633,7 +1768,7 @@ function TextPrompt({
1633
1768
  resolvedRef.current = true;
1634
1769
  onSubmit(trimmed);
1635
1770
  }, [validate, onSubmit]);
1636
- (0, import_ink12.useInput)((input, key) => {
1771
+ (0, import_ink13.useInput)((input, key) => {
1637
1772
  if (resolvedRef.current) return;
1638
1773
  if (key.escape) {
1639
1774
  resolvedRef.current = true;
@@ -1656,15 +1791,15 @@ function TextPrompt({
1656
1791
  setError(void 0);
1657
1792
  }
1658
1793
  });
1659
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1660
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "yellow", bold: true, children: title }),
1661
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink12.Box, { marginTop: 1, children: [
1662
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "cyan", children: "> " }),
1663
- 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,
1664
- /* @__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" })
1665
1800
  ] }),
1666
- error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink12.Text, { color: "red", children: error }),
1667
- /* @__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" })
1668
1803
  ] });
1669
1804
  }
1670
1805
 
@@ -1760,61 +1895,16 @@ function handleInstalledActionSelect(value, pluginId, callbacks, nav) {
1760
1895
  }
1761
1896
  }
1762
1897
 
1763
- // src/ui/PluginTUI.tsx
1764
- var import_jsx_runtime13 = require("react/jsx-runtime");
1765
- function PluginTUI({ callbacks, onClose, addMessage }) {
1766
- const [stack, setStack] = (0, import_react11.useState)([{ screen: "main" }]);
1767
- const [items, setItems] = (0, import_react11.useState)([]);
1768
- const [loading, setLoading] = (0, import_react11.useState)(false);
1769
- const [error, setError] = (0, import_react11.useState)();
1770
- const [confirm, setConfirm] = (0, import_react11.useState)();
1771
- const [refreshCounter, setRefreshCounter] = (0, import_react11.useState)(0);
1772
- const current = stack[stack.length - 1] ?? { screen: "main" };
1773
- const push = (0, import_react11.useCallback)((state) => {
1774
- 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)(() => {
1775
1905
  setItems([]);
1776
1906
  setError(void 0);
1777
- }, []);
1778
- const pop = (0, import_react11.useCallback)(() => {
1779
- setStack((prev) => {
1780
- if (prev.length <= 1) {
1781
- onClose();
1782
- return prev;
1783
- }
1784
- return prev.slice(0, -1);
1785
- });
1786
- setItems([]);
1787
- setError(void 0);
1788
- }, [onClose]);
1789
- const popN = (0, import_react11.useCallback)(
1790
- (n) => {
1791
- setStack((prev) => {
1792
- const next = prev.slice(0, Math.max(1, prev.length - n));
1793
- if (next.length === 0) {
1794
- onClose();
1795
- return prev;
1796
- }
1797
- return next;
1798
- });
1799
- setItems([]);
1800
- setError(void 0);
1801
- },
1802
- [onClose]
1803
- );
1804
- const notify = (0, import_react11.useCallback)(
1805
- (content) => {
1806
- addMessage?.({ role: "system", content });
1807
- },
1808
- [addMessage]
1809
- );
1810
- const refresh = (0, import_react11.useCallback)(() => {
1811
- setItems([]);
1812
- setRefreshCounter((c) => c + 1);
1813
- }, []);
1814
- const nav = { push, pop, popN, notify, setConfirm, refresh };
1815
- (0, import_react11.useEffect)(() => {
1816
- const screen2 = current.screen;
1817
- if (screen2 === "marketplace-list") {
1907
+ if (screen === "marketplace-list") {
1818
1908
  setLoading(true);
1819
1909
  callbacks.marketplaceList().then((sources) => {
1820
1910
  const baseItems = [{ label: "Add Marketplace", value: "__add__" }];
@@ -1829,10 +1919,10 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1829
1919
  setError(err instanceof Error ? err.message : String(err));
1830
1920
  setLoading(false);
1831
1921
  });
1832
- } else if (screen2 === "marketplace-browse") {
1833
- const marketplace = current.context?.marketplace ?? "";
1922
+ } else if (screen === "marketplace-browse") {
1923
+ const mp = marketplace ?? "";
1834
1924
  setLoading(true);
1835
- callbacks.listAvailablePlugins(marketplace).then((plugins) => {
1925
+ callbacks.listAvailablePlugins(mp).then((plugins) => {
1836
1926
  setItems(
1837
1927
  plugins.map((p) => ({
1838
1928
  label: p.name,
@@ -1845,7 +1935,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1845
1935
  setError(err instanceof Error ? err.message : String(err));
1846
1936
  setLoading(false);
1847
1937
  });
1848
- } else if (screen2 === "installed-list") {
1938
+ } else if (screen === "installed-list") {
1849
1939
  setLoading(true);
1850
1940
  callbacks.listInstalled().then((plugins) => {
1851
1941
  setItems(
@@ -1861,8 +1951,60 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1861
1951
  setLoading(false);
1862
1952
  });
1863
1953
  }
1864
- }, [stack.length, current.screen, current.context?.marketplace, callbacks, refreshCounter]);
1865
- 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)(
1866
2008
  (value) => {
1867
2009
  const screen2 = current.screen;
1868
2010
  const ctx = current.context;
@@ -1880,7 +2022,7 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1880
2022
  },
1881
2023
  [current, items, callbacks, push, pop, popN, notify, setConfirm, refresh]
1882
2024
  );
1883
- const handleTextSubmit = (0, import_react11.useCallback)(
2025
+ const handleTextSubmit = (0, import_react15.useCallback)(
1884
2026
  (value) => {
1885
2027
  if (current.screen === "marketplace-add") {
1886
2028
  callbacks.marketplaceAdd(value).then((name) => {
@@ -1988,9 +2130,12 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
1988
2130
  );
1989
2131
  }
1990
2132
 
2133
+ // src/ui/SessionPicker.tsx
2134
+ var import_ink15 = require("ink");
2135
+
1991
2136
  // src/ui/ListPicker.tsx
1992
- var import_react12 = require("react");
1993
- var import_ink13 = require("ink");
2137
+ var import_react16 = require("react");
2138
+ var import_ink14 = require("ink");
1994
2139
  var import_jsx_runtime14 = require("react/jsx-runtime");
1995
2140
  var DEFAULT_MAX_VISIBLE = 3;
1996
2141
  function ListPicker({
@@ -2000,11 +2145,11 @@ function ListPicker({
2000
2145
  onCancel,
2001
2146
  maxVisible = DEFAULT_MAX_VISIBLE
2002
2147
  }) {
2003
- const [selectedIndex, setSelectedIndex] = (0, import_react12.useState)(0);
2004
- const [scrollOffset, setScrollOffset] = (0, import_react12.useState)(0);
2005
- const selectedRef = (0, import_react12.useRef)(0);
2006
- const resolvedRef = (0, import_react12.useRef)(false);
2007
- (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) => {
2008
2153
  if (resolvedRef.current) return;
2009
2154
  if (key.escape) {
2010
2155
  resolvedRef.current = true;
@@ -2035,19 +2180,19 @@ function ListPicker({
2035
2180
  }
2036
2181
  });
2037
2182
  if (items.length === 0) {
2038
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, {});
2183
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink14.Box, {});
2039
2184
  }
2040
2185
  const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
2041
2186
  const hasMore = scrollOffset + maxVisible < items.length;
2042
2187
  const hasLess = scrollOffset > 0;
2043
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2044
- 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: [
2045
2190
  " \u2191 ",
2046
2191
  scrollOffset,
2047
2192
  " more above"
2048
2193
  ] }),
2049
- visibleItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
2050
- 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: [
2051
2196
  " \u2193 ",
2052
2197
  items.length - scrollOffset - maxVisible,
2053
2198
  " more below"
@@ -2055,13 +2200,62 @@ function ListPicker({
2055
2200
  ] });
2056
2201
  }
2057
2202
 
2058
- // src/ui/App.tsx
2203
+ // src/ui/SessionPicker.tsx
2059
2204
  var import_jsx_runtime15 = require("react/jsx-runtime");
2060
- var EXIT_DELAY_MS = 500;
2061
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");
2062
2256
  function App(props) {
2063
- const [activeSessionId, setActiveSessionId] = (0, import_react13.useState)(props.resumeSessionId);
2064
- 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)(
2065
2259
  AppInner,
2066
2260
  {
2067
2261
  ...props,
@@ -2072,7 +2266,6 @@ function App(props) {
2072
2266
  );
2073
2267
  }
2074
2268
  function AppInner(props) {
2075
- const { exit } = (0, import_ink14.useApp)();
2076
2269
  const cwd = props.cwd;
2077
2270
  const {
2078
2271
  interactiveSession,
@@ -2100,83 +2293,32 @@ function AppInner(props) {
2100
2293
  sessionName: props.sessionName
2101
2294
  });
2102
2295
  const pluginCallbacks = usePluginCallbacks(cwd);
2103
- const [pendingModelId, setPendingModelId] = (0, import_react13.useState)(null);
2104
- const pendingModelChangeRef = (0, import_react13.useRef)(null);
2105
- const [showPluginTUI, setShowPluginTUI] = (0, import_react13.useState)(false);
2106
- const [showSessionPicker, setShowSessionPicker] = (0, import_react13.useState)(
2107
- props.resumeSessionId === "__picker__"
2108
- );
2109
- const [sessionName, setSessionName] = (0, import_react13.useState)(props.sessionName);
2110
- (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)(() => {
2111
2312
  const name = interactiveSession?.getName?.();
2112
2313
  if (name && !sessionName) setSessionName(name);
2113
2314
  }, [interactiveSession, sessionName]);
2114
- (0, import_react13.useEffect)(() => {
2315
+ (0, import_react17.useEffect)(() => {
2115
2316
  const title = sessionName ? `Robota \u2014 ${sessionName}` : "Robota";
2116
2317
  process.stdout.write(`\x1B]0;${title}\x07`);
2117
2318
  }, [sessionName]);
2118
- const handleSubmit = async (input) => {
2119
- await baseHandleSubmit(input);
2120
- const sideEffects = interactiveSession;
2121
- if (sideEffects._pendingModelId) {
2122
- const modelId = sideEffects._pendingModelId;
2123
- delete sideEffects._pendingModelId;
2124
- pendingModelChangeRef.current = modelId;
2125
- setPendingModelId(modelId);
2126
- return;
2127
- }
2128
- if (sideEffects._pendingLanguage) {
2129
- const lang = sideEffects._pendingLanguage;
2130
- delete sideEffects._pendingLanguage;
2131
- const settingsPath = getUserSettingsPath();
2132
- const settings = readSettings(settingsPath);
2133
- settings.language = lang;
2134
- writeSettings(settingsPath, settings);
2135
- addEntry(
2136
- (0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Language set to "${lang}". Restarting...`))
2137
- );
2138
- setTimeout(() => exit(), EXIT_DELAY_MS);
2139
- return;
2140
- }
2141
- if (sideEffects._resetRequested) {
2142
- delete sideEffects._resetRequested;
2143
- const settingsPath = getUserSettingsPath();
2144
- if (deleteSettings(settingsPath)) {
2145
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Deleted ${settingsPath}. Exiting...`)));
2146
- } else {
2147
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("No user settings found.")));
2148
- }
2149
- setTimeout(() => exit(), EXIT_DELAY_MS);
2150
- return;
2151
- }
2152
- if (sideEffects._exitRequested) {
2153
- delete sideEffects._exitRequested;
2154
- setTimeout(() => exit(), EXIT_DELAY_MS);
2155
- return;
2156
- }
2157
- if (sideEffects._triggerPluginTUI) {
2158
- delete sideEffects._triggerPluginTUI;
2159
- setShowPluginTUI(true);
2160
- return;
2161
- }
2162
- if (sideEffects._triggerResumePicker) {
2163
- delete sideEffects._triggerResumePicker;
2164
- setShowSessionPicker(true);
2165
- return;
2166
- }
2167
- if (sideEffects._sessionName) {
2168
- const name = sideEffects._sessionName;
2169
- delete sideEffects._sessionName;
2170
- interactiveSession.setName(name);
2171
- setSessionName(name);
2172
- return;
2173
- }
2174
- };
2175
- (0, import_ink14.useInput)(
2319
+ (0, import_ink16.useInput)(
2176
2320
  (_input, key) => {
2177
- if (key.escape && isThinking) {
2178
- handleAbort();
2179
- }
2321
+ if (key.escape && isThinking) handleAbort();
2180
2322
  },
2181
2323
  { isActive: !permissionRequest && !showPluginTUI && !showSessionPicker }
2182
2324
  );
@@ -2188,117 +2330,60 @@ function AppInner(props) {
2188
2330
  sessionId = session.getSessionId();
2189
2331
  } catch {
2190
2332
  }
2191
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", children: [
2192
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2193
- /* @__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: `
2194
2336
  ____ ___ ____ ___ _____ _
2195
2337
  | _ \\ / _ \\| __ ) / _ \\_ _|/ \\
2196
2338
  | |_) | | | | _ \\| | | || | / _ \\
2197
2339
  | _ <| |_| | |_) | |_| || |/ ___ \\
2198
2340
  |_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
2199
2341
  ` }),
2200
- /* @__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: [
2201
2343
  " v",
2202
2344
  props.version ?? "0.0.0"
2203
2345
  ] })
2204
2346
  ] }),
2205
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
2206
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageList, { history }),
2207
- (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 }) })
2208
2350
  ] }),
2209
- permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PermissionPrompt, { request: permissionRequest }),
2210
- 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)(
2211
2353
  ConfirmPrompt,
2212
2354
  {
2213
- message: `Change model to ${(0, import_agent_core4.getModelName)(pendingModelId)}? This will restart the session.`,
2214
- onSelect: (index) => {
2215
- setPendingModelId(null);
2216
- pendingModelChangeRef.current = null;
2217
- if (index === 0) {
2218
- try {
2219
- const settingsPath = getUserSettingsPath();
2220
- updateModelInSettings(settingsPath, pendingModelId);
2221
- addEntry(
2222
- (0, import_agent_core4.messageToHistoryEntry)(
2223
- (0, import_agent_core4.createSystemMessage)(
2224
- `Model changed to ${(0, import_agent_core4.getModelName)(pendingModelId)}. Restarting...`
2225
- )
2226
- )
2227
- );
2228
- setTimeout(() => exit(), EXIT_DELAY_MS);
2229
- } catch (err) {
2230
- addEntry(
2231
- (0, import_agent_core4.messageToHistoryEntry)(
2232
- (0, import_agent_core4.createSystemMessage)(
2233
- `Failed: ${err instanceof Error ? err.message : String(err)}`
2234
- )
2235
- )
2236
- );
2237
- }
2238
- } else {
2239
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Model change cancelled.")));
2240
- }
2241
- }
2355
+ message: `Change model to ${(0, import_agent_core5.getModelName)(pendingModelId)}? This will restart the session.`,
2356
+ onSelect: handleModelConfirm
2242
2357
  }
2243
2358
  ),
2244
- showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2359
+ showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2245
2360
  PluginTUI,
2246
2361
  {
2247
2362
  callbacks: pluginCallbacks,
2248
2363
  onClose: () => setShowPluginTUI(false),
2249
- 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)))
2250
2365
  }
2251
2366
  ),
2252
- showSessionPicker && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2253
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
2254
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2255
- ListPicker,
2256
- {
2257
- items: (props.sessionStore?.list() ?? []).filter((s) => s.cwd === props.cwd),
2258
- renderItem: (session, isSelected) => {
2259
- const lastMsg = session.messages.slice().reverse().find((m) => {
2260
- const msg = m;
2261
- return msg.role === "assistant" && msg.content;
2262
- });
2263
- const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
2264
- const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
2265
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { children: [
2266
- isSelected ? "> " : " ",
2267
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
2268
- " ",
2269
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { dimColor: true, children: new Date(session.updatedAt).toLocaleString(void 0, {
2270
- month: "short",
2271
- day: "numeric",
2272
- hour: "2-digit",
2273
- minute: "2-digit"
2274
- }) }),
2275
- " ",
2276
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
2277
- "msgs: ",
2278
- session.messages.length
2279
- ] }),
2280
- preview ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2281
- "\n ",
2282
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "gray", children: preview })
2283
- ] }) : null
2284
- ] });
2285
- },
2286
- onSelect: (session) => {
2287
- setShowSessionPicker(false);
2288
- props.onSessionSwitch(session.id);
2289
- },
2290
- onCancel: () => {
2291
- setShowSessionPicker(false);
2292
- addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Session resume cancelled.")));
2293
- }
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.")));
2294
2379
  }
2295
- )
2296
- ] }),
2297
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2380
+ }
2381
+ ),
2382
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2298
2383
  StatusBar,
2299
2384
  {
2300
2385
  permissionMode,
2301
- modelName: props.modelId ? (0, import_agent_core4.getModelName)(props.modelId) : "",
2386
+ modelName: props.modelId ? (0, import_agent_core5.getModelName)(props.modelId) : "",
2302
2387
  sessionId,
2303
2388
  messageCount: history.length,
2304
2389
  isThinking,
@@ -2308,7 +2393,7 @@ function AppInner(props) {
2308
2393
  sessionName
2309
2394
  }
2310
2395
  ),
2311
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2396
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2312
2397
  InputArea,
2313
2398
  {
2314
2399
  onSubmit: handleSubmit,
@@ -2320,12 +2405,12 @@ function AppInner(props) {
2320
2405
  sessionName
2321
2406
  }
2322
2407
  ),
2323
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: " " })
2408
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink16.Text, { children: " " })
2324
2409
  ] });
2325
2410
  }
2326
2411
 
2327
2412
  // src/ui/render.tsx
2328
- var import_jsx_runtime16 = require("react/jsx-runtime");
2413
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2329
2414
  function renderApp(options) {
2330
2415
  process.on("unhandledRejection", (reason) => {
2331
2416
  process.stderr.write(`
@@ -2339,7 +2424,7 @@ function renderApp(options) {
2339
2424
  if (process.stdin.isTTY && process.stdout.isTTY) {
2340
2425
  process.stdout.write("\x1B[?2004h");
2341
2426
  }
2342
- 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 }), {
2343
2428
  exitOnCtrlC: true
2344
2429
  });
2345
2430
  instance.waitUntilExit().then(() => {
@@ -2544,7 +2629,7 @@ async function startCli() {
2544
2629
  process.stderr.write("Print mode (-p) requires a prompt argument.\n");
2545
2630
  process.exit(1);
2546
2631
  }
2547
- const session = new import_agent_sdk3.InteractiveSession({
2632
+ const session = new import_agent_sdk4.InteractiveSession({
2548
2633
  cwd,
2549
2634
  provider,
2550
2635
  permissionMode: args.permissionMode ?? "bypassPermissions",