u-foo 2.3.12 → 2.3.14

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/src/code/tui.js CHANGED
@@ -293,6 +293,111 @@ function moveCursorHorizontally(cursorPos = 0, inputValue = "", direction = "rig
293
293
  return Math.min(max, pos + 1);
294
294
  }
295
295
 
296
+ function clampCursorPos(cursorPos = 0, inputValue = "") {
297
+ const text = String(inputValue || "");
298
+ const pos = Number.isFinite(cursorPos) ? Math.floor(cursorPos) : 0;
299
+ return Math.max(0, Math.min(text.length, pos));
300
+ }
301
+
302
+ function findLogicalLineStart(inputValue = "", cursorPos = 0) {
303
+ const text = String(inputValue || "");
304
+ const pos = clampCursorPos(cursorPos, text);
305
+ const prevNewline = text.lastIndexOf("\n", Math.max(0, pos - 1));
306
+ return prevNewline === -1 ? 0 : prevNewline + 1;
307
+ }
308
+
309
+ function findLogicalLineEnd(inputValue = "", cursorPos = 0) {
310
+ const text = String(inputValue || "");
311
+ const pos = clampCursorPos(cursorPos, text);
312
+ const nextNewline = text.indexOf("\n", pos);
313
+ return nextNewline === -1 ? text.length : nextNewline;
314
+ }
315
+
316
+ function moveCursorToVisualLineBoundary({
317
+ cursorPos = 0,
318
+ inputValue = "",
319
+ width = 80,
320
+ boundary = "start",
321
+ strWidth,
322
+ } = {}) {
323
+ const inputMath = require("../chat/inputMath");
324
+ const text = String(inputValue || "");
325
+ const normalizedWidth = Number.isFinite(width) ? Math.max(1, Math.floor(width)) : 1;
326
+ const pos = clampCursorPos(cursorPos, text);
327
+ const { row } = inputMath.getCursorRowCol(text, pos, normalizedWidth, strWidth);
328
+ if (boundary === "end") {
329
+ return inputMath.getCursorPosForRowCol(text, row, normalizedWidth, normalizedWidth, strWidth);
330
+ }
331
+ return inputMath.getCursorPosForRowCol(text, row, 0, normalizedWidth, strWidth);
332
+ }
333
+
334
+ function moveCursorVertically({
335
+ cursorPos = 0,
336
+ inputValue = "",
337
+ width = 80,
338
+ direction = "down",
339
+ preferredCol = null,
340
+ strWidth,
341
+ } = {}) {
342
+ const inputMath = require("../chat/inputMath");
343
+ const text = String(inputValue || "");
344
+ const normalizedWidth = Number.isFinite(width) ? Math.max(1, Math.floor(width)) : 1;
345
+ const pos = clampCursorPos(cursorPos, text);
346
+ const { row, col } = inputMath.getCursorRowCol(text, pos, normalizedWidth, strWidth);
347
+ const totalRows = inputMath.countLines(text, normalizedWidth, strWidth);
348
+ const targetCol = Number.isFinite(preferredCol) ? preferredCol : col;
349
+
350
+ if (direction === "up") {
351
+ if (row <= 0) {
352
+ return { moved: false, nextCursorPos: pos, preferredCol: targetCol, boundary: "top" };
353
+ }
354
+ return {
355
+ moved: true,
356
+ nextCursorPos: inputMath.getCursorPosForRowCol(text, row - 1, targetCol, normalizedWidth, strWidth),
357
+ preferredCol: targetCol,
358
+ boundary: "",
359
+ };
360
+ }
361
+
362
+ if (row >= totalRows - 1) {
363
+ return { moved: false, nextCursorPos: pos, preferredCol: targetCol, boundary: "bottom" };
364
+ }
365
+ return {
366
+ moved: true,
367
+ nextCursorPos: inputMath.getCursorPosForRowCol(text, row + 1, targetCol, normalizedWidth, strWidth),
368
+ preferredCol: targetCol,
369
+ boundary: "",
370
+ };
371
+ }
372
+
373
+ function deleteWordBeforeCursor(inputValue = "", cursorPos = 0) {
374
+ const text = String(inputValue || "");
375
+ const pos = clampCursorPos(cursorPos, text);
376
+ if (pos <= 0) return { value: text, cursorPos: pos };
377
+ const before = text.slice(0, pos);
378
+ const after = text.slice(pos);
379
+ const match = before.match(/\s*\S+\s*$/);
380
+ const start = match ? pos - match[0].length : Math.max(0, pos - 1);
381
+ return {
382
+ value: before.slice(0, start) + after,
383
+ cursorPos: start,
384
+ };
385
+ }
386
+
387
+ function moveCursorByWord(inputValue = "", cursorPos = 0, direction = "forward") {
388
+ const text = String(inputValue || "");
389
+ const pos = clampCursorPos(cursorPos, text);
390
+ if (direction === "backward") {
391
+ const before = text.slice(0, pos);
392
+ const trimmedEnd = before.search(/\S\s*$/) >= 0 ? before.replace(/\s+$/, "") : before;
393
+ const match = trimmedEnd.match(/\S+$/);
394
+ return match ? trimmedEnd.length - match[0].length : 0;
395
+ }
396
+ const after = text.slice(pos);
397
+ const match = after.match(/^\s*\S+/);
398
+ return match ? Math.min(text.length, pos + match[0].length) : text.length;
399
+ }
400
+
296
401
  function resolveHistoryDownTransition({
297
402
  inputHistory = [],
298
403
  historyIndex = 0,
@@ -499,6 +604,11 @@ function runUcodeTui({
499
604
  let lastMergedToolGroup = null;
500
605
  let toolMergeId = 0;
501
606
  let cursorPos = 0;
607
+ let preferredCol = null;
608
+ let currentInputHeight = 4;
609
+ const MIN_INPUT_CONTENT_HEIGHT = 1;
610
+ const MAX_INPUT_CONTENT_HEIGHT = 8;
611
+ const DASHBOARD_HEIGHT = 1;
502
612
  let autoBusTimer = null;
503
613
  let autoBusQueued = false;
504
614
  let autoBusError = "";
@@ -510,12 +620,15 @@ function runUcodeTui({
510
620
  statusLine,
511
621
  completionPanel,
512
622
  dashboard,
623
+ inputTopLine,
513
624
  promptBox,
514
625
  input,
515
626
  } = createChatLayout({
516
627
  blessed,
517
628
  currentInputHeight: 4,
518
629
  version: UCODE_VERSION,
630
+ logBorder: true,
631
+ logScrollbar: true,
519
632
  });
520
633
 
521
634
  if (completionPanel && typeof completionPanel.hide === "function") {
@@ -555,6 +668,7 @@ function runUcodeTui({
555
668
  promptBox.width = Math.max(2, plain.length + 1);
556
669
  input.left = promptBox.width;
557
670
  input.width = `100%-${promptBox.width}`;
671
+ resizeInput();
558
672
  };
559
673
 
560
674
  // --- Cursor position helpers (mirrors chat inputListenerController) ---
@@ -565,6 +679,10 @@ function runUcodeTui({
565
679
 
566
680
  const getWrapWidth = () => inputMath.getWrapWidth(input, getInnerWidth());
567
681
 
682
+ const resetPreferredCol = () => {
683
+ preferredCol = null;
684
+ };
685
+
568
686
  const ensureInputCursorVisible = () => {
569
687
  const innerWidth = getWrapWidth();
570
688
  if (innerWidth <= 0) return;
@@ -583,6 +701,105 @@ function runUcodeTui({
583
701
  }
584
702
  };
585
703
 
704
+ const resizeInput = () => {
705
+ const innerWidth = getWrapWidth();
706
+ if (innerWidth <= 0) return;
707
+ const totalRows = inputMath.countLines(input.value || "", innerWidth, (v) => input.strWidth(v));
708
+ const contentHeight = Math.min(
709
+ MAX_INPUT_CONTENT_HEIGHT,
710
+ Math.max(MIN_INPUT_CONTENT_HEIGHT, totalRows)
711
+ );
712
+ const targetHeight = contentHeight + DASHBOARD_HEIGHT + 2;
713
+ if (targetHeight !== currentInputHeight) {
714
+ currentInputHeight = targetHeight;
715
+ input.height = contentHeight;
716
+ promptBox.height = contentHeight;
717
+ if (inputTopLine) inputTopLine.bottom = currentInputHeight - 1;
718
+ }
719
+ statusLine.bottom = currentInputHeight;
720
+ logBox.height = Math.max(1, screen.height - currentInputHeight - 1);
721
+ ensureInputCursorVisible();
722
+ };
723
+
724
+ const renderInput = () => {
725
+ resizeInput();
726
+ ensureInputCursorVisible();
727
+ input._updateCursor();
728
+ screen.render();
729
+ };
730
+
731
+ const setCursor = (nextPos) => {
732
+ cursorPos = clampCursorPos(nextPos, input.value || "");
733
+ ensureInputCursorVisible();
734
+ input._updateCursor();
735
+ screen.render();
736
+ };
737
+
738
+ const setInputValue = (value) => {
739
+ input.setValue(value || "");
740
+ cursorPos = (value || "").length;
741
+ resetPreferredCol();
742
+ renderInput();
743
+ };
744
+
745
+ const replaceInputRange = (start, end, replacement = "") => {
746
+ const value = input.value || "";
747
+ const safeStart = clampCursorPos(start, value);
748
+ const safeEnd = clampCursorPos(end, value);
749
+ const from = Math.min(safeStart, safeEnd);
750
+ const to = Math.max(safeStart, safeEnd);
751
+ input.value = value.slice(0, from) + String(replacement || "") + value.slice(to);
752
+ cursorPos = from + String(replacement || "").length;
753
+ resetPreferredCol();
754
+ renderInput();
755
+ };
756
+
757
+ const insertTextAtCursor = (text = "") => {
758
+ const normalized = inputMath.normalizePaste(text);
759
+ if (!normalized) return;
760
+ replaceInputRange(cursorPos, cursorPos, normalized);
761
+ };
762
+
763
+ const deleteBeforeCursor = () => {
764
+ if (cursorPos <= 0) return;
765
+ replaceInputRange(cursorPos - 1, cursorPos, "");
766
+ };
767
+
768
+ const deleteAtCursor = () => {
769
+ const value = input.value || "";
770
+ if (cursorPos >= value.length) return;
771
+ replaceInputRange(cursorPos, cursorPos + 1, "");
772
+ };
773
+
774
+ const deleteToBoundary = (boundary) => {
775
+ const value = input.value || "";
776
+ const innerWidth = getWrapWidth();
777
+ const target = boundary === "end"
778
+ ? moveCursorToVisualLineBoundary({
779
+ cursorPos,
780
+ inputValue: value,
781
+ width: innerWidth,
782
+ boundary: "end",
783
+ strWidth: (v) => input.strWidth(v),
784
+ })
785
+ : moveCursorToVisualLineBoundary({
786
+ cursorPos,
787
+ inputValue: value,
788
+ width: innerWidth,
789
+ boundary: "start",
790
+ strWidth: (v) => input.strWidth(v),
791
+ });
792
+ if (target === cursorPos && boundary === "end" && value[cursorPos] === "\n") {
793
+ replaceInputRange(cursorPos, cursorPos + 1, "");
794
+ return;
795
+ }
796
+ if (target === cursorPos && boundary === "start" && value[cursorPos - 1] === "\n") {
797
+ replaceInputRange(cursorPos - 1, cursorPos, "");
798
+ return;
799
+ }
800
+ replaceInputRange(Math.min(cursorPos, target), Math.max(cursorPos, target), "");
801
+ };
802
+
586
803
  // Override _updateCursor to use our tracked cursorPos
587
804
  input._updateCursor = function () {
588
805
  if (this.screen.focused !== this) return;
@@ -603,8 +820,8 @@ function runUcodeTui({
603
820
  };
604
821
 
605
822
  // Override _listener to support cursor-aware editing
606
- const origDone = input._done ? input._done.bind(input) : null;
607
823
  let lastKeyRef = null;
824
+ let skipSubmitKeyRef = null;
608
825
  input._listener = function (ch, key) {
609
826
  const keyName = key && key.name;
610
827
 
@@ -614,69 +831,161 @@ function runUcodeTui({
614
831
  if (key && key === lastKeyRef) return;
615
832
  lastKeyRef = key || null;
616
833
 
617
- // Let enter/return/escape pass through to blessed key handlers
618
- if (keyName === "return" || keyName === "enter" || keyName === "escape") return;
834
+ if (keyName === "escape") return;
835
+
836
+ if (keyName === "return" || keyName === "enter") {
837
+ const value = this.value || "";
838
+ if (key && (key.shift || key.meta)) {
839
+ insertTextAtCursor("\n");
840
+ skipSubmitKeyRef = key || true;
841
+ return;
842
+ }
843
+ if (cursorPos > 0 && value[cursorPos - 1] === "\\") {
844
+ replaceInputRange(cursorPos - 1, cursorPos, "\n");
845
+ skipSubmitKeyRef = key || true;
846
+ return;
847
+ }
848
+ return;
849
+ }
619
850
 
620
851
  // Arrow keys handled by input.key() handlers below
621
852
  if (keyName === "left" || keyName === "right" || keyName === "up" || keyName === "down") return;
622
853
 
854
+ if (key && key.ctrl) {
855
+ if (keyName === "a") {
856
+ setCursor(moveCursorToVisualLineBoundary({
857
+ cursorPos,
858
+ inputValue: this.value || "",
859
+ width: getWrapWidth(),
860
+ boundary: "start",
861
+ strWidth: (v) => this.strWidth(v),
862
+ }));
863
+ resetPreferredCol();
864
+ return;
865
+ }
866
+ if (keyName === "e") {
867
+ setCursor(moveCursorToVisualLineBoundary({
868
+ cursorPos,
869
+ inputValue: this.value || "",
870
+ width: getWrapWidth(),
871
+ boundary: "end",
872
+ strWidth: (v) => this.strWidth(v),
873
+ }));
874
+ resetPreferredCol();
875
+ return;
876
+ }
877
+ if (keyName === "b") {
878
+ setCursor(moveCursorHorizontally(cursorPos, this.value || "", "left"));
879
+ resetPreferredCol();
880
+ return;
881
+ }
882
+ if (keyName === "f") {
883
+ setCursor(moveCursorHorizontally(cursorPos, this.value || "", "right"));
884
+ resetPreferredCol();
885
+ return;
886
+ }
887
+ if (keyName === "d") {
888
+ deleteAtCursor();
889
+ return;
890
+ }
891
+ if (keyName === "h") {
892
+ deleteBeforeCursor();
893
+ return;
894
+ }
895
+ if (keyName === "k") {
896
+ deleteToBoundary("end");
897
+ return;
898
+ }
899
+ if (keyName === "u") {
900
+ deleteToBoundary("start");
901
+ return;
902
+ }
903
+ if (keyName === "w") {
904
+ const next = deleteWordBeforeCursor(this.value || "", cursorPos);
905
+ this.value = next.value;
906
+ cursorPos = next.cursorPos;
907
+ resetPreferredCol();
908
+ renderInput();
909
+ return;
910
+ }
911
+ }
912
+
913
+ if (key && key.meta) {
914
+ if (keyName === "b") {
915
+ setCursor(moveCursorByWord(this.value || "", cursorPos, "backward"));
916
+ resetPreferredCol();
917
+ return;
918
+ }
919
+ if (keyName === "f") {
920
+ setCursor(moveCursorByWord(this.value || "", cursorPos, "forward"));
921
+ resetPreferredCol();
922
+ return;
923
+ }
924
+ if (keyName === "d") {
925
+ const end = moveCursorByWord(this.value || "", cursorPos, "forward");
926
+ replaceInputRange(cursorPos, end, "");
927
+ return;
928
+ }
929
+ }
930
+
623
931
  if (keyName === "backspace") {
624
- if (cursorPos > 0 && this.value) {
625
- this.value = this.value.slice(0, cursorPos - 1) + this.value.slice(cursorPos);
626
- cursorPos -= 1;
627
- ensureInputCursorVisible();
628
- this._updateCursor();
629
- this.screen.render();
932
+ if (key && (key.meta || key.ctrl)) {
933
+ const next = deleteWordBeforeCursor(this.value || "", cursorPos);
934
+ this.value = next.value;
935
+ cursorPos = next.cursorPos;
936
+ resetPreferredCol();
937
+ renderInput();
938
+ } else {
939
+ deleteBeforeCursor();
630
940
  }
631
941
  return;
632
942
  }
633
943
 
634
944
  if (keyName === "delete") {
635
- if (this.value && cursorPos < this.value.length) {
636
- this.value = this.value.slice(0, cursorPos) + this.value.slice(cursorPos + 1);
637
- ensureInputCursorVisible();
638
- this._updateCursor();
639
- this.screen.render();
945
+ if (key && key.meta) {
946
+ deleteToBoundary("end");
947
+ } else {
948
+ deleteAtCursor();
640
949
  }
641
950
  return;
642
951
  }
643
952
 
644
953
  if (keyName === "home") {
645
- cursorPos = 0;
646
- ensureInputCursorVisible();
647
- this._updateCursor();
648
- this.screen.render();
954
+ setCursor(moveCursorToVisualLineBoundary({
955
+ cursorPos,
956
+ inputValue: this.value || "",
957
+ width: getWrapWidth(),
958
+ boundary: "start",
959
+ strWidth: (v) => this.strWidth(v),
960
+ }));
961
+ resetPreferredCol();
649
962
  return;
650
963
  }
651
964
 
652
965
  if (keyName === "end") {
653
- cursorPos = (this.value || "").length;
654
- ensureInputCursorVisible();
655
- this._updateCursor();
656
- this.screen.render();
966
+ setCursor(moveCursorToVisualLineBoundary({
967
+ cursorPos,
968
+ inputValue: this.value || "",
969
+ width: getWrapWidth(),
970
+ boundary: "end",
971
+ strWidth: (v) => this.strWidth(v),
972
+ }));
973
+ resetPreferredCol();
974
+ return;
975
+ }
976
+
977
+ if (ch && ch.length > 1 && (!keyName || keyName.length !== 1)) {
978
+ insertTextAtCursor(ch);
657
979
  return;
658
980
  }
659
981
 
660
982
  // Normal character insertion at cursor position
661
983
  const insertChar = (ch && ch.length === 1) ? ch : (keyName && keyName.length === 1 ? keyName : null);
662
984
  if (insertChar && !/^[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]$/.test(insertChar)) {
663
- this.value = (this.value || "").slice(0, cursorPos) + insertChar + (this.value || "").slice(cursorPos);
664
- cursorPos += 1;
665
- ensureInputCursorVisible();
666
- this._updateCursor();
667
- this.screen.render();
985
+ insertTextAtCursor(insertChar);
668
986
  }
669
987
  };
670
988
 
671
- // Helper to set input value and reset cursor to end
672
- const setInputValue = (value) => {
673
- input.setValue(value || "");
674
- cursorPos = (value || "").length;
675
- ensureInputCursorVisible();
676
- input._updateCursor();
677
- screen.render();
678
- };
679
-
680
989
  const renderDashboard = () => {
681
990
  let hint = "No target agents";
682
991
  if (activeAgents.length > 0) {
@@ -922,7 +1231,7 @@ function runUcodeTui({
922
1231
  statusInterval = null;
923
1232
  }
924
1233
  if (!message) {
925
- statusLine.setContent(escapeBlessed(`UCODE · Ready${getBackgroundSuffix()}`));
1234
+ statusLine.setContent(escapeBlessed(`UCODE · Ready · Enter send · Shift/Alt+Enter newline · PgUp/PgDn log · Ctrl+O tools${getBackgroundSuffix()}`));
926
1235
  screen.render();
927
1236
  return;
928
1237
  }
@@ -1321,6 +1630,8 @@ function runUcodeTui({
1321
1630
  const trimmed = raw.trim();
1322
1631
  input.setValue("");
1323
1632
  cursorPos = 0;
1633
+ resetPreferredCol();
1634
+ resizeInput();
1324
1635
  screen.render();
1325
1636
  agentSelectionMode = false;
1326
1637
 
@@ -1345,7 +1656,11 @@ function runUcodeTui({
1345
1656
  });
1346
1657
  };
1347
1658
 
1348
- input.key(["enter"], () => {
1659
+ input.key(["enter"], (ch, key) => {
1660
+ if (skipSubmitKeyRef && (!key || skipSubmitKeyRef === key || skipSubmitKeyRef === true)) {
1661
+ skipSubmitKeyRef = null;
1662
+ return false;
1663
+ }
1349
1664
  submitInput(input.getValue());
1350
1665
  return false;
1351
1666
  });
@@ -1355,7 +1670,6 @@ function runUcodeTui({
1355
1670
  agentSelectionMode,
1356
1671
  inputValue: currentValue,
1357
1672
  })) {
1358
- const previousTarget = targetAgent;
1359
1673
  targetAgent = null;
1360
1674
  selectedAgentIndex = -1;
1361
1675
  agentSelectionMode = false;
@@ -1365,12 +1679,43 @@ function runUcodeTui({
1365
1679
  input.focus();
1366
1680
  return false;
1367
1681
  }
1368
- if (inputHistory.length === 0) return;
1682
+ if (currentValue) {
1683
+ const move = moveCursorVertically({
1684
+ cursorPos,
1685
+ inputValue: currentValue,
1686
+ width: getWrapWidth(),
1687
+ direction: "up",
1688
+ preferredCol,
1689
+ strWidth: (v) => input.strWidth(v),
1690
+ });
1691
+ preferredCol = move.preferredCol;
1692
+ if (move.moved) {
1693
+ setCursor(move.nextCursorPos);
1694
+ return false;
1695
+ }
1696
+ }
1697
+ if (inputHistory.length === 0) return false;
1369
1698
  historyIndex = Math.max(0, historyIndex - 1);
1370
1699
  setInputValue(inputHistory[historyIndex] || "");
1700
+ return false;
1371
1701
  });
1372
1702
  input.key(["down"], () => {
1373
1703
  const currentValue = input.getValue();
1704
+ if (currentValue) {
1705
+ const move = moveCursorVertically({
1706
+ cursorPos,
1707
+ inputValue: currentValue,
1708
+ width: getWrapWidth(),
1709
+ direction: "down",
1710
+ preferredCol,
1711
+ strWidth: (v) => input.strWidth(v),
1712
+ });
1713
+ preferredCol = move.preferredCol;
1714
+ if (move.moved) {
1715
+ setCursor(move.nextCursorPos);
1716
+ return false;
1717
+ }
1718
+ }
1374
1719
  const historyTransition = resolveHistoryDownTransition({
1375
1720
  inputHistory,
1376
1721
  historyIndex,
@@ -1428,10 +1773,8 @@ function runUcodeTui({
1428
1773
  }
1429
1774
  const next = moveCursorHorizontally(cursorPos, currentValue, "left");
1430
1775
  if (next !== cursorPos) {
1431
- cursorPos = next;
1432
- ensureInputCursorVisible();
1433
- input._updateCursor();
1434
- screen.render();
1776
+ setCursor(next);
1777
+ resetPreferredCol();
1435
1778
  }
1436
1779
  return false;
1437
1780
  });
@@ -1450,10 +1793,8 @@ function runUcodeTui({
1450
1793
  }
1451
1794
  const next = moveCursorHorizontally(cursorPos, currentValue, "right");
1452
1795
  if (next !== cursorPos) {
1453
- cursorPos = next;
1454
- ensureInputCursorVisible();
1455
- input._updateCursor();
1456
- screen.render();
1796
+ setCursor(next);
1797
+ resetPreferredCol();
1457
1798
  }
1458
1799
  return false;
1459
1800
  });
@@ -1496,6 +1837,14 @@ function runUcodeTui({
1496
1837
  }
1497
1838
  screen.render();
1498
1839
  });
1840
+ screen.key(["pageup"], () => {
1841
+ logBox.scroll(-Math.max(1, Math.floor((logBox.height || 10) / 2)));
1842
+ screen.render();
1843
+ });
1844
+ screen.key(["pagedown"], () => {
1845
+ logBox.scroll(Math.max(1, Math.floor((logBox.height || 10) / 2)));
1846
+ screen.render();
1847
+ });
1499
1848
  input.key(["escape"], () => {
1500
1849
  if (pendingTask && pendingTask.abortController && !pendingTask.abortController.signal.aborted) {
1501
1850
  try {
@@ -1510,11 +1859,10 @@ function runUcodeTui({
1510
1859
  });
1511
1860
  return false;
1512
1861
  }
1513
- const previousTarget = targetAgent;
1514
1862
  targetAgent = null;
1515
1863
  selectedAgentIndex = -1;
1516
1864
  agentSelectionMode = false;
1517
- input.setValue("");
1865
+ setInputValue("");
1518
1866
  setPrompt();
1519
1867
  renderDashboard();
1520
1868
  // Target selection cleared - removed redundant log
@@ -1573,6 +1921,13 @@ module.exports = {
1573
1921
  cycleAgentSelectionIndex,
1574
1922
  shouldClearAgentSelectionOnUp,
1575
1923
  moveCursorHorizontally,
1924
+ clampCursorPos,
1925
+ findLogicalLineStart,
1926
+ findLogicalLineEnd,
1927
+ moveCursorToVisualLineBoundary,
1928
+ moveCursorVertically,
1929
+ deleteWordBeforeCursor,
1930
+ moveCursorByWord,
1576
1931
  resolveHistoryDownTransition,
1577
1932
  filterSelectableAgents,
1578
1933
  stripLeakedEscapeTags,
package/src/config.js CHANGED
@@ -29,6 +29,7 @@ const DEFAULT_UCODE_CONFIG = {
29
29
  function normalizeLaunchMode(value) {
30
30
  if (value === "auto") return "auto";
31
31
  if (value === "internal") return "internal";
32
+ if (value === "internal-pty") return "internal-pty";
32
33
  if (value === "tmux") return "tmux";
33
34
  if (value === "terminal") return "terminal";
34
35
  if (value === "host") return "host";