ideacode 1.3.1 → 1.3.3

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.
Files changed (2) hide show
  1. package/dist/repl.js +141 -56
  2. package/package.json +1 -1
package/dist/repl.js CHANGED
@@ -50,14 +50,14 @@ const PARALLEL_SAFE_TOOLS = new Set([
50
50
  ]);
51
51
  const LOADING_TICK_MS = 80;
52
52
  const MAX_EMPTY_ASSISTANT_RETRIES = 3;
53
+ const TYPING_LAYOUT_FREEZE_MS = 120;
54
+ const INPUT_COMMIT_INTERVAL_MS = 45;
53
55
  const TRUNCATE_NOTE = "\n\n(Output truncated to save context. Use read with offset/limit, grep with a specific pattern, or tail with fewer lines to get more.)";
54
56
  function truncateToolResult(content) {
55
57
  if (content.length <= MAX_TOOL_RESULT_CHARS)
56
58
  return content;
57
59
  return content.slice(0, MAX_TOOL_RESULT_CHARS) + TRUNCATE_NOTE;
58
60
  }
59
- const isMac = process.platform === "darwin";
60
- const pasteShortcut = isMac ? "Cmd+V" : "Ctrl+V";
61
61
  function listFilesWithFilter(cwd, filter) {
62
62
  try {
63
63
  const pattern = path.join(cwd, "**", "*").replace(/\\/g, "/");
@@ -403,12 +403,20 @@ export function Repl({ apiKey, cwd, onQuit }) {
403
403
  const [showHelpModal, setShowHelpModal] = useState(false);
404
404
  const [slashSuggestionIndex, setSlashSuggestionIndex] = useState(0);
405
405
  const [inputCursor, setInputCursor] = useState(0);
406
+ const inputValueRef = useRef(inputValue);
407
+ const inputCursorRef = useRef(inputCursor);
408
+ const inputCommitTimerRef = useRef(null);
409
+ const [layoutInputLineCount, setLayoutInputLineCount] = useState(1);
410
+ const shrinkLineTimerRef = useRef(null);
411
+ const [isInputLayoutFrozen, setIsInputLayoutFrozen] = useState(false);
412
+ const [frozenFooterLines, setFrozenFooterLines] = useState(2);
406
413
  const skipNextSubmitRef = useRef(false);
407
414
  const queuedMessageRef = useRef(null);
408
415
  const lastUserMessageRef = useRef("");
409
416
  const [logScrollOffset, setLogScrollOffset] = useState(0);
410
417
  const scrollBoundsRef = useRef({ maxLogScrollOffset: 0, logViewportHeight: 1 });
411
418
  const prevEscRef = useRef(false);
419
+ const typingFreezeTimerRef = useRef(null);
412
420
  useEffect(() => {
413
421
  // Enable SGR mouse + basic tracking so trackpad wheel scrolling works.
414
422
  process.stdout.write("\x1b[?1006h\x1b[?1000h");
@@ -483,18 +491,96 @@ export function Repl({ apiKey, cwd, onQuit }) {
483
491
  const lines = inputValue.split("\n");
484
492
  return lines.reduce((sum, line) => sum + Math.max(1, Math.ceil(line.length / wrapWidth)), 0);
485
493
  }, [inputValue, wrapWidth]);
486
- const [stableInputLineCount, setStableInputLineCount] = useState(inputLineCount);
487
494
  useEffect(() => {
488
- if (inputLineCount <= 1) {
489
- setStableInputLineCount(1);
495
+ if (inputLineCount >= layoutInputLineCount) {
496
+ if (shrinkLineTimerRef.current) {
497
+ clearTimeout(shrinkLineTimerRef.current);
498
+ shrinkLineTimerRef.current = null;
499
+ }
500
+ setLayoutInputLineCount(inputLineCount);
501
+ return;
502
+ }
503
+ if (shrinkLineTimerRef.current) {
504
+ clearTimeout(shrinkLineTimerRef.current);
505
+ }
506
+ shrinkLineTimerRef.current = setTimeout(() => {
507
+ setLayoutInputLineCount(inputLineCount);
508
+ shrinkLineTimerRef.current = null;
509
+ }, 120);
510
+ return () => {
511
+ if (shrinkLineTimerRef.current) {
512
+ clearTimeout(shrinkLineTimerRef.current);
513
+ }
514
+ };
515
+ }, [inputLineCount, layoutInputLineCount]);
516
+ useEffect(() => {
517
+ inputValueRef.current = inputValue;
518
+ }, [inputValue]);
519
+ useEffect(() => {
520
+ inputCursorRef.current = inputCursor;
521
+ }, [inputCursor]);
522
+ const commitInputState = useCallback((immediate = false) => {
523
+ const flush = () => {
524
+ inputCommitTimerRef.current = null;
525
+ setInputValue(inputValueRef.current);
526
+ setInputCursor(inputCursorRef.current);
527
+ };
528
+ if (immediate) {
529
+ if (inputCommitTimerRef.current) {
530
+ clearTimeout(inputCommitTimerRef.current);
531
+ inputCommitTimerRef.current = null;
532
+ }
533
+ flush();
490
534
  return;
491
535
  }
492
- const t = setTimeout(() => setStableInputLineCount(inputLineCount), 90);
493
- return () => clearTimeout(t);
494
- }, [inputLineCount]);
536
+ if (inputCommitTimerRef.current)
537
+ return;
538
+ inputCommitTimerRef.current = setTimeout(flush, INPUT_COMMIT_INTERVAL_MS);
539
+ }, []);
540
+ const applyInputMutation = useCallback((nextValue, nextCursor, immediate = false) => {
541
+ inputValueRef.current = nextValue;
542
+ inputCursorRef.current = Math.max(0, Math.min(nextCursor, nextValue.length));
543
+ // Keep cursor/text rendering strictly in sync while typing.
544
+ void immediate;
545
+ commitInputState(true);
546
+ }, [commitInputState]);
495
547
  useEffect(() => {
496
548
  setInputCursor((c) => Math.min(c, Math.max(0, inputValue.length)));
497
549
  }, [inputValue.length]);
550
+ useEffect(() => {
551
+ if (inputLineCount > layoutInputLineCount) {
552
+ setIsInputLayoutFrozen(false);
553
+ if (typingFreezeTimerRef.current) {
554
+ clearTimeout(typingFreezeTimerRef.current);
555
+ typingFreezeTimerRef.current = null;
556
+ }
557
+ return;
558
+ }
559
+ setIsInputLayoutFrozen(true);
560
+ if (typingFreezeTimerRef.current) {
561
+ clearTimeout(typingFreezeTimerRef.current);
562
+ }
563
+ typingFreezeTimerRef.current = setTimeout(() => {
564
+ setIsInputLayoutFrozen(false);
565
+ typingFreezeTimerRef.current = null;
566
+ }, TYPING_LAYOUT_FREEZE_MS);
567
+ }, [inputValue, inputCursor, inputLineCount, layoutInputLineCount]);
568
+ useEffect(() => {
569
+ return () => {
570
+ if (typingFreezeTimerRef.current) {
571
+ clearTimeout(typingFreezeTimerRef.current);
572
+ typingFreezeTimerRef.current = null;
573
+ }
574
+ if (shrinkLineTimerRef.current) {
575
+ clearTimeout(shrinkLineTimerRef.current);
576
+ shrinkLineTimerRef.current = null;
577
+ }
578
+ if (inputCommitTimerRef.current) {
579
+ clearTimeout(inputCommitTimerRef.current);
580
+ inputCommitTimerRef.current = null;
581
+ }
582
+ };
583
+ }, []);
498
584
  useEffect(() => {
499
585
  if (apiKey)
500
586
  fetchModels(apiKey).then(setModelList);
@@ -990,11 +1076,13 @@ export function Repl({ apiKey, cwd, onQuit }) {
990
1076
  }
991
1077
  }
992
1078
  if (!showModelSelector && !showPalette) {
1079
+ const inputNow = inputValueRef.current;
1080
+ const cursorNow = inputCursorRef.current;
993
1081
  const withModifier = key.ctrl || key.meta || key.shift;
994
1082
  const scrollUp = key.pageUp ||
995
- (key.upArrow && (withModifier || !inputValue.trim()));
1083
+ (key.upArrow && (withModifier || !inputNow.trim()));
996
1084
  const scrollDown = key.pageDown ||
997
- (key.downArrow && (withModifier || !inputValue.trim()));
1085
+ (key.downArrow && (withModifier || !inputNow.trim()));
998
1086
  if (scrollUp) {
999
1087
  setLogScrollOffset((prev) => Math.min(maxLogScrollOffset, prev + logViewportHeight));
1000
1088
  return;
@@ -1005,26 +1093,24 @@ export function Repl({ apiKey, cwd, onQuit }) {
1005
1093
  }
1006
1094
  if (!key.escape)
1007
1095
  prevEscRef.current = false;
1008
- const len = inputValue.length;
1009
- const cur = inputCursor;
1096
+ const len = inputNow.length;
1097
+ const cur = cursorNow;
1010
1098
  if (key.tab) {
1011
- if (inputValue.trim()) {
1012
- queuedMessageRef.current = inputValue;
1013
- setInputValue("");
1014
- setInputCursor(0);
1099
+ if (inputNow.trim()) {
1100
+ queuedMessageRef.current = inputNow;
1101
+ applyInputMutation("", 0, true);
1015
1102
  appendLog(colors.muted(" Message queued. Send to run after this turn."));
1016
1103
  appendLog("");
1017
1104
  }
1018
1105
  return;
1019
1106
  }
1020
1107
  if (key.escape) {
1021
- if (inputValue.length === 0) {
1108
+ if (inputNow.length === 0) {
1022
1109
  if (prevEscRef.current) {
1023
1110
  prevEscRef.current = false;
1024
1111
  const last = lastUserMessageRef.current;
1025
1112
  if (last) {
1026
- setInputValue(last);
1027
- setInputCursor(last.length);
1113
+ applyInputMutation(last, last.length, true);
1028
1114
  setMessages((prev) => (prev.length > 0 && prev[prev.length - 1]?.role === "user" ? prev.slice(0, -1) : prev));
1029
1115
  appendLog(colors.muted(" Editing previous message. Submit to replace."));
1030
1116
  appendLog("");
@@ -1034,113 +1120,107 @@ export function Repl({ apiKey, cwd, onQuit }) {
1034
1120
  prevEscRef.current = true;
1035
1121
  }
1036
1122
  else {
1037
- setInputValue("");
1038
- setInputCursor(0);
1123
+ applyInputMutation("", 0, true);
1039
1124
  prevEscRef.current = false;
1040
1125
  }
1041
1126
  return;
1042
1127
  }
1043
1128
  if (key.return) {
1044
- handleSubmit(inputValue);
1045
- setInputValue("");
1046
- setInputCursor(0);
1129
+ commitInputState(true);
1130
+ handleSubmit(inputValueRef.current);
1131
+ applyInputMutation("", 0, true);
1047
1132
  return;
1048
1133
  }
1049
1134
  if (key.ctrl && input === "u") {
1050
- setInputValue((prev) => prev.slice(cur));
1051
- setInputCursor(0);
1135
+ applyInputMutation(inputNow.slice(cur), 0);
1052
1136
  return;
1053
1137
  }
1054
1138
  if (key.ctrl && input === "k") {
1055
- setInputValue((prev) => prev.slice(0, cur));
1139
+ applyInputMutation(inputNow.slice(0, cur), cur);
1056
1140
  return;
1057
1141
  }
1058
1142
  const killWordBefore = (key.ctrl && input === "w") ||
1059
1143
  (key.meta && key.backspace) ||
1060
1144
  (key.meta && key.delete && cur > 0);
1061
1145
  if (killWordBefore) {
1062
- const start = wordStartBackward(inputValue, cur);
1146
+ const start = wordStartBackward(inputNow, cur);
1063
1147
  if (start < cur) {
1064
- setInputValue((prev) => prev.slice(0, start) + prev.slice(cur));
1065
- setInputCursor(start);
1148
+ applyInputMutation(inputNow.slice(0, start) + inputNow.slice(cur), start);
1066
1149
  }
1067
1150
  return;
1068
1151
  }
1069
1152
  if (key.meta && input === "d") {
1070
- const end = wordEndForward(inputValue, cur);
1153
+ const end = wordEndForward(inputNow, cur);
1071
1154
  if (end > cur) {
1072
- setInputValue((prev) => prev.slice(0, cur) + prev.slice(end));
1155
+ applyInputMutation(inputNow.slice(0, cur) + inputNow.slice(end), cur);
1073
1156
  }
1074
1157
  return;
1075
1158
  }
1076
1159
  if ((key.meta && key.leftArrow) || (key.ctrl && key.leftArrow)) {
1077
- setInputCursor(wordStartBackward(inputValue, cur));
1160
+ applyInputMutation(inputNow, wordStartBackward(inputNow, cur));
1078
1161
  return;
1079
1162
  }
1080
1163
  if ((key.meta && key.rightArrow) || (key.ctrl && key.rightArrow)) {
1081
- setInputCursor(wordEndForward(inputValue, cur));
1164
+ applyInputMutation(inputNow, wordEndForward(inputNow, cur));
1082
1165
  return;
1083
1166
  }
1084
1167
  if (key.meta && (input === "b" || input === "f")) {
1085
1168
  if (input === "b")
1086
- setInputCursor(wordStartBackward(inputValue, cur));
1169
+ applyInputMutation(inputNow, wordStartBackward(inputNow, cur));
1087
1170
  else
1088
- setInputCursor(wordEndForward(inputValue, cur));
1171
+ applyInputMutation(inputNow, wordEndForward(inputNow, cur));
1089
1172
  return;
1090
1173
  }
1091
1174
  if (key.ctrl && (input === "f" || input === "b")) {
1092
1175
  if (input === "f")
1093
- setInputCursor(Math.min(len, cur + 1));
1176
+ applyInputMutation(inputNow, Math.min(len, cur + 1));
1094
1177
  else
1095
- setInputCursor(Math.max(0, cur - 1));
1178
+ applyInputMutation(inputNow, Math.max(0, cur - 1));
1096
1179
  return;
1097
1180
  }
1098
1181
  if (key.ctrl && input === "j") {
1099
- setInputValue((prev) => prev.slice(0, cur) + "\n" + prev.slice(cur));
1100
- setInputCursor(cur + 1);
1182
+ applyInputMutation(inputNow.slice(0, cur) + "\n" + inputNow.slice(cur), cur + 1);
1101
1183
  return;
1102
1184
  }
1103
1185
  if (key.ctrl && input === "a") {
1104
- setInputCursor(0);
1186
+ applyInputMutation(inputNow, 0);
1105
1187
  return;
1106
1188
  }
1107
1189
  if (key.ctrl && input === "e") {
1108
- setInputCursor(len);
1190
+ applyInputMutation(inputNow, len);
1109
1191
  return;
1110
1192
  }
1111
1193
  if (key.ctrl && input === "h") {
1112
1194
  if (cur > 0) {
1113
- setInputValue((prev) => prev.slice(0, cur - 1) + prev.slice(cur));
1114
- setInputCursor(cur - 1);
1195
+ applyInputMutation(inputNow.slice(0, cur - 1) + inputNow.slice(cur), cur - 1);
1115
1196
  }
1116
1197
  return;
1117
1198
  }
1118
1199
  if (key.ctrl && input === "d") {
1119
1200
  if (cur < len) {
1120
- setInputValue((prev) => prev.slice(0, cur) + prev.slice(cur + 1));
1201
+ applyInputMutation(inputNow.slice(0, cur) + inputNow.slice(cur + 1), cur);
1121
1202
  }
1122
1203
  return;
1123
1204
  }
1124
1205
  if (key.backspace || (key.delete && cur > 0)) {
1125
1206
  if (cur > 0) {
1126
- setInputValue((prev) => prev.slice(0, cur - 1) + prev.slice(cur));
1127
- setInputCursor(cur - 1);
1207
+ applyInputMutation(inputNow.slice(0, cur - 1) + inputNow.slice(cur), cur - 1);
1128
1208
  }
1129
1209
  return;
1130
1210
  }
1131
1211
  if (key.delete && cur < len) {
1132
- setInputValue((prev) => prev.slice(0, cur) + prev.slice(cur + 1));
1212
+ applyInputMutation(inputNow.slice(0, cur) + inputNow.slice(cur + 1), cur);
1133
1213
  return;
1134
1214
  }
1135
1215
  if (key.leftArrow) {
1136
- setInputCursor(Math.max(0, cur - 1));
1216
+ applyInputMutation(inputNow, Math.max(0, cur - 1));
1137
1217
  return;
1138
1218
  }
1139
1219
  if (key.rightArrow) {
1140
- setInputCursor(Math.min(len, cur + 1));
1220
+ applyInputMutation(inputNow, Math.min(len, cur + 1));
1141
1221
  return;
1142
1222
  }
1143
- if (input === "?" && !inputValue.trim()) {
1223
+ if (input === "?" && !inputNow.trim()) {
1144
1224
  setShowHelpModal(true);
1145
1225
  return;
1146
1226
  }
@@ -1148,8 +1228,7 @@ export function Repl({ apiKey, cwd, onQuit }) {
1148
1228
  return;
1149
1229
  }
1150
1230
  if (input && !key.ctrl && !key.meta) {
1151
- setInputValue((prev) => prev.slice(0, cur) + input + prev.slice(cur));
1152
- setInputCursor(cur + input.length);
1231
+ applyInputMutation(inputNow.slice(0, cur) + input + inputNow.slice(cur), cur + input.length);
1153
1232
  return;
1154
1233
  }
1155
1234
  }
@@ -1182,7 +1261,7 @@ export function Repl({ apiKey, cwd, onQuit }) {
1182
1261
  : 0;
1183
1262
  const suggestionBoxLines = slashSuggestionBoxLines || atSuggestionBoxLines;
1184
1263
  // Keep a fixed loading row reserved to avoid viewport jumps/flicker when loading starts/stops.
1185
- const reservedLines = 1 + stableInputLineCount + 2;
1264
+ const reservedLines = 1 + layoutInputLineCount + 2;
1186
1265
  const logViewportHeight = Math.max(1, termRows - reservedLines - suggestionBoxLines);
1187
1266
  const effectiveLogLines = logLines;
1188
1267
  const maxLogScrollOffset = Math.max(0, effectiveLogLines.length - logViewportHeight);
@@ -1216,7 +1295,13 @@ export function Repl({ apiKey, cwd, onQuit }) {
1216
1295
  const leftPad = Math.max(0, Math.floor((termColumns - paletteModalWidth) / 2));
1217
1296
  return (_jsxs(Box, { flexDirection: "column", height: termRows, overflow: "hidden", children: [_jsx(Box, { height: topPad }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: leftPad }), _jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: inkColors.primary, paddingX: 2, paddingY: 1, width: paletteModalWidth, minHeight: paletteModalHeight, children: [_jsx(Text, { bold: true, children: " Command palette " }), COMMANDS.map((c, i) => (_jsxs(Text, { color: i === paletteIndex ? inkColors.primary : undefined, children: [i === paletteIndex ? "› " : " ", c.cmd, _jsxs(Text, { color: inkColors.textSecondary, children: [" \u2014 ", c.desc] })] }, c.cmd))), _jsxs(Text, { color: paletteIndex === COMMANDS.length ? inkColors.primary : undefined, children: [paletteIndex === COMMANDS.length ? "› " : " ", "Cancel (Esc)"] }), _jsx(Text, { color: inkColors.textSecondary, children: " \u2191/\u2193 select, Enter confirm, Esc close " })] })] }), _jsx(Box, { flexGrow: 1 })] }));
1218
1297
  }
1219
- const footerLines = suggestionBoxLines + 1 + stableInputLineCount;
1298
+ const calculatedFooterLines = suggestionBoxLines + 1 + layoutInputLineCount;
1299
+ useEffect(() => {
1300
+ if (!isInputLayoutFrozen) {
1301
+ setFrozenFooterLines(calculatedFooterLines);
1302
+ }
1303
+ }, [isInputLayoutFrozen, calculatedFooterLines]);
1304
+ const footerLines = isInputLayoutFrozen ? frozenFooterLines : calculatedFooterLines;
1220
1305
  loadingFooterLinesRef.current = footerLines;
1221
1306
  return (_jsxs(Box, { flexDirection: "column", height: termRows, overflow: "hidden", children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, minHeight: 0, overflow: "hidden", children: [_jsx(LogViewport, { lines: visibleLogLines, startIndex: logStartIndex, height: logViewportHeight }), _jsx(Box, { flexDirection: "row", marginTop: 1, marginBottom: 0, children: _jsx(Text, { color: inkColors.textSecondary, children: "\u00A0" }) })] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, height: footerLines, children: [showSlashSuggestions && (_jsxs(Box, { flexDirection: "column", marginBottom: 0, paddingLeft: 2, borderStyle: "single", borderColor: inkColors.textDisabled, children: [filteredSlashCommands.length === 0 ? (_jsx(Text, { color: inkColors.textSecondary, children: " No match " })) : ([...filteredSlashCommands].reverse().map((c, rev) => {
1222
1307
  const i = filteredSlashCommands.length - 1 - rev;
@@ -1224,7 +1309,7 @@ export function Repl({ apiKey, cwd, onQuit }) {
1224
1309
  })), _jsx(Text, { color: inkColors.textSecondary, children: " Commands (\u2191/\u2193 select, Enter run, Esc clear) " })] })), cursorInAtSegment && !showSlashSuggestions && (_jsxs(Box, { flexDirection: "column", marginBottom: 0, paddingLeft: 2, borderStyle: "single", borderColor: inkColors.textDisabled, children: [filteredFilePaths.length === 0 ? (_jsxs(Text, { color: inkColors.textSecondary, children: [" ", hasCharsAfterAt ? "No match" : "Type to search files", " "] })) : ([...filteredFilePaths].reverse().map((p, rev) => {
1225
1310
  const i = filteredFilePaths.length - 1 - rev;
1226
1311
  return (_jsxs(Text, { color: i === clampedAtFileIndex ? inkColors.primary : undefined, children: [i === clampedAtFileIndex ? "› " : " ", p] }, p));
1227
- })), _jsx(Box, { flexDirection: "row", marginTop: 1, children: _jsx(Text, { color: inkColors.textSecondary, children: " Files (\u2191/\u2193 select, Enter/Tab complete, Esc clear) " }) })] })), _jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsxs(Text, { color: "gray", children: [" ", icons.tool, " ", tokenDisplay] }), _jsx(Text, { color: "gray", children: ` · / ! @ trackpad/↑/↓ scroll Opt/Fn+select Ctrl+J newline Tab queue Esc Esc edit ${pasteShortcut} paste Ctrl+C exit` })] }), _jsx(Box, { flexDirection: "column", marginTop: 0, children: inputValue.length === 0 ? (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: inkColors.primary, children: [icons.prompt, " "] }), cursorBlinkOn ? (_jsx(Text, { inverse: true, color: inkColors.primary, children: " " })) : (_jsx(Text, { color: inkColors.primary, children: " " })), _jsx(Text, { color: inkColors.textSecondary, children: "Message or / for commands, @ for files, ! for shell, ? for help..." })] })) : ((() => {
1312
+ })), _jsx(Box, { flexDirection: "row", marginTop: 1, children: _jsx(Text, { color: inkColors.textSecondary, children: " Files (\u2191/\u2193 select, Enter/Tab complete, Esc clear) " }) })] })), _jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsxs(Text, { color: inkColors.mutedDark, children: [" ", icons.tool, " ", tokenDisplay] }), _jsx(Text, { color: inkColors.mutedDark, children: ` · / ! @ trackpad/↑/↓ scroll Ctrl+J newline Tab queue Esc Esc edit` })] }), _jsx(Box, { flexDirection: "column", marginTop: 0, children: inputValue.length === 0 ? (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: inkColors.primary, children: [icons.prompt, " "] }), cursorBlinkOn ? (_jsx(Text, { inverse: true, color: inkColors.primary, children: " " })) : (_jsx(Text, { color: inkColors.primary, children: " " })), _jsx(Text, { color: inkColors.textSecondary, children: "Message or / for commands, @ for files, ! for shell, ? for help..." })] })) : ((() => {
1228
1313
  const lines = inputValue.split("\n");
1229
1314
  let lineStart = 0;
1230
1315
  return (_jsx(_Fragment, { children: lines.flatMap((lineText, lineIdx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ideacode",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "CLI TUI for AI agents via OpenRouter — agentic loop, tools, markdown",
5
5
  "type": "module",
6
6
  "repository": {