@meowlynxsea/koi 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -342737,7 +342737,7 @@ function DialogProvider(props) {
342737
342737
  }
342738
342738
 
342739
342739
  // src/tui/app.tsx
342740
- var import_react48 = __toESM(require_react(), 1);
342740
+ var import_react53 = __toESM(require_react(), 1);
342741
342741
 
342742
342742
  // src/tui/components/chat-panel.tsx
342743
342743
  var import_react19 = __toESM(require_react(), 1);
@@ -415433,23 +415433,40 @@ var InputBox = import_react20.forwardRef(function InputBox2({
415433
415433
  onSlashEmpty,
415434
415434
  focused = true,
415435
415435
  disabled = false,
415436
+ disabledHint,
415436
415437
  width,
415437
415438
  mode = "build",
415438
415439
  isBusy = false,
415439
- onModeSwitch
415440
+ onModeSwitch,
415441
+ externalEditorResult,
415442
+ onExternalEditorResultUsed
415440
415443
  }, ref) {
415441
415444
  const textareaRef = import_react20.useRef(null);
415442
415445
  const [historyIndex, setHistoryIndex] = import_react20.useState(-1);
415443
415446
  const [savedInput, setSavedInput] = import_react20.useState("");
415444
415447
  const getText = () => textareaRef.current?.editBuffer.getText() ?? "";
415448
+ import_react20.useEffect(() => {
415449
+ if (externalEditorResult !== undefined && externalEditorResult !== null) {
415450
+ textareaRef.current?.editBuffer.replaceText(externalEditorResult);
415451
+ setHistoryIndex(-1);
415452
+ setSavedInput("");
415453
+ onExternalEditorResultUsed?.();
415454
+ }
415455
+ }, [externalEditorResult, onExternalEditorResultUsed]);
415445
415456
  import_react20.useImperativeHandle(ref, () => ({
415446
415457
  clearInput: () => {
415447
415458
  textareaRef.current?.editBuffer.replaceText("");
415448
415459
  setHistoryIndex(-1);
415449
415460
  setSavedInput("");
415450
415461
  },
415451
- isInputEmpty: () => getText().trim() === ""
415452
- }), []);
415462
+ isInputEmpty: () => getText().trim() === "",
415463
+ getText,
415464
+ setText: (text) => {
415465
+ textareaRef.current?.editBuffer.replaceText(text);
415466
+ setHistoryIndex(-1);
415467
+ setSavedInput("");
415468
+ }
415469
+ }), [getText]);
415453
415470
  const navigateToPreviousHistory = import_react20.useCallback(() => {
415454
415471
  const history = getUserHistory();
415455
415472
  if (history.length === 0)
@@ -415691,7 +415708,11 @@ var InputBox = import_react20.forwardRef(function InputBox2({
415691
415708
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
415692
415709
  flexGrow: 1,
415693
415710
  height: 3,
415694
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("textarea", {
415711
+ children: disabled && disabledHint ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
415712
+ fg: "#6c6c7c",
415713
+ attributes: createTextAttributes({ dim: true }),
415714
+ children: disabledHint
415715
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("textarea", {
415695
415716
  ref: textareaRef,
415696
415717
  focused,
415697
415718
  showCursor: true,
@@ -473819,6 +473840,7 @@ var sessionTitle = "New Session";
473819
473840
  var providerConfigs = new Map;
473820
473841
  var currentModel = null;
473821
473842
  var auxiliaryModel = null;
473843
+ var externalEditor = null;
473822
473844
  var piAuthStorage = null;
473823
473845
  var piModelRegistry = null;
473824
473846
  var piSettingsManager = null;
@@ -473879,7 +473901,8 @@ function saveSettings() {
473879
473901
  sessionTitle,
473880
473902
  providers: Object.fromEntries(providerConfigs),
473881
473903
  currentModel,
473882
- auxiliaryModel
473904
+ auxiliaryModel,
473905
+ externalEditor: externalEditor ?? undefined
473883
473906
  };
473884
473907
  const json3 = JSON.stringify(data, null, 2);
473885
473908
  fs15.writeFileSync(SETTINGS_PATH, json3 + `
@@ -473907,6 +473930,9 @@ function loadSettings() {
473907
473930
  if (data.auxiliaryModel) {
473908
473931
  auxiliaryModel = data.auxiliaryModel;
473909
473932
  }
473933
+ if (data.externalEditor) {
473934
+ externalEditor = data.externalEditor;
473935
+ }
473910
473936
  syncCredentialsToPi();
473911
473937
  } catch {}
473912
473938
  }
@@ -473960,6 +473986,13 @@ function setAuxiliaryModel(ref6) {
473960
473986
  auxiliaryModel = ref6;
473961
473987
  saveSettings();
473962
473988
  }
473989
+ function getExternalEditor() {
473990
+ return externalEditor;
473991
+ }
473992
+ function setExternalEditor(path7) {
473993
+ externalEditor = path7;
473994
+ saveSettings();
473995
+ }
473963
473996
  function getAllProviders() {
473964
473997
  return getProviders();
473965
473998
  }
@@ -474931,7 +474964,6 @@ class BunPty extends EventEmitter13 {
474931
474964
  const args = process.platform === "win32" ? [] : ["--login"];
474932
474965
  const command = options4.command ?? shell;
474933
474966
  const commandArgs = options4.args ?? args;
474934
- const self2 = this;
474935
474967
  this.proc = Bun.spawn([command, ...commandArgs], {
474936
474968
  cwd: options4.cwd ?? process.cwd(),
474937
474969
  env: {
@@ -474944,12 +474976,12 @@ class BunPty extends EventEmitter13 {
474944
474976
  name: options4.name ?? "xterm-256color",
474945
474977
  cols: options4.cols ?? DEFAULT_COLS,
474946
474978
  rows: options4.rows ?? DEFAULT_ROWS,
474947
- data(_terminal, data) {
474948
- self2.emit("data", self2.textDecoder.decode(data));
474979
+ data: (_terminal, data) => {
474980
+ this.emit("data", this.textDecoder.decode(data));
474949
474981
  }
474950
474982
  },
474951
- onExit(_subprocess, exitCode, signalCode) {
474952
- self2.emit("exit", { exitCode: exitCode ?? 0, signal: signalCode ?? "" });
474983
+ onExit: (_subprocess, exitCode, signalCode) => {
474984
+ this.emit("exit", { exitCode: exitCode ?? 0, signal: signalCode !== null ? String(signalCode) : "" });
474953
474985
  }
474954
474986
  });
474955
474987
  this.pid = this.proc.pid;
@@ -475023,7 +475055,7 @@ class PtySession extends EventEmitter13 {
475023
475055
  resize(cols, rows) {
475024
475056
  try {
475025
475057
  this.pty.resize(cols, rows);
475026
- } catch (e) {}
475058
+ } catch {}
475027
475059
  }
475028
475060
  get isRunning() {
475029
475061
  return this._isRunning;
@@ -475289,7 +475321,6 @@ async function execBashWithPty(command, timeoutSec = 60, onData, signal, onTimeo
475289
475321
  let output = "";
475290
475322
  let timeoutHandle;
475291
475323
  let timedOut = false;
475292
- let ptySession;
475293
475324
  let resolvePromise;
475294
475325
  const ptyProcess = spawnPty({
475295
475326
  command: "bash",
@@ -475299,7 +475330,7 @@ async function execBashWithPty(command, timeoutSec = 60, onData, signal, onTimeo
475299
475330
  output += data;
475300
475331
  onData?.(data);
475301
475332
  });
475302
- ptySession = new PtySession(ptyId, ptyProcess, command);
475333
+ const ptySession = new PtySession(ptyId, ptyProcess, command);
475303
475334
  if (timeoutSec > 0) {
475304
475335
  timeoutHandle = setTimeout(() => {
475305
475336
  timedOut = true;
@@ -482649,7 +482680,7 @@ function generateLoremIpsum(targetTokens) {
482649
482680
  const sentenceLength = 10 + Math.floor(Math.random() * 11);
482650
482681
  let wordsInSentence = 0;
482651
482682
  for (let i = 0;i < sentenceLength && tokens < targetTokens; i++) {
482652
- const word = ONE_TOKEN_WORDS[Math.floor(Math.random() * ONE_TOKEN_WORDS.length)];
482683
+ const word = ONE_TOKEN_WORDS[Math.floor(Math.random() * ONE_TOKEN_WORDS.length)] ?? "";
482653
482684
  result += word;
482654
482685
  tokens++;
482655
482686
  wordsInSentence++;
@@ -483604,19 +483635,19 @@ var SOURCE_LABELS = {
483604
483635
  bundled: "Built-in Skills",
483605
483636
  mcp: "MCP Skills"
483606
483637
  };
483607
- function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483638
+ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill: _onInvokeSkill }) {
483608
483639
  const { width, height } = useTerminalDimensions();
483609
483640
  const inputRef = import_react21.useRef(null);
483610
483641
  const [filterText, setFilterText] = import_react21.useState("");
483611
483642
  const [selectedIndex, setSelectedIndex] = import_react21.useState(0);
483612
483643
  const [showDetails, setShowDetails] = import_react21.useState(false);
483613
483644
  const scrollOffsetRef = import_react21.useRef(0);
483614
- const panelWidth = Math.min(80, Math.max(50, Math.floor(width * 0.8)));
483615
- const panelHeight = Math.min(height - 4, 25);
483616
- const inputHeight = 1;
483617
- const separatorHeight = 1;
483618
- const detailsHeight = showDetails ? 8 : 0;
483619
- const listHeight = panelHeight - inputHeight - separatorHeight - detailsHeight - 2;
483645
+ const layout = import_react21.useMemo(() => {
483646
+ const panelWidth = Math.min(80, Math.max(50, Math.floor(width * 0.8)));
483647
+ const listHeight = Math.min(20, Math.max(3, Math.floor(height * 0.4)));
483648
+ const detailsHeight = showDetails ? 3 : 0;
483649
+ return { panelWidth, listHeight, detailsHeight };
483650
+ }, [width, height, showDetails]);
483620
483651
  const skillGroups = import_react21.useMemo(() => {
483621
483652
  const groups = new Map;
483622
483653
  for (const skill of skills) {
@@ -483691,23 +483722,8 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483691
483722
  if (newFlatIndex !== -1) {
483692
483723
  if (newFlatIndex < currentScroll) {
483693
483724
  scrollOffsetRef.current = newFlatIndex;
483694
- } else if (newFlatIndex > currentScroll + listHeight - 1) {
483695
- scrollOffsetRef.current = newFlatIndex - listHeight + 1;
483696
- }
483697
- }
483698
- return;
483699
- }
483700
- if (key.name === "return" || key.name === "enter") {
483701
- key.preventDefault();
483702
- key.stopPropagation();
483703
- if (selectedSkill) {
483704
- if (onInvokeSkill && selectedSkill.argumentHint) {
483705
- setShowDetails(true);
483706
- } else if (onInvokeSkill) {
483707
- onInvokeSkill(selectedSkill, "");
483708
- onClose();
483709
- } else {
483710
- onClose();
483725
+ } else if (newFlatIndex > currentScroll + layout.listHeight - 1) {
483726
+ scrollOffsetRef.current = newFlatIndex - layout.listHeight + 1;
483711
483727
  }
483712
483728
  }
483713
483729
  return;
@@ -483736,7 +483752,7 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483736
483752
  if (!isActive)
483737
483753
  return null;
483738
483754
  const effectiveScrollOffset = scrollOffsetRef.current;
483739
- const visibleItems = flatItems.slice(effectiveScrollOffset, effectiveScrollOffset + listHeight);
483755
+ const visibleItems = flatItems.slice(effectiveScrollOffset, effectiveScrollOffset + layout.listHeight);
483740
483756
  const renderDetails = () => {
483741
483757
  if (!showDetails || !selectedSkill)
483742
483758
  return null;
@@ -483748,18 +483764,17 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483748
483764
  selectedSkill.context && `Context: ${selectedSkill.context}`
483749
483765
  ].filter(Boolean);
483750
483766
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483751
- height: detailsHeight,
483767
+ height: layout.detailsHeight,
483752
483768
  flexDirection: "column",
483753
- marginTop: 1,
483754
483769
  children: [
483755
483770
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483756
483771
  height: 1,
483757
483772
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
483758
483773
  fg: "#6272a4",
483759
- children: "\u2500".repeat(panelWidth - 4)
483774
+ children: "\u2500".repeat(layout.panelWidth - 4)
483760
483775
  }, undefined, false, undefined, this)
483761
483776
  }, undefined, false, undefined, this),
483762
- details.map((line, idx) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483777
+ details.slice(0, 2).map((line, idx) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483763
483778
  height: 1,
483764
483779
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
483765
483780
  fg: "#8be9fd",
@@ -483780,8 +483795,7 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483780
483795
  alignItems: "center",
483781
483796
  justifyContent: "center",
483782
483797
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483783
- width: panelWidth,
483784
- height: panelHeight,
483798
+ width: layout.panelWidth,
483785
483799
  flexDirection: "column",
483786
483800
  borderStyle: "rounded",
483787
483801
  borderColor: "#6272a4",
@@ -483805,12 +483819,12 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483805
483819
  }, undefined, true, undefined, this),
483806
483820
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
483807
483821
  fg: "#6272a4",
483808
- children: "\u2191\u2193 navigate \xB7 Enter select \xB7 Tab details \xB7 Esc close"
483822
+ children: "\u2191\u2193 navigate \xB7 Tab details \xB7 Esc close"
483809
483823
  }, undefined, false, undefined, this)
483810
483824
  ]
483811
483825
  }, undefined, true, undefined, this),
483812
483826
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483813
- height: inputHeight,
483827
+ height: 1,
483814
483828
  marginTop: 1,
483815
483829
  children: [
483816
483830
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
@@ -483824,7 +483838,7 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483824
483838
  showCursor: true,
483825
483839
  height: 1,
483826
483840
  wrapMode: "none",
483827
- width: panelWidth - 10,
483841
+ width: layout.panelWidth - 10,
483828
483842
  textColor: "#f8f8f2",
483829
483843
  backgroundColor: "#44475a",
483830
483844
  onContentChange: handleContentChange
@@ -483832,15 +483846,15 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483832
483846
  ]
483833
483847
  }, undefined, true, undefined, this),
483834
483848
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483835
- height: separatorHeight,
483849
+ height: 1,
483836
483850
  marginTop: 1,
483837
483851
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
483838
483852
  fg: "#6272a4",
483839
- children: "\u2500".repeat(panelWidth - 2)
483853
+ children: "\u2500".repeat(layout.panelWidth - 2)
483840
483854
  }, undefined, false, undefined, this)
483841
483855
  }, undefined, false, undefined, this),
483842
483856
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483843
- height: listHeight,
483857
+ height: layout.listHeight,
483844
483858
  flexDirection: "column",
483845
483859
  overflow: "hidden",
483846
483860
  children: [
@@ -483867,11 +483881,8 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483867
483881
  children: [
483868
483882
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
483869
483883
  fg: "#ffb86c",
483870
- children: [
483871
- "/",
483872
- item.skill.name
483873
- ]
483874
- }, undefined, true, undefined, this),
483884
+ children: item.skill.name
483885
+ }, undefined, false, undefined, this),
483875
483886
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
483876
483887
  fg: "#6272a4",
483877
483888
  children: [
@@ -483886,7 +483897,7 @@ function SkillsMenu({ isActive, onClose, skills, onInvokeSkill }) {
483886
483897
  return null;
483887
483898
  }),
483888
483899
  flatItems.length === 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
483889
- height: listHeight,
483900
+ height: layout.listHeight,
483890
483901
  alignItems: "center",
483891
483902
  justifyContent: "center",
483892
483903
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
@@ -486159,8 +486170,9 @@ function EditPendingModal({
486159
486170
  type: type3,
486160
486171
  onConfirm,
486161
486172
  onCancel,
486162
- width = 70
486173
+ width: widthProp
486163
486174
  }) {
486175
+ const { width } = useTerminalDimensions();
486164
486176
  const textareaRef = import_react24.useRef(null);
486165
486177
  import_react24.useEffect(() => {
486166
486178
  if (isActive && textareaRef.current) {
@@ -486177,6 +486189,7 @@ function EditPendingModal({
486177
486189
  if (!isActive)
486178
486190
  return null;
486179
486191
  const label = type3 === "sheer" ? "Edit Sheer" : "Edit Queued";
486192
+ const modalWidth = Math.min(widthProp ?? 70, Math.max(40, Math.floor(width * 0.85)));
486180
486193
  const handleConfirm = () => {
486181
486194
  const text = textareaRef.current?.editBuffer.getText() ?? "";
486182
486195
  if (text.trim()) {
@@ -486200,7 +486213,7 @@ function EditPendingModal({
486200
486213
  backgroundColor: "#1a1a2e",
486201
486214
  paddingX: 2,
486202
486215
  paddingY: 1,
486203
- width,
486216
+ width: modalWidth,
486204
486217
  children: [
486205
486218
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486206
486219
  alignSelf: "center",
@@ -486215,7 +486228,7 @@ function EditPendingModal({
486215
486228
  onSubmit: handleConfirm,
486216
486229
  focused: true,
486217
486230
  disabled: false,
486218
- width: width - 4
486231
+ width: modalWidth - 4
486219
486232
  }, undefined, false, undefined, this)
486220
486233
  }, undefined, false, undefined, this),
486221
486234
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -486442,6 +486455,7 @@ function Divider({
486442
486455
  }
486443
486456
  function SideBar({
486444
486457
  width = 28,
486458
+ height = 50,
486445
486459
  workingDir = "/",
486446
486460
  sessionTitle: sessionTitle2 = "New Session",
486447
486461
  modelName = "Not configured",
@@ -486460,95 +486474,137 @@ function SideBar({
486460
486474
  const hasMoreSubagents = subagents.length > visibleSubagents.length;
486461
486475
  const visibleMonitors = monitors.slice(0, 8);
486462
486476
  const hasMoreMonitors = monitors.length > visibleMonitors.length;
486463
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486477
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("scrollbox", {
486478
+ scrollY: true,
486479
+ scrollX: false,
486464
486480
  width,
486465
- flexDirection: "column",
486466
- paddingLeft: 1,
486467
- children: [
486468
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486469
- children: " "
486470
- }, undefined, false, undefined, this),
486471
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486472
- width: usableWidth,
486473
- flexDirection: "row",
486474
- justifyContent: "space-between",
486475
- children: [
486476
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486477
- attributes: createTextAttributes({ bold: true }),
486478
- fg: "#5a6a7a",
486479
- children: "Meowdream"
486480
- }, undefined, false, undefined, this),
486481
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486482
- fg: "#7a8a9a",
486483
- children: VERSION6
486484
- }, undefined, false, undefined, this)
486485
- ]
486486
- }, undefined, true, undefined, this),
486487
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486488
- children: " "
486489
- }, undefined, false, undefined, this),
486490
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486491
- width: usableWidth
486492
- }, undefined, false, undefined, this),
486493
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486494
- width: usableWidth,
486495
- char: "\xB7",
486496
- fg: "#c5cdd5"
486497
- }, undefined, false, undefined, this),
486498
- KOI_LOGO.map((line, i) => {
486499
- const color = GRADIENT_STOPS[Math.min(i, GRADIENT_STOPS.length - 1)];
486500
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486501
- fg: color,
486502
- wrapMode: "none",
486503
- truncate: true,
486504
- children: line.slice(0, usableWidth)
486505
- }, i, false, undefined, this);
486506
- }),
486507
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486508
- width: usableWidth,
486509
- char: "\xB7",
486510
- fg: "#c5cdd5"
486511
- }, undefined, false, undefined, this),
486512
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486513
- width: usableWidth
486514
- }, undefined, false, undefined, this),
486515
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486516
- children: " "
486517
- }, undefined, false, undefined, this),
486518
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486519
- attributes: createTextAttributes({ bold: true }),
486520
- fg: "#5a6a7a",
486521
- children: sessionTitle2
486522
- }, undefined, false, undefined, this),
486523
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486524
- children: " "
486525
- }, undefined, false, undefined, this),
486526
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486527
- fg: "#8a9aaa",
486528
- children: abbreviatePath(workingDir, usableWidth)
486529
- }, undefined, false, undefined, this),
486530
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486531
- children: " "
486532
- }, undefined, false, undefined, this),
486533
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486534
- attributes: createTextAttributes({ bold: true }),
486535
- fg: "#5a6a7a",
486536
- children: modelName
486537
- }, undefined, false, undefined, this),
486538
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486539
- fg: "#8a9aaa",
486540
- children: provider
486541
- }, undefined, false, undefined, this),
486542
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486543
- fg: "#8a9aaa",
486544
- children: `${contextUsage} ${tokenCount} ${cost}`
486545
- }, undefined, false, undefined, this),
486546
- (() => {
486547
- const mcpSummary = getMcpStatusSummary();
486548
- const mcpConnections = getMcpConnections();
486549
- if (mcpSummary.total === 0)
486550
- return null;
486551
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486481
+ height,
486482
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486483
+ width,
486484
+ flexDirection: "column",
486485
+ paddingLeft: 1,
486486
+ children: [
486487
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486488
+ children: " "
486489
+ }, undefined, false, undefined, this),
486490
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486491
+ width: usableWidth,
486492
+ flexDirection: "row",
486493
+ justifyContent: "space-between",
486494
+ children: [
486495
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486496
+ attributes: createTextAttributes({ bold: true }),
486497
+ fg: "#5a6a7a",
486498
+ children: "Meowdream"
486499
+ }, undefined, false, undefined, this),
486500
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486501
+ fg: "#7a8a9a",
486502
+ children: VERSION6
486503
+ }, undefined, false, undefined, this)
486504
+ ]
486505
+ }, undefined, true, undefined, this),
486506
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486507
+ children: " "
486508
+ }, undefined, false, undefined, this),
486509
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486510
+ width: usableWidth
486511
+ }, undefined, false, undefined, this),
486512
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486513
+ width: usableWidth,
486514
+ char: "\xB7",
486515
+ fg: "#c5cdd5"
486516
+ }, undefined, false, undefined, this),
486517
+ KOI_LOGO.map((line, i) => {
486518
+ const color = GRADIENT_STOPS[Math.min(i, GRADIENT_STOPS.length - 1)];
486519
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486520
+ fg: color,
486521
+ wrapMode: "none",
486522
+ truncate: true,
486523
+ children: line.slice(0, usableWidth)
486524
+ }, i, false, undefined, this);
486525
+ }),
486526
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486527
+ width: usableWidth,
486528
+ char: "\xB7",
486529
+ fg: "#c5cdd5"
486530
+ }, undefined, false, undefined, this),
486531
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Divider, {
486532
+ width: usableWidth
486533
+ }, undefined, false, undefined, this),
486534
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486535
+ children: " "
486536
+ }, undefined, false, undefined, this),
486537
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486538
+ attributes: createTextAttributes({ bold: true }),
486539
+ fg: "#5a6a7a",
486540
+ children: sessionTitle2
486541
+ }, undefined, false, undefined, this),
486542
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486543
+ children: " "
486544
+ }, undefined, false, undefined, this),
486545
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486546
+ fg: "#8a9aaa",
486547
+ children: abbreviatePath(workingDir, usableWidth)
486548
+ }, undefined, false, undefined, this),
486549
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486550
+ children: " "
486551
+ }, undefined, false, undefined, this),
486552
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486553
+ attributes: createTextAttributes({ bold: true }),
486554
+ fg: "#5a6a7a",
486555
+ children: modelName
486556
+ }, undefined, false, undefined, this),
486557
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486558
+ fg: "#8a9aaa",
486559
+ children: provider
486560
+ }, undefined, false, undefined, this),
486561
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486562
+ fg: "#8a9aaa",
486563
+ children: `${contextUsage} ${tokenCount} ${cost}`
486564
+ }, undefined, false, undefined, this),
486565
+ (() => {
486566
+ const mcpSummary = getMcpStatusSummary();
486567
+ const mcpConnections = getMcpConnections();
486568
+ if (mcpSummary.total === 0)
486569
+ return null;
486570
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486571
+ children: [
486572
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486573
+ children: " "
486574
+ }, undefined, false, undefined, this),
486575
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486576
+ attributes: createTextAttributes({ bold: true }),
486577
+ fg: "#5a6a7a",
486578
+ children: [
486579
+ "MCP (",
486580
+ mcpSummary.connected,
486581
+ "/",
486582
+ mcpSummary.total,
486583
+ ")"
486584
+ ]
486585
+ }, undefined, true, undefined, this),
486586
+ Array.from(mcpConnections.entries()).map(([name, connection]) => {
486587
+ const color = MCP_STATUS_COLORS[connection.status] ?? "#6c6c7c";
486588
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486589
+ flexDirection: "row",
486590
+ gap: 1,
486591
+ children: [
486592
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486593
+ fg: color,
486594
+ children: "\u25CF"
486595
+ }, undefined, false, undefined, this),
486596
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486597
+ text: name,
486598
+ width: Math.max(1, usableWidth - 4),
486599
+ fg: "#8a9aaa"
486600
+ }, undefined, false, undefined, this)
486601
+ ]
486602
+ }, name, true, undefined, this);
486603
+ })
486604
+ ]
486605
+ }, undefined, true, undefined, this);
486606
+ })(),
486607
+ visibleSubagents.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486552
486608
  children: [
486553
486609
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486554
486610
  children: " "
@@ -486557,15 +486613,13 @@ function SideBar({
486557
486613
  attributes: createTextAttributes({ bold: true }),
486558
486614
  fg: "#5a6a7a",
486559
486615
  children: [
486560
- "MCP (",
486561
- mcpSummary.connected,
486562
- "/",
486563
- mcpSummary.total,
486616
+ "Subagents (",
486617
+ subagents.length,
486564
486618
  ")"
486565
486619
  ]
486566
486620
  }, undefined, true, undefined, this),
486567
- Array.from(mcpConnections.entries()).map(([name, connection]) => {
486568
- const color = MCP_STATUS_COLORS[connection.status] ?? "#6c6c7c";
486621
+ visibleSubagents.map((sa) => {
486622
+ const color = SUBAGENT_STATUS_COLORS[sa.status] ?? "#fbbf24";
486569
486623
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486570
486624
  flexDirection: "row",
486571
486625
  gap: 1,
@@ -486575,133 +486629,99 @@ function SideBar({
486575
486629
  children: "\u25CF"
486576
486630
  }, undefined, false, undefined, this),
486577
486631
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486578
- text: name,
486632
+ text: sa.description,
486579
486633
  width: Math.max(1, usableWidth - 4),
486580
486634
  fg: "#8a9aaa"
486581
486635
  }, undefined, false, undefined, this)
486582
486636
  ]
486583
- }, name, true, undefined, this);
486584
- })
486637
+ }, sa.id, true, undefined, this);
486638
+ }),
486639
+ hasMoreSubagents && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486640
+ fg: "#9aa5b0",
486641
+ children: `\u2026 and ${subagents.length - visibleSubagents.length} more`
486642
+ }, undefined, false, undefined, this)
486585
486643
  ]
486586
- }, undefined, true, undefined, this);
486587
- })(),
486588
- visibleSubagents.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486589
- children: [
486590
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486591
- children: " "
486592
- }, undefined, false, undefined, this),
486593
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486594
- attributes: createTextAttributes({ bold: true }),
486595
- fg: "#5a6a7a",
486596
- children: [
486597
- "Subagents (",
486598
- subagents.length,
486599
- ")"
486600
- ]
486601
- }, undefined, true, undefined, this),
486602
- visibleSubagents.map((sa) => {
486603
- const color = SUBAGENT_STATUS_COLORS[sa.status] ?? "#fbbf24";
486604
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486605
- flexDirection: "row",
486606
- gap: 1,
486607
- children: [
486608
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486609
- fg: color,
486610
- children: "\u25CF"
486611
- }, undefined, false, undefined, this),
486612
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486613
- text: sa.description,
486614
- width: Math.max(1, usableWidth - 4),
486615
- fg: "#8a9aaa"
486616
- }, undefined, false, undefined, this)
486617
- ]
486618
- }, sa.id, true, undefined, this);
486619
- }),
486620
- hasMoreSubagents && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486621
- fg: "#9aa5b0",
486622
- children: `\u2026 and ${subagents.length - visibleSubagents.length} more`
486623
- }, undefined, false, undefined, this)
486624
- ]
486625
- }, undefined, true, undefined, this),
486626
- visibleTasks.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486627
- children: [
486628
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486629
- children: " "
486630
- }, undefined, false, undefined, this),
486631
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486632
- attributes: createTextAttributes({ bold: true }),
486633
- fg: "#5a6a7a",
486634
- children: [
486635
- "Tasks (",
486636
- tasks.length,
486637
- ")"
486638
- ]
486639
- }, undefined, true, undefined, this),
486640
- visibleTasks.map((task) => {
486641
- const color = TASK_STATUS_COLORS[task.status] ?? "#fbbf24";
486642
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486643
- flexDirection: "row",
486644
- gap: 1,
486644
+ }, undefined, true, undefined, this),
486645
+ visibleTasks.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486646
+ children: [
486647
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486648
+ children: " "
486649
+ }, undefined, false, undefined, this),
486650
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486651
+ attributes: createTextAttributes({ bold: true }),
486652
+ fg: "#5a6a7a",
486645
486653
  children: [
486646
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486647
- fg: color,
486648
- children: "\u25CF"
486649
- }, undefined, false, undefined, this),
486650
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486651
- text: task.content,
486652
- width: Math.max(1, usableWidth - 4),
486653
- fg: "#8a9aaa"
486654
- }, undefined, false, undefined, this)
486654
+ "Tasks (",
486655
+ tasks.length,
486656
+ ")"
486655
486657
  ]
486656
- }, task.id, true, undefined, this);
486657
- }),
486658
- hasMoreTasks && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486659
- fg: "#9aa5b0",
486660
- children: `\u2026 and ${tasks.length - visibleTasks.length} more`
486661
- }, undefined, false, undefined, this)
486662
- ]
486663
- }, undefined, true, undefined, this),
486664
- visibleMonitors.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486665
- children: [
486666
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486667
- children: " "
486668
- }, undefined, false, undefined, this),
486669
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486670
- attributes: createTextAttributes({ bold: true }),
486671
- fg: "#5a6a7a",
486672
- children: [
486673
- "Monitors (",
486674
- monitors.length,
486675
- ")"
486676
- ]
486677
- }, undefined, true, undefined, this),
486678
- visibleMonitors.map((mon) => {
486679
- const color = MONITOR_STATUS_COLORS[mon.status] ?? "#fbbf24";
486680
- const displayText = mon.lastOutput ? `${mon.description}: ${mon.lastOutput.slice(0, 20)}` : mon.description;
486681
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486682
- flexDirection: "row",
486683
- gap: 1,
486658
+ }, undefined, true, undefined, this),
486659
+ visibleTasks.map((task) => {
486660
+ const color = TASK_STATUS_COLORS[task.status] ?? "#fbbf24";
486661
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486662
+ flexDirection: "row",
486663
+ gap: 1,
486664
+ children: [
486665
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486666
+ fg: color,
486667
+ children: "\u25CF"
486668
+ }, undefined, false, undefined, this),
486669
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486670
+ text: task.content,
486671
+ width: Math.max(1, usableWidth - 4),
486672
+ fg: "#8a9aaa"
486673
+ }, undefined, false, undefined, this)
486674
+ ]
486675
+ }, task.id, true, undefined, this);
486676
+ }),
486677
+ hasMoreTasks && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486678
+ fg: "#9aa5b0",
486679
+ children: `\u2026 and ${tasks.length - visibleTasks.length} more`
486680
+ }, undefined, false, undefined, this)
486681
+ ]
486682
+ }, undefined, true, undefined, this),
486683
+ visibleMonitors.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
486684
+ children: [
486685
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486686
+ children: " "
486687
+ }, undefined, false, undefined, this),
486688
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486689
+ attributes: createTextAttributes({ bold: true }),
486690
+ fg: "#5a6a7a",
486684
486691
  children: [
486685
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486686
- fg: color,
486687
- children: "\u25CF"
486688
- }, undefined, false, undefined, this),
486689
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486690
- text: displayText,
486691
- width: Math.max(1, usableWidth - 4),
486692
- fg: "#8a9aaa"
486693
- }, undefined, false, undefined, this)
486692
+ "Monitors (",
486693
+ monitors.length,
486694
+ ")"
486694
486695
  ]
486695
- }, mon.id, true, undefined, this);
486696
- }),
486697
- hasMoreMonitors && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486698
- fg: "#9aa5b0",
486699
- children: `\u2026 and ${monitors.length - visibleMonitors.length} more`
486700
- }, undefined, false, undefined, this)
486701
- ]
486702
- }, undefined, true, undefined, this)
486703
- ]
486704
- }, undefined, true, undefined, this);
486696
+ }, undefined, true, undefined, this),
486697
+ visibleMonitors.map((mon) => {
486698
+ const color = MONITOR_STATUS_COLORS[mon.status] ?? "#fbbf24";
486699
+ const displayText = mon.lastOutput ? `${mon.description}: ${mon.lastOutput.slice(0, 20)}` : mon.description;
486700
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486701
+ flexDirection: "row",
486702
+ gap: 1,
486703
+ children: [
486704
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486705
+ fg: color,
486706
+ children: "\u25CF"
486707
+ }, undefined, false, undefined, this),
486708
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FixedWidthText, {
486709
+ text: displayText,
486710
+ width: Math.max(1, usableWidth - 4),
486711
+ fg: "#8a9aaa"
486712
+ }, undefined, false, undefined, this)
486713
+ ]
486714
+ }, mon.id, true, undefined, this);
486715
+ }),
486716
+ hasMoreMonitors && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486717
+ fg: "#9aa5b0",
486718
+ children: `\u2026 and ${monitors.length - visibleMonitors.length} more`
486719
+ }, undefined, false, undefined, this)
486720
+ ]
486721
+ }, undefined, true, undefined, this)
486722
+ ]
486723
+ }, undefined, true, undefined, this)
486724
+ }, undefined, false, undefined, this);
486705
486725
  }
486706
486726
 
486707
486727
  // src/tui/components/exit-modal.tsx
@@ -486744,6 +486764,7 @@ function Button({
486744
486764
  }, undefined, false, undefined, this);
486745
486765
  }
486746
486766
  function ExitModal({ isActive, onConfirm, onCancel }) {
486767
+ const { width } = useTerminalDimensions();
486747
486768
  useKeyboard((key) => {
486748
486769
  if (!isActive)
486749
486770
  return;
@@ -486755,6 +486776,7 @@ function ExitModal({ isActive, onConfirm, onCancel }) {
486755
486776
  });
486756
486777
  if (!isActive)
486757
486778
  return null;
486779
+ const modalWidth = Math.min(35, Math.max(20, Math.floor(width * 0.4)));
486758
486780
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
486759
486781
  position: "absolute",
486760
486782
  top: 0,
@@ -486772,6 +486794,7 @@ function ExitModal({ isActive, onConfirm, onCancel }) {
486772
486794
  paddingY: 1,
486773
486795
  flexDirection: "column",
486774
486796
  alignItems: "center",
486797
+ width: modalWidth,
486775
486798
  children: [
486776
486799
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
486777
486800
  attributes: createTextAttributes({ bold: true }),
@@ -487026,6 +487049,7 @@ function CommandPanel({ isActive, onClose, commands }) {
487026
487049
  // src/tui/components/rename-modal.tsx
487027
487050
  var import_react31 = __toESM(require_react(), 1);
487028
487051
  function RenameModal({ isActive, currentTitle, onConfirm, onCancel }) {
487052
+ const { width } = useTerminalDimensions();
487029
487053
  const inputRef = import_react31.useRef(null);
487030
487054
  const [value2, setValue] = import_react31.useState(currentTitle);
487031
487055
  import_react31.useEffect(() => {
@@ -487060,6 +487084,7 @@ function RenameModal({ isActive, currentTitle, onConfirm, onCancel }) {
487060
487084
  };
487061
487085
  if (!isActive)
487062
487086
  return null;
487087
+ const modalWidth = Math.min(50, Math.max(30, Math.floor(width * 0.6)));
487063
487088
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
487064
487089
  position: "absolute",
487065
487090
  top: 0,
@@ -487070,7 +487095,7 @@ function RenameModal({ isActive, currentTitle, onConfirm, onCancel }) {
487070
487095
  alignItems: "center",
487071
487096
  justifyContent: "center",
487072
487097
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
487073
- width: 50,
487098
+ width: modalWidth,
487074
487099
  flexDirection: "column",
487075
487100
  borderStyle: "rounded",
487076
487101
  borderColor: "#4a4a5a",
@@ -487153,7 +487178,9 @@ function ConnectModal({ isActive, onClose }) {
487153
487178
  const [filterText, setFilterText] = import_react33.useState("");
487154
487179
  const inputRef = import_react33.useRef(null);
487155
487180
  const searchRef = import_react33.useRef(null);
487156
- const listHeight = Math.min(10, Math.floor(height * 0.35));
487181
+ const layout = import_react33.useMemo(() => ({
487182
+ listHeight: Math.min(10, Math.max(3, Math.floor(height * 0.35)))
487183
+ }), [height]);
487157
487184
  const query2 = filterText;
487158
487185
  const filteredProviders = import_react33.useMemo(() => {
487159
487186
  if (!query2)
@@ -487244,10 +487271,10 @@ function ConnectModal({ isActive, onClose }) {
487244
487271
  import_react33.useEffect(() => {
487245
487272
  if (selectedProviderIndex < scrollOffset) {
487246
487273
  setScrollOffset(selectedProviderIndex);
487247
- } else if (selectedProviderIndex >= scrollOffset + listHeight) {
487248
- setScrollOffset(selectedProviderIndex - listHeight + 1);
487274
+ } else if (selectedProviderIndex >= scrollOffset + layout.listHeight) {
487275
+ setScrollOffset(selectedProviderIndex - layout.listHeight + 1);
487249
487276
  }
487250
- }, [selectedProviderIndex, listHeight, scrollOffset]);
487277
+ }, [selectedProviderIndex, layout.listHeight, scrollOffset]);
487251
487278
  import_react33.useEffect(() => {
487252
487279
  if (selectedProviderIndex >= filteredProviders.length && filteredProviders.length > 0) {
487253
487280
  setSelectedProviderIndex(filteredProviders.length - 1);
@@ -487343,7 +487370,7 @@ function ConnectModal({ isActive, onClose }) {
487343
487370
  const existingConfig = selectedProvider ? getProviderConfig(selectedProvider) : undefined;
487344
487371
  if (!isActive)
487345
487372
  return null;
487346
- const visibleProviders = filteredProviders.slice(scrollOffset, scrollOffset + listHeight);
487373
+ const visibleProviders = filteredProviders.slice(scrollOffset, scrollOffset + layout.listHeight);
487347
487374
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
487348
487375
  position: "absolute",
487349
487376
  top: 0,
@@ -487395,7 +487422,7 @@ function ConnectModal({ isActive, onClose }) {
487395
487422
  }, undefined, false, undefined, this)
487396
487423
  }, undefined, false, undefined, this),
487397
487424
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
487398
- height: listHeight,
487425
+ height: layout.listHeight,
487399
487426
  flexDirection: "column",
487400
487427
  overflow: "hidden",
487401
487428
  marginTop: 1,
@@ -487652,7 +487679,9 @@ function ModelModal({
487652
487679
  const [filterText, setFilterText] = import_react35.useState("");
487653
487680
  const scrollOffsetRef = import_react35.useRef(0);
487654
487681
  const inputRef = import_react35.useRef(null);
487655
- const listHeight = Math.min(12, Math.floor(height * 0.4));
487682
+ const layout = import_react35.useMemo(() => ({
487683
+ listHeight: Math.min(12, Math.max(3, Math.floor(height * 0.4)))
487684
+ }), [height]);
487656
487685
  const primaryModel = getCurrentModel();
487657
487686
  const auxiliaryModel2 = getAuxiliaryModel();
487658
487687
  import_react35.useLayoutEffect(() => {
@@ -487745,8 +487774,8 @@ function ModelModal({
487745
487774
  if (newFlatIndex !== -1) {
487746
487775
  if (newFlatIndex < scrollOffsetRef.current) {
487747
487776
  newScrollOffset = newFlatIndex;
487748
- } else if (newFlatIndex > scrollOffsetRef.current + listHeight - 1) {
487749
- newScrollOffset = newFlatIndex - listHeight + 1;
487777
+ } else if (newFlatIndex > scrollOffsetRef.current + layout.listHeight - 1) {
487778
+ newScrollOffset = newFlatIndex - layout.listHeight + 1;
487750
487779
  }
487751
487780
  }
487752
487781
  scrollOffsetRef.current = newScrollOffset;
@@ -487774,7 +487803,7 @@ function ModelModal({
487774
487803
  });
487775
487804
  if (!isActive)
487776
487805
  return null;
487777
- const visibleItems = flatItems.slice(effectiveScrollOffset, effectiveScrollOffset + listHeight);
487806
+ const visibleItems = flatItems.slice(effectiveScrollOffset, effectiveScrollOffset + layout.listHeight);
487778
487807
  const isCurrent = (provider, modelId) => {
487779
487808
  const target2 = activeTab === "primary" ? primaryModel : auxiliaryModel2;
487780
487809
  return target2?.provider === provider && target2?.modelId === modelId;
@@ -487880,7 +487909,7 @@ function ModelModal({
487880
487909
  }, undefined, false, undefined, this)
487881
487910
  }, undefined, false, undefined, this),
487882
487911
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
487883
- height: listHeight,
487912
+ height: layout.listHeight,
487884
487913
  flexDirection: "column",
487885
487914
  overflow: "hidden",
487886
487915
  marginTop: 1,
@@ -487991,8 +488020,10 @@ function SessionModal({
487991
488020
  const { width, height } = useTerminalDimensions();
487992
488021
  const [selectedIndex, setSelectedIndex] = import_react37.useState(0);
487993
488022
  const [scrollOffset, setScrollOffset] = import_react37.useState(0);
487994
- const panelWidth = Math.min(70, Math.max(50, Math.floor(width * 0.7)));
487995
- const listHeight = Math.min(14, Math.floor(height * 0.5));
488023
+ const layout = import_react37.useMemo(() => ({
488024
+ panelWidth: Math.min(70, Math.max(50, Math.floor(width * 0.7))),
488025
+ listHeight: Math.min(14, Math.max(3, Math.floor(height * 0.5)))
488026
+ }), [width, height]);
487996
488027
  import_react37.useEffect(() => {
487997
488028
  if (isActive) {
487998
488029
  setSelectedIndex(0);
@@ -488016,10 +488047,10 @@ function SessionModal({
488016
488047
  return;
488017
488048
  if (safeIndex < scrollOffset) {
488018
488049
  setScrollOffset(safeIndex);
488019
- } else if (safeIndex >= scrollOffset + listHeight) {
488020
- setScrollOffset(safeIndex - listHeight + 1);
488050
+ } else if (safeIndex >= scrollOffset + layout.listHeight) {
488051
+ setScrollOffset(safeIndex - layout.listHeight + 1);
488021
488052
  }
488022
- }, [safeIndex, listHeight, scrollOffset]);
488053
+ }, [safeIndex, layout.listHeight, scrollOffset]);
488023
488054
  useKeyboard((key) => {
488024
488055
  if (!isActive || keyboardDisabled)
488025
488056
  return;
@@ -488056,7 +488087,7 @@ function SessionModal({
488056
488087
  });
488057
488088
  if (!isActive)
488058
488089
  return null;
488059
- const visibleSessions = sessions.slice(scrollOffset, scrollOffset + listHeight);
488090
+ const visibleSessions = sessions.slice(scrollOffset, scrollOffset + layout.listHeight);
488060
488091
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488061
488092
  position: "absolute",
488062
488093
  top: 0,
@@ -488067,7 +488098,7 @@ function SessionModal({
488067
488098
  alignItems: "center",
488068
488099
  justifyContent: "center",
488069
488100
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488070
- width: panelWidth,
488101
+ width: layout.panelWidth,
488071
488102
  flexDirection: "column",
488072
488103
  borderStyle: "rounded",
488073
488104
  borderColor: "#4a4a5a",
@@ -488092,7 +488123,7 @@ function SessionModal({
488092
488123
  ]
488093
488124
  }, undefined, true, undefined, this),
488094
488125
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488095
- height: listHeight,
488126
+ height: layout.listHeight,
488096
488127
  flexDirection: "column",
488097
488128
  overflow: "hidden",
488098
488129
  marginTop: 1,
@@ -488108,8 +488139,9 @@ function SessionModal({
488108
488139
  const flatIndex = scrollOffset + idx;
488109
488140
  const isSelected = flatIndex === safeIndex;
488110
488141
  const isCurrent = s.id === currentSessionId;
488111
- const safeTitle = String(s.title ?? "Untitled Session");
488142
+ const safeTitle = s.title ?? "Untitled Session";
488112
488143
  const safeMessageCount = typeof s.messageCount === "number" ? s.messageCount : 0;
488144
+ const messageCountDisplay = safeMessageCount > 0 ? safeMessageCount.toString() : "0";
488113
488145
  const safeUpdatedAt = s.updatedAt instanceof Date && !isNaN(s.updatedAt.getTime()) ? s.updatedAt : new Date;
488114
488146
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488115
488147
  height: 1,
@@ -488123,7 +488155,7 @@ function SessionModal({
488123
488155
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
488124
488156
  fg: isSelected ? "#ff79c6" : isCurrent ? "#00f5ff" : "#f8f8f2",
488125
488157
  attributes: createTextAttributes({ bold: isCurrent }),
488126
- width: Math.max(1, panelWidth - 24),
488158
+ width: Math.max(1, layout.panelWidth - 24),
488127
488159
  truncate: true,
488128
488160
  children: [
488129
488161
  isCurrent ? "\u25CF " : " ",
@@ -488138,7 +488170,7 @@ function SessionModal({
488138
488170
  fg: "#6c6c7c",
488139
488171
  attributes: createTextAttributes({ dim: true }),
488140
488172
  children: [
488141
- String(safeMessageCount),
488173
+ messageCountDisplay,
488142
488174
  "msg"
488143
488175
  ]
488144
488176
  }, undefined, true, undefined, this),
@@ -488225,6 +488257,7 @@ function ConfirmModal({
488225
488257
  onConfirm,
488226
488258
  onCancel
488227
488259
  }) {
488260
+ const { width } = useTerminalDimensions();
488228
488261
  useKeyboard((key) => {
488229
488262
  if (!isActive)
488230
488263
  return;
@@ -488236,13 +488269,14 @@ function ConfirmModal({
488236
488269
  });
488237
488270
  if (!isActive)
488238
488271
  return null;
488272
+ const modalWidth = Math.min(40, Math.max(25, Math.floor(width * 0.5)));
488239
488273
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488240
488274
  position: "absolute",
488241
488275
  top: 0,
488242
488276
  left: 0,
488243
488277
  width: "100%",
488244
488278
  height: "100%",
488245
- backgroundColor: "#00000080",
488279
+ backgroundColor: "#00000090",
488246
488280
  alignItems: "center",
488247
488281
  justifyContent: "center",
488248
488282
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -488253,6 +488287,7 @@ function ConfirmModal({
488253
488287
  paddingY: 1,
488254
488288
  flexDirection: "column",
488255
488289
  alignItems: "center",
488290
+ width: modalWidth,
488256
488291
  children: [
488257
488292
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
488258
488293
  attributes: createTextAttributes({ bold: true }),
@@ -488366,6 +488401,7 @@ function ProgressBar({ completed, total }) {
488366
488401
  function ConnectingModal({ isActive, progress }) {
488367
488402
  if (!isActive)
488368
488403
  return null;
488404
+ const { width, height } = useTerminalDimensions();
488369
488405
  const defaultProgress = progress ?? {
488370
488406
  total: 0,
488371
488407
  completed: 0,
@@ -488375,6 +488411,8 @@ function ConnectingModal({ isActive, progress }) {
488375
488411
  const { total, completed, currentServer, status, error: error55 } = defaultProgress;
488376
488412
  const isComplete = completed >= total && total > 0;
488377
488413
  const percentage = total > 0 ? Math.round(completed / total * 100) : 0;
488414
+ const modalWidth = Math.min(60, Math.max(40, Math.floor(width * 0.7)));
488415
+ const modalHeight = Math.min(height - 4, 12);
488378
488416
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488379
488417
  position: "absolute",
488380
488418
  top: 0,
@@ -488391,8 +488429,8 @@ function ConnectingModal({ isActive, progress }) {
488391
488429
  paddingX: 3,
488392
488430
  paddingY: 2,
488393
488431
  flexDirection: "column",
488394
- minWidth: 50,
488395
- maxWidth: 60,
488432
+ width: modalWidth,
488433
+ height: modalHeight,
488396
488434
  children: [
488397
488435
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488398
488436
  flexDirection: "row",
@@ -488491,7 +488529,7 @@ function ConnectingModal({ isActive, progress }) {
488491
488529
  }
488492
488530
 
488493
488531
  // src/tui/components/fork-modal.tsx
488494
- var import_react42 = __toESM(require_react(), 1);
488532
+ var import_react43 = __toESM(require_react(), 1);
488495
488533
  function isMessageEntry(entry) {
488496
488534
  return typeof entry === "object" && entry !== null && "type" in entry && entry["type"] === "message" && "message" in entry && typeof entry["message"] === "object" && entry["message"] !== null;
488497
488535
  }
@@ -488594,13 +488632,15 @@ function ForkModal({
488594
488632
  onFork
488595
488633
  }) {
488596
488634
  const { width, height } = useTerminalDimensions();
488597
- const [selectedIndex, setSelectedIndex] = import_react42.useState(0);
488598
- const [scrollOffset, setScrollOffset] = import_react42.useState(0);
488599
- const [rows, setRows] = import_react42.useState([]);
488600
- const panelWidth = Math.min(80, Math.max(52, Math.floor(width * 0.8)));
488601
- const listHeight = Math.min(16, Math.floor(height * 0.5));
488602
- const contentWidth = Math.max(1, panelWidth - 4);
488603
- import_react42.useEffect(() => {
488635
+ const [selectedIndex, setSelectedIndex] = import_react43.useState(0);
488636
+ const [scrollOffset, setScrollOffset] = import_react43.useState(0);
488637
+ const [rows, setRows] = import_react43.useState([]);
488638
+ const layout = import_react43.useMemo(() => ({
488639
+ panelWidth: Math.min(80, Math.max(52, Math.floor(width * 0.8))),
488640
+ listHeight: Math.min(16, Math.max(3, Math.floor(height * 0.5))),
488641
+ contentWidth: Math.max(1, Math.min(80, Math.max(52, Math.floor(width * 0.8))) - 4)
488642
+ }), [width, height]);
488643
+ import_react43.useEffect(() => {
488604
488644
  if (!isActive || !session) {
488605
488645
  setRows([]);
488606
488646
  return;
@@ -488615,22 +488655,22 @@ function ForkModal({
488615
488655
  setSelectedIndex(0);
488616
488656
  }
488617
488657
  }, [isActive, session]);
488618
- const selectableRows = import_react42.useMemo(() => rows.filter((r) => r.isUserMessage), [rows]);
488619
- const safeIndex = import_react42.useMemo(() => {
488658
+ const selectableRows = import_react43.useMemo(() => rows.filter((r) => r.isUserMessage), [rows]);
488659
+ const safeIndex = import_react43.useMemo(() => {
488620
488660
  if (selectableRows.length === 0)
488621
488661
  return -1;
488622
488662
  return Math.max(0, Math.min(selectedIndex, selectableRows.length - 1));
488623
488663
  }, [selectedIndex, selectableRows.length]);
488624
488664
  const selectedRow = safeIndex >= 0 ? selectableRows[safeIndex] : null;
488625
- import_react42.useEffect(() => {
488665
+ import_react43.useEffect(() => {
488626
488666
  if (!selectedRow) {
488627
488667
  setScrollOffset(0);
488628
488668
  return;
488629
488669
  }
488630
488670
  const flatIndex = selectedRow.index;
488631
- const maxOffset = Math.max(0, rows.length - listHeight);
488671
+ const maxOffset = Math.max(0, rows.length - layout.listHeight);
488632
488672
  setScrollOffset(Math.max(0, Math.min(flatIndex - 4, maxOffset)));
488633
- }, [selectedRow, listHeight, rows.length]);
488673
+ }, [selectedRow, layout.listHeight, rows.length]);
488634
488674
  useKeyboard((key) => {
488635
488675
  if (!isActive)
488636
488676
  return;
@@ -488655,7 +488695,7 @@ function ForkModal({
488655
488695
  });
488656
488696
  if (!isActive)
488657
488697
  return null;
488658
- const visibleRows = rows.slice(scrollOffset, scrollOffset + listHeight);
488698
+ const visibleRows = rows.slice(scrollOffset, scrollOffset + layout.listHeight);
488659
488699
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488660
488700
  position: "absolute",
488661
488701
  top: 0,
@@ -488667,7 +488707,7 @@ function ForkModal({
488667
488707
  justifyContent: "center",
488668
488708
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488669
488709
  alignSelf: "center",
488670
- width: panelWidth,
488710
+ width: layout.panelWidth,
488671
488711
  flexDirection: "column",
488672
488712
  borderStyle: "rounded",
488673
488713
  borderColor: "#4a4a5a",
@@ -488687,7 +488727,7 @@ function ForkModal({
488687
488727
  children: "Select a user message to branch from:"
488688
488728
  }, undefined, false, undefined, this),
488689
488729
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488690
- height: listHeight,
488730
+ height: layout.listHeight,
488691
488731
  flexDirection: "column",
488692
488732
  overflow: "hidden",
488693
488733
  marginTop: 1,
@@ -488701,8 +488741,8 @@ function ForkModal({
488701
488741
  }, undefined, false, undefined, this),
488702
488742
  visibleRows.map((row) => {
488703
488743
  const isSelected = selectedRow?.index === row.index;
488704
- const prefix = getVisiblePrefix(row, contentWidth);
488705
- const availableWidth = Math.max(1, contentWidth - prefix.length);
488744
+ const prefix = getVisiblePrefix(row, layout.contentWidth);
488745
+ const availableWidth = Math.max(1, layout.contentWidth - prefix.length);
488706
488746
  const displayText = row.displayText.length > availableWidth ? row.displayText.slice(0, availableWidth - 1) + "\u2026" : row.displayText;
488707
488747
  const fgColor = row.isUserMessage ? isSelected ? "#ff79c6" : "#f8f8f2" : "#6c6c7c";
488708
488748
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -488749,7 +488789,7 @@ function ForkModal({
488749
488789
  }
488750
488790
 
488751
488791
  // src/tui/components/image-preview-modal.tsx
488752
- var import_react44 = __toESM(require_react(), 1);
488792
+ var import_react45 = __toESM(require_react(), 1);
488753
488793
  function ImagePreviewContent({ rows }) {
488754
488794
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488755
488795
  flexDirection: "column",
@@ -488769,8 +488809,8 @@ function ImagePreviewModal({
488769
488809
  terminalWidth,
488770
488810
  terminalHeight
488771
488811
  }) {
488772
- const [rows, setRows] = import_react44.useState(null);
488773
- const [loading, setLoading] = import_react44.useState(false);
488812
+ const [rows, setRows] = import_react45.useState(null);
488813
+ const [loading, setLoading] = import_react45.useState(false);
488774
488814
  useKeyboard((key) => {
488775
488815
  if (!isActive)
488776
488816
  return;
@@ -488782,7 +488822,7 @@ function ImagePreviewModal({
488782
488822
  const modalH = Math.max(10, Math.floor(terminalHeight * 0.8));
488783
488823
  const imgMaxW = Math.max(10, modalW - 4);
488784
488824
  const imgMaxH = Math.max(4, modalH - 4);
488785
- import_react44.useEffect(() => {
488825
+ import_react45.useEffect(() => {
488786
488826
  if (!isActive) {
488787
488827
  setRows(null);
488788
488828
  setLoading(false);
@@ -488878,35 +488918,394 @@ function ImagePreviewModal({
488878
488918
  }, undefined, false, undefined, this);
488879
488919
  }
488880
488920
 
488921
+ // src/tui/components/external-editor-modal.tsx
488922
+ var import_react47 = __toESM(require_react(), 1);
488923
+ function ExternalEditorModal({
488924
+ isActive,
488925
+ onClose,
488926
+ currentPath,
488927
+ onSave
488928
+ }) {
488929
+ const { width, height } = useTerminalDimensions();
488930
+ const inputRef = import_react47.useRef(null);
488931
+ const [editorPath, setEditorPath] = import_react47.useState(currentPath ?? "");
488932
+ const layout = import_react47.useMemo(() => ({
488933
+ panelWidth: Math.min(60, Math.max(40, Math.floor(width * 0.7))),
488934
+ maxSuggestions: Math.max(2, Math.floor(height * 0.25))
488935
+ }), [width, height]);
488936
+ import_react47.useEffect(() => {
488937
+ if (isActive) {
488938
+ setEditorPath(currentPath ?? "");
488939
+ setTimeout(() => {
488940
+ const ta = inputRef.current;
488941
+ if (ta) {
488942
+ ta.editBuffer.replaceText(currentPath ?? "");
488943
+ ta.focus();
488944
+ }
488945
+ }, 10);
488946
+ }
488947
+ }, [isActive, currentPath]);
488948
+ useKeyboard((key) => {
488949
+ if (!isActive)
488950
+ return;
488951
+ if (key.name === "escape") {
488952
+ key.preventDefault();
488953
+ key.stopPropagation();
488954
+ onClose();
488955
+ return;
488956
+ }
488957
+ if (key.name === "return") {
488958
+ key.preventDefault();
488959
+ key.stopPropagation();
488960
+ const path7 = editorPath.trim();
488961
+ if (path7) {
488962
+ onSave(path7);
488963
+ }
488964
+ return;
488965
+ }
488966
+ });
488967
+ const handleContentChange = () => {
488968
+ const text = inputRef.current?.editBuffer.getText() ?? "";
488969
+ setEditorPath(text);
488970
+ };
488971
+ if (!isActive)
488972
+ return null;
488973
+ const suggestedEditors = [
488974
+ { cmd: "code --wait", desc: "VS Code" },
488975
+ { cmd: "vim", desc: "Vim" },
488976
+ { cmd: "nano", desc: "Nano" },
488977
+ { cmd: "emacs", desc: "Emacs" },
488978
+ { cmd: "subl -w", desc: "Sublime Text" },
488979
+ { cmd: "hx", desc: "Helix" }
488980
+ ];
488981
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488982
+ position: "absolute",
488983
+ top: 0,
488984
+ left: 0,
488985
+ width: "100%",
488986
+ height: "100%",
488987
+ backgroundColor: "#00000080",
488988
+ alignItems: "center",
488989
+ justifyContent: "center",
488990
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
488991
+ width: layout.panelWidth,
488992
+ flexDirection: "column",
488993
+ borderStyle: "rounded",
488994
+ borderColor: "#4a4a5a",
488995
+ backgroundColor: "#1a1a2e",
488996
+ paddingX: 2,
488997
+ paddingY: 1,
488998
+ children: [
488999
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489000
+ attributes: createTextAttributes({ bold: true }),
489001
+ fg: "#ff79c6",
489002
+ children: "External Editor Configuration"
489003
+ }, undefined, false, undefined, this),
489004
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489005
+ marginTop: 1,
489006
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489007
+ fg: "#6c6c7c",
489008
+ children: "Enter the command to launch your preferred editor."
489009
+ }, undefined, false, undefined, this)
489010
+ }, undefined, false, undefined, this),
489011
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489012
+ marginTop: 1,
489013
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489014
+ fg: "#6c6c7c",
489015
+ children: "The editor should wait for the file to be closed before returning."
489016
+ }, undefined, false, undefined, this)
489017
+ }, undefined, false, undefined, this),
489018
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489019
+ marginTop: 1,
489020
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489021
+ fg: "#f8f8f2",
489022
+ children: "Editor command:"
489023
+ }, undefined, false, undefined, this)
489024
+ }, undefined, false, undefined, this),
489025
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489026
+ height: 1,
489027
+ marginTop: 1,
489028
+ backgroundColor: "#16213e",
489029
+ paddingX: 1,
489030
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("textarea", {
489031
+ ref: inputRef,
489032
+ initialValue: "",
489033
+ focused: isActive,
489034
+ showCursor: true,
489035
+ height: 1,
489036
+ wrapMode: "none",
489037
+ textColor: "#f8f8f2",
489038
+ backgroundColor: "#16213e",
489039
+ onContentChange: handleContentChange
489040
+ }, undefined, false, undefined, this)
489041
+ }, undefined, false, undefined, this),
489042
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489043
+ marginTop: 1,
489044
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489045
+ fg: "#6c6c7c",
489046
+ attributes: createTextAttributes({ dim: true }),
489047
+ children: "Suggestions:"
489048
+ }, undefined, false, undefined, this)
489049
+ }, undefined, false, undefined, this),
489050
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("scrollbox", {
489051
+ height: layout.maxSuggestions,
489052
+ flexDirection: "column",
489053
+ overflow: "hidden",
489054
+ children: suggestedEditors.slice(0, layout.maxSuggestions).map((editor) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489055
+ height: 1,
489056
+ flexDirection: "row",
489057
+ children: [
489058
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489059
+ fg: "#50fa7b",
489060
+ children: editor.cmd
489061
+ }, undefined, false, undefined, this),
489062
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489063
+ fg: "#6c6c7c",
489064
+ marginLeft: 2,
489065
+ children: editor.desc
489066
+ }, undefined, false, undefined, this)
489067
+ ]
489068
+ }, editor.cmd, true, undefined, this))
489069
+ }, undefined, false, undefined, this),
489070
+ currentPath && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489071
+ marginTop: 1,
489072
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489073
+ fg: "#f1fa8c",
489074
+ children: [
489075
+ "Current: ",
489076
+ currentPath
489077
+ ]
489078
+ }, undefined, true, undefined, this)
489079
+ }, undefined, false, undefined, this),
489080
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489081
+ marginTop: 2,
489082
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489083
+ fg: "#6c6c7c",
489084
+ attributes: createTextAttributes({ dim: true }),
489085
+ children: "Enter Confirm Esc Cancel"
489086
+ }, undefined, false, undefined, this)
489087
+ }, undefined, false, undefined, this),
489088
+ currentPath && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489089
+ marginTop: 1,
489090
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489091
+ fg: "#ff5555",
489092
+ onMouseUp: (e) => {
489093
+ e.stopPropagation();
489094
+ onSave("");
489095
+ },
489096
+ children: "Click here to clear the editor setting"
489097
+ }, undefined, false, undefined, this)
489098
+ }, undefined, false, undefined, this)
489099
+ ]
489100
+ }, undefined, true, undefined, this)
489101
+ }, undefined, false, undefined, this);
489102
+ }
489103
+
489104
+ // src/tui/components/alert-modal.tsx
489105
+ var import_react49 = __toESM(require_react(), 1);
489106
+ function Button3({
489107
+ label,
489108
+ bgColor,
489109
+ hoverBgColor,
489110
+ isActive,
489111
+ onClick
489112
+ }) {
489113
+ const [hover, setHover] = import_react49.useState(false);
489114
+ const currentBg = hover ? hoverBgColor : bgColor;
489115
+ const handleMouseUp = (e) => {
489116
+ if (isActive) {
489117
+ e.stopPropagation();
489118
+ onClick();
489119
+ }
489120
+ };
489121
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489122
+ paddingX: 2,
489123
+ paddingY: 0,
489124
+ backgroundColor: currentBg,
489125
+ onMouseUp: handleMouseUp,
489126
+ onMouseOver: () => isActive && setHover(true),
489127
+ onMouseOut: () => isActive && setHover(false),
489128
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489129
+ fg: "white",
489130
+ attributes: createTextAttributes({ bold: true }),
489131
+ children: label
489132
+ }, undefined, false, undefined, this)
489133
+ }, undefined, false, undefined, this);
489134
+ }
489135
+ function AlertModal({
489136
+ isActive,
489137
+ title,
489138
+ message,
489139
+ onClose
489140
+ }) {
489141
+ const { width } = useTerminalDimensions();
489142
+ useKeyboard((key) => {
489143
+ if (!isActive)
489144
+ return;
489145
+ if (key.name === "return" || key.name === "escape" || key.name === "o") {
489146
+ onClose();
489147
+ }
489148
+ });
489149
+ if (!isActive)
489150
+ return null;
489151
+ const messageLines = message.split(`
489152
+ `);
489153
+ const maxLineLength = Math.max(...messageLines.map((l) => l.length));
489154
+ const modalWidth = Math.min(70, Math.max(40, Math.min(maxLineLength + 10, Math.floor(width * 0.7))));
489155
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489156
+ position: "absolute",
489157
+ top: 0,
489158
+ left: 0,
489159
+ width: "100%",
489160
+ height: "100%",
489161
+ backgroundColor: "#00000090",
489162
+ alignItems: "center",
489163
+ justifyContent: "center",
489164
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489165
+ borderStyle: "rounded",
489166
+ borderColor: "#4a4a5a",
489167
+ backgroundColor: "#1a1a2e",
489168
+ paddingX: 2,
489169
+ paddingY: 1,
489170
+ flexDirection: "column",
489171
+ alignItems: "center",
489172
+ width: modalWidth,
489173
+ children: [
489174
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489175
+ attributes: createTextAttributes({ bold: true }),
489176
+ fg: "#fb7185",
489177
+ children: title
489178
+ }, undefined, false, undefined, this),
489179
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489180
+ marginTop: 1,
489181
+ flexDirection: "column",
489182
+ children: messageLines.map((line, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489183
+ fg: "#f8f8f2",
489184
+ wrapMode: "none",
489185
+ children: line
489186
+ }, i, false, undefined, this))
489187
+ }, undefined, false, undefined, this),
489188
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489189
+ marginTop: 2,
489190
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Button3, {
489191
+ label: " OK ",
489192
+ bgColor: "#2dd4bf",
489193
+ hoverBgColor: "#5eead4",
489194
+ isActive,
489195
+ onClick: onClose
489196
+ }, undefined, false, undefined, this)
489197
+ }, undefined, false, undefined, this),
489198
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
489199
+ marginTop: 1,
489200
+ fg: "#6c6c7c",
489201
+ attributes: createTextAttributes({ dim: true }),
489202
+ children: "Enter/O/ESC to close"
489203
+ }, undefined, false, undefined, this)
489204
+ ]
489205
+ }, undefined, true, undefined, this)
489206
+ }, undefined, false, undefined, this);
489207
+ }
489208
+
489209
+ // src/tui/components/external-editor.ts
489210
+ import { spawn as spawn15 } from "child_process";
489211
+ import fs22 from "fs";
489212
+ import path27 from "path";
489213
+ import os18 from "os";
489214
+ function openExternalEditor(renderer, editorPath, initialContent, onComplete) {
489215
+ const tmpDir = os18.tmpdir();
489216
+ const tmpFile = path27.join(tmpDir, `koi-prompt-${Date.now()}.txt`);
489217
+ let rendererResumed = false;
489218
+ const resumeRenderer = () => {
489219
+ if (!rendererResumed) {
489220
+ rendererResumed = true;
489221
+ try {
489222
+ renderer.resume();
489223
+ } catch {}
489224
+ }
489225
+ };
489226
+ const cleanupTempFile = () => {
489227
+ try {
489228
+ fs22.unlinkSync(tmpFile);
489229
+ } catch {}
489230
+ };
489231
+ const complete2 = (result, error55) => {
489232
+ resumeRenderer();
489233
+ cleanupTempFile();
489234
+ onComplete(result, error55);
489235
+ };
489236
+ try {
489237
+ fs22.writeFileSync(tmpFile, initialContent, "utf-8");
489238
+ renderer.suspend();
489239
+ const parts = editorPath.trim().split(/\s+/);
489240
+ const cmd = parts[0];
489241
+ const args = parts.slice(1);
489242
+ const child = spawn15(cmd, [...args, tmpFile], {
489243
+ stdio: "inherit",
489244
+ env: { ...process.env }
489245
+ });
489246
+ const timeout = setTimeout(() => {
489247
+ try {
489248
+ child.kill("SIGTERM");
489249
+ } catch {}
489250
+ }, 120000);
489251
+ child.on("close", (code2) => {
489252
+ clearTimeout(timeout);
489253
+ if (code2 === 0) {
489254
+ try {
489255
+ const result = fs22.readFileSync(tmpFile, "utf-8");
489256
+ complete2(result);
489257
+ } catch {
489258
+ complete2(null, { message: "Failed to read edited file" });
489259
+ }
489260
+ } else {
489261
+ complete2(null, {
489262
+ code: code2 ?? undefined,
489263
+ message: `Editor exited with code ${code2}`
489264
+ });
489265
+ }
489266
+ });
489267
+ child.on("error", (err) => {
489268
+ clearTimeout(timeout);
489269
+ complete2(null, {
489270
+ message: `Failed to launch editor: ${err.message}. Make sure "${cmd}" is installed and in your PATH.`
489271
+ });
489272
+ });
489273
+ } catch (err) {
489274
+ complete2(null, {
489275
+ message: `Failed to start external editor: ${err instanceof Error ? err.message : String(err)}`
489276
+ });
489277
+ }
489278
+ }
489279
+
488881
489280
  // src/tui/components/mcp/MCPSettings.tsx
488882
- var import_react46 = __toESM(require_react(), 1);
489281
+ var import_react51 = __toESM(require_react(), 1);
488883
489282
  init_config2();
488884
489283
  init_connection_manager();
488885
489284
  function MCPSettings({ isActive, onClose, onMcpChange }) {
488886
489285
  const { width } = useTerminalDimensions();
488887
- const [view, setView] = import_react46.useState("list");
488888
- const [selectedIndex, setSelectedIndex] = import_react46.useState(0);
488889
- const [servers, setServers] = import_react46.useState([]);
488890
- const [message, setMessage] = import_react46.useState(null);
488891
- const [editName, setEditName] = import_react46.useState("");
488892
- const [editType, setEditType] = import_react46.useState("stdio");
488893
- const [editCommand, setEditCommand] = import_react46.useState("");
488894
- const [editArgs, setEditArgs] = import_react46.useState("");
488895
- const [editUrl, setEditUrl] = import_react46.useState("");
488896
- const [editHeaders, setEditHeaders] = import_react46.useState("");
488897
- const nameRef = import_react46.useRef(null);
488898
- const commandRef = import_react46.useRef(null);
488899
- const argsRef = import_react46.useRef(null);
488900
- const urlRef = import_react46.useRef(null);
488901
- const headersRef = import_react46.useRef(null);
489286
+ const [view, setView] = import_react51.useState("list");
489287
+ const [selectedIndex, setSelectedIndex] = import_react51.useState(0);
489288
+ const [servers, setServers] = import_react51.useState([]);
489289
+ const [message, setMessage] = import_react51.useState(null);
489290
+ const [editName, setEditName] = import_react51.useState("");
489291
+ const [editType, setEditType] = import_react51.useState("stdio");
489292
+ const [editCommand, setEditCommand] = import_react51.useState("");
489293
+ const [editArgs, setEditArgs] = import_react51.useState("");
489294
+ const [editUrl, setEditUrl] = import_react51.useState("");
489295
+ const [editHeaders, setEditHeaders] = import_react51.useState("");
489296
+ const nameRef = import_react51.useRef(null);
489297
+ const commandRef = import_react51.useRef(null);
489298
+ const argsRef = import_react51.useRef(null);
489299
+ const urlRef = import_react51.useRef(null);
489300
+ const headersRef = import_react51.useRef(null);
488902
489301
  const panelWidth = Math.min(75, Math.max(50, Math.floor(width * 0.8)));
488903
- const refreshServers = import_react46.useCallback(() => {
489302
+ const refreshServers = import_react51.useCallback(() => {
488904
489303
  loadMcpConfigs();
488905
489304
  const configs = getAllMcpConfigs();
488906
489305
  setServers(Array.from(configs.keys()));
488907
489306
  setSelectedIndex(0);
488908
489307
  }, []);
488909
- import_react46.useEffect(() => {
489308
+ import_react51.useEffect(() => {
488910
489309
  if (isActive) {
488911
489310
  refreshServers();
488912
489311
  setView("list");
@@ -489460,13 +489859,13 @@ function CustomPromptContent({
489460
489859
  width,
489461
489860
  height
489462
489861
  }) {
489463
- const taRef = import_react48.useRef(null);
489862
+ const taRef = import_react53.useRef(null);
489464
489863
  const handleSubmit = () => {
489465
489864
  resolve4(taRef.current?.editBuffer.getText() ?? "");
489466
489865
  };
489467
489866
  const contentWidth = Math.min(70, Math.max(20, width - 8));
489468
489867
  const questionLines = wrapText(question, contentWidth - 4, 0);
489469
- const keyBindings = import_react48.useMemo(() => [{ name: "return", action: "submit" }], []);
489868
+ const keyBindings = import_react53.useMemo(() => [{ name: "return", action: "submit" }], []);
489470
489869
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
489471
489870
  flexDirection: "column",
489472
489871
  alignSelf: "center",
@@ -489538,41 +489937,45 @@ function CustomPromptContent({
489538
489937
  ]
489539
489938
  }, undefined, true, undefined, this);
489540
489939
  }
489541
- function App({ onExit }) {
489940
+ function App({ renderer, onExit }) {
489542
489941
  const { width, height } = useTerminalDimensions();
489543
- const [showExitModal, setShowExitModal] = import_react48.useState(false);
489544
- const [showCommandPanel, setShowCommandPanel] = import_react48.useState(false);
489545
- const [showRenameModal, setShowRenameModal] = import_react48.useState(false);
489546
- const [showConnectModal, setShowConnectModal] = import_react48.useState(false);
489547
- const [showModelModal, setShowModelModal] = import_react48.useState(false);
489548
- const [showSessionModal, setShowSessionModal] = import_react48.useState(false);
489549
- const [showForkModal, setShowForkModal] = import_react48.useState(false);
489550
- const [showDeleteConfirm, setShowDeleteConfirm] = import_react48.useState(false);
489551
- const [sessionToDelete, setSessionToDelete] = import_react48.useState(null);
489552
- const [showImageModal, setShowImageModal] = import_react48.useState(false);
489553
- const [imageModalUrl, setImageModalUrl] = import_react48.useState("");
489554
- const [showEditPendingModal, setShowEditPendingModal] = import_react48.useState(false);
489555
- const [editPendingType, setEditPendingType] = import_react48.useState(null);
489556
- const [editPendingIndex, setEditPendingIndex] = import_react48.useState(-1);
489557
- const [editPendingText, setEditPendingText] = import_react48.useState("");
489558
- const [currentModel2, setCurrentModelState] = import_react48.useState(getCurrentModel);
489559
- const [, setAuxiliaryModelState] = import_react48.useState(getAuxiliaryModel);
489560
- const [sidebarContextUsage, setSidebarContextUsage] = import_react48.useState("0%");
489561
- const [sidebarTokenCount, setSidebarTokenCount] = import_react48.useState("(0)");
489562
- const [sidebarCost, setSidebarCost] = import_react48.useState("$0.00");
489563
- const [tasks, setTasks] = import_react48.useState([]);
489564
- const [subagents, setSubagents] = import_react48.useState([]);
489565
- const [monitors, setMonitors] = import_react48.useState([]);
489566
- const [yoloMode2, setYoloMode2] = import_react48.useState(false);
489567
- const [agentMode, setAgentMode2] = import_react48.useState(getAgentMode());
489568
- const [showMCPSettings, setShowMCPSettings] = import_react48.useState(false);
489569
- const [showSkillsModal, setShowSkillsModal] = import_react48.useState(false);
489570
- const [skills, setSkills] = import_react48.useState([]);
489571
- import_react48.useEffect(() => {
489942
+ const [showExitModal, setShowExitModal] = import_react53.useState(false);
489943
+ const [showCommandPanel, setShowCommandPanel] = import_react53.useState(false);
489944
+ const [showRenameModal, setShowRenameModal] = import_react53.useState(false);
489945
+ const [showConnectModal, setShowConnectModal] = import_react53.useState(false);
489946
+ const [showModelModal, setShowModelModal] = import_react53.useState(false);
489947
+ const [showSessionModal, setShowSessionModal] = import_react53.useState(false);
489948
+ const [showForkModal, setShowForkModal] = import_react53.useState(false);
489949
+ const [showDeleteConfirm, setShowDeleteConfirm] = import_react53.useState(false);
489950
+ const [sessionToDelete, setSessionToDelete] = import_react53.useState(null);
489951
+ const [showImageModal, setShowImageModal] = import_react53.useState(false);
489952
+ const [imageModalUrl, setImageModalUrl] = import_react53.useState("");
489953
+ const [showEditPendingModal, setShowEditPendingModal] = import_react53.useState(false);
489954
+ const [editPendingType, setEditPendingType] = import_react53.useState(null);
489955
+ const [editPendingIndex, setEditPendingIndex] = import_react53.useState(-1);
489956
+ const [editPendingText, setEditPendingText] = import_react53.useState("");
489957
+ const [currentModel2, setCurrentModelState] = import_react53.useState(getCurrentModel);
489958
+ const [, setAuxiliaryModelState] = import_react53.useState(getAuxiliaryModel);
489959
+ const [sidebarContextUsage, setSidebarContextUsage] = import_react53.useState("0%");
489960
+ const [sidebarTokenCount, setSidebarTokenCount] = import_react53.useState("(0)");
489961
+ const [sidebarCost, setSidebarCost] = import_react53.useState("$0.00");
489962
+ const [tasks, setTasks] = import_react53.useState([]);
489963
+ const [subagents, setSubagents] = import_react53.useState([]);
489964
+ const [monitors, setMonitors] = import_react53.useState([]);
489965
+ const [yoloMode2, setYoloMode2] = import_react53.useState(false);
489966
+ const [agentMode, setAgentMode2] = import_react53.useState(getAgentMode());
489967
+ const [showMCPSettings, setShowMCPSettings] = import_react53.useState(false);
489968
+ const [showSkillsModal, setShowSkillsModal] = import_react53.useState(false);
489969
+ const [skills, setSkills] = import_react53.useState([]);
489970
+ const [showExternalEditorModal, setShowExternalEditorModal] = import_react53.useState(false);
489971
+ const [externalEditorBusy, setExternalEditorBusy] = import_react53.useState(false);
489972
+ const [externalEditorResult, setExternalEditorResult] = import_react53.useState(undefined);
489973
+ const [externalEditorError, setExternalEditorError] = import_react53.useState(null);
489974
+ import_react53.useEffect(() => {
489572
489975
  setYoloMode(yoloMode2);
489573
489976
  }, [yoloMode2]);
489574
489977
  const dialog = useDialog();
489575
- import_react48.useEffect(() => {
489978
+ import_react53.useEffect(() => {
489576
489979
  (async () => {
489577
489980
  initBundledSkills();
489578
489981
  await loadAllSkills(process.cwd());
@@ -489612,7 +490015,7 @@ function App({ onExit }) {
489612
490015
  addPlanMessage,
489613
490016
  syncAgentMode
489614
490017
  } = useKoiAgent();
489615
- const handleInvokeSkill = import_react48.useCallback(async (skill, args) => {
490018
+ const handleInvokeSkill = import_react53.useCallback(async (skill, args) => {
489616
490019
  const content = await invokeSkill(skill, args, session);
489617
490020
  const skillPrompt = extractTextFromContent(content);
489618
490021
  if (skillPrompt) {
@@ -489620,34 +490023,34 @@ function App({ onExit }) {
489620
490023
  }
489621
490024
  setShowSkillsModal(false);
489622
490025
  }, [session, prompt]);
489623
- const applyAgentMode = import_react48.useCallback((mode) => {
490026
+ const applyAgentMode = import_react53.useCallback((mode) => {
489624
490027
  setAgentMode(mode);
489625
490028
  setAgentMode2(mode);
489626
490029
  syncAgentMode(mode);
489627
490030
  }, [syncAgentMode]);
489628
- const handleModeSwitch = import_react48.useCallback(() => {
490031
+ const handleModeSwitch = import_react53.useCallback(() => {
489629
490032
  const next2 = cycleAgentMode();
489630
490033
  applyAgentMode(next2);
489631
490034
  }, [applyAgentMode]);
489632
- import_react48.useEffect(() => {
490035
+ import_react53.useEffect(() => {
489633
490036
  return subscribeModeChanges(() => {
489634
490037
  const mode = getAgentMode();
489635
490038
  setAgentMode2(mode);
489636
490039
  });
489637
490040
  }, []);
489638
- import_react48.useEffect(() => {
490041
+ import_react53.useEffect(() => {
489639
490042
  if (!session)
489640
490043
  return;
489641
490044
  session.setActiveToolsByName(getActiveToolNamesForMode(agentMode));
489642
490045
  injectModeIntoSystemPrompt(session, agentMode);
489643
490046
  }, [agentMode, session]);
489644
- import_react48.useEffect(() => {
490047
+ import_react53.useEffect(() => {
489645
490048
  const unsubscribe = subagentRegistry.subscribe(() => {
489646
490049
  setSubagents(subagentRegistry.getAll());
489647
490050
  });
489648
490051
  return unsubscribe;
489649
490052
  }, []);
489650
- import_react48.useEffect(() => {
490053
+ import_react53.useEffect(() => {
489651
490054
  const unsubscribe = monitorRegistry.subscribe(() => {
489652
490055
  if (currentSessionId) {
489653
490056
  setMonitors(monitorRegistry.getBySession(currentSessionId));
@@ -489658,7 +490061,7 @@ function App({ onExit }) {
489658
490061
  }
489659
490062
  return unsubscribe;
489660
490063
  }, [currentSessionId]);
489661
- import_react48.useEffect(() => {
490064
+ import_react53.useEffect(() => {
489662
490065
  const update2 = () => {
489663
490066
  if (!session) {
489664
490067
  setSidebarContextUsage("0%");
@@ -489694,13 +490097,13 @@ function App({ onExit }) {
489694
490097
  const interval = setInterval(update2, 2000);
489695
490098
  return () => clearInterval(interval);
489696
490099
  }, [session, currentSessionId]);
489697
- const processingPermissionRef = import_react48.useRef(false);
489698
- const permissionResolveRef = import_react48.useRef(null);
489699
- const [permissionModalOpen, setPermissionModalOpen] = import_react48.useState(false);
489700
- const planApprovalResolveRef = import_react48.useRef(null);
489701
- const questionResolveRef = import_react48.useRef(null);
489702
- const questionOptionsRef = import_react48.useRef([]);
489703
- const processPermissionQueue = import_react48.useCallback(async () => {
490100
+ const processingPermissionRef = import_react53.useRef(false);
490101
+ const permissionResolveRef = import_react53.useRef(null);
490102
+ const [permissionModalOpen, setPermissionModalOpen] = import_react53.useState(false);
490103
+ const planApprovalResolveRef = import_react53.useRef(null);
490104
+ const questionResolveRef = import_react53.useRef(null);
490105
+ const questionOptionsRef = import_react53.useRef([]);
490106
+ const processPermissionQueue = import_react53.useCallback(async () => {
489704
490107
  if (processingPermissionRef.current)
489705
490108
  return;
489706
490109
  const queue4 = getPermissionQueue();
@@ -489820,14 +490223,14 @@ function App({ onExit }) {
489820
490223
  processPermissionQueue();
489821
490224
  }, 0);
489822
490225
  }, [dialog, width, height]);
489823
- import_react48.useEffect(() => {
490226
+ import_react53.useEffect(() => {
489824
490227
  const unsubscribe = subscribePermissions(() => {
489825
490228
  processPermissionQueue();
489826
490229
  });
489827
490230
  return unsubscribe;
489828
490231
  }, [processPermissionQueue]);
489829
- const processingQuestionRef = import_react48.useRef(false);
489830
- import_react48.useEffect(() => {
490232
+ const processingQuestionRef = import_react53.useRef(false);
490233
+ import_react53.useEffect(() => {
489831
490234
  const unsubscribe = subscribeQuestions(async () => {
489832
490235
  if (processingQuestionRef.current)
489833
490236
  return;
@@ -489940,8 +490343,8 @@ function App({ onExit }) {
489940
490343
  });
489941
490344
  return unsubscribe;
489942
490345
  }, [dialog, width, height]);
489943
- const processingPlanApprovalRef = import_react48.useRef(false);
489944
- import_react48.useEffect(() => {
490346
+ const processingPlanApprovalRef = import_react53.useRef(false);
490347
+ import_react53.useEffect(() => {
489945
490348
  const unsubscribe = subscribePlanApprovals(async () => {
489946
490349
  if (processingPlanApprovalRef.current)
489947
490350
  return;
@@ -490089,11 +490492,11 @@ function App({ onExit }) {
490089
490492
  const pendingCount = steeringMessages.length + followUpMessages.length;
490090
490493
  const pendingHeight = pendingCount > 0 ? Math.min(pendingCount, 3) + (pendingCount > 3 ? 1 : 0) : 0;
490091
490494
  const chatPanelHeight = Math.max(1, height - (error55 ? 1 : 0) - 5 - 1 - pendingHeight);
490092
- const chatPanelRef = import_react48.useRef(null);
490093
- const inputBoxRef = import_react48.useRef(null);
490094
- const visibleMessages = import_react48.useMemo(() => messages.filter((m2) => !(m2.type === "user" && isInternalNotification(m2.content))), [messages]);
490095
- const anyModalOpen = showExitModal || showCommandPanel || showRenameModal || showConnectModal || showModelModal || showSessionModal || showForkModal || permissionModalOpen || showDeleteConfirm || showImageModal || showEditPendingModal || showMCPSettings || showSkillsModal;
490096
- const handleSubmit = import_react48.useCallback((text) => {
490495
+ const chatPanelRef = import_react53.useRef(null);
490496
+ const inputBoxRef = import_react53.useRef(null);
490497
+ const visibleMessages = import_react53.useMemo(() => messages.filter((m2) => !(m2.type === "user" && isInternalNotification(m2.content))), [messages]);
490498
+ const anyModalOpen = showExitModal || showCommandPanel || showRenameModal || showConnectModal || showModelModal || showSessionModal || showForkModal || permissionModalOpen || showDeleteConfirm || showImageModal || showEditPendingModal || showMCPSettings || showSkillsModal || showExternalEditorModal || externalEditorBusy || externalEditorError !== null;
490499
+ const handleSubmit = import_react53.useCallback((text) => {
490097
490500
  if (!text.trim() || !isReady)
490098
490501
  return;
490099
490502
  if (text.trim() === "/plan") {
@@ -490122,7 +490525,7 @@ function App({ onExit }) {
490122
490525
  prompt(text);
490123
490526
  }
490124
490527
  }, [isReady, isStreaming, steer, prompt, applyAgentMode, session]);
490125
- const handleQueueSubmit = import_react48.useCallback((text) => {
490528
+ const handleQueueSubmit = import_react53.useCallback((text) => {
490126
490529
  if (!text.trim() || !isReady)
490127
490530
  return;
490128
490531
  if (isStreaming) {
@@ -490131,51 +490534,51 @@ function App({ onExit }) {
490131
490534
  prompt(text);
490132
490535
  }
490133
490536
  }, [isReady, isStreaming, followUp, prompt]);
490134
- const handleRename = import_react48.useCallback((newTitle) => {
490537
+ const handleRename = import_react53.useCallback((newTitle) => {
490135
490538
  setSessionTitle2(newTitle);
490136
490539
  setShowRenameModal(false);
490137
490540
  }, [setSessionTitle2]);
490138
- const modelInfo = import_react48.useMemo(() => {
490541
+ const modelInfo = import_react53.useMemo(() => {
490139
490542
  if (!currentModel2) {
490140
490543
  return { modelName: "Not configured", provider: "Use /model to select" };
490141
490544
  }
490142
490545
  return { modelName: currentModel2.modelId, provider: `via ${currentModel2.provider}` };
490143
490546
  }, [currentModel2]);
490144
- const handleNewSession = import_react48.useCallback(async () => {
490547
+ const handleNewSession = import_react53.useCallback(async () => {
490145
490548
  await newSession();
490146
490549
  setShowSessionModal(false);
490147
490550
  }, [newSession]);
490148
- const handleSwitchSession = import_react48.useCallback(async (filePath) => {
490551
+ const handleSwitchSession = import_react53.useCallback(async (filePath) => {
490149
490552
  await switchSession(filePath);
490150
490553
  setShowSessionModal(false);
490151
490554
  }, [switchSession]);
490152
- const handleFork = import_react48.useCallback(async (entryId) => {
490555
+ const handleFork = import_react53.useCallback(async (entryId) => {
490153
490556
  await forkSession(entryId);
490154
490557
  setShowForkModal(false);
490155
490558
  }, [forkSession]);
490156
- const handleDeleteRequest = import_react48.useCallback((sessionId) => {
490559
+ const handleDeleteRequest = import_react53.useCallback((sessionId) => {
490157
490560
  const meta4 = sessionList.find((s) => s.id === sessionId);
490158
490561
  if (!meta4)
490159
490562
  return;
490160
490563
  setSessionToDelete(meta4);
490161
490564
  setShowDeleteConfirm(true);
490162
490565
  }, [sessionList]);
490163
- const handleConfirmDelete = import_react48.useCallback(async () => {
490566
+ const handleConfirmDelete = import_react53.useCallback(async () => {
490164
490567
  if (!sessionToDelete)
490165
490568
  return;
490166
490569
  await deleteSession2(sessionToDelete.id);
490167
490570
  setShowDeleteConfirm(false);
490168
490571
  setSessionToDelete(null);
490169
490572
  }, [sessionToDelete, deleteSession2]);
490170
- const handleCancelDelete = import_react48.useCallback(() => {
490573
+ const handleCancelDelete = import_react53.useCallback(() => {
490171
490574
  setShowDeleteConfirm(false);
490172
490575
  setSessionToDelete(null);
490173
490576
  }, []);
490174
- const handleImageClick = import_react48.useCallback((url4) => {
490577
+ const handleImageClick = import_react53.useCallback((url4) => {
490175
490578
  setImageModalUrl(url4);
490176
490579
  setShowImageModal(true);
490177
490580
  }, []);
490178
- const handleEditPending = import_react48.useCallback((type3, index2) => {
490581
+ const handleEditPending = import_react53.useCallback((type3, index2) => {
490179
490582
  const text = type3 === "sheer" ? steeringMessages[index2] : followUpMessages[index2];
490180
490583
  if (text === undefined)
490181
490584
  return;
@@ -490184,7 +490587,7 @@ function App({ onExit }) {
490184
490587
  setEditPendingText(text);
490185
490588
  setShowEditPendingModal(true);
490186
490589
  }, [steeringMessages, followUpMessages]);
490187
- const handleConfirmEditPending = import_react48.useCallback((text) => {
490590
+ const handleConfirmEditPending = import_react53.useCallback((text) => {
490188
490591
  if (!editPendingType || editPendingIndex < 0)
490189
490592
  return;
490190
490593
  removePendingMessage(editPendingType, editPendingIndex);
@@ -490195,11 +490598,11 @@ function App({ onExit }) {
490195
490598
  }
490196
490599
  setShowEditPendingModal(false);
490197
490600
  }, [editPendingType, editPendingIndex, removePendingMessage, steer, followUp]);
490198
- const handleCloseImageModal = import_react48.useCallback(() => {
490601
+ const handleCloseImageModal = import_react53.useCallback(() => {
490199
490602
  setShowImageModal(false);
490200
490603
  setImageModalUrl("");
490201
490604
  }, []);
490202
- const skillCommands = import_react48.useMemo(() => {
490605
+ const skillCommands = import_react53.useMemo(() => {
490203
490606
  return skills.filter((skill) => skill.userInvocable && !skill.isHidden).map((skill) => ({
490204
490607
  id: `/${skill.name}`,
490205
490608
  label: skill.description || skill.name,
@@ -490213,7 +490616,7 @@ function App({ onExit }) {
490213
490616
  }
490214
490617
  }));
490215
490618
  }, [skills, session, prompt]);
490216
- const commands = import_react48.useMemo(() => [
490619
+ const commands = import_react53.useMemo(() => [
490217
490620
  { id: "/new", label: "Start a new session", section: "Session", action: () => void handleNewSession(), disabled: isStreaming },
490218
490621
  { id: "/fork", label: "Fork current session", section: "Session", action: () => setShowForkModal(true), disabled: isStreaming },
490219
490622
  { id: "/sessions", label: "Browse sessions", section: "Session", action: async () => {
@@ -490239,6 +490642,7 @@ function App({ onExit }) {
490239
490642
  { id: "/model", label: "Select a model", section: "Model", action: () => setShowModelModal(true), disabled: isStreaming },
490240
490643
  { id: "/mcp", label: "Open MCP settings", section: "Extensions", action: () => setShowMCPSettings(true) },
490241
490644
  { id: "/skills", label: "List and manage skills", section: "Extensions", action: () => setShowSkillsModal(true) },
490645
+ { id: "/editor", label: "Set external editor for prompts", section: "Settings", action: () => setShowExternalEditorModal(true) },
490242
490646
  ...skillCommands
490243
490647
  ], [isStreaming, session, handleNewSession, refreshSessionList, agentMode, handleModeSwitch, applyAgentMode, skillCommands]);
490244
490648
  useKeyboard((key) => {
@@ -490320,6 +490724,26 @@ function App({ onExit }) {
490320
490724
  }
490321
490725
  return;
490322
490726
  }
490727
+ if (key.ctrl && key.name === "g") {
490728
+ if (!isStreaming && !externalEditorBusy) {
490729
+ const editorPath = getExternalEditor();
490730
+ if (editorPath) {
490731
+ const inputText = inputBoxRef.current?.getText?.() ?? "";
490732
+ openExternalEditor(renderer, editorPath, inputText, (result, error56) => {
490733
+ if (result !== null && result.trim()) {
490734
+ setExternalEditorResult(result);
490735
+ } else if (error56) {
490736
+ setExternalEditorError(error56.message);
490737
+ }
490738
+ setExternalEditorBusy(false);
490739
+ });
490740
+ setExternalEditorBusy(true);
490741
+ } else {
490742
+ setShowExternalEditorModal(true);
490743
+ }
490744
+ }
490745
+ return;
490746
+ }
490323
490747
  if (key.name === "pageup") {
490324
490748
  chatPanelRef.current?.scrollUp?.();
490325
490749
  return;
@@ -490329,10 +490753,10 @@ function App({ onExit }) {
490329
490753
  return;
490330
490754
  }
490331
490755
  });
490332
- const handleSlashEmpty = import_react48.useCallback(() => {
490756
+ const handleSlashEmpty = import_react53.useCallback(() => {
490333
490757
  setShowCommandPanel(true);
490334
490758
  }, []);
490335
- const handleSelectPrimary = import_react48.useCallback((model) => {
490759
+ const handleSelectPrimary = import_react53.useCallback((model) => {
490336
490760
  setCurrentModelState(model);
490337
490761
  setCurrentModel(model);
490338
490762
  setShowModelModal(false);
@@ -490342,7 +490766,7 @@ function App({ onExit }) {
490342
490766
  session.setModel(piModel).catch(() => {});
490343
490767
  }
490344
490768
  }, [session]);
490345
- const handleSelectAuxiliary = import_react48.useCallback((model) => {
490769
+ const handleSelectAuxiliary = import_react53.useCallback((model) => {
490346
490770
  setAuxiliaryModelState(model);
490347
490771
  setAuxiliaryModel(model);
490348
490772
  setShowModelModal(false);
@@ -490393,11 +490817,14 @@ function App({ onExit }) {
490393
490817
  onQueueSubmit: handleQueueSubmit,
490394
490818
  onSlashEmpty: handleSlashEmpty,
490395
490819
  focused: !anyModalOpen,
490396
- disabled: !isReady,
490820
+ disabled: !isReady || externalEditorBusy,
490821
+ disabledHint: externalEditorBusy ? "External editor in use..." : undefined,
490397
490822
  width: leftWidth,
490398
490823
  mode: agentMode,
490399
490824
  isBusy: isStreaming,
490400
- onModeSwitch: handleModeSwitch
490825
+ onModeSwitch: handleModeSwitch,
490826
+ externalEditorResult,
490827
+ onExternalEditorResultUsed: () => setExternalEditorResult(undefined)
490401
490828
  }, undefined, false, undefined, this),
490402
490829
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InfoBar, {
490403
490830
  width: leftWidth,
@@ -490423,6 +490850,7 @@ function App({ onExit }) {
490423
490850
  }, undefined, false, undefined, this),
490424
490851
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SideBar, {
490425
490852
  width: SIDEBAR_WIDTH,
490853
+ height,
490426
490854
  workingDir: process.cwd(),
490427
490855
  sessionTitle: sessionTitle2,
490428
490856
  modelName: modelInfo.modelName,
@@ -490523,6 +490951,21 @@ function App({ onExit }) {
490523
490951
  onClose: () => setShowSkillsModal(false),
490524
490952
  skills,
490525
490953
  onInvokeSkill: handleInvokeSkill
490954
+ }, undefined, false, undefined, this),
490955
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ExternalEditorModal, {
490956
+ isActive: showExternalEditorModal,
490957
+ onClose: () => setShowExternalEditorModal(false),
490958
+ currentPath: getExternalEditor(),
490959
+ onSave: (path7) => {
490960
+ setExternalEditor(path7 || null);
490961
+ setShowExternalEditorModal(false);
490962
+ }
490963
+ }, undefined, false, undefined, this),
490964
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AlertModal, {
490965
+ isActive: externalEditorError !== null,
490966
+ title: "External Editor Error",
490967
+ message: externalEditorError ?? "",
490968
+ onClose: () => setExternalEditorError(null)
490526
490969
  }, undefined, false, undefined, this)
490527
490970
  ]
490528
490971
  }, undefined, true, undefined, this);
@@ -490534,6 +490977,7 @@ async function main3() {
490534
490977
  const renderer = await createCliRenderer({ exitOnCtrlC: false });
490535
490978
  createRoot(renderer).render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DialogProvider, {
490536
490979
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
490980
+ renderer,
490537
490981
  onExit: () => {
490538
490982
  renderer.destroy();
490539
490983
  process.exit(0);