fluxflow-cli 2.13.0 → 2.13.2

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 (3) hide show
  1. package/README.md +133 -133
  2. package/dist/fluxflow.js +423 -211
  3. package/package.json +68 -67
package/dist/fluxflow.js CHANGED
@@ -2227,12 +2227,21 @@ var init_MultilineInput = __esm({
2227
2227
  const visibleLines = useMemo(() => {
2228
2228
  return visualLines.slice(newScrollOffset, newScrollOffset + visibleRows);
2229
2229
  }, [visualLines, newScrollOffset, visibleRows]);
2230
+ const [blink, setBlink] = useState2(true);
2231
+ useEffect2(() => {
2232
+ setBlink(true);
2233
+ if (!focus || !showCursor) return;
2234
+ const timer = setInterval(() => {
2235
+ setBlink((prev) => !prev);
2236
+ }, 530);
2237
+ return () => clearInterval(timer);
2238
+ }, [focus, showCursor, value, cursorIndex]);
2230
2239
  const cursorStyle = useMemo(() => ({
2231
2240
  ...textStyle,
2232
- color: showCursor && focus ? "white" : void 0,
2233
- bold: showCursor && focus,
2234
- inverse: showCursor && focus
2235
- }), [textStyle, showCursor, focus]);
2241
+ color: showCursor && focus && blink ? "white" : void 0,
2242
+ bold: showCursor && focus && blink,
2243
+ inverse: showCursor && focus && blink
2244
+ }), [textStyle, showCursor, focus, blink]);
2236
2245
  return /* @__PURE__ */ React2.createElement(Box, { height: visibleRows, width: wrapWidth, overflow: "hidden", flexDirection: "column", flexGrow: 0, flexShrink: 0 }, visibleLines.map((lineObj, idx) => {
2237
2246
  const globalLineIdx = newScrollOffset + idx;
2238
2247
  const isCursorLine = globalLineIdx === cursorLine && focus && showCursor;
@@ -2316,6 +2325,16 @@ var init_MultilineInput = __esm({
2316
2325
  cursorIndexRef.current = newIndex;
2317
2326
  setCursorIndex(newIndex);
2318
2327
  setPasteLength(0);
2328
+ } else if (key.upArrow && cursorLine === 0) {
2329
+ cursorIndexRef.current = 0;
2330
+ setCursorIndex(0);
2331
+ setPasteLength(0);
2332
+ } else if (key.downArrow && cursorLine === visualLines.length - 1) {
2333
+ const lastLineObj = visualLines[visualLines.length - 1];
2334
+ const newIndex = lastLineObj.globalStart + lastLineObj.text.length;
2335
+ cursorIndexRef.current = newIndex;
2336
+ setCursorIndex(newIndex);
2337
+ setPasteLength(0);
2319
2338
  }
2320
2339
  }
2321
2340
  } else if (key.leftArrow) {
@@ -2346,6 +2365,22 @@ var init_MultilineInput = __esm({
2346
2365
  onChange(newValue);
2347
2366
  setPasteLength(0);
2348
2367
  }
2368
+ } else if (key.home || key.end) {
2369
+ if (showCursor) {
2370
+ const { visualLines, cursorLine } = computeVisualMatrix(val, curIdx, wrapWidth, identity);
2371
+ const currentLineObj = visualLines[cursorLine];
2372
+ if (currentLineObj) {
2373
+ let newIndex;
2374
+ if (key.home) {
2375
+ newIndex = currentLineObj.globalStart;
2376
+ } else if (key.end) {
2377
+ newIndex = currentLineObj.globalStart + currentLineObj.text.length;
2378
+ }
2379
+ cursorIndexRef.current = newIndex;
2380
+ setCursorIndex(newIndex);
2381
+ setPasteLength(0);
2382
+ }
2383
+ }
2349
2384
  } else {
2350
2385
  if (input) {
2351
2386
  const newValue = val.slice(0, curIdx) + input + val.slice(curIdx);
@@ -2741,6 +2776,7 @@ var init_text = __esm({
2741
2776
  text: line,
2742
2777
  gutterWidth,
2743
2778
  lineNum: idx + 1,
2779
+ isFirstLine: idx === 0,
2744
2780
  isLastLine: isLast
2745
2781
  };
2746
2782
  if (isLast && msg.isStreaming) {
@@ -2758,61 +2794,6 @@ var init_text = __esm({
2758
2794
  const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
2759
2795
  const diffBody = match ? match[1].trim() : "";
2760
2796
  const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
2761
- const highlightInfos = Array(diffLines.length).fill(null);
2762
- let idx = 0;
2763
- while (idx < diffLines.length) {
2764
- const removals = [];
2765
- const additions = [];
2766
- while (idx < diffLines.length) {
2767
- const line = diffLines[idx];
2768
- const cleanLine = line.replace("[UI_CONTEXT]", "");
2769
- if (cleanLine.startsWith("-")) {
2770
- removals.push({ idx, line: cleanLine });
2771
- idx++;
2772
- } else {
2773
- break;
2774
- }
2775
- }
2776
- while (idx < diffLines.length) {
2777
- const line = diffLines[idx];
2778
- const cleanLine = line.replace("[UI_CONTEXT]", "");
2779
- if (cleanLine.startsWith("+")) {
2780
- additions.push({ idx, line: cleanLine });
2781
- idx++;
2782
- } else {
2783
- break;
2784
- }
2785
- }
2786
- if (removals.length > 0 && additions.length > 0) {
2787
- const pairCount = Math.min(removals.length, additions.length);
2788
- for (let k = 0; k < pairCount; k++) {
2789
- const r = removals[k];
2790
- const a = additions[k];
2791
- const rRest = r.line.substring(1);
2792
- const rSplit = rRest.indexOf("|");
2793
- const rContent = rSplit !== -1 ? rRest.substring(rSplit + 1) : rRest;
2794
- const aRest = a.line.substring(1);
2795
- const aSplit = aRest.indexOf("|");
2796
- const aContent = aSplit !== -1 ? aRest.substring(aSplit + 1) : aRest;
2797
- let prefixLen = 0;
2798
- while (prefixLen < rContent.length && prefixLen < aContent.length && rContent[prefixLen] === aContent[prefixLen]) {
2799
- prefixLen++;
2800
- }
2801
- let suffixLen = 0;
2802
- const maxSuffix = Math.min(rContent.length - prefixLen, aContent.length - prefixLen);
2803
- while (suffixLen < maxSuffix && rContent[rContent.length - 1 - suffixLen] === aContent[aContent.length - 1 - suffixLen]) {
2804
- suffixLen++;
2805
- }
2806
- if (prefixLen > 0 || suffixLen > 0) {
2807
- highlightInfos[r.idx] = { prefixLen, suffixLen };
2808
- highlightInfos[a.idx] = { prefixLen, suffixLen };
2809
- }
2810
- }
2811
- }
2812
- if (removals.length === 0 && additions.length === 0) {
2813
- idx++;
2814
- }
2815
- }
2816
2797
  const completedBlocks2 = [];
2817
2798
  let activeBlock2 = null;
2818
2799
  diffLines.forEach((line, i) => {
@@ -2822,7 +2803,8 @@ var init_text = __esm({
2822
2803
  msg,
2823
2804
  type: "diff-line",
2824
2805
  text: line,
2825
- highlightInfo: highlightInfos[i]
2806
+ isFirstLine: i === 0,
2807
+ isLastLine: isLast
2826
2808
  };
2827
2809
  if (isLast && msg.isStreaming) {
2828
2810
  activeBlock2 = block;
@@ -2865,6 +2847,7 @@ var init_text = __esm({
2865
2847
  text: line
2866
2848
  };
2867
2849
  if (isLast && msg.isStreaming) {
2850
+ block.isActiveBlock = true;
2868
2851
  activeBlock = block;
2869
2852
  } else {
2870
2853
  completedBlocks.push(block);
@@ -2900,6 +2883,7 @@ var init_text = __esm({
2900
2883
  text: codeLines.join("\n")
2901
2884
  };
2902
2885
  if (isLast && msg.isStreaming && inCodeBlock) {
2886
+ block.isActiveBlock = true;
2903
2887
  activeBlock = block;
2904
2888
  } else {
2905
2889
  completedBlocks.push(block);
@@ -2918,6 +2902,7 @@ var init_text = __esm({
2918
2902
  text: codeLines.join("\n")
2919
2903
  };
2920
2904
  if (msg.isStreaming) {
2905
+ block.isActiveBlock = true;
2921
2906
  activeBlock = block;
2922
2907
  } else {
2923
2908
  completedBlocks.push(block);
@@ -2933,7 +2918,8 @@ var init_text = __esm({
2933
2918
  msg,
2934
2919
  type: "table",
2935
2920
  text: tableLines.join("\n"),
2936
- isStreaming: true
2921
+ isStreaming: true,
2922
+ isActiveBlock: true
2937
2923
  };
2938
2924
  } else {
2939
2925
  completedBlocks.push({
@@ -2964,6 +2950,7 @@ var init_text = __esm({
2964
2950
  text: line
2965
2951
  };
2966
2952
  if (isLast && msg.isStreaming) {
2953
+ block.isActiveBlock = true;
2967
2954
  activeBlock = block;
2968
2955
  } else {
2969
2956
  completedBlocks.push(block);
@@ -3214,6 +3201,7 @@ var init_TerminalBox = __esm({
3214
3201
  paddingLeft: 2,
3215
3202
  paddingRight: 0,
3216
3203
  paddingY: completed ? 0 : 1,
3204
+ marginTop: 1,
3217
3205
  width: "100%"
3218
3206
  },
3219
3207
  /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React3.createElement(Box2, { flexShrink: 1, paddingRight: 2 }, /* @__PURE__ */ React3.createElement(Text3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", bold: true }, completed ? "\u{1F3C1} FINISHED:" : "\u26A1 EXECUTING:", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, command))), isPty && /* @__PURE__ */ React3.createElement(Box2, { flexShrink: 0, paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", bold: true }, "ADVANCE"))),
@@ -3496,12 +3484,77 @@ ${coloredArt[7]}`;
3496
3484
  // src/components/ChatLayout.jsx
3497
3485
  import React4, { useState as useState3, useEffect as useEffect3, useRef as useRef2 } from "react";
3498
3486
  import { Box as Box3, Text as Text4 } from "ink";
3499
- var formatThinkText, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
3487
+ import { diffWordsWithSpace } from "diff";
3488
+ var useStreamingText, formatThinkText, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, parseLineInfo, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
3500
3489
  var init_ChatLayout = __esm({
3501
3490
  "src/components/ChatLayout.jsx"() {
3502
3491
  init_TerminalBox();
3503
3492
  init_text();
3504
3493
  init_terminal();
3494
+ useStreamingText = (targetText, isStreaming, isActiveBlock) => {
3495
+ const [displayedText, setDisplayedText] = useState3(isActiveBlock && isStreaming ? "" : targetText);
3496
+ const targetTextRef = useRef2(targetText);
3497
+ useEffect3(() => {
3498
+ targetTextRef.current = targetText;
3499
+ }, [targetText]);
3500
+ useEffect3(() => {
3501
+ if (!isActiveBlock) {
3502
+ setDisplayedText(targetText);
3503
+ return;
3504
+ }
3505
+ if (!isStreaming && displayedText === targetText) {
3506
+ return;
3507
+ }
3508
+ const interval = setInterval(() => {
3509
+ setDisplayedText((current) => {
3510
+ const target = targetTextRef.current;
3511
+ if (current.length >= target.length) {
3512
+ if (!isStreaming) {
3513
+ clearInterval(interval);
3514
+ }
3515
+ return current;
3516
+ }
3517
+ if (!target.startsWith(current)) {
3518
+ return target;
3519
+ }
3520
+ const remaining = target.substring(current.length);
3521
+ const words = remaining.split(/(\s+)/);
3522
+ if (words.length <= 1) {
3523
+ if (!isStreaming) {
3524
+ clearInterval(interval);
3525
+ }
3526
+ return target;
3527
+ }
3528
+ const currentWordsCount = current.split(/\s+/).filter(Boolean).length;
3529
+ const targetWordsCount = target.split(/\s+/).filter(Boolean).length;
3530
+ const diff = targetWordsCount - currentWordsCount;
3531
+ let wordsToAdd = 1;
3532
+ if (diff > 15) {
3533
+ wordsToAdd = 4;
3534
+ } else if (diff > 8) {
3535
+ wordsToAdd = 3;
3536
+ } else if (diff > 3) {
3537
+ wordsToAdd = 2;
3538
+ }
3539
+ let addedText = "";
3540
+ let wordCount = 0;
3541
+ for (let i = 0; i < words.length; i++) {
3542
+ const w = words[i];
3543
+ addedText += w;
3544
+ if (/\S/.test(w)) {
3545
+ wordCount++;
3546
+ if (wordCount >= wordsToAdd) {
3547
+ break;
3548
+ }
3549
+ }
3550
+ }
3551
+ return current + addedText;
3552
+ });
3553
+ }, 100);
3554
+ return () => clearInterval(interval);
3555
+ }, [isStreaming, isActiveBlock, targetText, displayedText]);
3556
+ return displayedText;
3557
+ };
3505
3558
  formatThinkText = (cleaned, columns = 80) => {
3506
3559
  if (!cleaned) return null;
3507
3560
  const availableWidth = columns - 10;
@@ -3685,97 +3738,95 @@ var init_ChatLayout = __esm({
3685
3738
  flushBuffers("final");
3686
3739
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: columns - 2 }, result);
3687
3740
  });
3688
- DiffLine = React4.memo(({ line, columns = 80, highlightInfo }) => {
3741
+ parseLineInfo = (l) => {
3742
+ if (!l) return null;
3743
+ const clean = l.replace("[UI_CONTEXT]", "").replace(/\r/g, "");
3744
+ const isR = clean.startsWith("-");
3745
+ const isA = clean.startsWith("+");
3746
+ let rest = isR || isA ? clean.substring(1) : clean;
3747
+ rest = rest.trim();
3748
+ const splitIdx = rest.indexOf("|");
3749
+ const num = splitIdx !== -1 ? rest.substring(0, splitIdx).trim() : "";
3750
+ const content = splitIdx !== -1 ? rest.substring(splitIdx + 1) : rest;
3751
+ return { isR, isA, num, content };
3752
+ };
3753
+ DiffLine = React4.memo(({ line, pairContent, parentText, columns = 80 }) => {
3689
3754
  const isContext = line.includes("[UI_CONTEXT]");
3690
3755
  const cleanLine = line.replace("[UI_CONTEXT]", "");
3691
3756
  if (isContext && cleanLine.includes("\u2550")) {
3692
3757
  return /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2550".repeat(Math.max(10, columns - 4))));
3693
3758
  }
3694
- const isRemoval = cleanLine.startsWith("-");
3695
- const isAddition = cleanLine.startsWith("+");
3696
- const prefixChar = cleanLine[0];
3697
- const rest = cleanLine.substring(1);
3698
- const splitIdx = rest.indexOf("|");
3699
- const lineNum = splitIdx !== -1 ? rest.substring(0, splitIdx).trim() : "";
3700
- const content = splitIdx !== -1 ? rest.substring(splitIdx + 1) : rest;
3701
- const bgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : "#1a1a1a";
3702
- const textColor = isRemoval ? "#ff4d4d" : isAddition ? "#4dff88" : isContext ? "white" : "white";
3703
- const numColor = isRemoval ? "#cf3a3a" : isAddition ? "#3acf65" : "gray";
3704
- const hasHighlight = highlightInfo && (highlightInfo.prefixLen > 0 || highlightInfo.suffixLen > 0);
3705
- const rowBgColor = hasHighlight ? "#1a1a1a" : bgColor;
3706
- if (hasHighlight) {
3707
- const prefixLen = highlightInfo.prefixLen;
3708
- const suffixLen = highlightInfo.suffixLen;
3709
- const prefix = content.substring(0, prefixLen);
3710
- const delta = content.substring(prefixLen, content.length - suffixLen);
3711
- const suffix = content.substring(content.length - suffixLen);
3712
- return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: rowBgColor, paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: numColor, dimColor: isContext }, lineNum)), /* @__PURE__ */ React4.createElement(Box3, { width: 2, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: textColor, bold: true }, isRemoval ? "-" : isAddition ? "+" : " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: textColor, dimColor: isContext }, prefix, /* @__PURE__ */ React4.createElement(Text4, { backgroundColor: bgColor }, delta), suffix)));
3713
- }
3714
- return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: rowBgColor, paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: numColor, dimColor: isContext }, lineNum)), /* @__PURE__ */ React4.createElement(Box3, { width: 2, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: textColor, bold: true }, isRemoval ? "-" : isAddition ? "+" : " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: textColor, dimColor: isContext }, wrapText(content, columns - 14))));
3759
+ const parsedCurrent = parseLineInfo(line);
3760
+ if (!parsedCurrent) {
3761
+ return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 3, flexShrink: 0 }), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, wrapText(cleanLine, columns - 14))));
3762
+ }
3763
+ const { isR: isRemoval, isA: isAddition, num: lineNum, content } = parsedCurrent;
3764
+ const innerBgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : void 0;
3765
+ let finalPairContent = pairContent;
3766
+ if (!finalPairContent && parentText && (isRemoval || isAddition)) {
3767
+ const cleanParent = parentText.replace(/\[DIFF_START\]|\[DIFF_END\]/g, "").trim();
3768
+ const diffLines = cleanParent.split("\n");
3769
+ const pairLine = diffLines.find((l) => {
3770
+ const p = parseLineInfo(l);
3771
+ return p && p.num === lineNum && p.isR !== isRemoval;
3772
+ });
3773
+ if (pairLine) {
3774
+ finalPairContent = parseLineInfo(pairLine).content;
3775
+ }
3776
+ }
3777
+ let words = [];
3778
+ if (finalPairContent !== void 0 && finalPairContent !== null) {
3779
+ const oldStr = isRemoval ? content : finalPairContent;
3780
+ const newStr = isRemoval ? finalPairContent : content;
3781
+ try {
3782
+ words = diffWordsWithSpace(oldStr, newStr);
3783
+ } catch (e) {
3784
+ words = [];
3785
+ }
3786
+ }
3787
+ const hasInlineChange = words.some((part) => isRemoval && part.removed || isAddition && part.added);
3788
+ const isPureUnpairedBlock = !finalPairContent && (isRemoval || isAddition);
3789
+ const hasRealChange = hasInlineChange || isPureUnpairedBlock;
3790
+ const finalNumColor = isRemoval || isAddition ? isRemoval ? "#d96868" : "#68d98c" : "gray";
3791
+ const finalPrefixColor = isRemoval ? "#ff4d4d" : "#4dff88";
3792
+ const displayPrefix = isRemoval ? "-" : isAddition ? "+" : " ";
3793
+ const renderInlineDiff = () => {
3794
+ if (isPureUnpairedBlock) {
3795
+ const blockColor = isRemoval ? "#ff3333" : "#33ff66";
3796
+ return /* @__PURE__ */ React4.createElement(Text4, { color: blockColor }, wrapText(content, columns - 14));
3797
+ }
3798
+ if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
3799
+ const textColor = isRemoval ? "#b34d4d" : isAddition ? "#4db36b" : "gray";
3800
+ return /* @__PURE__ */ React4.createElement(Text4, { color: textColor }, wrapText(content, columns - 14));
3801
+ }
3802
+ return /* @__PURE__ */ React4.createElement(Text4, { wrap: "anywhere" }, words.map((part, idx) => {
3803
+ const isWhitespace = /^\s+$/.test(part.value);
3804
+ if (isRemoval) {
3805
+ const isSurroundedByRemoval = words[idx - 1]?.removed || words[idx + 1]?.removed;
3806
+ if (part.removed || isWhitespace && isSurroundedByRemoval) {
3807
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#ff3333" }, part.value);
3808
+ }
3809
+ if (part.added) return null;
3810
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#b34d4d" }, part.value);
3811
+ }
3812
+ if (isAddition) {
3813
+ const isSurroundedByAddition = words[idx - 1]?.added || words[idx + 1]?.added;
3814
+ if (part.added || isWhitespace && isSurroundedByAddition) {
3815
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#33ff66" }, part.value);
3816
+ }
3817
+ if (part.removed) return null;
3818
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#4db36b" }, part.value);
3819
+ }
3820
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "gray" }, part.value);
3821
+ }));
3822
+ };
3823
+ return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 3, flexShrink: 0, justifyContent: "flex-end" }, /* @__PURE__ */ React4.createElement(Text4, { color: finalNumColor }, lineNum)), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: finalPrefixColor }, displayPrefix)), /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 1, backgroundColor: innerBgColor, flexShrink: 1 }, renderInlineDiff()));
3715
3824
  });
3716
3825
  DiffBlock = React4.memo(({ text, columns = 80 }) => {
3717
3826
  const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
3718
3827
  const diffBody = match ? match[1].trim() : "";
3719
3828
  const diffLines = diffBody.split("\n");
3720
- const highlightInfos = React4.useMemo(() => {
3721
- const infos = Array(diffLines.length).fill(null);
3722
- let idx = 0;
3723
- while (idx < diffLines.length) {
3724
- const removals = [];
3725
- const additions = [];
3726
- while (idx < diffLines.length) {
3727
- const line = diffLines[idx];
3728
- const cleanLine = line.replace("[UI_CONTEXT]", "");
3729
- if (cleanLine.startsWith("-")) {
3730
- removals.push({ idx, line: cleanLine });
3731
- idx++;
3732
- } else {
3733
- break;
3734
- }
3735
- }
3736
- while (idx < diffLines.length) {
3737
- const line = diffLines[idx];
3738
- const cleanLine = line.replace("[UI_CONTEXT]", "");
3739
- if (cleanLine.startsWith("+")) {
3740
- additions.push({ idx, line: cleanLine });
3741
- idx++;
3742
- } else {
3743
- break;
3744
- }
3745
- }
3746
- if (removals.length > 0 && additions.length > 0) {
3747
- const pairCount = Math.min(removals.length, additions.length);
3748
- for (let k = 0; k < pairCount; k++) {
3749
- const r = removals[k];
3750
- const a = additions[k];
3751
- const rRest = r.line.substring(1);
3752
- const rSplit = rRest.indexOf("|");
3753
- const rContent = rSplit !== -1 ? rRest.substring(rSplit + 1) : rRest;
3754
- const aRest = a.line.substring(1);
3755
- const aSplit = aRest.indexOf("|");
3756
- const aContent = aSplit !== -1 ? aRest.substring(aSplit + 1) : aRest;
3757
- let prefixLen = 0;
3758
- while (prefixLen < rContent.length && prefixLen < aContent.length && rContent[prefixLen] === aContent[prefixLen]) {
3759
- prefixLen++;
3760
- }
3761
- let suffixLen = 0;
3762
- const maxSuffix = Math.min(rContent.length - prefixLen, aContent.length - prefixLen);
3763
- while (suffixLen < maxSuffix && rContent[rContent.length - 1 - suffixLen] === aContent[aContent.length - 1 - suffixLen]) {
3764
- suffixLen++;
3765
- }
3766
- if (prefixLen > 0 || suffixLen > 0) {
3767
- infos[r.idx] = { prefixLen, suffixLen };
3768
- infos[a.idx] = { prefixLen, suffixLen };
3769
- }
3770
- }
3771
- }
3772
- if (removals.length === 0 && additions.length === 0) {
3773
- idx++;
3774
- }
3775
- }
3776
- return infos;
3777
- }, [diffLines]);
3778
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: columns - 3, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingY: 0, width: "100%" }, diffLines.map((line, i) => /* @__PURE__ */ React4.createElement(DiffLine, { key: i, line, columns: columns - 3, highlightInfo: highlightInfos[i] }))));
3829
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: columns - 3, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingY: 0, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: 3, flexShrink: 0 }), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, " "))), diffLines.map((line, i) => /* @__PURE__ */ React4.createElement(DiffLine, { key: i, line, parentText: text, columns: columns - 3 })), /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: 3, flexShrink: 0 }), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, " ")))));
3779
3830
  });
3780
3831
  CodeRenderer = React4.memo(({ text, columns = 80 }) => {
3781
3832
  if (!text) return null;
@@ -3808,7 +3859,7 @@ var init_ChatLayout = __esm({
3808
3859
  marginBottom: 1,
3809
3860
  backgroundColor: "#1a1a1a"
3810
3861
  },
3811
- /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: "100%" }, codeLines.map((line, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, line)))))
3862
+ /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, null, " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, " "))), codeLines.map((line, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, line)))), /* @__PURE__ */ React4.createElement(Box3, { width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, null, " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, " "))))
3812
3863
  ));
3813
3864
  }
3814
3865
  if (text.includes("```")) {
@@ -3894,13 +3945,70 @@ var init_ChatLayout = __esm({
3894
3945
  const selectionMatch = msg.text.match(/Selection: (.*)/);
3895
3946
  const selection = selectionMatch ? selectionMatch[1] : "No selection";
3896
3947
  const s = emojiSpace(2);
3897
- return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, "AGENT REQUEST: RESOLVED")), /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, "Selection: ", /* @__PURE__ */ React4.createElement(Text4, { color: "grey", bold: true }, selection)))));
3948
+ return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(
3949
+ Box3,
3950
+ {
3951
+ flexDirection: "column",
3952
+ borderStyle: "single",
3953
+ borderLeft: true,
3954
+ borderRight: false,
3955
+ borderTop: false,
3956
+ borderBottom: false,
3957
+ borderColor: "#444444",
3958
+ paddingLeft: 2,
3959
+ paddingRight: 0,
3960
+ paddingTop: 1,
3961
+ paddingBottom: 1,
3962
+ backgroundColor: "#1a1a1a",
3963
+ width: "100%"
3964
+ },
3965
+ /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, "AGENT REQUEST: RESOLVED")),
3966
+ /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, "Selection: ", /* @__PURE__ */ React4.createElement(Text4, { color: "grey", bold: true }, selection)))
3967
+ ));
3898
3968
  }
3899
3969
  if (msg.isAboutRecord) {
3900
- return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, "ABOUT FLUX FLOW")), /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, msg.text))));
3970
+ return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(
3971
+ Box3,
3972
+ {
3973
+ flexDirection: "column",
3974
+ borderStyle: "single",
3975
+ borderLeft: true,
3976
+ borderRight: false,
3977
+ borderTop: false,
3978
+ borderBottom: false,
3979
+ borderColor: "#444444",
3980
+ paddingLeft: 2,
3981
+ paddingRight: 0,
3982
+ paddingTop: 1,
3983
+ paddingBottom: 1,
3984
+ backgroundColor: "#1a1a1a",
3985
+ width: "100%"
3986
+ },
3987
+ /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, "ABOUT FLUX FLOW")),
3988
+ /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, msg.text))
3989
+ ));
3901
3990
  }
3902
3991
  if (msg.isUpdateNotification) {
3903
- return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, "UPDATE AVAILABLE")), /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(CodeRenderer, { text: msg.text, columns }))));
3992
+ return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(
3993
+ Box3,
3994
+ {
3995
+ flexDirection: "column",
3996
+ borderStyle: "single",
3997
+ borderLeft: true,
3998
+ borderRight: false,
3999
+ borderTop: false,
4000
+ borderBottom: false,
4001
+ borderColor: "#444444",
4002
+ paddingLeft: 2,
4003
+ paddingRight: 0,
4004
+ paddingTop: 1,
4005
+ paddingBottom: 1,
4006
+ backgroundColor: "#1a1a1a",
4007
+ width: "100%"
4008
+ },
4009
+ /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, "UPDATE AVAILABLE")),
4010
+ /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(CodeRenderer, { text: msg.text, columns }))
4011
+ ));
3904
4012
  }
