fluxflow-cli 2.15.3 → 2.16.1

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/fluxflow.js +368 -155
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -2104,7 +2104,7 @@ var init_build = __esm({
2104
2104
 
2105
2105
  // src/utils/text.js
2106
2106
  import os2 from "os";
2107
- var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseLineInfo, getSimilarity, alignChangeGroup, blocksCache, streamingBlocksCache, MAX_CACHE_SIZE, CHUNK_SIZE, indexBlockIntoMap, parseMessageToBlocks, TOOL_LABELS, REGEX_INITIAL_THINK, REGEX_INITIAL_TOOL, REGEX_SYSTEM, REGEX_THINK, REGEX_ANSWER, REGEX_TOOL_RES, REGEX_SUCCESS_ERROR, REGEX_TURN_1, REGEX_END, REGEX_TURN_2, REGEX_TURN_3, REGEX_OPEN_BRACKET, REGEX_RESPONDED, REGEX_PROMPTED, REGEX_ARROWS, REGEX_ARROWS_L, REGEX_ARROWS_U, REGEX_ARROWS_D, REGEX_ARROWS_LR, REGEX_TERMINAL, REGEX_TOOLS, cleanSignals, clearBlocksCache;
2107
+ var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseLineInfo, getSimilarity, alignChangeGroup, blocksCache, streamingBlocksCache, MAX_CACHE_SIZE, CHUNK_SIZE, indexBlockIntoMap, parseMessageToBlocks, TOOL_LABELS, REGEX_INITIAL_THINK, REGEX_INITIAL_TOOL, REGEX_CLEAN_SIGNALS, REGEX_ARROWS_ALL, REGEX_TOOLS, cleanSignals, clearBlocksCache;
2108
2108
  var init_text = __esm({
2109
2109
  "src/utils/text.js"() {
2110
2110
  init_paths();
@@ -2571,15 +2571,31 @@ var init_text = __esm({
2571
2571
  if (existing && existing.text === textContent && existing.type === type && !!existing.isActiveBlock === !!extra.isActiveBlock && !!existing.isStreaming === !!extra.isStreaming && existing.pairContent === extra.pairContent) {
2572
2572
  return existing;
2573
2573
  }
2574
+ const flatText = typeof textContent === "string" ? (" " + textContent).slice(1) : textContent;
2575
+ const flatExtra = { ...extra };
2576
+ if (typeof flatExtra.pairContent === "string") {
2577
+ flatExtra.pairContent = (" " + flatExtra.pairContent).slice(1);
2578
+ }
2579
+ if (Array.isArray(flatExtra.wrappedLines)) {
2580
+ flatExtra.wrappedLines = flatExtra.wrappedLines.map((l) => typeof l === "string" ? (" " + l).slice(1) : l);
2581
+ }
2574
2582
  return {
2575
2583
  key,
2576
- msg,
2584
+ isStreamingMsg: !!msg.isStreaming,
2585
+ workedDuration: msg.workedDuration,
2577
2586
  type,
2578
- text: textContent,
2579
- ...extra
2587
+ text: flatText,
2588
+ msg: type === "full-message" ? msg : void 0,
2589
+ // Only full-message requires role/meta checks
2590
+ ...flatExtra
2580
2591
  };
2581
2592
  };
2582
2593
  if (text.includes("- Content Preview:")) {
2594
+ let extension = "";
2595
+ const fileMatch = text.match(/File\s+\[(.*?)\]/i);
2596
+ if (fileMatch) {
2597
+ extension = fileMatch[1].split(".").pop().toLowerCase();
2598
+ }
2583
2599
  const mainParts = text.split("- Content Preview:");
2584
2600
  const contentPart = mainParts[1] || "";
2585
2601
  const footerMarker = "[SYSTEM] Check the content preview for verification [/SYSTEM]";
@@ -2595,18 +2611,21 @@ var init_text = __esm({
2595
2611
  writeChunk = [];
2596
2612
  completedBlocks2.push(batch.length === 1 ? batch[0] : {
2597
2613
  key: `${batch[0].key}-chunk`,
2598
- msg,
2599
2614
  type: "chunk",
2600
2615
  blocks: batch
2601
2616
  });
2602
2617
  };
2618
+ const innerWidth = columns - (gutterWidth + 6);
2603
2619
  codeLines.forEach((line, idx) => {
2604
2620
  const isLast = idx === codeLines.length - 1;
2621
+ const wrappedLines = wrapText(line, innerWidth).split("\n");
2605
2622
  const block = getBlock(`${msg.id || Date.now()}-write-line-${idx}`, "write-line", line, {
2606
2623
  gutterWidth,
2607
2624
  lineNum: idx + 1,
2608
2625
  isFirstLine: idx === 0,
2609
- isLastLine: isLast
2626
+ isLastLine: isLast,
2627
+ extension,
2628
+ wrappedLines
2610
2629
  });
2611
2630
  if (isLast && msg.isStreaming) {
2612
2631
  flushWrite();
@@ -2646,17 +2665,22 @@ var init_text = __esm({
2646
2665
  diffChunk = [];
2647
2666
  completedBlocks2.push(batch.length === 1 ? batch[0] : {
2648
2667
  key: `${batch[0].key}-chunk`,
2649
- msg,
2650
2668
  type: "chunk",
2651
2669
  blocks: batch
2652
2670
  });
2653
2671
  };
2654
2672
  diffLines.forEach((line, i) => {
2655
2673
  const isLast = i === diffLines.length - 1;
2674
+ const parsed = parsedLines[i].parsed;
2675
+ let wrappedLines = null;
2676
+ if (parsed) {
2677
+ wrappedLines = wrapText(parsed.content, columns - 17).split("\n");
2678
+ }
2656
2679
  const block = getBlock(`${msg.id || Date.now()}-diff-${i}`, "diff-line", line, {
2657
2680
  isFirstLine: i === 0,
2658
2681
  isLastLine: isLast,
2659
- pairContent: parsedLines[i].pairContent
2682
+ pairContent: parsedLines[i].pairContent,
2683
+ wrappedLines
2660
2684
  });
2661
2685
  if (isLast && msg.isStreaming) {
2662
2686
  flushDiff();
@@ -2679,42 +2703,43 @@ var init_text = __esm({
2679
2703
  let activeBlock = null;
2680
2704
  let pendingChunk = [];
2681
2705
  let pendingChunkType = null;
2682
- const flushPending = (force = false) => {
2706
+ const flushPending = () => {
2683
2707
  if (!pendingChunk.length) return;
2684
- if (msg.isStreaming && !force) {
2685
- return;
2686
- }
2687
2708
  const batch = pendingChunk;
2688
2709
  pendingChunk = [];
2689
2710
  pendingChunkType = null;
2690
2711
  completedBlocks.push(batch.length === 1 ? batch[0] : {
2691
2712
  key: `${msg.id || "x"}-chunk-${batch[0].key}`,
2692
- msg,
2693
2713
  type: "chunk",
2694
2714
  blocks: batch
2695
2715
  });
2696
2716
  };
2697
- const enqueue = (block) => {
2698
- if (pendingChunkType !== null && pendingChunkType !== block.type) flushPending(true);
2717
+ const enqueue = (block, isLastOfMessage = false) => {
2718
+ if (pendingChunkType !== null && pendingChunkType !== block.type) flushPending();
2699
2719
  pendingChunk.push(block);
2700
2720
  pendingChunkType = block.type;
2701
- if (pendingChunk.length >= CHUNK_SIZE) flushPending(false);
2721
+ if (pendingChunk.length >= CHUNK_SIZE) {
2722
+ if (msg.isStreaming && isLastOfMessage) return;
2723
+ flushPending();
2724
+ }
2702
2725
  };
2703
2726
  if (msg.role === "think") {
2704
2727
  completedBlocks.push(getBlock(`${msg.id}-header`, "think-header", ""));
2705
2728
  const lines = text.split("\n");
2706
2729
  lines.forEach((line, idx) => {
2707
- enqueue(getBlock(`${msg.id}-${idx}`, "think-line", line, {}));
2730
+ const isLast = idx === lines.length - 1;
2731
+ enqueue(getBlock(`${msg.id}-${idx}`, "think-line", line, {}), isLast);
2708
2732
  });
2709
2733
  if (!msg.isStreaming) {
2710
2734
  flushPending();
2711
- completedBlocks.push({ key: `${msg.id}-footer-padding`, msg, type: "think-footer-padding", text: "" });
2735
+ completedBlocks.push({ key: `${msg.id}-footer-padding`, type: "think-footer-padding", text: "" });
2712
2736
  }
2713
2737
  } else {
2714
2738
  const lines = text.split("\n");
2715
2739
  let inTable = false;
2716
2740
  let tableLines = [];
2717
2741
  let inCodeBlock = false;
2742
+ let currentLang = "";
2718
2743
  let codeLineNum = 0;
2719
2744
  let codeStartIdx = 0;
2720
2745
  lines.forEach((line, idx) => {
@@ -2724,17 +2749,17 @@ var init_text = __esm({
2724
2749
  if (inCodeBlock) {
2725
2750
  if (isCodeBlockMarker) {
2726
2751
  inCodeBlock = false;
2727
- enqueue(getBlock(`${msg.id}-code-close-${codeStartIdx}`, "code-fence-close", "", {}));
2752
+ enqueue(getBlock(`${msg.id}-code-close-${codeStartIdx}`, "code-fence-close", "", {}), isLast);
2728
2753
  } else {
2729
2754
  codeLineNum++;
2730
- enqueue(getBlock(`${msg.id}-code-line-${idx}`, "code-line", line, { lineNum: codeLineNum }));
2755
+ enqueue(getBlock(`${msg.id}-code-line-${idx}`, "code-line", line, { lineNum: codeLineNum, lang: currentLang }), isLast);
2731
2756
  }
2732
2757
  } else if (isCodeBlockMarker) {
2733
2758
  inCodeBlock = true;
2734
2759
  codeStartIdx = idx;
2735
2760
  codeLineNum = 0;
2736
- const lang = line.trim().replace(/^```/, "").trim();
2737
- enqueue(getBlock(`${msg.id}-code-open-${idx}`, "code-fence-open", lang, {}));
2761
+ currentLang = line.trim().replace(/^```/, "").trim();
2762
+ enqueue(getBlock(`${msg.id}-code-open-${idx}`, "code-fence-open", currentLang, {}), isLast);
2738
2763
  } else if (isTableRow) {
2739
2764
  inTable = true;
2740
2765
  tableLines.push(line);
@@ -2753,7 +2778,7 @@ var init_text = __esm({
2753
2778
  inTable = false;
2754
2779
  tableLines = [];
2755
2780
  }
2756
- enqueue(getBlock(`${msg.id}-${idx}`, "agent-line", line, {}));
2781
+ enqueue(getBlock(`${msg.id}-${idx}`, "agent-line", line, {}), isLast);
2757
2782
  }
2758
2783
  });
2759
2784
  if (!msg.isStreaming && msg.workedDuration) {
@@ -2764,7 +2789,6 @@ var init_text = __esm({
2764
2789
  if (msg.isStreaming && pendingChunk.length > 0) {
2765
2790
  activeBlock = pendingChunk.length === 1 ? pendingChunk[0] : {
2766
2791
  key: `${msg.id || "x"}-chunk-active-${pendingChunk[0].key}`,
2767
- msg,
2768
2792
  type: "chunk",
2769
2793
  blocks: pendingChunk
2770
2794
  };
@@ -2823,24 +2847,8 @@ var init_text = __esm({
2823
2847
  };
2824
2848
  REGEX_INITIAL_THINK = /<\/think>(\r?\n){2}/gi;
2825
2849
  REGEX_INITIAL_TOOL = /(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi;
2826
- REGEX_SYSTEM = /\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi;
2827
- REGEX_THINK = /<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi;
2828
- REGEX_ANSWER = /\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi;
2829
- REGEX_TOOL_RES = /\[TOOL RESULT\]:?\s*/gi;
2830
- REGEX_SUCCESS_ERROR = /^\s*(SUCCESS|ERROR):.*(\r?\n)?/gm;
2831
- REGEX_TURN_1 = /\[\s*turn\s*:\s*(continue|finish)\s*\]/gi;
2832
- REGEX_END = /\[\[END\]\]/gi;
2833
- REGEX_TURN_2 = /\[\s*turn\s*:?.*?$/gi;
2834
- REGEX_TURN_3 = /\n\s*turn\s*:?.*?$/gi;
2835
- REGEX_OPEN_BRACKET = /\[\s*$/gi;
2836
- REGEX_RESPONDED = /\n\nResponded on .*/g;
2837
- REGEX_PROMPTED = /\n\n\[Prompted on: .*\]/g;
2838
- REGEX_ARROWS = /(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi;
2839
- REGEX_ARROWS_L = /(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi;
2840
- REGEX_ARROWS_U = /(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi;
2841
- REGEX_ARROWS_D = /(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi;
2842
- REGEX_ARROWS_LR = /(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi;
2843
- REGEX_TERMINAL = /@\[TerminalName:.*?, ProcessId:.*?\]/gi;
2850
+ REGEX_CLEAN_SIGNALS = /\[SYSTEM\][\s\S]*?\[\/SYSTEM\]|<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)|\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)|\[TOOL RESULT\]:?\s*|^\s*(SUCCESS|ERROR):.*(\r?\n)?|\[\s*turn\s*:\s*(continue|finish)\s*\]|\[\[END\]\]|\[\s*turn\s*:?.*?$|\n\s*turn\s*:?.*?$|\[\s*$|\n\nResponded on .*|\n\n\[Prompted on: .*\]|@\[TerminalName:.*?, ProcessId:.*?\]/gmi;
2851
+ REGEX_ARROWS_ALL = /(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)|(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)|(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)|(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)|(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi;
2844
2852
  REGEX_TOOLS = /\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_docx|generate_image)\b/gi;
2845
2853
  cleanSignals = (text) => {
2846
2854
  if (!text) return text;
@@ -2898,7 +2906,18 @@ var init_text = __esm({
2898
2906
  }
2899
2907
  }
2900
2908
  }
2901
- return result.replaceAll(REGEX_SYSTEM, "").replaceAll(REGEX_THINK, "").replace(REGEX_ANSWER, "").replaceAll(REGEX_TOOL_RES, "").replaceAll(REGEX_SUCCESS_ERROR, "").replaceAll(REGEX_TURN_1, "").replaceAll(REGEX_END, "").replaceAll(REGEX_TURN_2, "").replaceAll(REGEX_TURN_3, "").replaceAll(REGEX_OPEN_BRACKET, "").replaceAll(REGEX_RESPONDED, "").replaceAll(REGEX_PROMPTED, "").replaceAll(REGEX_ARROWS, "\u2192").replaceAll(REGEX_ARROWS_L, "\u2190").replaceAll(REGEX_ARROWS_U, "\u2191").replaceAll(REGEX_ARROWS_D, "\u2193").replaceAll(REGEX_ARROWS_LR, "\u2194").replaceAll(REGEX_TERMINAL, "").replaceAll(REGEX_TOOLS, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
2909
+ result = result.replace(REGEX_CLEAN_SIGNALS, "");
2910
+ result = result.replace(REGEX_ARROWS_ALL, (match) => {
2911
+ const lower = match.toLowerCase();
2912
+ if (lower.includes("leftrightarrow")) return "\u2194";
2913
+ if (lower.includes("rightarrow")) return "\u2192";
2914
+ if (lower.includes("leftarrow")) return "\u2190";
2915
+ if (lower.includes("uparrow")) return "\u2191";
2916
+ if (lower.includes("downarrow")) return "\u2193";
2917
+ return match;
2918
+ });
2919
+ result = result.replace(REGEX_TOOLS, (match) => TOOL_LABELS[match.toLowerCase()] || match);
2920
+ return result.trim();
2902
2921
  };
2903
2922
  clearBlocksCache = () => {
2904
2923
  blocksCache.clear();
@@ -3512,7 +3531,7 @@ var init_MultilineInput = __esm({
3512
3531
  } else {
3513
3532
  pasteTimerRef.current = setTimeout(() => {
3514
3533
  finalizePasteTransaction();
3515
- }, 100);
3534
+ }, 80);
3516
3535
  }
3517
3536
  } else {
3518
3537
  adjustPasteBlocksOnEdit(curIdx, cleanInput.length);
@@ -3672,19 +3691,19 @@ var init_TerminalBox = __esm({
3672
3691
  return resultLines.join("\n");
3673
3692
  };
3674
3693
  const cleanOutput = processPTY(output).replace(/\n{3,}/g, "\n\n");
3675
- const displayOutput = isPty ? cleanOutput : cleanOutput ? wrapText(cleanOutput, columns - 6) : "";
3694
+ const rawLines = isPty ? cleanOutput ? cleanOutput.split("\n") : [] : cleanOutput ? wrapText(cleanOutput, columns - 6) : [];
3676
3695
  const [isExpanded, setIsExpanded] = useState3(false);
3677
3696
  useInput2((input, key) => {
3678
3697
  if (isFocused && key.ctrl && (input === "o" || input === "")) {
3679
3698
  setIsExpanded((prev) => !prev);
3680
3699
  }
3681
3700
  }, { isActive: isFocused });
3682
- const rawLines = displayOutput ? displayOutput.split("\n") : [];
3683
3701
  const limit = Math.max(5, completed ? terminalHeight - 10 : terminalHeight - 20);
3684
3702
  const hasCollapsibleContent = rawLines.length > limit;
3685
3703
  const collapsedCount = rawLines.length - limit;
3686
3704
  const visibleLines = hasCollapsibleContent && !isExpanded ? rawLines.slice(rawLines.length - limit) : rawLines;
3687
3705
  const renderedOutput = visibleLines.join("\n");
3706
+ const displayOutput = rawLines.length > 0;
3688
3707
  return /* @__PURE__ */ React3.createElement(
3689
3708
  Box2,
3690
3709
  {
@@ -3697,7 +3716,7 @@ var init_TerminalBox = __esm({
3697
3716
  borderColor: "#555555",
3698
3717
  paddingLeft: 2,
3699
3718
  paddingRight: 0,
3700
- paddingY: completed ? 0 : 1,
3719
+ paddingY: 1,
3701
3720
  marginTop: 1,
3702
3721
  width: "100%"
3703
3722
  },
@@ -3982,7 +4001,7 @@ ${coloredArt[7]}`;
3982
4001
  import React4, { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
3983
4002
  import { Box as Box3, Text as Text4 } from "ink";
3984
4003
  import { diffWordsWithSpace } from "diff";
3985
- var useStreamingText, formatThinkText, REGEX_MD_TOKENS, REGEX_LATEX_FRAC, REGEX_LATEX_STYLE, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
4004
+ var useStreamingText, formatThinkText, REGEX_MD_TOKENS, REGEX_LATEX_FRAC, REGEX_LATEX_STYLE, parseMathSymbols, SYNTAX_KEYWORDS, SYNTAX_RULES, REGEX_SYNTAX, tokenCache, MAX_TOKEN_CACHE_SIZE, tokenizeLine, renderHighlightedLine, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
3986
4005
  var init_ChatLayout = __esm({
3987
4006
  "src/components/ChatLayout.jsx"() {
3988
4007
  init_TerminalBox();
@@ -4023,6 +4042,74 @@ var init_ChatLayout = __esm({
4023
4042
  parseMathSymbols = (content) => {
4024
4043
  return content.replace(/\\multiply|\\mul|\\times/g, "\xD7").replace(/\\div/g, "\xF7").replace(/\\cdot/g, "\u22C5").replace(/\\infty/g, "\u221E").replace(/\\pm/g, "\xB1").replace(/\\leq/g, "\u2264").replace(/\\geq/g, "\u2265").replace(/\\neq/g, "\u2260").replace(/\\sqrt\s*\{([^}]+)\}/g, "\u221A($1)").replace(/\\sqrt\s*(\w+|\d+)/g, "\u221A($1)").replace(/\\alpha/g, "\u03B1").replace(/\\beta/g, "\u03B2").replace(/\\theta/g, "\u03B8").replace(/\\pi/g, "\u03C0").replace(/\\approx/g, "\u2248").replace(/\\Delta/g, "\u0394").replace(/\\sigma/g, "\u03C3").replace(/\\sum/g, "\u03A3").replace(/\\prod/g, "\u03A0").replace(/\\rightarrow|\\to/g, "\u2192").replace(/\\left\b|\\right\b/g, "").replace(/\\left\(|\\right\)/g, (match) => match.includes("left") ? "(" : ")").replace(/\\left\[|\\right\]/g, (match) => match.includes("left") ? "[" : "]").replace(/\\\{|\\\}/g, (match) => match.includes("{") ? "{" : "}").replace(/\\text\s*\{([^}]+)\}/g, "$1").replace(/\\text\s+(\w+)/g, "$1").replace(/\\%/g, "%");
4025
4044
  };
4045
+ SYNTAX_KEYWORDS = /\b(const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|import|export|from|default|class|extends|new|this|typeof|instanceof|try|catch|finally|throw|async|await|yield|public|private|protected|static|void|int|float|double|char|bool|boolean|def|elif|fn|pub|mut|struct|impl|enum|type|interface|package|namespace|using|include|define|nil|None|self|lambda)\b/;
4046
+ SYNTAX_RULES = [
4047
+ // Include paths
4048
+ /((?<=\binclude\s+)(?:<[^>]+>|"[^"]+"))/.source,
4049
+ // Import paths
4050
+ /((?<=\b(?:from|import|require\s*\(\s*)\s*)(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"))/.source,
4051
+ // Comments
4052
+ /(\/\/.*|#.*)/.source,
4053
+ // Strings
4054
+ /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^\`\\])*`)/.source,
4055
+ SYNTAX_KEYWORDS.source,
4056
+ /\b([a-zA-Z_][a-zA-Z0-9_]*)(?=\s*\()/.source,
4057
+ /\b(true|false|null|undefined|nil|None)\b/.source,
4058
+ /\b(\d+(?:\.\d+)?|0x[0-9a-fA-F]+)\b/.source
4059
+ ];
4060
+ REGEX_SYNTAX = new RegExp(SYNTAX_RULES.join("|"), "g");
4061
+ tokenCache = /* @__PURE__ */ new Map();
4062
+ MAX_TOKEN_CACHE_SIZE = 1e3;
4063
+ tokenizeLine = (line, lang) => {
4064
+ if (!line) return [];
4065
+ const cacheKey = `${lang}:${line}`;
4066
+ if (tokenCache.has(cacheKey)) {
4067
+ return tokenCache.get(cacheKey);
4068
+ }
4069
+ let lastIndex = 0;
4070
+ const tokens = [];
4071
+ let match;
4072
+ REGEX_SYNTAX.lastIndex = 0;
4073
+ while ((match = REGEX_SYNTAX.exec(line)) !== null) {
4074
+ const matchText = match[0];
4075
+ const matchIndex = match.index;
4076
+ if (matchIndex > lastIndex) {
4077
+ tokens.push({ text: line.substring(lastIndex, matchIndex) });
4078
+ }
4079
+ let color = void 0;
4080
+ let bold = false;
4081
+ if (match[1] || match[2]) {
4082
+ color = "#ce9178";
4083
+ } else if (match[3]) {
4084
+ color = "#9ece6a";
4085
+ } else if (match[4]) {
4086
+ color = "#fcfca4";
4087
+ } else if (match[5]) {
4088
+ color = "#ff7b72";
4089
+ bold = true;
4090
+ } else if (match[6]) {
4091
+ color = "#b392f0";
4092
+ } else if (match[7] || match[8]) {
4093
+ color = "#ff9e64";
4094
+ }
4095
+ tokens.push({ text: matchText, color, bold });
4096
+ lastIndex = REGEX_SYNTAX.lastIndex;
4097
+ }
4098
+ if (lastIndex < line.length) {
4099
+ tokens.push({ text: line.substring(lastIndex) });
4100
+ }
4101
+ if (tokenCache.size >= MAX_TOKEN_CACHE_SIZE) {
4102
+ const firstKey = tokenCache.keys().next().value;
4103
+ tokenCache.delete(firstKey);
4104
+ }
4105
+ tokenCache.set(cacheKey, tokens);
4106
+ return tokens;
4107
+ };
4108
+ renderHighlightedLine = (line, lang, defaultColor = void 0) => {
4109
+ if (!line) return /* @__PURE__ */ React4.createElement(Text4, null, " ");
4110
+ const tokens = tokenizeLine(line, lang);
4111
+ return /* @__PURE__ */ React4.createElement(Text4, { color: defaultColor }, tokens.map((token, idx) => /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: token.color || defaultColor, bold: token.bold }, token.text)));
4112
+ };
4026
4113
  renderLatexText = (content, key) => {
4027
4114
  if (!content) return null;
4028
4115
  let formatted = content.replace(REGEX_LATEX_FRAC, "($1/$2)");
@@ -4169,15 +4256,16 @@ var init_ChatLayout = __esm({
4169
4256
  } else {
4170
4257
  content = wrapText(trimmed, columns - 4);
4171
4258
  }
4259
+ const linesOfContent = content.split("\n");
4172
4260
  result.push(
4173
- /* @__PURE__ */ React4.createElement(Box3, { key: i, width: "100%" }, /* @__PURE__ */ React4.createElement(InlineMarkdown, { text: content, color, italic }))
4261
+ /* @__PURE__ */ React4.createElement(Box3, { key: i, flexDirection: "column", width: "100%" }, linesOfContent.map((l, lIdx) => /* @__PURE__ */ React4.createElement(InlineMarkdown, { key: lIdx, text: l, color, italic })))
4174
4262
  );
4175
4263
  }
4176
4264
  });
4177
4265
  flushBuffers("final");
4178
4266
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: columns - 2 }, result);
4179
4267
  });
4180
- DiffLine = React4.memo(({ line, pairContent, parentText, columns = 80 }) => {
4268
+ DiffLine = React4.memo(({ line, pairContent, parentText, columns = 80, extension }) => {
4181
4269
  const isContext = line.includes("[UI_CONTEXT]");
4182
4270
  const cleanLine = line.replace("[UI_CONTEXT]", "");
4183
4271
  if (isContext && cleanLine.includes("\u2550")) {
@@ -4189,37 +4277,6 @@ var init_ChatLayout = __esm({
4189
4277
  }
4190
4278
  const { isR: isRemoval, isA: isAddition, num: lineNum, content } = parsedCurrent;
4191
4279
  let finalPairContent = pairContent;
4192
- if (!finalPairContent && parentText && (isRemoval || isAddition)) {
4193
- const match = parentText.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
4194
- const diffBody = match ? match[1].trim() : "";
4195
- const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
4196
- const parsedLines = diffLines.map((l) => {
4197
- return {
4198
- line: l,
4199
- parsed: parseLineInfo(l),
4200
- pairContent: null
4201
- };
4202
- });
4203
- let currentGroup = [];
4204
- for (let idx = 0; idx < parsedLines.length; idx++) {
4205
- const item = parsedLines[idx];
4206
- if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
4207
- currentGroup.push(item);
4208
- } else {
4209
- if (currentGroup.length > 0) {
4210
- alignChangeGroup(currentGroup);
4211
- currentGroup = [];
4212
- }
4213
- }
4214
- }
4215
- if (currentGroup.length > 0) {
4216
- alignChangeGroup(currentGroup);
4217
- }
4218
- const matchedItem = parsedLines.find((item) => item.parsed && item.parsed.num === lineNum && item.parsed.isR === isRemoval);
4219
- if (matchedItem) {
4220
- finalPairContent = matchedItem.pairContent;
4221
- }
4222
- }
4223
4280
  let words = [];
4224
4281
  if (finalPairContent !== void 0 && finalPairContent !== null) {
4225
4282
  const oldStr = isRemoval ? content : finalPairContent;
@@ -4238,19 +4295,21 @@ var init_ChatLayout = __esm({
4238
4295
  const displayPrefix = isRemoval ? "-" : isAddition ? "+" : " ";
4239
4296
  const renderInlineDiff = () => {
4240
4297
  if (isPureUnpairedBlock) {
4241
- const blockColor = isRemoval ? "#ff3333" : "#33ff66";
4242
- return /* @__PURE__ */ React4.createElement(Text4, { color: blockColor }, wrapText(content, columns - 14));
4298
+ const blockColor = isRemoval ? "#ffdddd" : "#ddffdd";
4299
+ const wrappedLines = wrapText(content, columns - 14).split("\n");
4300
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, blockColor))));
4243
4301
  }
4244
4302
  if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
4245
4303
  const textColor = isRemoval ? "#885555" : isAddition ? "#558866" : "gray";
4246
- return /* @__PURE__ */ React4.createElement(Text4, { color: textColor }, wrapText(content, columns - 14));
4304
+ const wrappedLines = wrapText(content, columns - 14).split("\n");
4305
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, textColor))));
4247
4306
  }
4248
4307
  return /* @__PURE__ */ React4.createElement(Text4, { wrap: "anywhere" }, words.map((part, idx) => {
4249
4308
  const isWhitespace = /^\s+$/.test(part.value);
4250
4309
  if (isRemoval) {
4251
4310
  const isSurroundedByRemoval = words[idx - 1]?.removed || words[idx + 1]?.removed;
4252
4311
  if (part.removed || isWhitespace && isSurroundedByRemoval) {
4253
- return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#ff3333" }, part.value);
4312
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#ff3333", backgroundColor: "#5a1818" }, part.value);
4254
4313
  }
4255
4314
  if (part.added) return null;
4256
4315
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#885555" }, part.value);
@@ -4258,7 +4317,7 @@ var init_ChatLayout = __esm({
4258
4317
  if (isAddition) {
4259
4318
  const isSurroundedByAddition = words[idx - 1]?.added || words[idx + 1]?.added;
4260
4319
  if (part.added || isWhitespace && isSurroundedByAddition) {
4261
- return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#33ff66" }, part.value);
4320
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#33ff66", backgroundColor: "#185a25" }, part.value);
4262
4321
  }
4263
4322
  if (part.removed) return null;
4264
4323
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#558866" }, part.value);
@@ -4268,8 +4327,8 @@ var init_ChatLayout = __esm({
4268
4327
  };
4269
4328
  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()));
4270
4329
  });
4271
- DiffBlock = React4.memo(({ text, columns = 80 }) => {
4272
- const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
4330
+ DiffBlock = React4.memo(({ text, columns = 80, extension }) => {
4331
+ const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
4273
4332
  const diffBody = match ? match[1].trim() : "";
4274
4333
  const diffLines = diffBody.split("\n");
4275
4334
  const parsedLines = diffLines.map((line) => {
@@ -4300,14 +4359,20 @@ var init_ChatLayout = __esm({
4300
4359
  key: i,
4301
4360
  line: item.line,
4302
4361
  pairContent: item.pairContent,
4303
- columns: columns - 3
4362
+ columns: columns - 3,
4363
+ extension
4304
4364
  }
4305
4365
  )), /* @__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, " ")))));
4306
4366
  });
4307
4367
  CodeRenderer = React4.memo(({ text, columns = 80 }) => {
4308
4368
  if (!text) return null;
4369
+ let extension = "";
4370
+ const fileMatch = text.match(/File\s+\[(.*?)\]/i);
4371
+ if (fileMatch) {
4372
+ extension = fileMatch[1].split(".").pop().toLowerCase();
4373
+ }
4309
4374
  if (text.includes("[DIFF_START]")) {
4310
- return /* @__PURE__ */ React4.createElement(DiffBlock, { text, columns });
4375
+ return /* @__PURE__ */ React4.createElement(DiffBlock, { text, columns, extension });
4311
4376
  }
4312
4377
  if (text.includes("- Content Preview:")) {
4313
4378
  const mainParts = text.split("- Content Preview:");
@@ -4335,7 +4400,7 @@ var init_ChatLayout = __esm({
4335
4400
  marginBottom: 1,
4336
4401
  backgroundColor: "#1a1a1a"
4337
4402
  },
4338
- /* @__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, " "))))
4403
+ /* @__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 }, renderHighlightedLine(line, extension, "white")))), /* @__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, " "))))
4339
4404
  ));
4340
4405
  }
4341
4406
  if (text.includes("```")) {
@@ -4364,7 +4429,7 @@ var init_ChatLayout = __esm({
4364
4429
  width: "100%"
4365
4430
  },
4366
4431
  /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "\u25B6_ ", lang.toUpperCase() || "CODE")),
4367
- /* @__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" }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "#fcfca4ff" }, line)))))
4432
+ /* @__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" }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, renderHighlightedLine(line, lang, "#e1e4e8")))))
4368
4433
  );
4369
4434
  }
4370
4435
  let cleanPart = part;
@@ -4556,7 +4621,7 @@ var init_ChatLayout = __esm({
4556
4621
  );
4557
4622
  });
4558
4623
  BlockItem = React4.memo(({ block, columns = 80, showFullThinking, aiProvider, version }) => {
4559
- const { msg, type, text, isStreaming } = block;
4624
+ const { msg, type, text, isStreamingMsg, workedDuration } = block;
4560
4625
  if (type === "chunk") {
4561
4626
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: "100%" }, block.blocks.map((b) => /* @__PURE__ */ React4.createElement(
4562
4627
  BlockItem,
@@ -4583,14 +4648,14 @@ var init_ChatLayout = __esm({
4583
4648
  );
4584
4649
  }
4585
4650
  if (type === "think-header") {
4586
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%", marginTop: 0, marginBottom: 0 }, msg.isStreaming ? /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "white" }, "\u2727 Thinking...") : /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "white" }, "\u2726 Thought..."), showFullThinking && /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2502 ")));
4651
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%", marginTop: 0, marginBottom: 0 }, isStreamingMsg ? /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "white" }, "\u2727 Thinking...") : /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "white" }, "\u2726 Thought..."), showFullThinking && /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2502 ")));
4587
4652
  }
4588
4653
  if (type === "think-line") {
4589
4654
  if (!showFullThinking) return null;
4590
4655
  if (!text || text.trim() === "") {
4591
4656
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", width: "100%", paddingX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2502 "));
4592
4657
  }
4593
- const animatedText = useStreamingText(text, msg.isStreaming, block.isActiveBlock);
4658
+ const animatedText = useStreamingText(text, isStreamingMsg, block.isActiveBlock);
4594
4659
  const trimmed = animatedText.trim();
4595
4660
  const isUnordered = /^[\*\-\+]\s/.test(trimmed);
4596
4661
  const isOrdered = /^\d+\.\s/.test(trimmed);
@@ -4614,7 +4679,7 @@ var init_ChatLayout = __esm({
4614
4679
  if (!text || text.trim() === "") {
4615
4680
  return /* @__PURE__ */ React4.createElement(Box3, { height: 1 });
4616
4681
  }
4617
- const animatedText = useStreamingText(text, msg.isStreaming, block.isActiveBlock);
4682
+ const animatedText = useStreamingText(text, isStreamingMsg, block.isActiveBlock);
4618
4683
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(CodeRenderer, { text: animatedText, columns }));
4619
4684
  }
4620
4685
  if (type === "table") {
@@ -4628,7 +4693,7 @@ var init_ChatLayout = __esm({
4628
4693
  {
4629
4694
  line: text,
4630
4695
  pairContent: block.pairContent,
4631
- parentText: msg?.text,
4696
+ parentText: void 0,
4632
4697
  columns
4633
4698
  }
4634
4699
  ), isLastLine && renderPaddingLine(true));
@@ -4647,7 +4712,7 @@ var init_ChatLayout = __esm({
4647
4712
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", ...borderProps }, /* @__PURE__ */ React4.createElement(Text4, null, " ")), /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", ...borderProps }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "\u25B6_ ", (text || "CODE").toUpperCase())));
4648
4713
  }
4649
4714
  if (type === "code-line") {
4650
- const { lineNum } = block;
4715
+ const { lineNum, lang } = block;
4651
4716
  return /* @__PURE__ */ React4.createElement(
4652
4717
  Box3,
4653
4718
  {
@@ -4662,7 +4727,7 @@ var init_ChatLayout = __esm({
4662
4727
  width: "100%"
4663
4728
  },
4664
4729
  /* @__PURE__ */ React4.createElement(Box3, { width: 4, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(lineNum).padStart(3, " "), " ")),
4665
- /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "#fcfca4ff" }, text))
4730
+ /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, renderHighlightedLine(text, lang, "#e1e4e8"))
4666
4731
  );
4667
4732
  }
4668
4733
  if (type === "code-fence-close") {
@@ -4687,7 +4752,7 @@ var init_ChatLayout = __esm({
4687
4752
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(MarkdownText, { text, columns }));
4688
4753
  }
4689
4754
  if (type === "write-line") {
4690
- const { gutterWidth, lineNum, isFirstLine, isLastLine } = block;
4755
+ const { gutterWidth, lineNum, isFirstLine, isLastLine, extension, wrappedLines } = block;
4691
4756
  const renderPaddingLine = (isEnd = false) => /* @__PURE__ */ React4.createElement(
4692
4757
  Box3,
4693
4758
  {
@@ -4723,14 +4788,14 @@ var init_ChatLayout = __esm({
4723
4788
  backgroundColor: "#1a1a1a"
4724
4789
  },
4725
4790
  /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(lineNum).padStart(gutterWidth, " "), " ")),
4726
- /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, text))
4791
+ /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1, flexDirection: "column" }, (wrappedLines || [text]).map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, "white"))))
4727
4792
  ), isLastLine && renderPaddingLine(true));
4728
4793
  }
4729
4794
  if (type === "write-footer") {
4730
4795
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: columns, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React4.createElement(MarkdownText, { text, columns }));
4731
4796
  }
4732
4797
  if (type === "worked-duration") {
4733
- return /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1, marginBottom: 2, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, null, "["), /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "Worked for ", /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "white" }, formatThinkingDuration(msg.workedDuration))), /* @__PURE__ */ React4.createElement(Text4, null, "]"));
4798
+ return /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1, marginBottom: 2, paddingX: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, null, "["), /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "Worked for ", /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "white" }, formatThinkingDuration(workedDuration))), /* @__PURE__ */ React4.createElement(Text4, null, "]"));
4734
4799
  }
4735
4800
  return null;
4736
4801
  });
@@ -4779,7 +4844,7 @@ var init_StatusBar = __esm({
4779
4844
  getMemoryInfo();
4780
4845
  const interval = setInterval(() => {
4781
4846
  getMemoryInfo();
4782
- }, 3e3);
4847
+ }, 3e4);
4783
4848
  return () => clearInterval(interval);
4784
4849
  }, []);
4785
4850
  let maxLimit = 256e3;
@@ -5512,10 +5577,22 @@ var init_exec_command = __esm({
5512
5577
  netEnv.NO_PROXY = "localhost,127.0.0.1";
5513
5578
  }
5514
5579
  return new Promise((resolve) => {
5515
- const attempt = (usePowerShell) => {
5516
- const command = adjustWindowsCommand(rawCommand, usePowerShell);
5517
- let shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
5518
- let shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
5580
+ const attempt = (shellType) => {
5581
+ const isPowerShell = shellType === "pwsh" || shellType === "powershell";
5582
+ const command = adjustWindowsCommand(rawCommand, isPowerShell);
5583
+ let shell;
5584
+ if (isWin) {
5585
+ if (shellType === "pwsh") {
5586
+ shell = "C:\\Users\\User\\AppData\\Local\\Microsoft\\WindowsApps\\pwsh.exe";
5587
+ } else if (shellType === "powershell") {
5588
+ shell = "powershell.exe";
5589
+ } else {
5590
+ shell = "cmd.exe";
5591
+ }
5592
+ } else {
5593
+ shell = process.env.SHELL || "bash";
5594
+ }
5595
+ let shellArgs = isWin ? isPowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
5519
5596
  if (systemSettings.networkAccess === false && !isWin) {
5520
5597
  const originalShell = shell;
5521
5598
  const originalArgs = [...shellArgs];
@@ -5577,30 +5654,44 @@ ${finalOutput}`);
5577
5654
  });
5578
5655
  return true;
5579
5656
  } catch (err) {
5580
- if (isWin && usePowerShell && err.code === "ENOENT") {
5657
+ if (isWin && (shellType === "pwsh" || shellType === "powershell") && err.code === "ENOENT") {
5581
5658
  return false;
5582
5659
  }
5583
- runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell, systemSettings);
5660
+ runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, shellType, systemSettings);
5584
5661
  return true;
5585
5662
  }
5586
5663
  } else {
5587
- runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell, systemSettings);
5664
+ runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, shellType, systemSettings);
5588
5665
  return true;
5589
5666
  }
5590
5667
  };
5591
5668
  if (isWin) {
5592
- if (!attempt(true)) {
5593
- attempt(false);
5669
+ if (!attempt("pwsh")) {
5670
+ if (!attempt("powershell")) {
5671
+ attempt("cmd");
5672
+ }
5594
5673
  }
5595
5674
  } else {
5596
- attempt(false);
5675
+ attempt("bash");
5597
5676
  }
5598
5677
  });
5599
5678
  };
5600
- runStandardSpawn = (resolve, command, rawCommand, netEnv, onChunk, usePowerShell = true, systemSettings = {}) => {
5679
+ runStandardSpawn = (resolve, command, rawCommand, netEnv, onChunk, shellType = "powershell", systemSettings = {}) => {
5601
5680
  const isWin = process.platform === "win32";
5602
- let shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
5603
- let shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
5681
+ const isPowerShell = shellType === "pwsh" || shellType === "powershell";
5682
+ let shell;
5683
+ if (isWin) {
5684
+ if (shellType === "pwsh") {
5685
+ shell = "C:\\Users\\User\\AppData\\Local\\Microsoft\\WindowsApps\\pwsh.exe";
5686
+ } else if (shellType === "powershell") {
5687
+ shell = "powershell.exe";
5688
+ } else {
5689
+ shell = "cmd.exe";
5690
+ }
5691
+ } else {
5692
+ shell = process.env.SHELL || "bash";
5693
+ }
5694
+ let shellArgs = isWin ? isPowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
5604
5695
  if (systemSettings.networkAccess === false && !isWin) {
5605
5696
  const originalShell = shell;
5606
5697
  const originalArgs = [...shellArgs];
@@ -5678,9 +5769,14 @@ ${finalOutput}`);
5678
5769
  }
5679
5770
  });
5680
5771
  child.on("error", (err) => {
5681
- if (isWin && usePowerShell && err.code === "ENOENT") {
5682
- const cmdCommand = adjustWindowsCommand(rawCommand, false);
5683
- return runStandardSpawn(resolve, cmdCommand, rawCommand, netEnv, onChunk, false, systemSettings);
5772
+ if (isWin && err.code === "ENOENT") {
5773
+ if (shellType === "pwsh") {
5774
+ const nextCommand = adjustWindowsCommand(rawCommand, true);
5775
+ return runStandardSpawn(resolve, nextCommand, rawCommand, netEnv, onChunk, "powershell", systemSettings);
5776
+ } else if (shellType === "powershell") {
5777
+ const nextCommand = adjustWindowsCommand(rawCommand, false);
5778
+ return runStandardSpawn(resolve, nextCommand, rawCommand, netEnv, onChunk, "cmd", systemSettings);
5779
+ }
5684
5780
  }
5685
5781
  activeChildProcess = null;
5686
5782
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -5731,7 +5827,7 @@ function SettingsMenu({
5731
5827
  getMemoryStats();
5732
5828
  const interval = setInterval(() => {
5733
5829
  getMemoryStats();
5734
- }, 5e3);
5830
+ }, 3e4);
5735
5831
  return () => clearInterval(interval);
5736
5832
  }, []);
5737
5833
  const getCategoryItems = (catId) => {
@@ -11218,6 +11314,7 @@ Provide a consolidated summary of the entire session.`;
11218
11314
  });
11219
11315
  return result;
11220
11316
  };
11317
+ yield { type: "status", content: "[start]" };
11221
11318
  yield { type: "status", content: "Gathering Context..." };
11222
11319
  await new Promise((resolve) => setTimeout(resolve, 500));
11223
11320
  const totalFolders = countFolders(process.cwd());
@@ -13318,6 +13415,7 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
13318
13415
  } else {
13319
13416
  modifiedHistory.push({ role: "agent", text: cleanedFullResponse });
13320
13417
  }
13418
+ yield { type: "status", content: "[end]" };
13321
13419
  }
13322
13420
  if (isActuallyFinished) break;
13323
13421
  const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
@@ -14406,6 +14504,7 @@ import TextInput4 from "ink-text-input";
14406
14504
  import SelectInput2 from "ink-select-input";
14407
14505
  import gradient2 from "gradient-string";
14408
14506
  function App({ args = [] }) {
14507
+ let lastGCTime = 1;
14409
14508
  const [confirmExit, setConfirmExit] = useState14(false);
14410
14509
  const [exitCountdown, setExitCountdown] = useState14(10);
14411
14510
  const { stdout } = useStdout2();
@@ -14436,9 +14535,25 @@ function App({ args = [] }) {
14436
14535
  setShowBridgePromo(false);
14437
14536
  }
14438
14537
  }, 1e3);
14538
+ lastGCTime = Date.now();
14539
+ const memInterval = setInterval(() => {
14540
+ if (lastGCTime) {
14541
+ const diff = Date.now() - lastGCTime || 0;
14542
+ if (diff > 3e4) {
14543
+ if (global.gc) {
14544
+ try {
14545
+ global.gc();
14546
+ lastGCTime = Date.now();
14547
+ } catch (e) {
14548
+ }
14549
+ }
14550
+ }
14551
+ }
14552
+ }, 3e3);
14439
14553
  return () => {
14440
14554
  clearTimeout(graceTimer);
14441
14555
  clearInterval(interval);
14556
+ clearInterval(memInterval);
14442
14557
  };
14443
14558
  }, []);
14444
14559
  const parsedArgs = useMemo2(() => {
@@ -14707,6 +14822,7 @@ function App({ args = [] }) {
14707
14822
  const PLAYGROUND_CHAT_ID = "flow-playground";
14708
14823
  const [chatId, setChatId] = useState14(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
14709
14824
  useEffect11(() => {
14825
+ if (chatLoadingRef.current) return;
14710
14826
  const nextTokens = sessionTotalTokens - chatTokenStartRef.current;
14711
14827
  setChatTokens(nextTokens);
14712
14828
  if (chatId) {
@@ -14854,6 +14970,8 @@ function App({ args = [] }) {
14854
14970
  const [statusText, setStatusText] = useState14(null);
14855
14971
  const [wittyPhrase, setWittyPhrase] = useState14("");
14856
14972
  const [hasPasteBlock, setHasPasteBlock] = useState14(false);
14973
+ const [activeTime, setActiveTime] = useState14(0);
14974
+ let interval_for_timer;
14857
14975
  useEffect11(() => {
14858
14976
  let interval;
14859
14977
  if (statusText) {
@@ -14866,7 +14984,9 @@ function App({ args = [] }) {
14866
14984
  } else {
14867
14985
  setWittyPhrase("");
14868
14986
  }
14869
- return () => clearInterval(interval);
14987
+ return () => {
14988
+ clearInterval(interval);
14989
+ };
14870
14990
  }, [statusText]);
14871
14991
  const [isSpinnerActive, setIsSpinnerActive] = useState14(true);
14872
14992
  const [isProcessing, setIsProcessing] = useState14(false);
@@ -14876,6 +14996,14 @@ function App({ args = [] }) {
14876
14996
  const [escPressCount, setEscPressCount] = useState14(0);
14877
14997
  const [recentPrompts, setRecentPrompts] = useState14([]);
14878
14998
  const escDoubleTimerRef = useRef3(null);
14999
+ const chatLoadingRef = useRef3(false);
15000
+ useEffect11(() => {
15001
+ return () => {
15002
+ if (escDoubleTimerRef.current) {
15003
+ clearTimeout(escDoubleTimerRef.current);
15004
+ }
15005
+ };
15006
+ }, []);
14879
15007
  const didSignalTerminationRef = useRef3(false);
14880
15008
  const [queuedPrompt, setQueuedPrompt] = useState14(null);
14881
15009
  const [resolutionData, setResolutionData] = useState14(null);
@@ -14959,7 +15087,9 @@ function App({ args = [] }) {
14959
15087
  completedIndex: 0,
14960
15088
  columns: 0,
14961
15089
  historicalBlocks: [],
14962
- seenSelections: /* @__PURE__ */ new Set()
15090
+ seenSelections: /* @__PURE__ */ new Set(),
15091
+ chatId: "",
15092
+ clearKey: 0
14963
15093
  });
14964
15094
  const parsedBlocks = useMemo2(() => {
14965
15095
  const columns = terminalSize.columns || 80;
@@ -14968,7 +15098,9 @@ function App({ args = [] }) {
14968
15098
  let seenAskSelections = /* @__PURE__ */ new Set();
14969
15099
  const isResize = cachedHistoryRef.current.columns !== columns;
14970
15100
  const isClear = completedIndex < cachedHistoryRef.current.completedIndex;
14971
- if (isResize || isClear) {
15101
+ const isChatChanged = cachedHistoryRef.current.chatId !== chatId;
15102
+ const isClearKeyChanged = cachedHistoryRef.current.clearKey !== clearKey;
15103
+ if (isResize || isClear || isChatChanged || isClearKeyChanged) {
14972
15104
  const completedMsgs = messages.slice(0, completedIndex);
14973
15105
  for (let i = 0; i < completedMsgs.length; i++) {
14974
15106
  const msg = completedMsgs[i];
@@ -14988,7 +15120,9 @@ function App({ args = [] }) {
14988
15120
  completedIndex,
14989
15121
  columns,
14990
15122
  historicalBlocks,
14991
- seenSelections: new Set(seenAskSelections)
15123
+ seenSelections: new Set(seenAskSelections),
15124
+ chatId,
15125
+ clearKey
14992
15126
  };
14993
15127
  } else {
14994
15128
  historicalBlocks = cachedHistoryRef.current.historicalBlocks;
@@ -15015,7 +15149,9 @@ function App({ args = [] }) {
15015
15149
  completedIndex,
15016
15150
  columns,
15017
15151
  historicalBlocks,
15018
- seenSelections: seenAskSelections
15152
+ seenSelections: seenAskSelections,
15153
+ chatId,
15154
+ clearKey
15019
15155
  };
15020
15156
  }
15021
15157
  }
@@ -15035,7 +15171,10 @@ function App({ args = [] }) {
15035
15171
  for (let j = 0; j < parsed.completed.length; j++) streamingCompletedBlocks.push(parsed.completed[j]);
15036
15172
  for (let j = 0; j < parsed.active.length; j++) activeBlocks.push(parsed.active[j]);
15037
15173
  }
15038
- const finalCompleted = historicalBlocks.concat(streamingCompletedBlocks);
15174
+ const finalCompleted = [...historicalBlocks];
15175
+ for (let j = 0; j < streamingCompletedBlocks.length; j++) {
15176
+ finalCompleted.push(streamingCompletedBlocks[j]);
15177
+ }
15039
15178
  if (finalCompleted.length >= 75e3) {
15040
15179
  finalCompleted.push({
15041
15180
  key: `memory-warning-block-${finalCompleted.length}`,
@@ -15052,7 +15191,7 @@ function App({ args = [] }) {
15052
15191
  completed: finalCompleted,
15053
15192
  active: activeBlocks
15054
15193
  };
15055
- }, [messages, completedIndex, terminalSize.columns]);
15194
+ }, [messages, completedIndex, terminalSize.columns, clearKey, chatId]);
15056
15195
  const isTerminalWaitingForInput = useMemo2(() => {
15057
15196
  if (!activeCommand || !execOutput) return false;
15058
15197
  const lastChunk = execOutput.trim();
@@ -15184,10 +15323,18 @@ function App({ args = [] }) {
15184
15323
  setConfirmExit(false);
15185
15324
  return;
15186
15325
  }
15187
- if (isProcessing || activeCommand) {
15326
+ if (isProcessing || activeCommand || pendingApproval || pendingAsk) {
15188
15327
  didSignalTerminationRef.current = true;
15189
15328
  signalTermination();
15190
15329
  terminateActiveCommand();
15330
+ if (pendingApproval) {
15331
+ pendingApproval.resolve("deny");
15332
+ setPendingApproval(null);
15333
+ }
15334
+ if (pendingAsk) {
15335
+ pendingAsk.resolve(null);
15336
+ setPendingAsk(null);
15337
+ }
15191
15338
  setEscPressed(false);
15192
15339
  if (escTimer) clearTimeout(escTimer);
15193
15340
  } else {
@@ -15421,9 +15568,11 @@ function App({ args = [] }) {
15421
15568
  const h = await loadHistory();
15422
15569
  const id = parsedArgs.resume;
15423
15570
  if (h[id]) {
15571
+ chatLoadingRef.current = true;
15424
15572
  setChatId(id);
15425
15573
  const savedData = await loadChatContext(id);
15426
15574
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
15575
+ chatLoadingRef.current = false;
15427
15576
  setChatTokens(savedData.total);
15428
15577
  setSessionStats({ tokens: savedData.context });
15429
15578
  const resumedMsgs = [...h[id].messages];
@@ -15601,7 +15750,7 @@ function App({ args = [] }) {
15601
15750
  lastSavedTimeRef.current += deltaSecs * 1e3;
15602
15751
  }
15603
15752
  }
15604
- }, 2e3);
15753
+ }, 5e3);
15605
15754
  return () => clearInterval(interval);
15606
15755
  }, [isInitializing]);
15607
15756
  const COMMANDS = [
@@ -15966,9 +16115,11 @@ ${cleanText}`, color: "magenta" }];
15966
16115
  if (target) {
15967
16116
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
15968
16117
  clearBlocksCache();
16118
+ chatLoadingRef.current = true;
15969
16119
  setChatId(targetId);
15970
16120
  const savedData = await loadChatContext(targetId);
15971
16121
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
16122
+ chatLoadingRef.current = false;
15972
16123
  setChatTokens(savedData.total);
15973
16124
  setSessionStats({ tokens: savedData.context });
15974
16125
  const resumedMsgs = [...target.messages];
@@ -16050,6 +16201,14 @@ ${cleanText}`, color: "magenta" }];
16050
16201
  setCompletedIndex(1);
16051
16202
  setClearKey((prev) => prev + 1);
16052
16203
  clearBlocksCache();
16204
+ cachedHistoryRef.current = {
16205
+ completedIndex: 0,
16206
+ columns: terminalSize.columns,
16207
+ historicalBlocks: [],
16208
+ seenSelections: /* @__PURE__ */ new Set(),
16209
+ chatId,
16210
+ clearKey: clearKey + 1
16211
+ };
16053
16212
  if (parsedArgs.playground) {
16054
16213
  parsedArgs.playground = false;
16055
16214
  deleteChat(PLAYGROUND_CHAT_ID).catch(() => {
@@ -16099,6 +16258,7 @@ ${cleanText}`, color: "magenta" }];
16099
16258
  if (global.gc) {
16100
16259
  try {
16101
16260
  global.gc();
16261
+ lastGCTime = Date.now();
16102
16262
  } catch (e) {
16103
16263
  }
16104
16264
  }
@@ -16122,6 +16282,7 @@ ${cleanText}`, color: "magenta" }];
16122
16282
  if (global.gc) {
16123
16283
  try {
16124
16284
  global.gc();
16285
+ lastGCTime = Date.now();
16125
16286
  } catch (e) {
16126
16287
  }
16127
16288
  }
@@ -16948,20 +17109,23 @@ Selection: ${val}`,
16948
17109
  let toolCallBalance = 0;
16949
17110
  let inToolCallString = null;
16950
17111
  const signalRegex = /\[?\s*turn\s*:\s*.*?\s*\]?/gi;
16951
- const bullyTheBug = path20.join(DATA_DIR, "padding");
16952
17112
  for await (const packet of stream) {
16953
- if (packet.type === "interactive_turn_finished") {
16954
- fs22.writeFileSync(bullyTheBug, "pad_0xa\n");
16955
- } else {
16956
- fs22.appendFileSync(bullyTheBug, "\r");
16957
- parsedBlocks.completed = [];
16958
- }
16959
17113
  if (isFirstPacket && packet.type === "text") {
16960
17114
  apiStart = Date.now();
16961
17115
  isFirstPacket = false;
16962
17116
  }
16963
17117
  if (packet.type === "status") {
16964
17118
  setStatusText(packet.content);
17119
+ if (packet.content?.includes("[start]")) {
17120
+ clearInterval(interval_for_timer);
17121
+ setActiveTime(0);
17122
+ interval_for_timer = setInterval(() => {
17123
+ setActiveTime((prev) => prev + 1);
17124
+ }, 1e3);
17125
+ } else if (packet.content?.includes("[end]")) {
17126
+ setActiveTime(0);
17127
+ clearInterval(interval_for_timer);
17128
+ }
16965
17129
  if (isBridgeConnected()) {
16966
17130
  sendStatus(packet.content);
16967
17131
  }
@@ -17001,26 +17165,39 @@ Selection: ${val}`,
17001
17165
  toolCallEncounteredInTurn = false;
17002
17166
  thinkConsumedInTurn = false;
17003
17167
  setMessages((prev) => {
17004
- const newMsgs = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
17168
+ const newMsgs = prev.map((m) => {
17169
+ if (m.isStreaming) {
17170
+ const flatText = m.text ? (" " + m.text).slice(1) : m.text;
17171
+ const flatFullText = m.fullText ? (" " + m.fullText).slice(1) : m.fullText;
17172
+ return { ...m, isStreaming: false, text: flatText, fullText: flatFullText };
17173
+ }
17174
+ return m;
17175
+ });
17005
17176
  setCompletedIndex(newMsgs.length);
17006
17177
  return newMsgs;
17007
17178
  });
17008
- setTimeout(() => {
17009
- if (global.gc) {
17010
- try {
17011
- global.gc();
17012
- } catch (e) {
17013
- }
17179
+ clearBlocksCache();
17180
+ if (global.gc) {
17181
+ try {
17182
+ global.gc();
17183
+ setTimeout(() => {
17184
+ if (global.gc) global.gc();
17185
+ lastGCTime = Date.now();
17186
+ }, 100);
17187
+ } catch (e) {
17014
17188
  }
17015
- }, 100);
17189
+ }
17016
17190
  continue;
17017
17191
  }
17018
17192
  if (packet.type === "interactive_turn_finished") {
17019
17193
  setIsProcessing(false);
17194
+ setActiveTime(0);
17195
+ clearInterval(interval_for_timer);
17020
17196
  if (isBridgeConnected()) {
17021
17197
  sendStatus(null);
17022
17198
  }
17023
17199
  hasFiredJanitor = true;
17200
+ clearBlocksCache();
17024
17201
  runJanitorTask(
17025
17202
  { profile: profileData, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats, aiProvider, apiKey },
17026
17203
  packet.data.agentText,
@@ -17035,6 +17212,16 @@ Selection: ${val}`,
17035
17212
  onBackgroundIncrement: () => setSessionBackgroundCalls((prev) => prev + 1)
17036
17213
  }
17037
17214
  );
17215
+ if (global.gc) {
17216
+ try {
17217
+ global.gc();
17218
+ setTimeout(() => {
17219
+ if (global.gc) global.gc();
17220
+ lastGCTime = Date.now();
17221
+ }, 150);
17222
+ } catch (e) {
17223
+ }
17224
+ }
17038
17225
  continue;
17039
17226
  }
17040
17227
  if (packet.type === "visual_feedback") {
@@ -17149,6 +17336,10 @@ Selection: ${val}`,
17149
17336
  }
17150
17337
  let chunkText = packet.content;
17151
17338
  if (packet.type === "text" && chunkText.includes("Request Cancelled")) {
17339
+ if (global.gc) {
17340
+ global.gc();
17341
+ lastGCTime = Date.now();
17342
+ }
17152
17343
  continue;
17153
17344
  }
17154
17345
  const chunkLower = chunkText.toLowerCase();
@@ -17279,9 +17470,22 @@ Selection: ${val}`,
17279
17470
  } finally {
17280
17471
  setIsProcessing(false);
17281
17472
  setStatusText(null);
17473
+ setActiveTime(0);
17474
+ clearInterval(interval_for_timer);
17282
17475
  if (didSignalTerminationRef.current) {
17283
17476
  appendCancelMessage();
17284
17477
  }
17478
+ clearBlocksCache();
17479
+ if (global.gc) {
17480
+ try {
17481
+ global.gc();
17482
+ setTimeout(() => {
17483
+ if (global.gc) global.gc();
17484
+ lastGCTime = Date.now();
17485
+ }, 500);
17486
+ } catch (e) {
17487
+ }
17488
+ }
17285
17489
  if (!hasFiredJanitor) {
17286
17490
  if (process.stdout.isTTY) {
17287
17491
  process.stdout.write("\x1B]0;FluxFlow | Idle\x07");
@@ -17312,6 +17516,9 @@ Selection: ${val}`,
17312
17516
  let foundLastAgent = false;
17313
17517
  const newMsgs = [...prev].reverse().map((m) => {
17314
17518
  let updated = m.isStreaming ? { ...m, isStreaming: false } : m;
17519
+ if (updated.text) {
17520
+ updated.text = (" " + updated.text).slice(1);
17521
+ }
17315
17522
  if (!foundLastAgent && updated.role === "agent") {
17316
17523
  foundLastAgent = true;
17317
17524
  updated = { ...updated, workedDuration: totalDuration };
@@ -18025,24 +18232,26 @@ Selection: ${val}`,
18025
18232
  {
18026
18233
  prompts: recentPrompts,
18027
18234
  onSelect: async (txId) => {
18235
+ if (stdout) {
18236
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
18237
+ if (stdout.isTTY) {
18238
+ stdout.write("\x1B[?2004h");
18239
+ }
18240
+ }
18028
18241
  try {
18029
18242
  const result = await RevertManager.rollbackToBefore(txId);
18030
18243
  if (result.success) {
18031
18244
  const { targetPrompt } = result;
18032
18245
  deleteChatSummary(chatId);
18033
- if (stdout) {
18034
- stdout.write("\x1B[2J\x1B[3J\x1B[H");
18035
- if (stdout.isTTY) {
18036
- stdout.write("\x1B[?2004h");
18037
- }
18038
- }
18039
18246
  setClearKey((prev) => prev + 1);
18040
18247
  clearBlocksCache();
18041
18248
  cachedHistoryRef.current = {
18042
18249
  completedIndex: 0,
18043
- columns: 0,
18250
+ columns: terminalSize.columns,
18044
18251
  historicalBlocks: [],
18045
- seenSelections: /* @__PURE__ */ new Set()
18252
+ seenSelections: /* @__PURE__ */ new Set(),
18253
+ chatId,
18254
+ clearKey: clearKey + 1
18046
18255
  };
18047
18256
  const targetIdx = messages.findLastIndex(
18048
18257
  (m) => m.role === "user" && m.text && (m.text.startsWith(targetPrompt) || m.text.includes(targetPrompt))
@@ -18097,9 +18306,11 @@ Selection: ${val}`,
18097
18306
  if (h[id]) {
18098
18307
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
18099
18308
  clearBlocksCache();
18309
+ chatLoadingRef.current = true;
18100
18310
  setChatId(id);
18101
18311
  const savedData = await loadChatContext(id);
18102
18312
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
18313
+ chatLoadingRef.current = false;
18103
18314
  setChatTokens(savedData.total);
18104
18315
  setSessionStats({ tokens: savedData.context });
18105
18316
  const resumedMsgs = [...h[id].messages];
@@ -18311,7 +18522,7 @@ Selection: ${val}`,
18311
18522
  }
18312
18523
  )));
18313
18524
  default:
18314
- return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, showBtwBox && btwResponse && /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%", marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Box15, { justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Text16, { color: "white", bold: true, underline: true }, "INQUIRY RESPONSE"), /* @__PURE__ */ React15.createElement(Text16, { color: "gray" }, "[ ESC to Close ]")), /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React15.createElement(CodeRenderer, { text: btwResponse, columns: terminalSize.columns - 6 }))), /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, null, statusText ? /* @__PURE__ */ React15.createElement(Box15, { gap: 1 }, /* @__PURE__ */ React15.createElement(dist_default, { colors: ["#001a1a", "#080510", "#12021c"] }, /* @__PURE__ */ React15.createElement(build_default, null)), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true, italic: true }, statusText)) : /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : hasPasteBlock ? "Press CTRL + O to expand" : "Waiting for input...")), /* @__PURE__ */ React15.createElement(Box15, null, wittyPhrase && /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, wittyPhrase, " "), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React15.createElement(Text16, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React15.createElement(
18525
+ return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, showBtwBox && btwResponse && /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%", marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Box15, { justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Text16, { color: "white", bold: true, underline: true }, "INQUIRY RESPONSE"), /* @__PURE__ */ React15.createElement(Text16, { color: "gray" }, "[ ESC to Close ]")), /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React15.createElement(CodeRenderer, { text: btwResponse, columns: terminalSize.columns - 6 }))), /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, null, statusText ? /* @__PURE__ */ React15.createElement(Box15, { gap: 1 }, /* @__PURE__ */ React15.createElement(dist_default, { colors: ["#001a1a", "#080510", "#12021c"] }, /* @__PURE__ */ React15.createElement(build_default, null)), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true, italic: true }, statusText), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true, dimColor: true }, activeTime > 0 ? ` [${activeTime.toFixed(0)}s]` : "")) : /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : hasPasteBlock ? "Press CTRL + O to expand" : "Waiting for input...")), /* @__PURE__ */ React15.createElement(Box15, null, wittyPhrase && /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, wittyPhrase, " "), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React15.createElement(Text16, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React15.createElement(
18315
18526
  Box15,
18316
18527
  {
18317
18528
  backgroundColor: "#555555",
@@ -18348,7 +18559,7 @@ Selection: ${val}`,
18348
18559
  ), /* @__PURE__ */ React15.createElement(Box15, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React15.createElement(Text16, { color: "#555555" }, "\u2580".repeat(Math.max(1, terminalSize.columns))))));
18349
18560
  }
18350
18561
  };
18351
- return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", width: "100%" }, showBridgePromo ? /* @__PURE__ */ React15.createElement(BridgePromo, { width: stdout?.columns || 80, height: stdout?.rows || 24, selectedIndex: promoSelectedIndex }) : /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, flexDirection: "column", width: "100%" }, /* @__PURE__ */ React15.createElement(Static, { key: `static-${clearKey}-${terminalSize.columns}-${terminalSize.rows}`, items: parsedBlocks.completed }, (block) => /* @__PURE__ */ React15.createElement(
18562
+ return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", width: "100%" }, showBridgePromo ? /* @__PURE__ */ React15.createElement(BridgePromo, { width: stdout?.columns || 80, height: stdout?.rows || 24, selectedIndex: promoSelectedIndex }) : /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, flexDirection: "column", width: "100%" }, /* @__PURE__ */ React15.createElement(Static, { key: `static-${clearKey}-${chatId}-${terminalSize.columns}-${terminalSize.rows}`, items: parsedBlocks.completed }, (block) => /* @__PURE__ */ React15.createElement(
18352
18563
  BlockItem,
18353
18564
  {
18354
18565
  key: block.key,
@@ -18758,11 +18969,13 @@ var isBundled = fileURLToPath2(import.meta.url).endsWith(".js");
18758
18969
  if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-size"))) {
18759
18970
  if (!Number.isNaN(_allocValue)) {
18760
18971
  console.log(`
18761
- [MEMORY] Starting with: '${_allocValue > _maxAllowed ? _maxAllowed : _allocValue} MB' Allocation ${_allocValue > _maxAllowed ? "(Max allowed: '" + _maxAllowed + " MB')" : ""}. Please Wait...`);
18972
+ [MEMORY] Starting with: '${_allocValue > _maxAllowed ? _maxAllowed : _allocValue} MB' Allocation${_allocValue > _maxAllowed ? " (Max allowed: '" + _maxAllowed + " MB')" : ""}. Please Wait...`);
18762
18973
  await new Promise((resolve) => setTimeout(resolve, 5e3));
18763
18974
  }
18764
18975
  const cp = spawn3(process.execPath, [
18765
18976
  `--max-old-space-size=${HEAP_LIMIT}`,
18977
+ `--expose-gc`,
18978
+ `--max-semi-space-size=1`,
18766
18979
  fileURLToPath2(import.meta.url),
18767
18980
  ...process.argv.slice(2)
18768
18981
  ], { stdio: "inherit" });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.15.3",
4
- "date": "2026-06-30",
3
+ "version": "2.16.1",
4
+ "date": "2026-07-01",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",