3905
4013
  if (msg.isHelpRecord) {
3906
4014
  const commandList = [
@@ -3993,17 +4101,18 @@ var init_ChatLayout = __esm({
3993
4101
  if (!text || text.trim() === "") {
3994
4102
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", width: "100%", paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2502 "));
3995
4103
  }
3996
- const trimmed = text.trim();
4104
+ const animatedText = useStreamingText(text, msg.isStreaming, block.isActiveBlock);
4105
+ const trimmed = animatedText.trim();
3997
4106
  const isUnordered = /^[\*\-\+]\s/.test(trimmed);
3998
4107
  const isOrdered = /^\d+\.\s/.test(trimmed);
3999
- let content = text;
4108
+ let content = animatedText;
4000
4109
  if (isUnordered || isOrdered) {
4001
4110
  const bullet = isUnordered ? " \u2022 " : trimmed.match(/^\d+\.\s/)[0];
4002
4111
  const indent = " ".repeat(bullet.length);
4003
4112
  const wrappedPart = wrapText(trimmed.replace(/^[\*\-\d+\.]+\s/, ""), columns - (bullet.length + 10));
4004
4113
  content = bullet + wrappedPart.split("\n").join("\n" + indent);
4005
4114
  } else {
4006
- content = wrapText(text, columns - 10);
4115
+ content = wrapText(animatedText, columns - 10);
4007
4116
  }
4008
4117
  const wrappedLines = content.split("\n");
4009
4118
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%" }, wrappedLines.map((wLine, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx, flexDirection: "row", width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2502 "), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(InlineMarkdown, { text: wLine, color: "gray", italic: true })))));
@@ -4016,27 +4125,31 @@ var init_ChatLayout = __esm({
4016
4125
  if (!text || text.trim() === "") {
4017
4126
  return /* @__PURE__ */ React4.createElement(Box3, { height: 1 });
4018
4127
  }
4019
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(CodeRenderer, { text, columns }));
4128
+ const animatedText = useStreamingText(text, msg.isStreaming, block.isActiveBlock);
4129
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(CodeRenderer, { text: animatedText, columns }));
4020
4130
  }
4021
4131
  if (type === "table") {
4022
4132
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(TableRenderer, { buffer: text.split("\n"), terminalWidth: columns }));
4023
4133
  }
4024
4134
  if (type === "diff-line") {
4025
- return /* @__PURE__ */ React4.createElement(
4135
+ const { isFirstLine, isLastLine } = block;
4136
+ const renderPaddingLine = (isEnd = false) => /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: columns, marginBottom: isEnd ? 1 : 0 }, /* @__PURE__ */ React4.createElement(Box3, { width: 3, flexShrink: 0 }), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, " ")));
4137
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, isFirstLine && renderPaddingLine(false), /* @__PURE__ */ React4.createElement(
4026
4138
  DiffLine,
4027
4139
  {
4028
4140
  line: text,
4029
- columns,
4030
- highlightInfo: block.highlightInfo
4141
+ pairContent: block.pairContent,
4142
+ parentText: msg?.text,
4143
+ columns
4031
4144
  }
4032
- );
4145
+ ), isLastLine && renderPaddingLine(true));
4033
4146
  }
4034
4147
  if (type === "write-header") {
4035
4148
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(MarkdownText, { text, columns }));
4036
4149
  }
4037
4150
  if (type === "write-line") {
4038
- const { gutterWidth, lineNum, isLastLine } = block;
4039
- return /* @__PURE__ */ React4.createElement(
4151
+ const { gutterWidth, lineNum, isFirstLine, isLastLine } = block;
4152
+ const renderPaddingLine = (isEnd = false) => /* @__PURE__ */ React4.createElement(
4040
4153
  Box3,
4041
4154
  {
4042
4155
  flexDirection: "row",
@@ -4050,11 +4163,29 @@ var init_ChatLayout = __esm({
4050
4163
  paddingLeft: 2,
4051
4164
  paddingRight: 0,
4052
4165
  backgroundColor: "#1a1a1a",
4053
- marginBottom: isLastLine ? 1 : 0
4166
+ marginBottom: isEnd ? 1 : 0
4167
+ },
4168
+ /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, null, " ".repeat(gutterWidth + 2))),
4169
+ /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, " "))
4170
+ );
4171
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, isFirstLine && renderPaddingLine(false), /* @__PURE__ */ React4.createElement(
4172
+ Box3,
4173
+ {
4174
+ flexDirection: "row",
4175
+ width: columns,
4176
+ borderStyle: "single",
4177
+ borderLeft: true,
4178
+ borderRight: false,
4179
+ borderTop: false,
4180
+ borderBottom: false,
4181
+ borderColor: "#444444",
4182
+ paddingLeft: 2,
4183
+ paddingRight: 0,
4184
+ backgroundColor: "#1a1a1a"
4054
4185
  },
4055
4186
  /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(lineNum).padStart(gutterWidth, " "), " ")),
4056
4187
  /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, text))
4057
- );
4188
+ ), isLastLine && renderPaddingLine(true));
4058
4189
  }
4059
4190
  if (type === "write-footer") {
4060
4191
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: columns, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(MarkdownText, { text, columns }));
@@ -5414,31 +5545,73 @@ var init_AskUserModal = __esm({
5414
5545
  });
5415
5546
  const s = emojiSpace(2);
5416
5547
  if (isSuggestingElse) {
5417
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "white", bold: true }, "\u{1F4AC} SUGGEST SOMETHING ELSE")), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, color: "gray" }, "Replying to: ", question)), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React9.createElement(Text9, { color: "white", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React9.createElement(
5418
- TextInput3,
5419
- {
5420
- value: customInput,
5421
- onChange: setCustomInput,
5422
- onSubmit: () => onResolve(customInput)
5423
- }
5424
- )), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", italic: true }, "(Press Enter to send)")));
5425
- }
5426
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "white", bold: true }, "AGENT REQUEST: ACTION REQUIRED")), /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { bold: true, color: "white" }, question)), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", width: "100%" }, allOptions.map((opt, idx) => {
5427
- const isSelected = idx === selectedIndex;
5428
5548
  return /* @__PURE__ */ React9.createElement(
5429
5549
  Box8,
5430
5550
  {
5431
- key: opt.id,
5432
5551
  flexDirection: "column",
5433
- width: "100%",
5434
- backgroundColor: isSelected ? "#2a2a2a" : void 0,
5435
- paddingX: 1,
5436
- marginBottom: idx === allOptions.length - 1 ? 0 : 1
5552
+ borderStyle: "single",
5553
+ borderLeft: true,
5554
+ borderRight: false,
5555
+ borderTop: false,
5556
+ borderBottom: false,
5557
+ borderColor: "#444444",
5558
+ paddingLeft: 2,
5559
+ paddingRight: 0,
5560
+ paddingTop: 1,
5561
+ paddingBottom: 1,
5562
+ backgroundColor: "#1a1a1a",
5563
+ width: "100%"
5437
5564
  },
5438
- /* @__PURE__ */ React9.createElement(Text9, { color: isSelected ? "white" : "grey", bold: isSelected }, isSelected ? "\u276F " : " ", opt.label),
5439
- opt.description && /* @__PURE__ */ React9.createElement(Box8, { marginLeft: 4 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", italic: true }, opt.description))
5565
+ /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "white", bold: true }, "\u{1F4AC} SUGGEST SOMETHING ELSE")),
5566
+ /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, color: "gray" }, "Replying to: ", question)),
5567
+ /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React9.createElement(Text9, { color: "white", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React9.createElement(
5568
+ TextInput3,
5569
+ {
5570
+ value: customInput,
5571
+ onChange: setCustomInput,
5572
+ onSubmit: () => onResolve(customInput)
5573
+ }
5574
+ )),
5575
+ /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", italic: true }, "(Press Enter to send)"))
5440
5576
  );
5441
- })), /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", italic: true }, "(Use Arrows to navigate, Enter to confirm)")));
5577
+ }
5578
+ return /* @__PURE__ */ React9.createElement(
5579
+ Box8,
5580
+ {
5581
+ flexDirection: "column",
5582
+ borderStyle: "single",
5583
+ borderLeft: true,
5584
+ borderRight: false,
5585
+ borderTop: false,
5586
+ borderBottom: false,
5587
+ borderColor: "#444444",
5588
+ paddingLeft: 2,
5589
+ paddingRight: 0,
5590
+ paddingTop: 1,
5591
+ paddingBottom: 1,
5592
+ backgroundColor: "#1a1a1a",
5593
+ width: "100%"
5594
+ },
5595
+ /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "white", bold: true }, "AGENT REQUEST: ACTION REQUIRED")),
5596
+ /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { bold: true, color: "white" }, question)),
5597
+ /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", width: "100%" }, allOptions.map((opt, idx) => {
5598
+ const isSelected = idx === selectedIndex;
5599
+ return /* @__PURE__ */ React9.createElement(
5600
+ Box8,
5601
+ {
5602
+ key: opt.id,
5603
+ flexDirection: "column",
5604
+ width: "100%",
5605
+ backgroundColor: isSelected ? "#2a2a2a" : void 0,
5606
+ paddingX: 1,
5607
+ marginBottom: idx === allOptions.length - 1 ? 0 : 1
5608
+ },
5609
+ /* @__PURE__ */ React9.createElement(Text9, { color: isSelected ? "white" : "grey", bold: isSelected }, isSelected ? "\u276F " : " ", opt.label),
5610
+ opt.description && /* @__PURE__ */ React9.createElement(Box8, { marginLeft: 4 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", italic: true }, opt.description))
5611
+ );
5612
+ })),
5613
+ /* @__PURE__ */ React9.createElement(Box8, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", italic: true }, "(Use Arrows to navigate, Enter to confirm)"))
5614
+ );
5442
5615
  };
5443
5616
  AskUserModal_default = AskUserModal;
5444
5617
  }
@@ -10461,10 +10634,10 @@ ${boxBottom}`) };
10461
10634
  if (!isError) {
10462
10635
  let label2 = "";
10463
10636
  if (isImage) {
10464
- label2 = `\u2714 Viewed: ${filePath}`;
10637
+ label2 = `\u2714 Viewed: ${filePath}`;
10465
10638
  attachedBinaryPart = binPart;
10466
10639
  } else if (isPdf || isOfficeFile) {
10467
- label2 = `\u2714 Viewed: ${filePath}`;
10640
+ label2 = `\u2714 Viewed: ${filePath}`;
10468
10641
  attachedBinaryPart = binPart;
10469
10642
  } else {
10470
10643
  let totalLines = "...";
@@ -10473,7 +10646,7 @@ ${boxBottom}`) };
10473
10646
  totalLines = content.split("\n").length;
10474
10647
  } catch (e) {
10475
10648
  }
10476
- label2 = `\u2714 Auto-Read: ${filePath} \u2192 Lines ${finalStart} - ${Math.min(finalEnd, totalLines)} of ${totalLines}`;
10649
+ label2 = `\u2714 Auto-Read: ${filePath} \u2192 Lines ${finalStart} - ${Math.min(finalEnd, totalLines)} of ${totalLines}`;
10477
10650
  taggedContextBlocks.push(textResult);
10478
10651
  }
10479
10652
  if (label2) {
@@ -11237,10 +11410,10 @@ ${ideErr} [/ERROR]`;
11237
11410
  let label2 = "";
11238
11411
  if (normToolName === "web_search") {
11239
11412
  const { query, limit = 10 } = parseArgs(toolCall.args);
11240
- label2 = `\u2714 Searched: ${query}`;
11413
+ label2 = `\u2714 Searched: ${query}`;
11241
11414
  } else if (normToolName === "web_scrape") {
11242
11415
  const url = parseArgs(toolCall.args).url || "...";
11243
- label2 = `\u2714 Visited: ${url}`;
11416
+ label2 = `\u2714 Visited: ${url}`;
11244
11417
  } else if (normToolName === "view_file") {
11245
11418
  const { path: targetPath2, StartLine, EndLine, start_line, end_line, startLine, endLine } = parseArgs(toolCall.args);
11246
11419
  const rawStart = StartLine || start_line || startLine;
@@ -11264,30 +11437,30 @@ ${ideErr} [/ERROR]`;
11264
11437
  const isOfficeFile = pathLower.endsWith(".docx") || pathLower.endsWith(".doc") || pathLower.endsWith(".ppt") || pathLower.endsWith(".pptx") || pathLower.endsWith(".xls") || pathLower.endsWith(".xlsx");
11265
11438
  const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
11266
11439
  if (isPdf || isOfficeFile) {
11267
- label2 = `\u2714 Viewed: ${targetPath2}`;
11440
+ label2 = `\u2714 Viewed: ${targetPath2}`;
11268
11441
  } else if (isImage) {
11269
- label2 = `\u2714 Viewed: ${targetPath2}`;
11442
+ label2 = `\u2714 Viewed: ${targetPath2}`;
11270
11443
  } else {
11271
- label2 = `\u2714 Read: ${targetPath2} \u2192 Lines ${sLine} - ${actualEndLine} of ${totalLines}`;
11444
+ label2 = `\u2714 Read: ${targetPath2} \u2192 Lines ${sLine} - ${actualEndLine} of ${totalLines}`;
11272
11445
  }
11273
11446
  } else if (normToolName === "list_files" || normToolName === "read_folder") {
11274
11447
  const action = normToolName === "list_files" ? "List" : "Viewed";
11275
11448
  const path21 = parseArgs(toolCall.args).path;
11276
- label2 = `\u2714 ${action}: ${path21 === "." ? "./" : path21}`;
11449
+ label2 = `\u2714 ${action}: ${path21 === "." ? "./" : path21}`;
11277
11450
  } else if (normToolName === "write_file" || normToolName === "update_file") {
11278
11451
  const action = normToolName === "write_file" ? "Created" : "Edited";
11279
- label2 = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
11452
+ label2 = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
11280
11453
  } else if (normToolName === "write_pdf") {
11281
- label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}`;
11454
+ label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}`;
11282
11455
  } else if (normToolName === "write_docx") {
11283
- label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}`;
11456
+ label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}`;
11284
11457
  } else if (normToolName === "file_map") {
11285
- label2 = `\u2714 Get Map: ${parseArgs(toolCall.args).path || "..."}`;
11458
+ label2 = `\u2714 Get Map: ${parseArgs(toolCall.args).path || "..."}`;
11286
11459
  } else if (normToolName.toLowerCase() === "search_keyword" || normToolName.toLowerCase() === "todo") {
11287
11460
  label2 = "";
11288
11461
  } else if (normToolName.toLowerCase() === "generate_image") {
11289
11462
  const { path: argPath, outputPath, output } = parseArgs(toolCall.args);
11290
- label2 = `\u2714 Generated: ${argPath || outputPath || output || "generated_image.png"}`;
11463
+ label2 = `\u2714 Generated: ${argPath || outputPath || output || "generated_image.png"}`;
11291
11464
  } else if (normToolName.toLowerCase() === "exec_command" || normToolName.toLowerCase() === "ask") {
11292
11465
  label2 = "";
11293
11466
  } else {
@@ -11657,7 +11830,7 @@ ${boxBottom}`) };
11657
11830
  if (successes.length === 0) {
11658
11831
  const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${path19.basename(absPath)}].
11659
11832
  ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
11660
- const errorLabel = `\u2714 Edited: ${path19.basename(absPath)}`.toUpperCase();
11833
+ const errorLabel = `\u2714 Edited: ${path19.basename(absPath)}`.toUpperCase();
11661
11834
  let terminalWidth = 115;
11662
11835
  if (process.stdout.isTTY) {
11663
11836
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -11809,7 +11982,7 @@ ${snippet2}
11809
11982
  [SYSTEM] Check the content preview for verification [/SYSTEM]`;
11810
11983
  }
11811
11984
  const action = normToolName === "write_file" ? "Created" : "Edited";
11812
- const feedbackLabel = `\u2714 ${action}: ${filePath || "..."}`;
11985
+ const feedbackLabel = `\u2714 ${action}: ${filePath || "..."}`;
11813
11986
  let terminalWidth = 115;
11814
11987
  if (process.stdout.isTTY) {
11815
11988
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -11842,7 +12015,7 @@ ${snippet2}
11842
12015
  }
11843
12016
  if (normToolName === "write_file" || normToolName === "update_file") {
11844
12017
  const action = normToolName === "write_file" ? "Write Cancelled" : "Edit Denied";
11845
- const deniedLabel = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
12018
+ const deniedLabel = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
11846
12019
  let terminalWidth = 115;
11847
12020
  if (process.stdout.isTTY) {
11848
12021
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -11938,7 +12111,7 @@ ${boxBottom}`}`) };
11938
12111
  matchCount = parseInt(m[1]);
11939
12112
  }
11940
12113
  }
11941
- const postLabel = `\u2714 Searched: "${keyword}" in ${file ? `"${file}"` : "./"} \u2192 ${matchCount} Match${matchCount === 1 ? "" : "es"}`;
12114
+ const postLabel = `\u2714 Searched: "${keyword}" in ${file ? `"${file}"` : "./"} \u2192 ${matchCount} Match${matchCount === 1 ? "" : "es"}`;
11942
12115
  let terminalWidth = 115;
11943
12116
  if (process.stdout.isTTY) {
11944
12117
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -13508,7 +13681,7 @@ function App({ args = [] }) {
13508
13681
  if (manual) {
13509
13682
  setMessages((prev) => {
13510
13683
  setCompletedIndex(prev.length + 1);
13511
- return [...prev, { id: "check-" + Date.now(), role: "system", text: "\u{1F50D} Checking for updates...", isMeta: true }];
13684
+ return [...prev, { id: "check-" + Date.now(), role: "system", text: "[SYSTEM] Checking for updates...", isMeta: true }];
13512
13685
  });
13513
13686
  }
13514
13687
  try {
@@ -13894,18 +14067,50 @@ function App({ args = [] }) {
13894
14067
  const completed = [];
13895
14068
  const active = [];
13896
14069
  const columns = terminalSize.columns || 80;
13897
- messages.slice(0, completedIndex).forEach((msg) => {
14070
+ const completedMsgs = messages.slice(0, completedIndex);
14071
+ const activeMsgs = messages.slice(completedIndex);
14072
+ const seenAskSelections = /* @__PURE__ */ new Set();
14073
+ const filterDuplicates = (msgList) => {
14074
+ return msgList.filter((msg) => {
14075
+ if (msg.isAskRecord) {
14076
+ const selectionMatch = msg.text?.match(/Selection: (.*)/);
14077
+ const selection = selectionMatch ? selectionMatch[1].trim() : "";
14078
+ if (selection) {
14079
+ if (seenAskSelections.has(selection)) {
14080
+ return false;
14081
+ }
14082
+ seenAskSelections.add(selection);
14083
+ }
14084
+ }
14085
+ return true;
14086
+ });
14087
+ };
14088
+ const uniqueCompleted = filterDuplicates(completedMsgs);
14089
+ const uniqueActive = filterDuplicates(activeMsgs);
14090
+ uniqueCompleted.forEach((msg) => {
13898
14091
  const parsed = parseMessageToBlocks(msg, columns);
13899
14092
  completed.push(...parsed.completed);
13900
14093
  completed.push(...parsed.active);
13901
14094
  });
13902
- messages.slice(completedIndex).forEach((msg) => {
14095
+ uniqueActive.forEach((msg) => {
13903
14096
  const parsed = parseMessageToBlocks(msg, columns);
13904
14097
  completed.push(...parsed.completed);
13905
14098
  active.push(...parsed.active);
13906
14099
  });
13907
- const MAX_BLOCKS = 1e3;
14100
+ const MAX_BLOCKS = 5e9;
13908
14101
  const slicedCompleted = completed.slice(Math.max(0, completed.length - MAX_BLOCKS));
14102
+ if (slicedCompleted.length >= 75e3) {
14103
+ slicedCompleted.push({
14104
+ key: "memory-warning-block",
14105
+ msg: {
14106
+ role: "system",
14107
+ text: `\u26A0\uFE0F MEMORY WARNING: CHAT IS GETTING VERY LONG`,
14108
+ subText: `This session has reached ${slicedCompleted.length} blocks. To maintain optimal performance and prevent high memory usage, it is highly recommended to save and start a clean chat with /clear.`,
14109
+ isHomeWarning: true
14110
+ },
14111
+ type: "full-message"
14112
+ });
14113
+ }
13909
14114
  return {
13910
14115
  completed: slicedCompleted,
13911
14116
  active
@@ -14438,9 +14643,9 @@ function App({ args = [] }) {
14438
14643
  { cmd: "/quit", desc: "Exit and shutdown Flux" },
14439
14644
  { cmd: "/help", desc: "Show all available commands" },
14440
14645
  ...parsedArgs.playground ? [{ cmd: "/move", desc: "Move playground directory to original CWD/playground-export" }] : [],
14646
+ { cmd: "/resume", desc: "Load previous session" },
14441
14647
  { cmd: "/compress", desc: "Summarize and compress chat history" },
14442
14648
  { cmd: "/clear", desc: "Clear terminal screen" },
14443
- { cmd: "/resume", desc: "Load previous session" },
14444
14649
  { cmd: "/revert", desc: "Revert codebase back to a checkpoint" },
14445
14650
  { cmd: "/gemini", desc: "Get a happy message from Gemini CLI" },
14446
14651
  { cmd: "/save", desc: "Force save current chat" },
@@ -15670,20 +15875,27 @@ ${timestamp}` };
15670
15875
  },
15671
15876
  onAskUser: async (question, options) => {
15672
15877
  return new Promise((resolve) => {
15878
+ let resolvedFlag = false;
15673
15879
  setPendingAsk({
15674
15880
  question,
15675
15881
  options,
15676
15882
  resolve: (val) => {
15677
- setMessages((prev) => [
15678
- ...prev,
15679
- {
15680
- id: "ask-" + Date.now(),
15681
- role: "system",
15682
- text: `\u{1F4AC} **Ask User**
15883
+ if (resolvedFlag) return;
15884
+ resolvedFlag = true;
15885
+ setMessages((prev) => {
15886
+ const hasAskRecord = prev.some((m) => m.isAskRecord && m.text?.includes(`Selection: ${val}`));
15887
+ if (hasAskRecord) return prev;
15888
+ return [
15889
+ ...prev,
15890
+ {
15891
+ id: "ask-" + Date.now(),
15892
+ role: "system",
15893
+ text: `\u{1F4AC} **Ask User**
15683
15894
  Selection: ${val}`,
15684
- isAskRecord: true
15685
- }
15686
- ]);
15895
+ isAskRecord: true
15896
+ }
15897
+ ];
15898
+ });
15687
15899
  resolve(val);
15688
15900
  }
15689
15901
  });
@@ -17329,7 +17541,7 @@ var init_app = __esm({
17329
17541
  // src/cli.jsx
17330
17542
  import { spawn as spawn3 } from "child_process";
17331
17543
  import { fileURLToPath as fileURLToPath2 } from "url";
17332
- var HEAP_LIMIT = 4096;
17544
+ var HEAP_LIMIT = 6144;
17333
17545
  var isBundled = fileURLToPath2(import.meta.url).endsWith(".js");
17334
17546
  if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-size"))) {
17335
17547
  const cp = spawn3(process.execPath, [