fluxflow-cli 2.13.5 → 2.14.0

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 +940 -615
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -40,6 +40,7 @@ __export(paths_exports, {
40
40
  CONTEXT_FILE: () => CONTEXT_FILE,
41
41
  DATA_DIR: () => DATA_DIR,
42
42
  FLUXFLOW_DIR: () => FLUXFLOW_DIR,
43
+ HISTORY_DIR: () => HISTORY_DIR,
43
44
  HISTORY_FILE: () => HISTORY_FILE,
44
45
  LEDGER_FILE: () => LEDGER_FILE,
45
46
  LOGS_DIR: () => LOGS_DIR,
@@ -56,7 +57,7 @@ import os from "os";
56
57
  import path from "path";
57
58
  import fs from "fs";
58
59
  import crypto from "crypto";
59
- var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE, ACTIVE_TX_FILE, PATHS_FILE, CONTEXT_FILE, PARSER_DIR;
60
+ var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, HISTORY_DIR, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE, ACTIVE_TX_FILE, PATHS_FILE, CONTEXT_FILE, PARSER_DIR;
60
61
  var init_paths = __esm({
61
62
  "src/utils/paths.js"() {
62
63
  FLUXFLOW_DIR = path.join(os.homedir(), ".fluxflow");
@@ -93,6 +94,7 @@ var init_paths = __esm({
93
94
  LOGS_DIR = path.join(DATA_DIR, "logs");
94
95
  SECRET_DIR = path.join(DATA_DIR, "secret");
95
96
  HISTORY_FILE = path.join(SECRET_DIR, "history.json");
97
+ HISTORY_DIR = path.join(SECRET_DIR, "history");
96
98
  USAGE_FILE = path.join(FLUXFLOW_DIR, "usage.json");
97
99
  MEMORIES_FILE = path.join(SECRET_DIR, "memories.json");
98
100
  TEMP_MEM_FILE = path.join(SECRET_DIR, "memory-temp.json");
@@ -114,7 +116,7 @@ var XOR_KEY, bypass, xorTransform, AES_ALGORITHM, AES_KEY, encryptAes, decryptAe
114
116
  var init_crypto = __esm({
115
117
  "src/utils/crypto.js"() {
116
118
  XOR_KEY = 66;
117
- bypass = false;
119
+ bypass = true;
118
120
  xorTransform = (data) => {
119
121
  const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
120
122
  const result = Buffer.alloc(buffer.length);
@@ -2089,7 +2091,7 @@ var init_build = __esm({
2089
2091
 
2090
2092
  // src/utils/text.js
2091
2093
  import os2 from "os";
2092
- var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseMessageToBlocks, TOOL_LABELS, cleanSignals;
2094
+ var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseLineInfo, getSimilarity, alignChangeGroup, blocksCache, streamingBlocksCache, MAX_CACHE_SIZE, 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;
2093
2095
  var init_text = __esm({
2094
2096
  "src/utils/text.js"() {
2095
2097
  init_paths();
@@ -2433,8 +2435,132 @@ var init_text = __esm({
2433
2435
  diffText += `[DIFF_END]`;
2434
2436
  return diffText;
2435
2437
  };
2438
+ parseLineInfo = (l) => {
2439
+ if (!l) return null;
2440
+ const clean = l.replace("[UI_CONTEXT]", "").replace(/\r/g, "");
2441
+ const isR = clean.startsWith("-");
2442
+ const isA = clean.startsWith("+");
2443
+ let rest = isR || isA ? clean.substring(1) : clean;
2444
+ rest = rest.trim();
2445
+ const splitIdx = rest.indexOf("|");
2446
+ const num = splitIdx !== -1 ? rest.substring(0, splitIdx).trim() : "";
2447
+ const content = splitIdx !== -1 ? rest.substring(splitIdx + 1) : rest;
2448
+ return { isR, isA, num, content };
2449
+ };
2450
+ getSimilarity = (s1, s2) => {
2451
+ if (!s1 && !s2) return 1;
2452
+ if (!s1 || !s2) return 0;
2453
+ const l1 = s1.length;
2454
+ const l2 = s2.length;
2455
+ const dp = Array.from({ length: l1 + 1 }, () => Array(l2 + 1).fill(0));
2456
+ for (let i = 0; i <= l1; i++) dp[i][0] = i;
2457
+ for (let j = 0; j <= l2; j++) dp[0][j] = j;
2458
+ for (let i = 1; i <= l1; i++) {
2459
+ for (let j = 1; j <= l2; j++) {
2460
+ if (s1[i - 1] === s2[j - 1]) {
2461
+ dp[i][j] = dp[i - 1][j - 1];
2462
+ } else {
2463
+ dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
2464
+ }
2465
+ }
2466
+ }
2467
+ const maxLen = Math.max(l1, l2);
2468
+ if (maxLen === 0) return 1;
2469
+ return 1 - dp[l1][l2] / maxLen;
2470
+ };
2471
+ alignChangeGroup = (group) => {
2472
+ const removals = [];
2473
+ const additions = [];
2474
+ group.forEach((item, index) => {
2475
+ if (item.parsed.isR) {
2476
+ removals.push({ index, content: item.parsed.content });
2477
+ } else if (item.parsed.isA) {
2478
+ additions.push({ index, content: item.parsed.content });
2479
+ }
2480
+ });
2481
+ const N = removals.length;
2482
+ const M = additions.length;
2483
+ if (N === 0 || M === 0) return;
2484
+ const dp = Array.from({ length: N + 1 }, () => Array(M + 1).fill(0));
2485
+ const choices = Array.from({ length: N + 1 }, () => Array(M + 1).fill(""));
2486
+ for (let i2 = 1; i2 <= N; i2++) choices[i2][0] = "up";
2487
+ for (let j2 = 1; j2 <= M; j2++) choices[0][j2] = "left";
2488
+ const simMatrix = Array.from({ length: N }, () => Array(M).fill(0));
2489
+ for (let i2 = 0; i2 < N; i2++) {
2490
+ for (let j2 = 0; j2 < M; j2++) {
2491
+ simMatrix[i2][j2] = getSimilarity(removals[i2].content.trim(), additions[j2].content.trim());
2492
+ }
2493
+ }
2494
+ for (let i2 = 1; i2 <= N; i2++) {
2495
+ for (let j2 = 1; j2 <= M; j2++) {
2496
+ const matchScore = simMatrix[i2 - 1][j2 - 1];
2497
+ const score = matchScore >= 0.2 ? matchScore : -10;
2498
+ const diag = dp[i2 - 1][j2 - 1] + score;
2499
+ const up = dp[i2 - 1][j2];
2500
+ const left = dp[i2][j2 - 1];
2501
+ if (diag >= up && diag >= left) {
2502
+ dp[i2][j2] = diag;
2503
+ choices[i2][j2] = "diag";
2504
+ } else if (up >= left) {
2505
+ dp[i2][j2] = up;
2506
+ choices[i2][j2] = "up";
2507
+ } else {
2508
+ dp[i2][j2] = left;
2509
+ choices[i2][j2] = "left";
2510
+ }
2511
+ }
2512
+ }
2513
+ let i = N;
2514
+ let j = M;
2515
+ while (i > 0 || j > 0) {
2516
+ if (choices[i][j] === "diag") {
2517
+ const matchScore = simMatrix[i - 1][j - 1];
2518
+ if (matchScore >= 0.2) {
2519
+ const rIdx = removals[i - 1].index;
2520
+ const aIdx = additions[j - 1].index;
2521
+ group[rIdx].pairContent = group[aIdx].parsed.content;
2522
+ group[aIdx].pairContent = group[rIdx].parsed.content;
2523
+ }
2524
+ i--;
2525
+ j--;
2526
+ } else if (choices[i][j] === "up") {
2527
+ i--;
2528
+ } else {
2529
+ j--;
2530
+ }
2531
+ }
2532
+ };
2533
+ blocksCache = /* @__PURE__ */ new Map();
2534
+ streamingBlocksCache = /* @__PURE__ */ new Map();
2535
+ MAX_CACHE_SIZE = 200;
2436
2536
  parseMessageToBlocks = (msg, columns) => {
2537
+ if (!msg) return { completed: [], active: [] };
2538
+ const cacheKey = `${msg.id}-${msg.text?.length || 0}-${columns}-${msg.isStreaming}`;
2539
+ if (!msg.isStreaming && blocksCache.has(cacheKey)) {
2540
+ return blocksCache.get(cacheKey);
2541
+ }
2437
2542
  const text = cleanSignals(msg.text || "");
2543
+ const streamCacheKey = `${msg.id}-${columns}`;
2544
+ let cachedBlocks = /* @__PURE__ */ new Map();
2545
+ if (msg.isStreaming) {
2546
+ const cached = streamingBlocksCache.get(streamCacheKey);
2547
+ if (cached && text.startsWith(cached.text)) {
2548
+ cachedBlocks = cached.blocksMap;
2549
+ }
2550
+ }
2551
+ const getBlock = (key, type, textContent, extra = {}) => {
2552
+ const existing = cachedBlocks.get(key);
2553
+ if (existing && existing.text === textContent && existing.type === type && !!existing.isActiveBlock === !!extra.isActiveBlock && !!existing.isStreaming === !!extra.isStreaming && existing.pairContent === extra.pairContent) {
2554
+ return existing;
2555
+ }
2556
+ return {
2557
+ key,
2558
+ msg,
2559
+ type,
2560
+ text: textContent,
2561
+ ...extra
2562
+ };
2563
+ };
2438
2564
  if (text.includes("- Content Preview:")) {
2439
2565
  const mainParts = text.split("- Content Preview:");
2440
2566
  const headerText = mainParts[0] || "";
@@ -2449,16 +2575,12 @@ var init_text = __esm({
2449
2575
  let activeBlock2 = null;
2450
2576
  codeLines.forEach((line, idx) => {
2451
2577
  const isLast = idx === codeLines.length - 1;
2452
- const block = {
2453
- key: `${msg.id || Date.now()}-write-line-${idx}`,
2454
- msg,
2455
- type: "write-line",
2456
- text: line,
2578
+ const block = getBlock(`${msg.id || Date.now()}-write-line-${idx}`, "write-line", line, {
2457
2579
  gutterWidth,
2458
2580
  lineNum: idx + 1,
2459
2581
  isFirstLine: idx === 0,
2460
2582
  isLastLine: isLast
2461
- };
2583
+ });
2462
2584
  if (isLast && msg.isStreaming) {
2463
2585
  activeBlock2 = block;
2464
2586
  } else {
@@ -2474,18 +2596,37 @@ var init_text = __esm({
2474
2596
  const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
2475
2597
  const diffBody = match ? match[1].trim() : "";
2476
2598
  const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
2599
+ const parsedLines = diffLines.map((line) => {
2600
+ return {
2601
+ line,
2602
+ parsed: parseLineInfo(line),
2603
+ pairContent: null
2604
+ };
2605
+ });
2606
+ let currentGroup = [];
2607
+ for (let i = 0; i < parsedLines.length; i++) {
2608
+ const item = parsedLines[i];
2609
+ if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
2610
+ currentGroup.push(item);
2611
+ } else {
2612
+ if (currentGroup.length > 0) {
2613
+ alignChangeGroup(currentGroup);
2614
+ currentGroup = [];
2615
+ }
2616
+ }
2617
+ }
2618
+ if (currentGroup.length > 0) {
2619
+ alignChangeGroup(currentGroup);
2620
+ }
2477
2621
  const completedBlocks2 = [];
2478
2622
  let activeBlock2 = null;
2479
2623
  diffLines.forEach((line, i) => {
2480
2624
  const isLast = i === diffLines.length - 1;
2481
- const block = {
2482
- key: `${msg.id || Date.now()}-diff-${i}`,
2483
- msg,
2484
- type: "diff-line",
2485
- text: line,
2625
+ const block = getBlock(`${msg.id || Date.now()}-diff-${i}`, "diff-line", line, {
2486
2626
  isFirstLine: i === 0,
2487
- isLastLine: isLast
2488
- };
2627
+ isLastLine: isLast,
2628
+ pairContent: parsedLines[i].pairContent
2629
+ });
2489
2630
  if (isLast && msg.isStreaming) {
2490
2631
  activeBlock2 = block;
2491
2632
  } else {
@@ -2499,35 +2640,19 @@ var init_text = __esm({
2499
2640
  }
2500
2641
  if (msg.role === "system" || msg.isLogo || msg.isHelpRecord || msg.isTerminalRecord || msg.isHomeWarning || msg.isImageStats || msg.isAskRecord || msg.isAboutRecord || msg.isUpdateNotification || msg.role === "user") {
2501
2642
  return {
2502
- completed: [{
2503
- key: `${msg.id || Date.now()}-full`,
2504
- msg,
2505
- type: "full-message",
2506
- text
2507
- }],
2643
+ completed: [getBlock(`${msg.id || Date.now()}-full`, "full-message", text)],
2508
2644
  active: []
2509
2645
  };
2510
2646
  }
2511
2647
  const completedBlocks = [];
2512
2648
  let activeBlock = null;
2513
2649
  if (msg.role === "think") {
2514
- completedBlocks.push({
2515
- key: `${msg.id}-header`,
2516
- msg,
2517
- type: "think-header",
2518
- text: ""
2519
- });
2650
+ completedBlocks.push(getBlock(`${msg.id}-header`, "think-header", ""));
2520
2651
  const lines = text.split("\n");
2521
2652
  lines.forEach((line, idx) => {
2522
2653
  const isLast = idx === lines.length - 1;
2523
- const block = {
2524
- key: `${msg.id}-${idx}`,
2525
- msg,
2526
- type: "think-line",
2527
- text: line
2528
- };
2654
+ const block = getBlock(`${msg.id}-${idx}`, "think-line", line, isLast && msg.isStreaming ? { isActiveBlock: true } : {});
2529
2655
  if (isLast && msg.isStreaming) {
2530
- block.isActiveBlock = true;
2531
2656
  activeBlock = block;
2532
2657
  } else {
2533
2658
  completedBlocks.push(block);
@@ -2556,14 +2681,8 @@ var init_text = __esm({
2556
2681
  if (isCodeBlockMarker || isLast) {
2557
2682
  inCodeBlock = !isCodeBlockMarker;
2558
2683
  if (!inCodeBlock || isLast) {
2559
- const block = {
2560
- key: `${msg.id}-code-${idx}`,
2561
- msg,
2562
- type: "agent-line",
2563
- text: codeLines.join("\n")
2564
- };
2684
+ const block = getBlock(`${msg.id}-code-${idx}`, "agent-line", codeLines.join("\n"), isLast && msg.isStreaming && inCodeBlock ? { isActiveBlock: true } : {});
2565
2685
  if (isLast && msg.isStreaming && inCodeBlock) {
2566
- block.isActiveBlock = true;
2567
2686
  activeBlock = block;
2568
2687
  } else {
2569
2688
  completedBlocks.push(block);
@@ -2575,14 +2694,8 @@ var init_text = __esm({
2575
2694
  inCodeBlock = true;
2576
2695
  codeLines.push(line);
2577
2696
  if (isLast) {
2578
- const block = {
2579
- key: `${msg.id}-code-${idx}`,
2580
- msg,
2581
- type: "agent-line",
2582
- text: codeLines.join("\n")
2583
- };
2697
+ const block = getBlock(`${msg.id}-code-${idx}`, "agent-line", codeLines.join("\n"), msg.isStreaming ? { isActiveBlock: true } : {});
2584
2698
  if (msg.isStreaming) {
2585
- block.isActiveBlock = true;
2586
2699
  activeBlock = block;
2587
2700
  } else {
2588
2701
  completedBlocks.push(block);
@@ -2593,44 +2706,19 @@ var init_text = __esm({
2593
2706
  tableLines.push(line);
2594
2707
  if (isLast) {
2595
2708
  if (msg.isStreaming) {
2596
- activeBlock = {
2597
- key: `${msg.id}-table-${idx}`,
2598
- msg,
2599
- type: "table",
2600
- text: tableLines.join("\n"),
2601
- isStreaming: true,
2602
- isActiveBlock: true
2603
- };
2709
+ activeBlock = getBlock(`${msg.id}-table-${idx}`, "table", tableLines.join("\n"), { isStreaming: true, isActiveBlock: true });
2604
2710
  } else {
2605
- completedBlocks.push({
2606
- key: `${msg.id}-table-${idx}`,
2607
- msg,
2608
- type: "table",
2609
- text: tableLines.join("\n"),
2610
- isStreaming: false
2611
- });
2711
+ completedBlocks.push(getBlock(`${msg.id}-table-${idx}`, "table", tableLines.join("\n"), { isStreaming: false }));
2612
2712
  }
2613
2713
  }
2614
2714
  } else {
2615
2715
  if (inTable) {
2616
- completedBlocks.push({
2617
- key: `${msg.id}-table-${idx}`,
2618
- msg,
2619
- type: "table",
2620
- text: tableLines.join("\n"),
2621
- isStreaming: false
2622
- });
2716
+ completedBlocks.push(getBlock(`${msg.id}-table-${idx}`, "table", tableLines.join("\n"), { isStreaming: false }));
2623
2717
  inTable = false;
2624
2718
  tableLines = [];
2625
2719
  }
2626
- const block = {
2627
- key: `${msg.id}-${idx}`,
2628
- msg,
2629
- type: "agent-line",
2630
- text: line
2631
- };
2720
+ const block = getBlock(`${msg.id}-${idx}`, "agent-line", line, isLast && msg.isStreaming ? { isActiveBlock: true } : {});
2632
2721
  if (isLast && msg.isStreaming) {
2633
- block.isActiveBlock = true;
2634
2722
  activeBlock = block;
2635
2723
  } else {
2636
2724
  completedBlocks.push(block);
@@ -2638,18 +2726,36 @@ var init_text = __esm({
2638
2726
  }
2639
2727
  });
2640
2728
  if (!msg.isStreaming && msg.workedDuration) {
2641
- completedBlocks.push({
2642
- key: `${msg.id}-worked-duration`,
2643
- msg,
2644
- type: "worked-duration",
2645
- text: ""
2646
- });
2729
+ completedBlocks.push(getBlock(`${msg.id}-worked-duration`, "worked-duration", ""));
2647
2730
  }
2648
2731
  }
2649
- return {
2732
+ const result = {
2650
2733
  completed: completedBlocks,
2651
2734
  active: activeBlock ? [activeBlock] : []
2652
2735
  };
2736
+ if (!msg.isStreaming) {
2737
+ blocksCache.set(cacheKey, result);
2738
+ if (blocksCache.size > MAX_CACHE_SIZE) {
2739
+ const firstKey = blocksCache.keys().next().value;
2740
+ blocksCache.delete(firstKey);
2741
+ }
2742
+ streamingBlocksCache.delete(streamCacheKey);
2743
+ } else {
2744
+ const blocksMap = /* @__PURE__ */ new Map();
2745
+ completedBlocks.forEach((b) => blocksMap.set(b.key, b));
2746
+ if (activeBlock) {
2747
+ blocksMap.set(activeBlock.key, activeBlock);
2748
+ }
2749
+ streamingBlocksCache.set(streamCacheKey, {
2750
+ text,
2751
+ blocksMap
2752
+ });
2753
+ if (streamingBlocksCache.size > MAX_CACHE_SIZE) {
2754
+ const firstKey = streamingBlocksCache.keys().next().value;
2755
+ streamingBlocksCache.delete(firstKey);
2756
+ }
2757
+ }
2758
+ return result;
2653
2759
  };
2654
2760
  TOOL_LABELS = {
2655
2761
  "write_file": "WriteFile",
@@ -2678,61 +2784,88 @@ var init_text = __esm({
2678
2784
  "Chat": "Chat",
2679
2785
  "GenerateImage": "GenerateImage"
2680
2786
  };
2787
+ REGEX_INITIAL_THINK = /<\/think>(\r?\n){2}/gi;
2788
+ REGEX_INITIAL_TOOL = /(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi;
2789
+ REGEX_SYSTEM = /\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi;
2790
+ REGEX_THINK = /<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi;
2791
+ REGEX_ANSWER = /\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi;
2792
+ REGEX_TOOL_RES = /\[TOOL RESULT\]:?\s*/gi;
2793
+ REGEX_SUCCESS_ERROR = /^\s*(SUCCESS|ERROR):.*(\r?\n)?/gm;
2794
+ REGEX_TURN_1 = /\[\s*turn\s*:\s*(continue|finish)\s*\]/gi;
2795
+ REGEX_END = /\[\[END\]\]/gi;
2796
+ REGEX_TURN_2 = /\[\s*turn\s*:?.*?$/gi;
2797
+ REGEX_TURN_3 = /\n\s*turn\s*:?.*?$/gi;
2798
+ REGEX_OPEN_BRACKET = /\[\s*$/gi;
2799
+ REGEX_RESPONDED = /\n\nResponded on .*/g;
2800
+ REGEX_PROMPTED = /\n\n\[Prompted on: .*\]/g;
2801
+ REGEX_ARROWS = /(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi;
2802
+ REGEX_ARROWS_L = /(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi;
2803
+ REGEX_ARROWS_U = /(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi;
2804
+ REGEX_ARROWS_D = /(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi;
2805
+ REGEX_ARROWS_LR = /(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi;
2806
+ REGEX_TERMINAL = /@\[TerminalName:.*?, ProcessId:.*?\]/gi;
2807
+ 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;
2681
2808
  cleanSignals = (text) => {
2682
2809
  if (!text) return text;
2683
- let result = text.replace(/<\/think>(\r?\n){2}/gi, "</think>").replace(/(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi, "");
2810
+ let result = text.replace(REGEX_INITIAL_THINK, "</think>").replace(REGEX_INITIAL_TOOL, "");
2684
2811
  const trigger = "tool:functions.";
2685
- while (true) {
2686
- const lowerResult = result.toLowerCase();
2687
- let triggerIdx = lowerResult.indexOf(trigger);
2688
- if (triggerIdx === -1) break;
2689
- let startIdx = triggerIdx;
2690
- let hasOuterBracket = false;
2691
- let k = triggerIdx - 1;
2692
- while (k >= 0 && /\s/.test(result[k])) k--;
2693
- if (k >= 0 && result[k] === "[") {
2694
- startIdx = k;
2695
- hasOuterBracket = true;
2696
- }
2697
- let balance = 0;
2698
- let foundStart = false;
2699
- let inString = null;
2700
- let j = triggerIdx;
2701
- while (j < result.length) {
2702
- const char = result[j];
2703
- if (!inString && (char === "'" || char === '"' || char === "`")) {
2704
- inString = char;
2705
- } else if (inString && char === inString && result[j - 1] !== "\\") {
2706
- inString = null;
2812
+ if (result.toLowerCase().includes(trigger)) {
2813
+ while (true) {
2814
+ const lowerResult = result.toLowerCase();
2815
+ let triggerIdx = lowerResult.indexOf(trigger);
2816
+ if (triggerIdx === -1) break;
2817
+ let startIdx = triggerIdx;
2818
+ let hasOuterBracket = false;
2819
+ let k = triggerIdx - 1;
2820
+ while (k >= 0 && /\s/.test(result[k])) k--;
2821
+ if (k >= 0 && result[k] === "[") {
2822
+ startIdx = k;
2823
+ hasOuterBracket = true;
2707
2824
  }
2708
- if (!inString) {
2709
- if (char === "(") {
2710
- balance++;
2711
- foundStart = true;
2712
- } else if (char === ")") {
2713
- balance--;
2825
+ let balance = 0;
2826
+ let foundStart = false;
2827
+ let inString = null;
2828
+ let j = triggerIdx;
2829
+ while (j < result.length) {
2830
+ const char = result[j];
2831
+ if (!inString && (char === "'" || char === '"' || char === "`")) {
2832
+ inString = char;
2833
+ } else if (inString && char === inString && result[j - 1] !== "\\") {
2834
+ inString = null;
2714
2835
  }
2715
- }
2716
- if (foundStart && balance === 0 && !inString) {
2717
- let endIdx = j;
2718
- if (hasOuterBracket) {
2719
- let m = j + 1;
2720
- while (m < result.length && /\s/.test(result[m])) m++;
2721
- if (m < result.length && result[m] === "]") {
2722
- endIdx = m;
2836
+ if (!inString) {
2837
+ if (char === "(") {
2838
+ balance++;
2839
+ foundStart = true;
2840
+ } else if (char === ")") {
2841
+ balance--;
2723
2842
  }
2724
2843
  }
2725
- result = result.substring(0, startIdx) + result.substring(endIdx + 1);
2726
- break;
2727
- }
2728
- j++;
2729
- if (j === result.length) {
2730
- result = result.substring(0, startIdx);
2731
- return result;
2844
+ if (foundStart && balance === 0 && !inString) {
2845
+ let endIdx = j;
2846
+ if (hasOuterBracket) {
2847
+ let m = j + 1;
2848
+ while (m < result.length && /\s/.test(result[m])) m++;
2849
+ if (m < result.length && result[m] === "]") {
2850
+ endIdx = m;
2851
+ }
2852
+ }
2853
+ result = result.substring(0, startIdx) + result.substring(endIdx + 1);
2854
+ break;
2855
+ }
2856
+ j++;
2857
+ if (j === result.length) {
2858
+ result = result.substring(0, startIdx);
2859
+ return result;
2860
+ }
2732
2861
  }
2733
2862
  }
2734
2863
  }
2735
- return result.replaceAll(/\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi, "").replaceAll(/<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi, "").replace(/\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi, "").replaceAll(/\[TOOL RESULT\]:?\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replaceAll(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replaceAll(/\[\[END\]\]/gi, "").replaceAll(/\[\s*turn\s*:?.*?$/gi, "").replaceAll(/\n\s*turn\s*:?.*?$/gi, "").replaceAll(/\[\s*$/gi, "").replaceAll(/\n\nResponded on .*/g, "").replaceAll(/\n\n\[Prompted on: .*\]/g, "").replaceAll(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replaceAll(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replaceAll(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replaceAll(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replaceAll(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replaceAll(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replaceAll(/\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, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
2864
+ 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();
2865
+ };
2866
+ clearBlocksCache = () => {
2867
+ blocksCache.clear();
2868
+ streamingBlocksCache.clear();
2736
2869
  };
2737
2870
  }
2738
2871
  });
@@ -3812,75 +3945,14 @@ ${coloredArt[7]}`;
3812
3945
  import React4, { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
3813
3946
  import { Box as Box3, Text as Text4 } from "ink";
3814
3947
  import { diffWordsWithSpace } from "diff";
3815
- var useStreamingText, formatThinkText, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, parseLineInfo, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
3948
+ var useStreamingText, formatThinkText, REGEX_MD_TOKENS, REGEX_LATEX_FRAC, REGEX_LATEX_STYLE, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
3816
3949
  var init_ChatLayout = __esm({
3817
3950
  "src/components/ChatLayout.jsx"() {
3818
3951
  init_TerminalBox();
3819
3952
  init_text();
3820
3953
  init_terminal();
3821
3954
  useStreamingText = (targetText, isStreaming, isActiveBlock) => {
3822
- const [displayedText, setDisplayedText] = useState4(isActiveBlock && isStreaming ? "" : targetText);
3823
- const targetTextRef = useRef2(targetText);
3824
- useEffect3(() => {
3825
- targetTextRef.current = targetText;
3826
- }, [targetText]);
3827
- useEffect3(() => {
3828
- if (!isActiveBlock) {
3829
- setDisplayedText(targetText);
3830
- return;
3831
- }
3832
- if (!isStreaming && displayedText === targetText) {
3833
- return;
3834
- }
3835
- const interval = setInterval(() => {
3836
- setDisplayedText((current) => {
3837
- const target = targetTextRef.current;
3838
- if (current.length >= target.length) {
3839
- if (!isStreaming) {
3840
- clearInterval(interval);
3841
- }
3842
- return current;
3843
- }
3844
- if (!target.startsWith(current)) {
3845
- return target;
3846
- }
3847
- const remaining = target.substring(current.length);
3848
- const words = remaining.split(/(\s+)/);
3849
- if (words.length <= 1) {
3850
- if (!isStreaming) {
3851
- clearInterval(interval);
3852
- }
3853
- return target;
3854
- }
3855
- const currentWordsCount = current.split(/\s+/).filter(Boolean).length;
3856
- const targetWordsCount = target.split(/\s+/).filter(Boolean).length;
3857
- const diff = targetWordsCount - currentWordsCount;
3858
- let wordsToAdd = 1;
3859
- if (diff > 15) {
3860
- wordsToAdd = 4;
3861
- } else if (diff > 8) {
3862
- wordsToAdd = 3;
3863
- } else if (diff > 3) {
3864
- wordsToAdd = 2;
3865
- }
3866
- let addedText = "";
3867
- let wordCount = 0;
3868
- for (let i = 0; i < words.length; i++) {
3869
- const w = words[i];
3870
- addedText += w;
3871
- if (/\S/.test(w)) {
3872
- wordCount++;
3873
- if (wordCount >= wordsToAdd) {
3874
- break;
3875
- }
3876
- }
3877
- }
3878
- return current + addedText;
3879
- });
3880
- }, 100);
3881
- return () => clearInterval(interval);
3882
- }, [isStreaming, isActiveBlock, targetText, displayedText]);
3883
- return displayedText;
3955
+ return targetText;
3884
3956
  };
3885
3957
  formatThinkText = (cleaned, columns = 80) => {
3886
3958
  if (!cleaned) return null;
@@ -3908,14 +3980,17 @@ var init_ChatLayout = __esm({
3908
3980
  return /* @__PURE__ */ React4.createElement(MarkdownText, { key: i, text: cleanPart, color: "gray", columns: availableWidth, italic: true });
3909
3981
  }));
3910
3982
  };
3983
+ REGEX_MD_TOKENS = /(```[\s\S]*?```|`[^`]+`|@\[.*?\]|\*\*.*?\*\*|\*.*?\*|\$.*?\$|\[.*?\]\s*\(.*?\)|\[.*?\]\s*\[.*?\]|https?:\/\/[^\s]+)/g;
3984
+ REGEX_LATEX_FRAC = /\\frac\s*\{([^{}]*)\}\s*\{([^{}]*)\}/g;
3985
+ REGEX_LATEX_STYLE = /(\\(?:mathbf|textbf|textit|underline|texttt)\{[^{}]*\})/g;
3911
3986
  parseMathSymbols = (content) => {
3912
3987
  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, "%");
3913
3988
  };
3914
3989
  renderLatexText = (content, key) => {
3915
3990
  if (!content) return null;
3916
- let formatted = content.replace(/\\frac\s*\{([^{}]*)\}\s*\{([^{}]*)\}/g, "($1/$2)");
3991
+ let formatted = content.replace(REGEX_LATEX_FRAC, "($1/$2)");
3917
3992
  formatted = parseMathSymbols(formatted);
3918
- const parts = formatted.split(/(\\(?:mathbf|textbf|textit|underline|texttt)\{[^{}]*\})/g);
3993
+ const parts = formatted.split(REGEX_LATEX_STYLE);
3919
3994
  return /* @__PURE__ */ React4.createElement(React4.Fragment, { key }, parts.map((p, idx) => {
3920
3995
  if (p.startsWith("\\")) {
3921
3996
  const match = p.match(/\\(\w+)\{([^{}]*)\}/);
@@ -3934,7 +4009,7 @@ var init_ChatLayout = __esm({
3934
4009
  };
3935
4010
  InlineMarkdown = React4.memo(({ text, color, italic }) => {
3936
4011
  if (!text) return null;
3937
- const parts = text.split(/(```[\s\S]*?```|`[^`]+`|@\[.*?\]|\*\*.*?\*\*|\*.*?\*|\$.*?\$|\[.*?\]\s*\(.*?\)|\[.*?\]\s*\[.*?\]|https?:\/\/[^\s]+)/g);
4012
+ const parts = text.split(REGEX_MD_TOKENS);
3938
4013
  return /* @__PURE__ */ React4.createElement(Text4, { color, wrap: "anywhere", italic }, parts.map((part, j) => {
3939
4014
  if (!part) return null;
3940
4015
  if (part.startsWith("```") && part.endsWith("```")) {
@@ -4065,40 +4140,47 @@ var init_ChatLayout = __esm({
4065
4140
  flushBuffers("final");
4066
4141
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: columns - 2 }, result);
4067
4142
  });
4068
- parseLineInfo = (l) => {
4069
- if (!l) return null;
4070
- const clean = l.replace("[UI_CONTEXT]", "").replace(/\r/g, "");
4071
- const isR = clean.startsWith("-");
4072
- const isA = clean.startsWith("+");
4073
- let rest = isR || isA ? clean.substring(1) : clean;
4074
- rest = rest.trim();
4075
- const splitIdx = rest.indexOf("|");
4076
- const num = splitIdx !== -1 ? rest.substring(0, splitIdx).trim() : "";
4077
- const content = splitIdx !== -1 ? rest.substring(splitIdx + 1) : rest;
4078
- return { isR, isA, num, content };
4079
- };
4080
4143
  DiffLine = React4.memo(({ line, pairContent, parentText, columns = 80 }) => {
4081
4144
  const isContext = line.includes("[UI_CONTEXT]");
4082
4145
  const cleanLine = line.replace("[UI_CONTEXT]", "");
4083
4146
  if (isContext && cleanLine.includes("\u2550")) {
4084
- return /* @__PURE__ */ React4.createElement(Box3, { paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2550".repeat(Math.max(10, columns - 4))));
4147
+ return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "\u2550".repeat(Math.max(10, columns - 4))));
4085
4148
  }
4086
4149
  const parsedCurrent = parseLineInfo(line);
4087
4150
  if (!parsedCurrent) {
4088
4151
  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))));
4089
4152
  }
4090
4153
  const { isR: isRemoval, isA: isAddition, num: lineNum, content } = parsedCurrent;
4091
- const innerBgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : void 0;
4092
4154
  let finalPairContent = pairContent;
4093
4155
  if (!finalPairContent && parentText && (isRemoval || isAddition)) {
4094
- const cleanParent = parentText.replace(/\[DIFF_START\]|\[DIFF_END\]/g, "").trim();
4095
- const diffLines = cleanParent.split("\n");
4096
- const pairLine = diffLines.find((l) => {
4097
- const p = parseLineInfo(l);
4098
- return p && p.num === lineNum && p.isR !== isRemoval;
4156
+ const match = parentText.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
4157
+ const diffBody = match ? match[1].trim() : "";
4158
+ const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
4159
+ const parsedLines = diffLines.map((l) => {
4160
+ return {
4161
+ line: l,
4162
+ parsed: parseLineInfo(l),
4163
+ pairContent: null
4164
+ };
4099
4165
  });
4100
- if (pairLine) {
4101
- finalPairContent = parseLineInfo(pairLine).content;
4166
+ let currentGroup = [];
4167
+ for (let idx = 0; idx < parsedLines.length; idx++) {
4168
+ const item = parsedLines[idx];
4169
+ if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
4170
+ currentGroup.push(item);
4171
+ } else {
4172
+ if (currentGroup.length > 0) {
4173
+ alignChangeGroup(currentGroup);
4174
+ currentGroup = [];
4175
+ }
4176
+ }
4177
+ }
4178
+ if (currentGroup.length > 0) {
4179
+ alignChangeGroup(currentGroup);
4180
+ }
4181
+ const matchedItem = parsedLines.find((item) => item.parsed && item.parsed.num === lineNum && item.parsed.isR === isRemoval);
4182
+ if (matchedItem) {
4183
+ finalPairContent = matchedItem.pairContent;
4102
4184
  }
4103
4185
  }
4104
4186
  let words = [];
@@ -4113,7 +4195,7 @@ var init_ChatLayout = __esm({
4113
4195
  }
4114
4196
  const hasInlineChange = words.some((part) => isRemoval && part.removed || isAddition && part.added);
4115
4197
  const isPureUnpairedBlock = !finalPairContent && (isRemoval || isAddition);
4116
- const hasRealChange = hasInlineChange || isPureUnpairedBlock;
4198
+ const innerBgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : void 0;
4117
4199
  const finalNumColor = isRemoval || isAddition ? isRemoval ? "#d96868" : "#68d98c" : "gray";
4118
4200
  const finalPrefixColor = isRemoval ? "#ff4d4d" : "#4dff88";
4119
4201
  const displayPrefix = isRemoval ? "-" : isAddition ? "+" : " ";
@@ -4123,7 +4205,7 @@ var init_ChatLayout = __esm({
4123
4205
  return /* @__PURE__ */ React4.createElement(Text4, { color: blockColor }, wrapText(content, columns - 14));
4124
4206
  }
4125
4207
  if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
4126
- const textColor = isRemoval ? "#b34d4d" : isAddition ? "#4db36b" : "gray";
4208
+ const textColor = isRemoval ? "#885555" : isAddition ? "#558866" : "gray";
4127
4209
  return /* @__PURE__ */ React4.createElement(Text4, { color: textColor }, wrapText(content, columns - 14));
4128
4210
  }
4129
4211
  return /* @__PURE__ */ React4.createElement(Text4, { wrap: "anywhere" }, words.map((part, idx) => {
@@ -4134,7 +4216,7 @@ var init_ChatLayout = __esm({
4134
4216
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#ff3333" }, part.value);
4135
4217
  }
4136
4218
  if (part.added) return null;
4137
- return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#b34d4d" }, part.value);
4219
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#885555" }, part.value);
4138
4220
  }
4139
4221
  if (isAddition) {
4140
4222
  const isSurroundedByAddition = words[idx - 1]?.added || words[idx + 1]?.added;
@@ -4142,7 +4224,7 @@ var init_ChatLayout = __esm({
4142
4224
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#33ff66" }, part.value);
4143
4225
  }
4144
4226
  if (part.removed) return null;
4145
- return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#4db36b" }, part.value);
4227
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#558866" }, part.value);
4146
4228
  }
4147
4229
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "gray" }, part.value);
4148
4230
  }));
@@ -4153,7 +4235,37 @@ var init_ChatLayout = __esm({
4153
4235
  const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
4154
4236
  const diffBody = match ? match[1].trim() : "";
4155
4237
  const diffLines = diffBody.split("\n");
4156
- 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, " ")))));
4238
+ const parsedLines = diffLines.map((line) => {
4239
+ return {
4240
+ line,
4241
+ parsed: parseLineInfo(line),
4242
+ pairContent: null
4243
+ };
4244
+ });
4245
+ let currentGroup = [];
4246
+ for (let i = 0; i < parsedLines.length; i++) {
4247
+ const item = parsedLines[i];
4248
+ if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
4249
+ currentGroup.push(item);
4250
+ } else {
4251
+ if (currentGroup.length > 0) {
4252
+ alignChangeGroup(currentGroup);
4253
+ currentGroup = [];
4254
+ }
4255
+ }
4256
+ }
4257
+ if (currentGroup.length > 0) {
4258
+ alignChangeGroup(currentGroup);
4259
+ }
4260
+ 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, " "))), parsedLines.map((item, i) => /* @__PURE__ */ React4.createElement(
4261
+ DiffLine,
4262
+ {
4263
+ key: i,
4264
+ line: item.line,
4265
+ pairContent: item.pairContent,
4266
+ columns: columns - 3
4267
+ }
4268
+ )), /* @__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, " ")))));
4157
4269
  });
4158
4270
  CodeRenderer = React4.memo(({ text, columns = 80 }) => {
4159
4271
  if (!text) return null;
@@ -4541,12 +4653,35 @@ var init_ChatLayout = __esm({
4541
4653
  // src/components/StatusBar.jsx
4542
4654
  import React5 from "react";
4543
4655
  import { Box as Box4, Text as Text5 } from "ink";
4656
+ import { useState as useState5, useEffect as useEffect4 } from "react";
4544
4657
  var StatusBar, StatusBar_default;
4545
4658
  var init_StatusBar = __esm({
4546
4659
  "src/components/StatusBar.jsx"() {
4547
4660
  init_text();
4548
4661
  StatusBar = React5.memo(({ mode, thinkingLevel, tokens = "0.0k", tokensTotal = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true, apiTier = "Free", aiProvider = "Google" }) => {
4549
4662
  const modeIcon = mode === "Flux" ? "" : "";
4663
+ const [memoryUsage, setMemoryUsage] = useState5(0);
4664
+ const [memoryLimit, setMemoryLimit] = useState5(0);
4665
+ const [memoryUnit, setMemoryUnit] = useState5("MB");
4666
+ useEffect4(() => {
4667
+ const getMemoryInfo = () => {
4668
+ const usage = process.memoryUsage();
4669
+ const isGB = usage.heapTotal / (1024 * 1024) >= 1024;
4670
+ const currentUnit = isGB ? "GB" : "MB";
4671
+ const formatToNumber = (bytes, toGB) => {
4672
+ const converted = bytes / (1024 * 1024 * (toGB ? 1024 : 1));
4673
+ return toGB ? parseFloat(converted.toFixed(2)) : Math.round(converted);
4674
+ };
4675
+ setMemoryUnit(currentUnit);
4676
+ setMemoryLimit(formatToNumber(usage.heapTotal, isGB));
4677
+ setMemoryUsage(formatToNumber(usage.heapUsed, isGB));
4678
+ };
4679
+ getMemoryInfo();
4680
+ const interval = setInterval(() => {
4681
+ getMemoryInfo();
4682
+ }, 3e3);
4683
+ return () => clearInterval(interval);
4684
+ }, []);
4550
4685
  let maxLimit = 256e3;
4551
4686
  if (aiProvider === "DeepSeek" || aiProvider === "Google" && apiTier === "Paid") {
4552
4687
  maxLimit = 4e5;
@@ -4561,7 +4696,7 @@ var init_StatusBar = __esm({
4561
4696
  },
4562
4697
  /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Box4, { marginRight: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white", bold: true }, modeIcon, " ", mode.toUpperCase())), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white", bold: true }, thinkingLevel.toUpperCase())), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "MEM: "), /* @__PURE__ */ React5.createElement(Text5, { color: "white", bold: true }, isMemoryEnabled ? "ON" : "OFF"))),
4563
4698
  /* @__PURE__ */ React5.createElement(Box4, { flexGrow: 1, justifyContent: "center", paddingX: 2 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white", italic: true }, " ", truncatePath(process.cwd(), 35))),
4564
- /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white" }, " ", formatTokens(tokensTotal), " ", /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, (tokens / maxLimit * 100).toFixed(0), "%"))), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginLeft: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", italic: true }, " ", chatId), (apiTier === "Custom" || apiTier === "Paid") && /* @__PURE__ */ React5.createElement(Text5, { color: "white" }, " | ", /* @__PURE__ */ React5.createElement(Text5, { color: "gray", bold: true }, "CUSTOM"))))
4699
+ /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white" }, " ", formatTokens(tokensTotal), " ", /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, (tokens / maxLimit * 100).toFixed(0), "%"))), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "grey", bold: true }, memoryUsage, "/", memoryLimit, " ", memoryUnit)), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React5.createElement(Box4, { marginLeft: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", italic: true }, " ", chatId), (apiTier === "Custom" || apiTier === "Paid") && /* @__PURE__ */ React5.createElement(Text5, { color: "white" }, " | ", /* @__PURE__ */ React5.createElement(Text5, { color: "gray", bold: true }, "CUSTOM"))))
4565
4700
  );
4566
4701
  });
4567
4702
  StatusBar_default = StatusBar;
@@ -4797,7 +4932,7 @@ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST A
4797
4932
  3. [tool:functions.FileMap(path="path/file")]. Shows file structure, functions, class, import/export, variable
4798
4933
  4. [tool:functions.PatchFile(path="...", replaceContent1="full line/block", newContent1="...", ...MAX 6)]. Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile >> guessing. **MUST VERIFY DIFF**
4799
4934
  5. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
4800
- 6. [tool:functions.SearchKeyword(keyword="...", file="optional")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
4935
+ 6. [tool:functions.SearchKeyword(keyword="...", file="optional", subString="true/false optional")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
4801
4936
  7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL ONLY` : `WINDOWS CMD ONLY` : `BASH`} command. Destructive/Irreversible ops -> Ask user
4802
4937
  8. [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASK STRINGS])]. Task List, Markdown IN ARRAY NOT ALLOWED. USAGE: ANALYZE USER REQUEST **IF** MULTIPLE TASK \u2192 BREAK DOWN TASK \u2192 CREATE TODO **BEFORE** DIVING IN. 'tasks' & 'markDone' OPTIONAL PARAMETERS WITH method 'get'. USE 'get' method WITH 'markDone' to mark task completed`.trim() : `- CREATIVE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
4803
4938
  1. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
@@ -5456,9 +5591,10 @@ ${finalOutput}`);
5456
5591
  });
5457
5592
 
5458
5593
  // src/components/SettingsMenu.jsx
5459
- import React7, { useState as useState5 } from "react";
5594
+ import React7, { useState as useState6, useEffect as useEffect5 } from "react";
5460
5595
  import { Box as Box6, Text as Text7, useInput as useInput3 } from "ink";
5461
5596
  import TextInput from "ink-text-input";
5597
+ import v8 from "v8";
5462
5598
  function SettingsMenu({
5463
5599
  systemSettings,
5464
5600
  setSystemSettings,
@@ -5470,11 +5606,34 @@ function SettingsMenu({
5470
5606
  setMessages,
5471
5607
  aiProvider
5472
5608
  }) {
5473
- const [activeColumn, setActiveColumn] = useState5("categories");
5474
- const [selectedCategoryIndex, setSelectedCategoryIndex] = useState5(0);
5475
- const [selectedItemIndex, setSelectedItemIndex] = useState5(0);
5476
- const [editingItem, setEditingItem] = useState5(null);
5477
- const [editValue, setEditValue] = useState5("");
5609
+ const [activeColumn, setActiveColumn] = useState6("categories");
5610
+ const [selectedCategoryIndex, setSelectedCategoryIndex] = useState6(0);
5611
+ const [selectedItemIndex, setSelectedItemIndex] = useState6(0);
5612
+ const [editingItem, setEditingItem] = useState6(null);
5613
+ const [editValue, setEditValue] = useState6("");
5614
+ const [currentMemory, setCurrentMemory] = useState6(0);
5615
+ const [maxMemory, setMaxMemory] = useState6(0);
5616
+ const [memoryUnit, setMemoryUnit] = useState6("MB");
5617
+ useEffect5(() => {
5618
+ const maxLimitBytes = v8.getHeapStatistics().heap_size_limit;
5619
+ const isGB = maxLimitBytes >= 1024 * 1024 * 1024;
5620
+ const unitLabel = isGB ? "GB" : "MB";
5621
+ const divisor = isGB ? 1024 * 1024 * 1024 : 1024 * 1024;
5622
+ setMaxMemory(parseFloat((maxLimitBytes / divisor).toFixed(2)));
5623
+ setMemoryUnit(unitLabel);
5624
+ const getMemoryStats = () => {
5625
+ const usage = process.memoryUsage();
5626
+ const targetBytes = usage.rss;
5627
+ const converted = targetBytes / divisor;
5628
+ const formattedCurrent = isGB ? parseFloat(converted.toFixed(2)) : Math.round(converted);
5629
+ setCurrentMemory(formattedCurrent);
5630
+ };
5631
+ getMemoryStats();
5632
+ const interval = setInterval(() => {
5633
+ getMemoryStats();
5634
+ }, 5e3);
5635
+ return () => clearInterval(interval);
5636
+ }, []);
5478
5637
  const getCategoryItems = (catId) => {
5479
5638
  switch (catId) {
5480
5639
  case "memory":
@@ -5734,7 +5893,10 @@ function SettingsMenu({
5734
5893
  });
5735
5894
  if (currentCatId === "other") {
5736
5895
  elements.push(
5737
- /* @__PURE__ */ React7.createElement(Box6, { key: "pty-notice", marginTop: 18, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "white" }, isPtyAvailable ? "\u2713 Advance Interactive Terminal Supported" : "\u26A0 Interactive Terminal is Limited"))
5896
+ /* @__PURE__ */ React7.createElement(Box6, { key: "pty-notice", marginTop: 17, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "white" }, isPtyAvailable ? "\u2713 Advance Interactive Terminal Supported" : "\u26A0 Interactive Terminal is Limited"))
5897
+ );
5898
+ elements.push(
5899
+ /* @__PURE__ */ React7.createElement(Box6, { key: "memory-load-2026", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "Memory Load: ", currentMemory, "/", maxMemory, " ", memoryUnit))
5738
5900
  );
5739
5901
  }
5740
5902
  if (hasConflict) {
@@ -5777,13 +5939,13 @@ var init_SettingsMenu = __esm({
5777
5939
  });
5778
5940
 
5779
5941
  // src/components/ProfileForm.jsx
5780
- import React8, { useState as useState6, useEffect as useEffect4 } from "react";
5942
+ import React8, { useState as useState7, useEffect as useEffect6 } from "react";
5781
5943
  import { Box as Box7, Text as Text8 } from "ink";
5782
5944
  import TextInput2 from "ink-text-input";
5783
5945
  function ProfileForm({ initialData, onSave, onCancel }) {
5784
- const [step, setStep] = useState6(0);
5785
- const [currentInput, setCurrentInput] = useState6("");
5786
- const [profile, setProfile] = useState6(() => ({
5946
+ const [step, setStep] = useState7(0);
5947
+ const [currentInput, setCurrentInput] = useState7("");
5948
+ const [profile, setProfile] = useState7(() => ({
5787
5949
  name: initialData?.name || "",
5788
5950
  nickname: initialData?.nickname || "",
5789
5951
  instructions: initialData?.instructions || ""
@@ -5793,7 +5955,7 @@ function ProfileForm({ initialData, onSave, onCancel }) {
5793
5955
  { key: "nickname", label: "Enter a Nickname (Agent will use this): " },
5794
5956
  { key: "instructions", label: "System Instructions (Persona overrides): " }
5795
5957
  ];
5796
- useEffect4(() => {
5958
+ useEffect6(() => {
5797
5959
  const currentKey = steps[step].key;
5798
5960
  setCurrentInput(profile[currentKey] || "");
5799
5961
  }, [step, profile]);
@@ -5841,7 +6003,7 @@ var init_ProfileForm = __esm({
5841
6003
  });
5842
6004
 
5843
6005
  // src/components/AskUserModal.jsx
5844
- import React9, { useState as useState7 } from "react";
6006
+ import React9, { useState as useState8 } from "react";
5845
6007
  import { Box as Box8, Text as Text9, useInput as useInput4 } from "ink";
5846
6008
  import TextInput3 from "ink-text-input";
5847
6009
  var AskUserModal, AskUserModal_default;
@@ -5849,9 +6011,9 @@ var init_AskUserModal = __esm({
5849
6011
  "src/components/AskUserModal.jsx"() {
5850
6012
  init_terminal();
5851
6013
  AskUserModal = ({ question, options, onResolve }) => {
5852
- const [isSuggestingElse, setIsSuggestingElse] = useState7(false);
5853
- const [customInput, setCustomInput] = useState7("");
5854
- const [selectedIndex, setSelectedIndex] = useState7(0);
6014
+ const [isSuggestingElse, setIsSuggestingElse] = useState8(false);
6015
+ const [customInput, setCustomInput] = useState8("");
6016
+ const [selectedIndex, setSelectedIndex] = useState8(0);
5855
6017
  const allOptions = [...options, { id: "CUSTOM", label: "Suggest something else...", description: "Provide a custom response" }];
5856
6018
  useInput4((input, key) => {
5857
6019
  if (isSuggestingElse) return;
@@ -6322,27 +6484,61 @@ var init_history = __esm({
6322
6484
  return nextLock;
6323
6485
  };
6324
6486
  loadHistory = async () => {
6487
+ await fs7.ensureDir(HISTORY_DIR);
6488
+ let history = {};
6325
6489
  if (await fs7.pathExists(HISTORY_FILE)) {
6326
6490
  try {
6327
- return readEncryptedJson(HISTORY_FILE, {});
6491
+ history = readEncryptedJson(HISTORY_FILE, {});
6328
6492
  } catch (e) {
6329
- return {};
6493
+ history = {};
6330
6494
  }
6331
6495
  }
6332
- return {};
6496
+ for (const id in history) {
6497
+ const chatFile = path6.join(HISTORY_DIR, `${id}.json`);
6498
+ Object.defineProperty(history[id], "messages", {
6499
+ get: () => {
6500
+ if (fs7.existsSync(chatFile)) {
6501
+ try {
6502
+ return readEncryptedJson(chatFile, []);
6503
+ } catch (e) {
6504
+ return [];
6505
+ }
6506
+ }
6507
+ return [];
6508
+ },
6509
+ set: (msgs) => {
6510
+ try {
6511
+ writeEncryptedJson(chatFile, msgs);
6512
+ } catch (e) {
6513
+ }
6514
+ },
6515
+ enumerable: false,
6516
+ configurable: true
6517
+ });
6518
+ }
6519
+ return history;
6333
6520
  };
6334
6521
  saveChat = async (id, name, messages) => {
6335
6522
  return withLock(async () => {
6523
+ await fs7.ensureDir(HISTORY_DIR);
6336
6524
  const history = await loadHistory();
6337
6525
  const existingChat = history[id];
6338
6526
  const persistentMessages = (messages || []).filter((m) => !m.isUpdateNotification && !m.isMeta);
6339
6527
  const finalName = name || (existingChat ? existingChat.name : `Session ${id.slice(-6)}`);
6528
+ const chatFile = path6.join(HISTORY_DIR, `${id}.json`);
6529
+ writeEncryptedJson(chatFile, persistentMessages);
6340
6530
  history[id] = {
6341
6531
  name: finalName,
6342
- messages: persistentMessages,
6343
6532
  updatedAt: Date.now()
6344
6533
  };
6345
- writeEncryptedJson(HISTORY_FILE, history);
6534
+ const indexHistory = {};
6535
+ for (const chatId in history) {
6536
+ indexHistory[chatId] = {
6537
+ name: history[chatId].name,
6538
+ updatedAt: history[chatId].updatedAt
6539
+ };
6540
+ }
6541
+ writeEncryptedJson(HISTORY_FILE, indexHistory);
6346
6542
  });
6347
6543
  };
6348
6544
  saveChatTitle = async (id, title) => {
@@ -6352,16 +6548,30 @@ var init_history = __esm({
6352
6548
  history[id].name = title;
6353
6549
  history[id].updatedAt = Date.now();
6354
6550
  } else {
6355
- history[id] = { name: title, messages: [], updatedAt: Date.now() };
6551
+ history[id] = { name: title, updatedAt: Date.now() };
6552
+ }
6553
+ const indexHistory = {};
6554
+ for (const chatId in history) {
6555
+ indexHistory[chatId] = {
6556
+ name: history[chatId].name,
6557
+ updatedAt: history[chatId].updatedAt
6558
+ };
6356
6559
  }
6357
- writeEncryptedJson(HISTORY_FILE, history);
6560
+ writeEncryptedJson(HISTORY_FILE, indexHistory);
6358
6561
  });
6359
6562
  };
6360
6563
  deleteChat = async (id) => {
6361
6564
  return withLock(async () => {
6362
6565
  const history = await loadHistory();
6363
6566
  delete history[id];
6364
- writeEncryptedJson(HISTORY_FILE, history);
6567
+ const indexHistory = {};
6568
+ for (const chatId in history) {
6569
+ indexHistory[chatId] = {
6570
+ name: history[chatId].name,
6571
+ updatedAt: history[chatId].updatedAt
6572
+ };
6573
+ }
6574
+ writeEncryptedJson(HISTORY_FILE, indexHistory);
6365
6575
  if (await fs7.pathExists(CONTEXT_FILE)) {
6366
6576
  try {
6367
6577
  const contextData = readEncryptedJson(CONTEXT_FILE, []);
@@ -6383,6 +6593,13 @@ var init_history = __esm({
6383
6593
  writeEncryptedJson(TEMP_MEM_CHAT_FILE, cache);
6384
6594
  }
6385
6595
  await RevertManager.deleteChatBackups(id);
6596
+ const chatFile = path6.join(HISTORY_DIR, `${id}.json`);
6597
+ if (await fs7.pathExists(chatFile)) {
6598
+ try {
6599
+ await fs7.remove(chatFile);
6600
+ } catch (e) {
6601
+ }
6602
+ }
6386
6603
  return history;
6387
6604
  });
6388
6605
  };
@@ -8085,8 +8302,10 @@ var init_search_keyword = __esm({
8085
8302
  "src/tools/search_keyword.js"() {
8086
8303
  init_arg_parser();
8087
8304
  search_keyword = async (args) => {
8088
- const { keyword, file } = parseArgs(args);
8305
+ const { keyword, file, subString } = parseArgs(args);
8089
8306
  if (!keyword) return 'ERROR: Missing "keyword" argument.';
8307
+ const matchSubstring = subString === true || subString === "true" || subString === 1 || subString === "1" || subString === "true";
8308
+ const wordRegex = new RegExp(`(?<![\\w])${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w])`, "i");
8090
8309
  const excludes = [
8091
8310
  "node_modules",
8092
8311
  ".git",
@@ -8126,7 +8345,8 @@ var init_search_keyword = __esm({
8126
8345
  const lines = content.split(/\r?\n/);
8127
8346
  const fileMatches = [];
8128
8347
  for (let i = 0; i < lines.length; i++) {
8129
- if (lines[i].includes(keyword)) {
8348
+ const matched = matchSubstring ? lines[i].toLowerCase().includes(keyword.toLowerCase()) : wordRegex.test(lines[i]);
8349
+ if (matched) {
8130
8350
  const displayPath = fileObj.relativePath.replace(/\\/g, "/");
8131
8351
  fileMatches.push(`${displayPath} \u2192 ${i + 1}`);
8132
8352
  }
@@ -8142,9 +8362,9 @@ var init_search_keyword = __esm({
8142
8362
  global.gc();
8143
8363
  }
8144
8364
  if (matches.length === 0) {
8145
- return `Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ". Try to specify files"}`;
8365
+ return `Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ". Try to specify files"} ${matchSubstring ? "(subString mode)" : ""}`;
8146
8366
  }
8147
- let output = `Found ${matches.length} matches:
8367
+ let output = `Found ${matches.length} matches ${matchSubstring ? "(subString mode)" : ""}:
8148
8368
 
8149
8369
  `;
8150
8370
  output += matches.join("\n");
@@ -9142,7 +9362,7 @@ var init_ai = __esm({
9142
9362
  colorMainWords = (label2) => {
9143
9363
  if (!label2) return label2;
9144
9364
  return label2.replace(/(?:(\x1b\[\d+m))?([✔✗✖🔍📖→➕↻•])(?:(\x1b\[\d+m))?\s*\b(Created|Read|Edited|Viewed|Auto-Read|List|Generated|Written|Searched|Get Map|Write Canceled|Edit Canceled|Write Cancelled|Edit Denied|Visited|Updated|Reviewed)\b/ig, (match, ansiBefore, icon, ansiAfter, word) => {
9145
- return `${ansiBefore || ""}${icon}${ansiAfter || ""} \x1B[95m${word}\x1B[0m`;
9365
+ return `${ansiBefore || ""}${icon}${ansiAfter || ""} \x1B[95m${word}\x1B[0m`;
9146
9366
  });
9147
9367
  };
9148
9368
  TERMINATION_SIGNAL = false;
@@ -9162,13 +9382,11 @@ var init_ai = __esm({
9162
9382
  "moonshotai/kimi-k2.6",
9163
9383
  // NVIDIA vision models
9164
9384
  "moonshotai/kimi-k2.6",
9385
+ "stepfun-ai/step-3.7-flash",
9386
+ "google/gemma-4-31b-it",
9387
+ "mistralai/mistral-medium-3.5-128b"
9165
9388
  // Google models
9166
- "gemma-4-31b-it",
9167
- "gemini-2.5-flash",
9168
- "gemini-3-flash-preview",
9169
- "gemini-3.5-flash",
9170
- "gemini-3.1-flash-lite",
9171
- "gemini-3.1-pro-preview"
9389
+ // No need. All models on Gemini API is Multimodal
9172
9390
  ];
9173
9391
  isModelMultimodal = (model) => {
9174
9392
  if (!model) return false;
@@ -9232,7 +9450,7 @@ var init_ai = __esm({
9232
9450
  }
9233
9451
  return fetch(url, options);
9234
9452
  };
9235
- getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.85) {
9453
+ getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.99) {
9236
9454
  const messages = [];
9237
9455
  if (systemInstruction) {
9238
9456
  messages.push({ role: "system", content: systemInstruction });
@@ -9364,7 +9582,7 @@ var init_ai = __esm({
9364
9582
  }
9365
9583
  }
9366
9584
  };
9367
- getNVIDIAStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal = false, signal, temperature = 0.7) {
9585
+ getNVIDIAStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal = false, signal, temperature = 0.99) {
9368
9586
  const messages = [];
9369
9587
  if (systemInstruction) {
9370
9588
  messages.push({ role: "system", content: systemInstruction });
@@ -9380,7 +9598,7 @@ var init_ai = __esm({
9380
9598
  const mimeType = part.inlineData.mimeType;
9381
9599
  const data = part.inlineData.data;
9382
9600
  const isImage = mimeType.startsWith("image/");
9383
- if (isImage) {
9601
+ if (isImage && MULTIMODAL_MODELS.includes(model)) {
9384
9602
  msgContent.push({
9385
9603
  type: "image_url",
9386
9604
  image_url: {
@@ -9404,7 +9622,7 @@ var init_ai = __esm({
9404
9622
  "High": "High",
9405
9623
  "xHigh": "High"
9406
9624
  };
9407
- const apiLevel = thinkingLevelMap[thinkingLevel] || "Standard";
9625
+ const apiLevel = thinkingLevelMap[thinkingLevel] || "High";
9408
9626
  const isThinking = apiLevel !== "Fast";
9409
9627
  const isKimi = model.includes("kimi");
9410
9628
  const isGemma = model.includes("gemma");
@@ -9412,6 +9630,15 @@ var init_ai = __esm({
9412
9630
  const isGlm = model.includes("glm");
9413
9631
  const isMistral = model.includes("mistral");
9414
9632
  const isMinimax = model.includes("minimax");
9633
+ const isGPT = model.includes("gpt");
9634
+ const GPT_THINKING_LEVELS = {
9635
+ "Fast": "low",
9636
+ "Low": "low",
9637
+ "Medium": "medium",
9638
+ "Standard": "medium",
9639
+ "High": "high",
9640
+ "xHigh": "high"
9641
+ };
9415
9642
  const maxTokens = isMinimax || isDeepSeek ? 16384 : 32768;
9416
9643
  const body = {
9417
9644
  model,
@@ -9419,7 +9646,8 @@ var init_ai = __esm({
9419
9646
  max_tokens: maxTokens,
9420
9647
  stream: true,
9421
9648
  stream_options: { include_usage: true },
9422
- temperature
9649
+ temperature,
9650
+ ...isGPT && { thinking: GPT_THINKING_LEVELS[thinkingLevel] || "high" }
9423
9651
  };
9424
9652
  if (isKimi) {
9425
9653
  body.chat_template_kwargs = { thinking: isThinking };
@@ -9516,7 +9744,7 @@ var init_ai = __esm({
9516
9744
  }
9517
9745
  }
9518
9746
  };
9519
- getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.45) {
9747
+ getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.95) {
9520
9748
  const messages = [];
9521
9749
  if (systemInstruction) {
9522
9750
  messages.push({ role: "system", content: systemInstruction });
@@ -9763,7 +9991,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9763
9991
  mode,
9764
9992
  false,
9765
9993
  null,
9766
- 0.4
9994
+ 0.75
9767
9995
  );
9768
9996
  const iterator2 = stream[Symbol.asyncIterator]();
9769
9997
  const firstResult2 = await iterator2.next();
@@ -9779,7 +10007,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9779
10007
  mode,
9780
10008
  false,
9781
10009
  null,
9782
- 0.4
10010
+ 0.75
9783
10011
  );
9784
10012
  const iterator2 = stream[Symbol.asyncIterator]();
9785
10013
  const firstResult2 = await iterator2.next();
@@ -9795,7 +10023,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9795
10023
  mode,
9796
10024
  false,
9797
10025
  null,
9798
- 0.4
10026
+ 0.75
9799
10027
  );
9800
10028
  const iterator2 = stream[Symbol.asyncIterator]();
9801
10029
  const firstResult2 = await iterator2.next();
@@ -9807,7 +10035,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9807
10035
  config: {
9808
10036
  systemInstruction: janitorPrompt,
9809
10037
  maxOutputTokens: 512,
9810
- temperature: 0.4,
10038
+ temperature: 0.75,
9811
10039
  safetySettings: [
9812
10040
  { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
9813
10041
  { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
@@ -10227,7 +10455,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
10227
10455
  client = new GoogleGenAI({ apiKey });
10228
10456
  return client;
10229
10457
  };
10230
- generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast", temperature = 0.4) => {
10458
+ generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast", temperature = 0.75) => {
10231
10459
  const { aiProvider = "Google", apiKey, mode } = settings;
10232
10460
  let fullText = "";
10233
10461
  let usageMetadata = null;
@@ -10245,7 +10473,6 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
10245
10473
  contents: normalizedContents,
10246
10474
  config: {
10247
10475
  systemInstruction,
10248
- maxOutputTokens: 2048,
10249
10476
  temperature,
10250
10477
  thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MINIMAL }
10251
10478
  }
@@ -11162,6 +11389,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
11162
11389
  let isStutteringLoop = false;
11163
11390
  let isGeneralLoop = false;
11164
11391
  let isInitialAttempt = true;
11392
+ let lastLoopCheckLen = 0;
11165
11393
  let accumulatedContext = "";
11166
11394
  let dedupeBuffer = "";
11167
11395
  let isDedupeActive = false;
@@ -11266,7 +11494,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
11266
11494
  } else if (retryCount > 0) {
11267
11495
  yield { type: "model_update", content: null };
11268
11496
  }
11269
- currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, isMultiModal);
11497
+ currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, aiProvider === "Google" ? true : isMultiModal);
11270
11498
  const lastUserMsg = contents[contents.length - 1];
11271
11499
  if (isBridgeConnected() & loop > 0) {
11272
11500
  yield { type: "status", content: "Checking Code..." };
@@ -11314,7 +11542,7 @@ ${ideErr} [/ERROR]`;
11314
11542
  mode,
11315
11543
  isMultiModal,
11316
11544
  abortController.signal,
11317
- 0.45
11545
+ 0.95
11318
11546
  );
11319
11547
  } else if (aiProvider === "DeepSeek") {
11320
11548
  stream = getDeepSeekStream(
@@ -11326,7 +11554,7 @@ ${ideErr} [/ERROR]`;
11326
11554
  mode,
11327
11555
  isMultiModal,
11328
11556
  abortController.signal,
11329
- 0.85
11557
+ 0.99
11330
11558
  );
11331
11559
  } else if (aiProvider === "NVIDIA") {
11332
11560
  stream = getNVIDIAStream(
@@ -11338,7 +11566,7 @@ ${ideErr} [/ERROR]`;
11338
11566
  mode,
11339
11567
  isMultiModal,
11340
11568
  abortController.signal,
11341
- 0.7
11569
+ 0.99
11342
11570
  );
11343
11571
  } else {
11344
11572
  const apiCallPromise = client.models.generateContentStream({
@@ -11347,7 +11575,7 @@ ${ideErr} [/ERROR]`;
11347
11575
  config: {
11348
11576
  systemInstruction: currentSystemInstruction,
11349
11577
  mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
11350
- temperature: 1.05,
11578
+ temperature: 1,
11351
11579
  safetySettings: [
11352
11580
  { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
11353
11581
  { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
@@ -11641,7 +11869,6 @@ ${ideErr} [/ERROR]`;
11641
11869
  for (const m of msgs) yield m;
11642
11870
  }
11643
11871
  }
11644
- const signalSafeText3 = getSanitizedText(turnText);
11645
11872
  const toolContext = getActiveToolContext(turnText);
11646
11873
  if (toolContext.inside) {
11647
11874
  if (!lastToolEventTime) lastToolEventTime = Date.now();
@@ -11712,78 +11939,60 @@ ${ideErr} [/ERROR]`;
11712
11939
  }
11713
11940
  }
11714
11941
  }
11715
- const contextSafeText = getContextSafeText(turnText, false);
11716
- const thinkBlocks = contextSafeText.match(/(?:<think>|\[think\])([\s\S]*?)(?:<\/think>|\[\/think\]|$)/gi) || [];
11717
- const thinkContent = thinkBlocks.join("").trim();
11718
- const sentences = thinkContent.split(/[.!?]\s+/);
11719
- const uniqueSentences = new Set(sentences);
11720
- const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
11721
- const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
11722
- let repetitionThresholdThinking = 0.4;
11723
- let repetitionThresholdResponse = 0.6;
11724
- let isOverVerboseThinking = false;
11725
- if ((targetModel || "").toLowerCase().startsWith("gemma")) {
11726
- const thinkingCaps = {
11727
- "low": 256,
11728
- "medium": 768,
11729
- "high": 2048,
11730
- "max": 4096,
11731
- "xhigh": 4096
11732
- };
11733
- const cap = thinkingCaps[thinkingLevel?.toLowerCase()] || 2500;
11734
- isOverVerboseThinking = wordCount > cap;
11735
- }
11736
- if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
11737
- const reason = repetitionRatio > repetitionThresholdThinking ? "Reasoning Loop Detected" : "Thinking Budget Exceeded";
11738
- yield { type: "status", content: `${reason}. Re-centering...` };
11739
- isThinkingLoop = true;
11740
- await new Promise((resolve) => setTimeout(resolve, 3e3));
11741
- break;
11742
- }
11743
- const responseContent = signalSafeText3.trim();
11744
- const respSentences = responseContent.split(/[.!?]\s+/);
11745
- const uniqueRespSentences = new Set(respSentences);
11746
- const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
11747
- if (respRepetitionRatio > repetitionThresholdResponse) {
11748
- yield { type: "status", content: `Response Loop Detected. Re-centering...` };
11749
- isThinkingLoop = false;
11750
- isGeneralLoop = true;
11751
- await new Promise((resolve) => setTimeout(resolve, 3e3));
11752
- break;
11753
- }
11754
- const allWords = contextSafeText.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
11755
- let stutterDetected = false;
11756
- if (allWords.length > 5) {
11757
- for (let p = 1; p <= 15; p++) {
11758
- const R = Math.max(3, Math.ceil(8 / p));
11759
- if (allWords.length < p * R) continue;
11760
- let isRepeating = true;
11761
- const pattern = allWords.slice(allWords.length - p);
11762
- const patternStr = pattern.join(" ");
11763
- for (let r = 1; r < R; r++) {
11764
- const prevPattern = allWords.slice(allWords.length - p * (r + 1), allWords.length - p * r);
11765
- if (prevPattern.join(" ") !== patternStr) {
11766
- isRepeating = false;
11767
- break;
11768
- }
11769
- }
11770
- if (isRepeating) {
11771
- stutterDetected = true;
11772
- break;
11773
- }
11942
+ if (turnText.length - lastLoopCheckLen > 150) {
11943
+ lastLoopCheckLen = turnText.length;
11944
+ const contextSafeText = getContextSafeText(turnText, false);
11945
+ const thinkBlocks = contextSafeText.match(/(?:<think>|\[think\])([\s\S]*?)(?:<\/think>|\[\/think\]|$)/gi) || [];
11946
+ const thinkContent = thinkBlocks.join("").trim();
11947
+ const sentences = thinkContent.split(/[.!?]\s+/);
11948
+ const uniqueSentences = new Set(sentences);
11949
+ const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
11950
+ const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
11951
+ let repetitionThresholdThinking = 0.4;
11952
+ let repetitionThresholdResponse = 0.6;
11953
+ let isOverVerboseThinking = false;
11954
+ if ((targetModel || "").toLowerCase().startsWith("gemma")) {
11955
+ const thinkingCaps = {
11956
+ "low": 256,
11957
+ "medium": 768,
11958
+ "high": 2048,
11959
+ "max": 4096,
11960
+ "xhigh": 4096
11961
+ };
11962
+ const cap = thinkingCaps[thinkingLevel?.toLowerCase()] || 2500;
11963
+ isOverVerboseThinking = wordCount > cap;
11774
11964
  }
11775
- }
11776
- if (!stutterDetected) {
11777
- const cleanChars = contextSafeText.toLowerCase().replace(/[^a-z0-9]/gi, "");
11778
- if (cleanChars.length >= 10) {
11779
- for (let p = 1; p <= 10; p++) {
11780
- const R = Math.max(4, Math.ceil(12 / p));
11781
- if (cleanChars.length < p * R) continue;
11782
- const pattern = cleanChars.substring(cleanChars.length - p);
11965
+ if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
11966
+ const reason = repetitionRatio > repetitionThresholdThinking ? "Reasoning Loop Detected" : "Thinking Budget Exceeded";
11967
+ yield { type: "status", content: `${reason}. Re-centering...` };
11968
+ isThinkingLoop = true;
11969
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
11970
+ break;
11971
+ }
11972
+ const signalSafeText3 = getSanitizedText(turnText);
11973
+ const responseContent = signalSafeText3.trim();
11974
+ const respSentences = responseContent.split(/[.!?]\s+/);
11975
+ const uniqueRespSentences = new Set(respSentences);
11976
+ const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
11977
+ if (respRepetitionRatio > repetitionThresholdResponse) {
11978
+ yield { type: "status", content: `Response Loop Detected. Re-centering...` };
11979
+ isThinkingLoop = false;
11980
+ isGeneralLoop = true;
11981
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
11982
+ break;
11983
+ }
11984
+ const allWords = contextSafeText.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
11985
+ let stutterDetected = false;
11986
+ if (allWords.length > 5) {
11987
+ for (let p = 1; p <= 15; p++) {
11988
+ const R = Math.max(3, Math.ceil(8 / p));
11989
+ if (allWords.length < p * R) continue;
11783
11990
  let isRepeating = true;
11991
+ const pattern = allWords.slice(allWords.length - p);
11992
+ const patternStr = pattern.join(" ");
11784
11993
  for (let r = 1; r < R; r++) {
11785
- const prevPattern = cleanChars.substring(cleanChars.length - p * (r + 1), cleanChars.length - p * r);
11786
- if (prevPattern !== pattern) {
11994
+ const prevPattern = allWords.slice(allWords.length - p * (r + 1), allWords.length - p * r);
11995
+ if (prevPattern.join(" ") !== patternStr) {
11787
11996
  isRepeating = false;
11788
11997
  break;
11789
11998
  }
@@ -11794,13 +12003,35 @@ ${ideErr} [/ERROR]`;
11794
12003
  }
11795
12004
  }
11796
12005
  }
11797
- }
11798
- if (stutterDetected) {
11799
- yield { type: "status", content: `Stuttering Detected. Re-centering...` };
11800
- isThinkingLoop = false;
11801
- isStutteringLoop = true;
11802
- await new Promise((resolve) => setTimeout(resolve, 3e3));
11803
- break;
12006
+ if (!stutterDetected) {
12007
+ const cleanChars = contextSafeText.toLowerCase().replace(/[^a-z0-9]/gi, "");
12008
+ if (cleanChars.length >= 10) {
12009
+ for (let p = 1; p <= 10; p++) {
12010
+ const R = Math.max(4, Math.ceil(12 / p));
12011
+ if (cleanChars.length < p * R) continue;
12012
+ const pattern = cleanChars.substring(cleanChars.length - p);
12013
+ let isRepeating = true;
12014
+ for (let r = 1; r < R; r++) {
12015
+ const prevPattern = cleanChars.substring(cleanChars.length - p * (r + 1), cleanChars.length - p * r);
12016
+ if (prevPattern !== pattern) {
12017
+ isRepeating = false;
12018
+ break;
12019
+ }
12020
+ }
12021
+ if (isRepeating) {
12022
+ stutterDetected = true;
12023
+ break;
12024
+ }
12025
+ }
12026
+ }
12027
+ }
12028
+ if (stutterDetected) {
12029
+ yield { type: "status", content: `Stuttering Detected. Re-centering...` };
12030
+ isThinkingLoop = false;
12031
+ isStutteringLoop = true;
12032
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
12033
+ break;
12034
+ }
11804
12035
  }
11805
12036
  const toolActionableText = turnText.replace(/(?:<(think|thought|thoughts)>|\[(think|thought|thoughts)\])[\s\S]*?(?:<\/(think|thought|thoughts)>|\[\/(think|thought|thoughts)\]|$)/gi, "");
11806
12037
  const allToolsFound = detectToolCalls(toolActionableText);
@@ -12952,13 +13183,13 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
12952
13183
  });
12953
13184
 
12954
13185
  // src/components/ResumeModal.jsx
12955
- import React10, { useState as useState8, useEffect as useEffect5 } from "react";
13186
+ import React10, { useState as useState9, useEffect as useEffect7 } from "react";
12956
13187
  import { Box as Box9, Text as Text10, useInput as useInput5 } from "ink";
12957
13188
  function ResumeModal({ onSelect, onDelete, onClose }) {
12958
- const [history, setHistory] = useState8({});
12959
- const [keys, setKeys] = useState8([]);
12960
- const [selectedIndex, setSelectedIndex] = useState8(0);
12961
- useEffect5(() => {
13189
+ const [history, setHistory] = useState9({});
13190
+ const [keys, setKeys] = useState9([]);
13191
+ const [selectedIndex, setSelectedIndex] = useState9(0);
13192
+ useEffect7(() => {
12962
13193
  const fetchHistory = async () => {
12963
13194
  const h = await loadHistory();
12964
13195
  setHistory(h);
@@ -13044,14 +13275,14 @@ var init_ResumeModal = __esm({
13044
13275
  });
13045
13276
 
13046
13277
  // src/components/MemoryModal.jsx
13047
- import React11, { useState as useState9, useEffect as useEffect6 } from "react";
13278
+ import React11, { useState as useState10, useEffect as useEffect8 } from "react";
13048
13279
  import { Box as Box10, Text as Text11, useInput as useInput6, useStdout } from "ink";
13049
13280
  function MemoryModal({ onClose }) {
13050
13281
  const { stdout } = useStdout();
13051
13282
  const columns = stdout?.columns || 80;
13052
- const [memories, setMemories] = useState9([]);
13053
- const [selectedIndex, setSelectedIndex] = useState9(0);
13054
- const [isMemoryOn, setIsMemoryOn] = useState9(true);
13283
+ const [memories, setMemories] = useState10([]);
13284
+ const [selectedIndex, setSelectedIndex] = useState10(0);
13285
+ const [isMemoryOn, setIsMemoryOn] = useState10(true);
13055
13286
  const loadMemories = () => {
13056
13287
  const data = readEncryptedJson(MEMORIES_FILE, []);
13057
13288
  setMemories(data);
@@ -13063,7 +13294,7 @@ function MemoryModal({ onClose }) {
13063
13294
  setIsMemoryOn(true);
13064
13295
  }
13065
13296
  };
13066
- useEffect6(() => {
13297
+ useEffect8(() => {
13067
13298
  loadMemories();
13068
13299
  }, []);
13069
13300
  useInput6((input, key) => {
@@ -13165,7 +13396,7 @@ var init_MemoryModal = __esm({
13165
13396
  });
13166
13397
 
13167
13398
  // src/components/UpdateProcessor.jsx
13168
- import React12, { useState as useState10, useEffect as useEffect7 } from "react";
13399
+ import React12, { useState as useState11, useEffect as useEffect9 } from "react";
13169
13400
  import { Box as Box11, Text as Text12 } from "ink";
13170
13401
  import { spawn as spawn2 } from "child_process";
13171
13402
  var pty2, SPINNER_FRAMES, UpdateProcessor, UpdateProcessor_default;
@@ -13180,17 +13411,17 @@ var init_UpdateProcessor = __esm({
13180
13411
  }
13181
13412
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
13182
13413
  UpdateProcessor = ({ latest, current, settings, onClose, onUpdateSettings, onSuccess }) => {
13183
- const [status, setStatus] = useState10("initializing");
13184
- const [log, setLog] = useState10("");
13185
- const [error, setError] = useState10(null);
13186
- const [tick, setTick] = useState10(0);
13187
- useEffect7(() => {
13414
+ const [status, setStatus] = useState11("initializing");
13415
+ const [log, setLog] = useState11("");
13416
+ const [error, setError] = useState11(null);
13417
+ const [tick, setTick] = useState11(0);
13418
+ useEffect9(() => {
13188
13419
  const interval = setInterval(() => {
13189
13420
  setTick((t) => (t + 1) % 1e3);
13190
13421
  }, 33);
13191
13422
  return () => clearInterval(interval);
13192
13423
  }, []);
13193
- useEffect7(() => {
13424
+ useEffect9(() => {
13194
13425
  let child;
13195
13426
  const runUpdate = async () => {
13196
13427
  const manager = settings.updateManager || "npm";
@@ -13323,12 +13554,12 @@ var init_UpdateProcessor = __esm({
13323
13554
  });
13324
13555
 
13325
13556
  // src/components/ParserDownloadModal.jsx
13326
- import React13, { useState as useState11, useEffect as useEffect8 } from "react";
13557
+ import React13, { useState as useState12, useEffect as useEffect10 } from "react";
13327
13558
  import { Box as Box12, Text as Text13, useInput as useInput7 } from "ink";
13328
13559
  function ParserDownloadModal({ onClose }) {
13329
- const [selectedIndex, setSelectedIndex] = useState11(0);
13330
- const [status, setStatus] = useState11({});
13331
- useEffect8(() => {
13560
+ const [selectedIndex, setSelectedIndex] = useState12(0);
13561
+ const [status, setStatus] = useState12({});
13562
+ useEffect10(() => {
13332
13563
  const initialStatus = {};
13333
13564
  EXTENSIONS.forEach((item) => {
13334
13565
  if (isParserInstalled(item.file)) {
@@ -13829,10 +14060,10 @@ var init_dist = __esm({
13829
14060
  });
13830
14061
 
13831
14062
  // src/components/RevertModal.jsx
13832
- import React14, { useState as useState12 } from "react";
14063
+ import React14, { useState as useState13 } from "react";
13833
14064
  import { Box as Box14, Text as Text15, useInput as useInput8 } from "ink";
13834
14065
  function RevertModal({ prompts, onSelect, onClose }) {
13835
- const [selectedIndex, setSelectedIndex] = useState12(0);
14066
+ const [selectedIndex, setSelectedIndex] = useState13(0);
13836
14067
  useInput8((input, key) => {
13837
14068
  if (key.escape) onClose();
13838
14069
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
@@ -13955,7 +14186,7 @@ __export(app_exports, {
13955
14186
  default: () => App
13956
14187
  });
13957
14188
  import os4 from "os";
13958
- import React15, { useState as useState13, useEffect as useEffect9, useRef as useRef3, useMemo as useMemo2 } from "react";
14189
+ import React15, { useState as useState14, useEffect as useEffect11, useRef as useRef3, useMemo as useMemo2 } from "react";
13959
14190
  import { Box as Box15, Text as Text16, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
13960
14191
  import fs22 from "fs-extra";
13961
14192
  import path20 from "path";
@@ -13965,24 +14196,24 @@ import TextInput4 from "ink-text-input";
13965
14196
  import SelectInput2 from "ink-select-input";
13966
14197
  import gradient2 from "gradient-string";
13967
14198
  function App({ args = [] }) {
13968
- const [confirmExit, setConfirmExit] = useState13(false);
13969
- const [exitCountdown, setExitCountdown] = useState13(10);
14199
+ const [confirmExit, setConfirmExit] = useState14(false);
14200
+ const [exitCountdown, setExitCountdown] = useState14(10);
13970
14201
  const { stdout } = useStdout2();
13971
- const [input, setInput] = useState13("");
13972
- const [inputKey, setInputKey] = useState13(0);
13973
- const [isExpanded, setIsExpanded] = useState13(false);
13974
- const [mode, setMode] = useState13("Flux");
13975
- const [terminalSize, setTerminalSize] = useState13({
14202
+ const [input, setInput] = useState14("");
14203
+ const [inputKey, setInputKey] = useState14(0);
14204
+ const [isExpanded, setIsExpanded] = useState14(false);
14205
+ const [mode, setMode] = useState14("Flux");
14206
+ const [terminalSize, setTerminalSize] = useState14({
13976
14207
  columns: stdout?.columns || 80,
13977
14208
  rows: stdout?.rows || 24
13978
14209
  });
13979
- const [selectedIndex, setSelectedIndex] = useState13(0);
13980
- const [isFilePickerDismissed, setIsFilePickerDismissed] = useState13(false);
13981
- const [showBridgePromo, setShowBridgePromo] = useState13(false);
13982
- const [promoSelectedIndex, setPromoSelectedIndex] = useState13(0);
14210
+ const [selectedIndex, setSelectedIndex] = useState14(0);
14211
+ const [isFilePickerDismissed, setIsFilePickerDismissed] = useState14(false);
14212
+ const [showBridgePromo, setShowBridgePromo] = useState14(false);
14213
+ const [promoSelectedIndex, setPromoSelectedIndex] = useState14(0);
13983
14214
  const suggestionOffsetRef = useRef3(0);
13984
14215
  const persistedModelRef = useRef3(null);
13985
- useEffect9(() => {
14216
+ useEffect11(() => {
13986
14217
  const ideName = getIDEName();
13987
14218
  const isIDE = !["Terminal", "Windows Terminal"].includes(ideName) || !!process.env.VSC_TERMINAL_URL;
13988
14219
  const graceTimer = setTimeout(() => {
@@ -14157,7 +14388,7 @@ function App({ args = [] }) {
14157
14388
  }
14158
14389
  }
14159
14390
  };
14160
- useEffect9(() => {
14391
+ useEffect11(() => {
14161
14392
  const handleResize = () => {
14162
14393
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
14163
14394
  setTerminalSize({
@@ -14170,18 +14401,18 @@ function App({ args = [] }) {
14170
14401
  stdout.off("resize", handleResize);
14171
14402
  };
14172
14403
  }, [stdout]);
14173
- const [thinkingLevel, setThinkingLevel] = useState13("Medium");
14174
- const [aiProvider, setAiProvider] = useState13("Google");
14175
- const [setupStep, setSetupStep] = useState13(0);
14176
- const [latestVer, setLatestVer] = useState13(null);
14177
- const [showFullThinking, setShowFullThinking] = useState13(false);
14178
- const [activeModel, setActiveModel] = useState13("gemma-4-31b-it");
14179
- const [janitorModel, setJanitorModel] = useState13("gemma-4-26b-a4b-it");
14180
- const [isInitializing, setIsInitializing] = useState13(true);
14181
- const [isAppFocused, setIsAppFocused] = useState13(true);
14404
+ const [thinkingLevel, setThinkingLevel] = useState14("Medium");
14405
+ const [aiProvider, setAiProvider] = useState14("Google");
14406
+ const [setupStep, setSetupStep] = useState14(0);
14407
+ const [latestVer, setLatestVer] = useState14(null);
14408
+ const [showFullThinking, setShowFullThinking] = useState14(false);
14409
+ const [activeModel, setActiveModel] = useState14("gemma-4-31b-it");
14410
+ const [janitorModel, setJanitorModel] = useState14("gemma-4-26b-a4b-it");
14411
+ const [isInitializing, setIsInitializing] = useState14(true);
14412
+ const [isAppFocused, setIsAppFocused] = useState14(true);
14182
14413
  const lastFocusEventTime = useRef3(0);
14183
- const [apiKey, setApiKey] = useState13(null);
14184
- const [tempKey, setTempKey] = useState13("");
14414
+ const [apiKey, setApiKey] = useState14(null);
14415
+ const [tempKey, setTempKey] = useState14("");
14185
14416
  const addShiftEnterBinding = async (ideName) => {
14186
14417
  const kbPath = getKeybindingsPath(ideName);
14187
14418
  if (!kbPath) return;
@@ -14232,35 +14463,35 @@ function App({ args = [] }) {
14232
14463
  });
14233
14464
  }
14234
14465
  };
14235
- const [activeView, setActiveView] = useState13("chat");
14236
- const [apiTier, setApiTier] = useState13("Free");
14237
- const [quotas, setQuotas] = useState13({ limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
14238
- const [inputConfig, setInputConfig] = useState13(null);
14239
- const [systemSettings, setSystemSettings] = useState13({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
14240
- const [profileData, setProfileData] = useState13({ name: null, nickname: null, instructions: null });
14241
- const [imageSettings, setImageSettings] = useState13({ keyType: "Default", quality: "Low-High", apiKey: "" });
14242
- const [sessionStats, setSessionStats] = useState13({ tokens: 0 });
14243
- const [sessionAgentCalls, setSessionAgentCalls] = useState13(0);
14244
- const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState13(0);
14245
- const [sessionTotalTokens, setSessionTotalTokens] = useState13(0);
14246
- const [chatTokens, setChatTokens] = useState13(0);
14466
+ const [activeView, setActiveView] = useState14("chat");
14467
+ const [apiTier, setApiTier] = useState14("Free");
14468
+ const [quotas, setQuotas] = useState14({ limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
14469
+ const [inputConfig, setInputConfig] = useState14(null);
14470
+ const [systemSettings, setSystemSettings] = useState14({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
14471
+ const [profileData, setProfileData] = useState14({ name: null, nickname: null, instructions: null });
14472
+ const [imageSettings, setImageSettings] = useState14({ keyType: "Default", quality: "Low-High", apiKey: "" });
14473
+ const [sessionStats, setSessionStats] = useState14({ tokens: 0 });
14474
+ const [sessionAgentCalls, setSessionAgentCalls] = useState14(0);
14475
+ const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState14(0);
14476
+ const [sessionTotalTokens, setSessionTotalTokens] = useState14(0);
14477
+ const [chatTokens, setChatTokens] = useState14(0);
14247
14478
  const chatTokenStartRef = useRef3(0);
14248
- const [sessionTotalCachedTokens, setSessionTotalCachedTokens] = useState13(0);
14249
- const [sessionTotalCandidateTokens, setSessionTotalCandidateTokens] = useState13(0);
14250
- const [sessionToolSuccess, setSessionToolSuccess] = useState13(0);
14251
- const [sessionToolFailure, setSessionToolFailure] = useState13(0);
14252
- const [sessionToolDenied, setSessionToolDenied] = useState13(0);
14253
- const [sessionApiTime, setSessionApiTime] = useState13(0);
14254
- const [sessionToolTime, setSessionToolTime] = useState13(0);
14255
- const [sessionImageCount, setSessionImageCount] = useState13(0);
14256
- const [sessionImageCredits, setSessionImageCredits] = useState13(0);
14257
- const [dailyUsage, setDailyUsage] = useState13(null);
14258
- const [monthlyUsage, setMonthlyUsage] = useState13(null);
14259
- const [customPeriodUsage, setCustomPeriodUsage] = useState13(null);
14260
- const [statsMode, setStatsMode] = useState13("daily");
14479
+ const [sessionTotalCachedTokens, setSessionTotalCachedTokens] = useState14(0);
14480
+ const [sessionTotalCandidateTokens, setSessionTotalCandidateTokens] = useState14(0);
14481
+ const [sessionToolSuccess, setSessionToolSuccess] = useState14(0);
14482
+ const [sessionToolFailure, setSessionToolFailure] = useState14(0);
14483
+ const [sessionToolDenied, setSessionToolDenied] = useState14(0);
14484
+ const [sessionApiTime, setSessionApiTime] = useState14(0);
14485
+ const [sessionToolTime, setSessionToolTime] = useState14(0);
14486
+ const [sessionImageCount, setSessionImageCount] = useState14(0);
14487
+ const [sessionImageCredits, setSessionImageCredits] = useState14(0);
14488
+ const [dailyUsage, setDailyUsage] = useState14(null);
14489
+ const [monthlyUsage, setMonthlyUsage] = useState14(null);
14490
+ const [customPeriodUsage, setCustomPeriodUsage] = useState14(null);
14491
+ const [statsMode, setStatsMode] = useState14("daily");
14261
14492
  const PLAYGROUND_CHAT_ID = "flow-playground";
14262
- const [chatId, setChatId] = useState13(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
14263
- useEffect9(() => {
14493
+ const [chatId, setChatId] = useState14(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
14494
+ useEffect11(() => {
14264
14495
  const nextTokens = sessionTotalTokens - chatTokenStartRef.current;
14265
14496
  setChatTokens(nextTokens);
14266
14497
  if (chatId) {
@@ -14268,7 +14499,7 @@ function App({ args = [] }) {
14268
14499
  });
14269
14500
  }
14270
14501
  }, [sessionTotalTokens, chatId, sessionStats.tokens]);
14271
- useEffect9(() => {
14502
+ useEffect11(() => {
14272
14503
  if (activeView === "apiTier") {
14273
14504
  const load = async () => {
14274
14505
  const d = await getDailyUsage();
@@ -14281,17 +14512,17 @@ function App({ args = [] }) {
14281
14512
  load();
14282
14513
  }
14283
14514
  }, [activeView, quotas.resetDay]);
14284
- const [activeCommand, setActiveCommand] = useState13(null);
14285
- const [execOutput, setExecOutput] = useState13("");
14286
- const [isTerminalFocused, setIsTerminalFocused] = useState13(false);
14287
- const [tick, setTick] = useState13(0);
14515
+ const [activeCommand, setActiveCommand] = useState14(null);
14516
+ const [execOutput, setExecOutput] = useState14("");
14517
+ const [isTerminalFocused, setIsTerminalFocused] = useState14(false);
14518
+ const [tick, setTick] = useState14(0);
14288
14519
  const isFirstRender = useRef3(true);
14289
14520
  const isSecondRender = useRef3(true);
14290
14521
  const isThirdRender = useRef3(true);
14291
14522
  const prevProviderRef = useRef3(aiProvider);
14292
14523
  const originalAllowExternalAccessRef = useRef3(false);
14293
14524
  const originalMemoryRef = useRef3(true);
14294
- useEffect9(() => {
14525
+ useEffect11(() => {
14295
14526
  if (prevProviderRef.current !== aiProvider) {
14296
14527
  prevProviderRef.current = aiProvider;
14297
14528
  const hasStandard = aiProvider === "DeepSeek" || aiProvider === "NVIDIA";
@@ -14304,7 +14535,7 @@ function App({ args = [] }) {
14304
14535
  }
14305
14536
  }
14306
14537
  }, [aiProvider, activeModel, thinkingLevel]);
14307
- useEffect9(() => {
14538
+ useEffect11(() => {
14308
14539
  if (!apiKey) return;
14309
14540
  if (isFirstRender.current) {
14310
14541
  isFirstRender.current = false;
@@ -14378,15 +14609,15 @@ function App({ args = [] }) {
14378
14609
  }, []);
14379
14610
  const activeCommandRef = useRef3(null);
14380
14611
  const execOutputRef = useRef3("");
14381
- useEffect9(() => {
14612
+ useEffect11(() => {
14382
14613
  activeCommandRef.current = activeCommand;
14383
14614
  }, [activeCommand]);
14384
- useEffect9(() => {
14615
+ useEffect11(() => {
14385
14616
  execOutputRef.current = execOutput;
14386
14617
  }, [execOutput]);
14387
- const [autoAcceptWrites, setAutoAcceptWrites] = useState13(false);
14388
- const [pendingApproval, setPendingApproval] = useState13(null);
14389
- const [pendingAsk, setPendingAsk] = useState13(null);
14618
+ const [autoAcceptWrites, setAutoAcceptWrites] = useState14(false);
14619
+ const [pendingApproval, setPendingApproval] = useState14(null);
14620
+ const [pendingAsk, setPendingAsk] = useState14(null);
14390
14621
  const resetPendingApproval = (decision) => {
14391
14622
  setPendingApproval(null);
14392
14623
  setActiveView("chat");
@@ -14405,10 +14636,10 @@ function App({ args = [] }) {
14405
14636
  if (ms < 1e3) return `${ms}ms`;
14406
14637
  return formatDuration(Math.floor(ms / 1e3));
14407
14638
  };
14408
- const [statusText, setStatusText] = useState13(null);
14409
- const [wittyPhrase, setWittyPhrase] = useState13("");
14410
- const [hasPasteBlock, setHasPasteBlock] = useState13(false);
14411
- useEffect9(() => {
14639
+ const [statusText, setStatusText] = useState14(null);
14640
+ const [wittyPhrase, setWittyPhrase] = useState14("");
14641
+ const [hasPasteBlock, setHasPasteBlock] = useState14(false);
14642
+ useEffect11(() => {
14412
14643
  let interval;
14413
14644
  if (statusText) {
14414
14645
  const updatePhrase = () => {
@@ -14422,20 +14653,20 @@ function App({ args = [] }) {
14422
14653
  }
14423
14654
  return () => clearInterval(interval);
14424
14655
  }, [statusText]);
14425
- const [isSpinnerActive, setIsSpinnerActive] = useState13(true);
14426
- const [isProcessing, setIsProcessing] = useState13(false);
14427
- const [isCompressing, setIsCompressing] = useState13(false);
14428
- const [escPressed, setEscPressed] = useState13(false);
14429
- const [escTimer, setEscTimer] = useState13(null);
14430
- const [escPressCount, setEscPressCount] = useState13(0);
14431
- const [recentPrompts, setRecentPrompts] = useState13([]);
14656
+ const [isSpinnerActive, setIsSpinnerActive] = useState14(true);
14657
+ const [isProcessing, setIsProcessing] = useState14(false);
14658
+ const [isCompressing, setIsCompressing] = useState14(false);
14659
+ const [escPressed, setEscPressed] = useState14(false);
14660
+ const [escTimer, setEscTimer] = useState14(null);
14661
+ const [escPressCount, setEscPressCount] = useState14(0);
14662
+ const [recentPrompts, setRecentPrompts] = useState14([]);
14432
14663
  const escDoubleTimerRef = useRef3(null);
14433
14664
  const didSignalTerminationRef = useRef3(false);
14434
- const [queuedPrompt, setQueuedPrompt] = useState13(null);
14435
- const [resolutionData, setResolutionData] = useState13(null);
14436
- const [tempModelOverride, setTempModelOverride] = useState13(null);
14437
- useEffect9(() => setEscPressCount(0), [input]);
14438
- const [messages, rawSetMessages] = useState13(() => {
14665
+ const [queuedPrompt, setQueuedPrompt] = useState14(null);
14666
+ const [resolutionData, setResolutionData] = useState14(null);
14667
+ const [tempModelOverride, setTempModelOverride] = useState14(null);
14668
+ useEffect11(() => setEscPressCount(0), [input]);
14669
+ const [messages, rawSetMessages] = useState14(() => {
14439
14670
  const logoMsg = { id: "logo-" + Date.now(), role: "system", isLogo: true, isMeta: true };
14440
14671
  const isHomeDir = process.cwd() === os4.homedir();
14441
14672
  const isSystemDir = (() => {
@@ -14473,24 +14704,22 @@ function App({ args = [] }) {
14473
14704
  const setMessages = (value) => {
14474
14705
  rawSetMessages((prev) => {
14475
14706
  const next = typeof value === "function" ? value(prev) : value;
14476
- const cleaned = [];
14477
- for (let i = 0; i < next.length; i++) {
14478
- const msg = next[i];
14479
- const prevMsg = cleaned[cleaned.length - 1];
14480
- if (msg && msg.text && msg.text.includes("Request Cancelled") && prevMsg && prevMsg.text && prevMsg.text.includes("Request Cancelled")) {
14481
- continue;
14707
+ if (next.length > 1) {
14708
+ const last = next[next.length - 1];
14709
+ const secondLast = next[next.length - 2];
14710
+ if (last?.text?.includes("Request Cancelled") && secondLast?.text?.includes("Request Cancelled")) {
14711
+ return next.slice(0, -1);
14482
14712
  }
14483
- cleaned.push(msg);
14484
14713
  }
14485
- return cleaned;
14714
+ return next;
14486
14715
  });
14487
14716
  };
14488
14717
  const queuedPromptRef = useRef3(null);
14489
- const [btwResponse, setBtwResponse] = useState13("");
14490
- const [showBtwBox, setShowBtwBox] = useState13(false);
14718
+ const [btwResponse, setBtwResponse] = useState14("");
14719
+ const [showBtwBox, setShowBtwBox] = useState14(false);
14491
14720
  const btwResponseRef = useRef3("");
14492
14721
  const btwClosedRef = useRef3(null);
14493
- useEffect9(() => {
14722
+ useEffect11(() => {
14494
14723
  if (messages.length === 0) return;
14495
14724
  const lastMsg = messages[messages.length - 1];
14496
14725
  if (lastMsg && (lastMsg.role === "agent" || lastMsg.role === "assistant")) {
@@ -14508,59 +14737,105 @@ function App({ args = [] }) {
14508
14737
  }
14509
14738
  }
14510
14739
  }, [messages]);
14511
- const [completedIndex, setCompletedIndex] = useState13(messages.length);
14512
- const [clearKey, setClearKey] = useState13(0);
14740
+ const [completedIndex, setCompletedIndex] = useState14(messages.length);
14741
+ const [clearKey, setClearKey] = useState14(0);
14742
+ const lastCompletedBlocksRef = useRef3([]);
14743
+ const cachedHistoryRef = useRef3({
14744
+ completedIndex: 0,
14745
+ columns: 0,
14746
+ historicalBlocks: [],
14747
+ seenSelections: /* @__PURE__ */ new Set()
14748
+ });
14513
14749
  const parsedBlocks = useMemo2(() => {
14514
- const completed = [];
14515
- const active = [];
14516
14750
  const columns = terminalSize.columns || 80;
14517
- const completedMsgs = messages.slice(0, completedIndex);
14518
- const activeMsgs = messages.slice(completedIndex);
14519
- const seenAskSelections = /* @__PURE__ */ new Set();
14520
- const filterDuplicates = (msgList) => {
14521
- return msgList.filter((msg) => {
14522
- if (msg.isAskRecord) {
14523
- const selectionMatch = msg.text?.match(/Selection: (.*)/);
14524
- const selection = selectionMatch ? selectionMatch[1].trim() : "";
14525
- if (selection) {
14526
- if (seenAskSelections.has(selection)) {
14527
- return false;
14528
- }
14751
+ const SELECTION_REGEX = /Selection: (.*)/;
14752
+ let historicalBlocks = [];
14753
+ let seenAskSelections = /* @__PURE__ */ new Set();
14754
+ const isResize = cachedHistoryRef.current.columns !== columns;
14755
+ const isClear = completedIndex < cachedHistoryRef.current.completedIndex;
14756
+ if (isResize || isClear) {
14757
+ const completedMsgs = messages.slice(0, completedIndex);
14758
+ for (let i = 0; i < completedMsgs.length; i++) {
14759
+ const msg = completedMsgs[i];
14760
+ if (msg.isAskRecord && msg.text) {
14761
+ const match = msg.text.match(SELECTION_REGEX);
14762
+ if (match && match[1].trim()) {
14763
+ const selection = match[1].trim();
14764
+ if (seenAskSelections.has(selection)) continue;
14529
14765
  seenAskSelections.add(selection);
14530
14766
  }
14531
14767
  }
14532
- return true;
14533
- });
14534
- };
14535
- const uniqueCompleted = filterDuplicates(completedMsgs);
14536
- const uniqueActive = filterDuplicates(activeMsgs);
14537
- uniqueCompleted.forEach((msg) => {
14538
- const parsed = parseMessageToBlocks(msg, columns);
14539
- completed.push(...parsed.completed);
14540
- completed.push(...parsed.active);
14541
- });
14542
- uniqueActive.forEach((msg) => {
14768
+ const parsed = parseMessageToBlocks(msg, columns);
14769
+ for (let j = 0; j < parsed.completed.length; j++) historicalBlocks.push(parsed.completed[j]);
14770
+ for (let j = 0; j < parsed.active.length; j++) historicalBlocks.push(parsed.active[j]);
14771
+ }
14772
+ cachedHistoryRef.current = {
14773
+ completedIndex,
14774
+ columns,
14775
+ historicalBlocks,
14776
+ seenSelections: new Set(seenAskSelections)
14777
+ };
14778
+ } else {
14779
+ historicalBlocks = cachedHistoryRef.current.historicalBlocks;
14780
+ seenAskSelections = cachedHistoryRef.current.seenSelections;
14781
+ if (completedIndex > cachedHistoryRef.current.completedIndex) {
14782
+ historicalBlocks = [...historicalBlocks];
14783
+ seenAskSelections = new Set(seenAskSelections);
14784
+ const newMsgs = messages.slice(cachedHistoryRef.current.completedIndex, completedIndex);
14785
+ for (let i = 0; i < newMsgs.length; i++) {
14786
+ const msg = newMsgs[i];
14787
+ if (msg.isAskRecord && msg.text) {
14788
+ const match = msg.text.match(SELECTION_REGEX);
14789
+ if (match && match[1].trim()) {
14790
+ const selection = match[1].trim();
14791
+ if (seenAskSelections.has(selection)) continue;
14792
+ seenAskSelections.add(selection);
14793
+ }
14794
+ }
14795
+ const parsed = parseMessageToBlocks(msg, columns);
14796
+ for (let j = 0; j < parsed.completed.length; j++) historicalBlocks.push(parsed.completed[j]);
14797
+ for (let j = 0; j < parsed.active.length; j++) historicalBlocks.push(parsed.active[j]);
14798
+ }
14799
+ cachedHistoryRef.current = {
14800
+ completedIndex,
14801
+ columns,
14802
+ historicalBlocks,
14803
+ seenSelections: seenAskSelections
14804
+ };
14805
+ }
14806
+ }
14807
+ const activeMsgs = messages.slice(completedIndex);
14808
+ const streamingCompletedBlocks = [];
14809
+ const activeBlocks = [];
14810
+ for (let i = 0; i < activeMsgs.length; i++) {
14811
+ const msg = activeMsgs[i];
14812
+ if (msg.isAskRecord && msg.text) {
14813
+ const match = msg.text.match(SELECTION_REGEX);
14814
+ if (match && match[1].trim()) {
14815
+ const selection = match[1].trim();
14816
+ if (seenAskSelections.has(selection)) continue;
14817
+ }
14818
+ }
14543
14819
  const parsed = parseMessageToBlocks(msg, columns);
14544
- completed.push(...parsed.completed);
14545
- active.push(...parsed.active);
14546
- });
14547
- const MAX_BLOCKS = 5e9;
14548
- const slicedCompleted = completed.slice(Math.max(0, completed.length - MAX_BLOCKS));
14549
- if (slicedCompleted.length >= 75e3) {
14550
- slicedCompleted.push({
14551
- key: "memory-warning-block",
14820
+ for (let j = 0; j < parsed.completed.length; j++) streamingCompletedBlocks.push(parsed.completed[j]);
14821
+ for (let j = 0; j < parsed.active.length; j++) activeBlocks.push(parsed.active[j]);
14822
+ }
14823
+ const finalCompleted = historicalBlocks.concat(streamingCompletedBlocks);
14824
+ if (finalCompleted.length >= 75e3) {
14825
+ finalCompleted.push({
14826
+ key: `memory-warning-block-${finalCompleted.length}`,
14552
14827
  msg: {
14553
14828
  role: "system",
14554
14829
  text: `\u26A0\uFE0F MEMORY WARNING: CHAT IS GETTING VERY LONG`,
14555
- 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.`,
14830
+ subText: `This session has reached ${finalCompleted.length} blocks. To maintain optimal performance and prevent high memory usage, it is highly recommended to save and start a clean chat with /clear.`,
14556
14831
  isHomeWarning: true
14557
14832
  },
14558
14833
  type: "full-message"
14559
14834
  });
14560
14835
  }
14561
14836
  return {
14562
- completed: slicedCompleted,
14563
- active
14837
+ completed: finalCompleted,
14838
+ active: activeBlocks
14564
14839
  };
14565
14840
  }, [messages, completedIndex, terminalSize.columns]);
14566
14841
  const isTerminalWaitingForInput = useMemo2(() => {
@@ -14749,7 +15024,7 @@ function App({ args = [] }) {
14749
15024
  setInput((prev) => prev.replace(/\\\r?$/, "").replace(/\r?$/, "") + "\n");
14750
15025
  }
14751
15026
  });
14752
- useEffect9(() => {
15027
+ useEffect11(() => {
14753
15028
  process.stdout.write("\x1B[?1004h");
14754
15029
  const onData = (data) => {
14755
15030
  const str = data.toString();
@@ -14767,7 +15042,7 @@ function App({ args = [] }) {
14767
15042
  process.stdin.off("data", onData);
14768
15043
  };
14769
15044
  }, []);
14770
- useEffect9(() => {
15045
+ useEffect11(() => {
14771
15046
  async function init() {
14772
15047
  try {
14773
15048
  const pkg = JSON.parse(fs22.readFileSync(path20.join(process.cwd(), "package.json"), "utf8"));
@@ -14986,7 +15261,7 @@ function App({ args = [] }) {
14986
15261
  }
14987
15262
  init();
14988
15263
  }, []);
14989
- useEffect9(() => {
15264
+ useEffect11(() => {
14990
15265
  let timer;
14991
15266
  if (confirmExit) {
14992
15267
  setExitCountdown(10);
@@ -15004,7 +15279,7 @@ function App({ args = [] }) {
15004
15279
  if (timer) clearInterval(timer);
15005
15280
  };
15006
15281
  }, [confirmExit]);
15007
- useEffect9(() => {
15282
+ useEffect11(() => {
15008
15283
  if (!isInitializing) {
15009
15284
  const modelToSave = parsedArgs.model && activeModel === parsedArgs.model ? persistedModelRef.current : activeModel;
15010
15285
  let settingsToSave = systemSettings;
@@ -15054,7 +15329,7 @@ function App({ args = [] }) {
15054
15329
  }
15055
15330
  };
15056
15331
  const lastSavedTimeRef = useRef3(SESSION_START_TIME);
15057
- useEffect9(() => {
15332
+ useEffect11(() => {
15058
15333
  if (activeView === "exit") {
15059
15334
  const flush = async () => {
15060
15335
  const now = Date.now();
@@ -15072,7 +15347,7 @@ function App({ args = [] }) {
15072
15347
  return () => clearTimeout(timer);
15073
15348
  }
15074
15349
  }, [activeView]);
15075
- useEffect9(() => {
15350
+ useEffect11(() => {
15076
15351
  const interval = setInterval(async () => {
15077
15352
  if (!isInitializing) {
15078
15353
  const now = Date.now();
@@ -15082,7 +15357,7 @@ function App({ args = [] }) {
15082
15357
  lastSavedTimeRef.current += deltaSecs * 1e3;
15083
15358
  }
15084
15359
  }
15085
- }, 1500);
15360
+ }, 2e3);
15086
15361
  return () => clearInterval(interval);
15087
15362
  }, [isInitializing]);
15088
15363
  const COMMANDS = [
@@ -15098,32 +15373,6 @@ function App({ args = [] }) {
15098
15373
  { cmd: "/export", desc: "Export current chat in a .txt file" },
15099
15374
  { cmd: "/chats", desc: "List all chat sessions" },
15100
15375
  { cmd: "/btw", desc: "Ask a question without intefering with ongoing tasks" },
15101
- // {
15102
- // cmd: '/image', desc: 'Generate images using Pollinations', subs: [
15103
- // {
15104
- // cmd: 'setup', desc: 'Configure defaults', subs: [
15105
- // {
15106
- // cmd: 'key', desc: 'Set API key strategy', subs: [
15107
- // { cmd: 'default', desc: 'Default (Quota: Dynamic 25 max/hr)' },
15108
- // { cmd: 'custom', desc: 'Custom Key' }
15109
- // ]
15110
- // },
15111
- // {
15112
- // cmd: 'quality', desc: 'Set default quality', subs: [
15113
- // { cmd: 'low', desc: imageSettings?.keyType === 'Custom' ? '(0.001/img)' : '(1/img)' },
15114
- // { cmd: 'low-high', desc: imageSettings?.keyType === 'Custom' ? '(0.002/img)' : '(2/img)' },
15115
- // { cmd: 'medium', desc: imageSettings?.keyType === 'Custom' ? '(0.008/img)' : '(8/img)' },
15116
- // { cmd: 'medium-high', desc: imageSettings?.keyType === 'Custom' ? '(0.01/img)' : '(10/img)' },
15117
- // { cmd: 'high', desc: imageSettings?.keyType === 'Custom' ? '(0.045/img)' : '(45/img)' },
15118
- // { cmd: 'ultra', desc: imageSettings?.keyType === 'Custom' ? '(0.0488/img)' : '(49/img)' },
15119
- // { cmd: 'premium', desc: imageSettings?.keyType === 'Custom' ? '(0.1/img)' : '(100/img)' }
15120
- // ]
15121
- // }
15122
- // ]
15123
- // },
15124
- // { cmd: 'stats', desc: 'Show remaining credits or Pollinations balance status' }
15125
- // ]
15126
- // },
15127
15376
  {
15128
15377
  cmd: "/mode",
15129
15378
  desc: "Toggle Flux/Flow modes",
@@ -15165,7 +15414,7 @@ function App({ args = [] }) {
15165
15414
  },
15166
15415
  {
15167
15416
  cmd: "/model",
15168
- desc: "Switch Model for Agent",
15417
+ desc: "Select Agent Model",
15169
15418
  subs: aiProvider === "OpenRouter" ? apiTier === "Free" ? [
15170
15419
  {
15171
15420
  cmd: "google/gemma-4-31b-it:free",
@@ -15177,11 +15426,11 @@ function App({ args = [] }) {
15177
15426
  },
15178
15427
  {
15179
15428
  cmd: "qwen/qwen3-coder:free",
15180
- desc: ""
15429
+ desc: "Text Only"
15181
15430
  },
15182
15431
  {
15183
15432
  cmd: "z-ai/glm-4.5-air:free",
15184
- desc: ""
15433
+ desc: "Text Only"
15185
15434
  }
15186
15435
  ] : [
15187
15436
  {
@@ -15210,19 +15459,19 @@ function App({ args = [] }) {
15210
15459
  },
15211
15460
  {
15212
15461
  cmd: "deepseek/deepseek-v4-pro",
15213
- desc: ""
15462
+ desc: "Text Only"
15214
15463
  },
15215
15464
  {
15216
15465
  cmd: "deepseek/deepseek-v4-flash",
15217
- desc: ""
15466
+ desc: "Text Only"
15218
15467
  },
15219
15468
  {
15220
15469
  cmd: "xiaomi/mimo-v2.5-pro",
15221
- desc: ""
15470
+ desc: "Text Only"
15222
15471
  },
15223
15472
  {
15224
15473
  cmd: "z-ai/glm-5",
15225
- desc: ""
15474
+ desc: "Text Only"
15226
15475
  },
15227
15476
  {
15228
15477
  cmd: "openai/gpt-5.2-codex",
@@ -15243,106 +15492,122 @@ function App({ args = [] }) {
15243
15492
  ] : aiProvider === "DeepSeek" ? [
15244
15493
  {
15245
15494
  cmd: "deepseek-v4-flash",
15246
- desc: "Fast & Efficient"
15495
+ desc: "Fast & Efficient (Text Only)"
15247
15496
  },
15248
15497
  {
15249
15498
  cmd: "deepseek-v4-pro",
15250
- desc: "High-Intelligence Reasoning"
15499
+ desc: "High-Intelligence Reasoning (Text Only)"
15251
15500
  }
15252
15501
  ] : aiProvider === "NVIDIA" ? [
15502
+ // --- Kimi (Moonshot AI) ---
15253
15503
  {
15254
15504
  cmd: "moonshotai/kimi-k2.6",
15255
15505
  desc: "Multimodal"
15256
15506
  },
15507
+ // --- DeepSeek Family ---
15257
15508
  {
15258
- cmd: "google/gemma-4-31b-it",
15259
- desc: ""
15509
+ cmd: "deepseek-ai/deepseek-v4-flash",
15510
+ desc: "Text Only"
15260
15511
  },
15261
15512
  {
15262
- cmd: "stepfun-ai/step-3.7-flash",
15263
- desc: ""
15513
+ cmd: "deepseek-ai/deepseek-v4-pro",
15514
+ desc: "Text Only"
15264
15515
  },
15516
+ // --- StepFun ---
15265
15517
  {
15266
- cmd: "minimaxai/minimax-m2.7",
15267
- desc: ""
15518
+ cmd: "stepfun-ai/step-3.7-flash",
15519
+ desc: "Multimodal"
15268
15520
  },
15521
+ // --- Gemma Family (Google) ---
15269
15522
  {
15270
- cmd: "deepseek-ai/deepseek-v4-flash",
15271
- desc: ""
15523
+ cmd: "google/gemma-4-31b-it",
15524
+ desc: "Multimodal"
15272
15525
  },
15273
15526
  {
15274
- cmd: "deepseek-ai/deepseek-v4-pro",
15275
- desc: ""
15527
+ cmd: "google/diffusiongemma-26b-a4b-it",
15528
+ desc: "Mega Fast [Experimental]"
15276
15529
  },
15530
+ // --- Mistral ---
15277
15531
  {
15278
15532
  cmd: "mistralai/mistral-medium-3.5-128b",
15279
- desc: ""
15533
+ desc: "Multimodal"
15534
+ },
15535
+ // --- GPT Open Source Series (OpenAI) ---
15536
+ {
15537
+ cmd: "openai/gpt-oss-20b",
15538
+ desc: "Text Only"
15539
+ },
15540
+ {
15541
+ cmd: "openai/gpt-oss-120b",
15542
+ desc: "Text Only"
15280
15543
  },
15544
+ // --- GLM (Zhipu AI) ---
15281
15545
  {
15282
15546
  cmd: "z-ai/glm-5.1",
15283
- desc: ""
15547
+ desc: "Text Only"
15284
15548
  },
15549
+ // --- MiniMax Family ---
15285
15550
  {
15286
- cmd: "google/diffusiongemma-26b-a4b-it",
15287
- desc: "Mega Fast [Experimental]"
15551
+ cmd: "minimaxai/minimax-m2.7",
15552
+ desc: "Text Only"
15288
15553
  },
15289
15554
  {
15290
15555
  cmd: "minimaxai/minimax-m3",
15291
- desc: ""
15556
+ desc: "Text Only"
15292
15557
  }
15293
15558
  ] : apiTier === "Free" ? [
15294
15559
  {
15295
15560
  cmd: "gemma-4-26b-a4b-it",
15296
- desc: "Standard & Faster"
15561
+ desc: "Standard & Faster (Multimodal)"
15297
15562
  },
15298
15563
  {
15299
15564
  cmd: "gemma-4-31b-it",
15300
- desc: "Standard Default"
15565
+ desc: "Standard Default (Multimodal)"
15301
15566
  },
15302
15567
  {
15303
15568
  cmd: "gemini-2.5-flash-lite",
15304
- desc: "Fast & Cheap (Limited Free Quota)"
15569
+ desc: "Fast & Cheap (Multimodal) [Limited Free Quota]"
15305
15570
  },
15306
15571
  {
15307
15572
  cmd: "gemini-2.5-flash",
15308
- desc: "Fast & Reliable (Limited Free Quota)"
15573
+ desc: "Fast & Reliable (Multimodal) [Limited Free Quota]"
15309
15574
  },
15310
15575
  {
15311
15576
  cmd: "gemini-3-flash-preview",
15312
- desc: "Fast & Lightweight (Limited Free Quota)"
15577
+ desc: "Fast & Lightweight (Multimodal) [Limited Free Quota]"
15313
15578
  },
15314
15579
  {
15315
15580
  cmd: "gemini-3.5-flash",
15316
- desc: "Flash Latest (Limited Free Quota) [Instability Issues]"
15581
+ desc: "Flash Latest (Multimodal) [Limited Free Quota] Instability Issues"
15317
15582
  }
15318
15583
  ] : [
15319
15584
  {
15320
15585
  cmd: "gemini-2.5-flash-lite",
15321
- desc: "Fast & Cheap"
15586
+ desc: "Fast & Cheap (Multimodal)"
15322
15587
  },
15323
15588
  {
15324
15589
  cmd: "gemini-2.5-flash",
15325
- desc: "Fast & Reliable"
15590
+ desc: "Fast & Reliable (Multimodal)"
15326
15591
  },
15327
15592
  {
15328
15593
  cmd: "gemini-2.5-pro",
15329
- desc: "Last gen Pro reasoning"
15594
+ desc: "Last gen Pro reasoning (Multimodal)"
15330
15595
  },
15331
15596
  {
15332
15597
  cmd: "gemini-3.1-flash-lite",
15333
- desc: "Ultra-Fast & Lite"
15598
+ desc: "Ultra-Fast & Lite (Multimodal)"
15334
15599
  },
15335
15600
  {
15336
15601
  cmd: "gemini-3-flash-preview",
15337
- desc: "Default, Fast & Lightweight"
15602
+ desc: "Default, Fast & Lightweight (Multimodal)"
15338
15603
  },
15339
15604
  {
15340
15605
  cmd: "gemini-3.5-flash",
15341
- desc: "Flash Latest [Instability Issues]"
15606
+ desc: "Flash Latest (Multimodal) [Instability Issues]"
15342
15607
  },
15343
15608
  {
15344
15609
  cmd: "gemini-3.1-pro-preview",
15345
- desc: "Pro Reasoning"
15610
+ desc: "Pro Reasoning (Multimodal)"
15346
15611
  }
15347
15612
  ]
15348
15613
  },
@@ -15359,7 +15624,7 @@ function App({ args = [] }) {
15359
15624
  cmd: "/fluxflow",
15360
15625
  desc: "Project management",
15361
15626
  subs: [
15362
- { cmd: "init", desc: "Create FluxFlow.md template" }
15627
+ { cmd: "init", desc: "Create empty FluxFlow.md template" }
15363
15628
  ]
15364
15629
  },
15365
15630
  {
@@ -15374,8 +15639,8 @@ function App({ args = [] }) {
15374
15639
  cmd: "/update",
15375
15640
  desc: "Check/Install updates",
15376
15641
  subs: [
15377
- { cmd: "check", desc: "Check for new version" },
15378
- { cmd: "latest", desc: "Install latest release" }
15642
+ { cmd: "latest", desc: "Install latest release" },
15643
+ { cmd: "check", desc: "Check for new version" }
15379
15644
  ]
15380
15645
  }
15381
15646
  ];
@@ -15455,6 +15720,7 @@ ${cleanText}`, color: "magenta" }];
15455
15720
  const target = h[targetId] || Object.values(h).find((h2) => h2.name.toLowerCase() === targetId.toLowerCase());
15456
15721
  if (target) {
15457
15722
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
15723
+ clearBlocksCache();
15458
15724
  setChatId(targetId);
15459
15725
  const savedData = await loadChatContext(targetId);
15460
15726
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
@@ -15538,6 +15804,7 @@ ${cleanText}`, color: "magenta" }];
15538
15804
  ]);
15539
15805
  setCompletedIndex(1);
15540
15806
  setClearKey((prev) => prev + 1);
15807
+ clearBlocksCache();
15541
15808
  if (parsedArgs.playground) {
15542
15809
  parsedArgs.playground = false;
15543
15810
  deleteChat(PLAYGROUND_CHAT_ID).catch(() => {
@@ -15583,6 +15850,14 @@ ${cleanText}`, color: "magenta" }];
15583
15850
  setIsExpanded(false);
15584
15851
  setChatTokens(0);
15585
15852
  chatTokenStartRef.current = sessionTotalTokens;
15853
+ setTimeout(() => {
15854
+ if (global.gc) {
15855
+ try {
15856
+ global.gc();
15857
+ } catch (e) {
15858
+ }
15859
+ }
15860
+ }, 500);
15586
15861
  break;
15587
15862
  }
15588
15863
  case "/revert": {
@@ -15598,6 +15873,14 @@ ${cleanText}`, color: "magenta" }];
15598
15873
  });
15599
15874
  }
15600
15875
  });
15876
+ setTimeout(() => {
15877
+ if (global.gc) {
15878
+ try {
15879
+ global.gc();
15880
+ } catch (e) {
15881
+ }
15882
+ }
15883
+ }, 500);
15601
15884
  break;
15602
15885
  }
15603
15886
  case "/mode": {
@@ -16205,24 +16488,24 @@ ${timestamp}` };
16205
16488
  });
16206
16489
  const streamChat = async () => {
16207
16490
  let didAppendCancel = false;
16208
- const appendCancelMessage = (prev) => {
16209
- if (didAppendCancel) {
16210
- return prev;
16211
- }
16212
- const lastMsg = prev[prev.length - 1];
16213
- if (lastMsg && lastMsg.text && lastMsg.text.includes("Request Cancelled")) {
16214
- return prev;
16215
- }
16491
+ const appendCancelMessage = () => {
16492
+ if (didAppendCancel) return;
16216
16493
  didAppendCancel = true;
16217
- const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
16218
- const newMsgs = [...updatedPrev, {
16219
- id: "cancel-" + Date.now(),
16220
- role: "system",
16221
- text: "\n\n\x1B[33m\u2139 Request Cancelled\x1B[0m",
16222
- isMeta: true
16223
- }];
16224
- setCompletedIndex(newMsgs.length);
16225
- return newMsgs;
16494
+ setMessages((prev) => {
16495
+ const lastMsg = prev[prev.length - 1];
16496
+ if (lastMsg && lastMsg.text && lastMsg.text.includes("Request Cancelled")) {
16497
+ return prev;
16498
+ }
16499
+ const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
16500
+ const newMsgs = [...updatedPrev, {
16501
+ id: "cancel-" + Date.now(),
16502
+ role: "system",
16503
+ text: "\n\n\x1B[33m\u2139 Request Cancelled\x1B[0m",
16504
+ isMeta: true
16505
+ }];
16506
+ setCompletedIndex(newMsgs.length);
16507
+ return newMsgs;
16508
+ });
16226
16509
  };
16227
16510
  let hasFiredJanitor = false;
16228
16511
  setIsProcessing(true);
@@ -16416,7 +16699,14 @@ Selection: ${val}`,
16416
16699
  let toolCallBalance = 0;
16417
16700
  let inToolCallString = null;
16418
16701
  const signalRegex = /\[?\s*turn\s*:\s*.*?\s*\]?/gi;
16702
+ const bullyTheBug = path20.join(DATA_DIR, "padding");
16419
16703
  for await (const packet of stream) {
16704
+ if (packet.type === "interactive_turn_finished") {
16705
+ fs22.writeFileSync(bullyTheBug, "pad_0xa\n");
16706
+ } else {
16707
+ fs22.appendFileSync(bullyTheBug, "\r");
16708
+ parsedBlocks.completed = [];
16709
+ }
16420
16710
  if (isFirstPacket && packet.type === "text") {
16421
16711
  apiStart = Date.now();
16422
16712
  isFirstPacket = false;
@@ -16427,7 +16717,7 @@ Selection: ${val}`,
16427
16717
  sendStatus(packet.content);
16428
16718
  }
16429
16719
  if (packet.content === "Request Cancelled") {
16430
- setMessages((prev) => appendCancelMessage(prev));
16720
+ appendCancelMessage();
16431
16721
  }
16432
16722
  continue;
16433
16723
  }
@@ -16466,6 +16756,14 @@ Selection: ${val}`,
16466
16756
  setCompletedIndex(newMsgs.length);
16467
16757
  return newMsgs;
16468
16758
  });
16759
+ setTimeout(() => {
16760
+ if (global.gc) {
16761
+ try {
16762
+ global.gc();
16763
+ } catch (e) {
16764
+ }
16765
+ }
16766
+ }, 100);
16469
16767
  continue;
16470
16768
  }
16471
16769
  if (packet.type === "interactive_turn_finished") {
@@ -16674,29 +16972,31 @@ Selection: ${val}`,
16674
16972
  }
16675
16973
  if (inThinkMode && currentThinkId) {
16676
16974
  setMessages((prev) => {
16975
+ const next = [...prev];
16677
16976
  let transitioning = false;
16678
16977
  let transitionContent = "";
16679
- const newMsgs = prev.map((m) => {
16680
- if (m.id === currentThinkId) {
16681
- const newText = m.text + chunkText;
16978
+ for (let i = next.length - 1; i >= 0; i--) {
16979
+ if (next[i].id === currentThinkId) {
16980
+ const newText = next[i].text + chunkText;
16682
16981
  if (newText.toLowerCase().includes("</think>")) {
16683
16982
  transitioning = true;
16684
16983
  const parts = newText.split(/<\/think>/gi);
16685
16984
  transitionContent = parts.slice(1).join("</think>") || "";
16686
- const startTime = m.startTime || parseInt(m.id.split("-")[1]) || Date.now();
16985
+ const startTime = next[i].startTime || parseInt(String(next[i].id).split("-")[1]) || Date.now();
16687
16986
  const duration = Date.now() - startTime;
16688
- return { ...m, text: parts[0], isStreaming: false, duration };
16987
+ next[i] = { ...next[i], text: parts[0], isStreaming: false, duration };
16988
+ } else {
16989
+ next[i] = { ...next[i], text: newText, isStreaming: true };
16689
16990
  }
16690
- return { ...m, text: newText, isStreaming: true };
16991
+ break;
16691
16992
  }
16692
- return m;
16693
- });
16993
+ }
16694
16994
  if (transitioning) {
16695
16995
  inThinkMode = false;
16696
16996
  currentAgentId = "agent-" + Date.now();
16697
- return [...newMsgs, { id: currentAgentId, role: "agent", text: transitionContent.replace(/<\/?(think|thought)>/gi, ""), isStreaming: true }];
16997
+ next.push({ id: currentAgentId, role: "agent", text: transitionContent.replace(/<\/?(think|thought)>/gi, ""), isStreaming: true });
16698
16998
  }
16699
- return newMsgs;
16999
+ return next;
16700
17000
  });
16701
17001
  } else if (!inThinkMode) {
16702
17002
  const chunkLower2 = chunkText.toLowerCase();
@@ -16707,9 +17007,16 @@ Selection: ${val}`,
16707
17007
  currentAgentId = "agent-" + Date.now();
16708
17008
  setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: chunkText, isStreaming: true }]);
16709
17009
  } else {
16710
- setMessages((prev) => prev.map(
16711
- (m) => m.id === currentAgentId ? { ...m, text: m.text + chunkText, isStreaming: true } : m
16712
- ));
17010
+ setMessages((prev) => {
17011
+ const next = [...prev];
17012
+ for (let i = next.length - 1; i >= 0; i--) {
17013
+ if (next[i].id === currentAgentId) {
17014
+ next[i] = { ...next[i], text: next[i].text + chunkText, isStreaming: true };
17015
+ break;
17016
+ }
17017
+ }
17018
+ return next;
17019
+ });
16713
17020
  }
16714
17021
  }
16715
17022
  }
@@ -16724,7 +17031,7 @@ Selection: ${val}`,
16724
17031
  setIsProcessing(false);
16725
17032
  setStatusText(null);
16726
17033
  if (didSignalTerminationRef.current) {
16727
- setMessages((prev) => appendCancelMessage(prev));
17034
+ appendCancelMessage();
16728
17035
  }
16729
17036
  if (!hasFiredJanitor) {
16730
17037
  if (process.stdout.isTTY) {
@@ -16817,7 +17124,7 @@ Selection: ${val}`,
16817
17124
  }
16818
17125
  return [];
16819
17126
  }, [input, isFilePickerDismissed]);
16820
- useEffect9(() => {
17127
+ useEffect11(() => {
16821
17128
  setSelectedIndex(0);
16822
17129
  }, [suggestions]);
16823
17130
  const CustomMenuItem = ({ label: label2, isSelected }) => {
@@ -17314,6 +17621,7 @@ Selection: ${val}`,
17314
17621
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
17315
17622
  }
17316
17623
  setClearKey((prev) => prev + 1);
17624
+ clearBlocksCache();
17317
17625
  const targetIdx = messages.findLastIndex(
17318
17626
  (m) => m.role === "user" && m.text && (m.text.startsWith(targetPrompt) || m.text.includes(targetPrompt))
17319
17627
  );
@@ -17366,6 +17674,7 @@ Selection: ${val}`,
17366
17674
  const h = await loadHistory();
17367
17675
  if (h[id]) {
17368
17676
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
17677
+ clearBlocksCache();
17369
17678
  setChatId(id);
17370
17679
  const savedData = await loadChatContext(id);
17371
17680
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
@@ -18007,7 +18316,22 @@ var init_app = __esm({
18007
18316
  // src/cli.jsx
18008
18317
  import { spawn as spawn3 } from "child_process";
18009
18318
  import { fileURLToPath as fileURLToPath2 } from "url";
18010
- var HEAP_LIMIT = 6144;
18319
+ import os5 from "os";
18320
+ var totalSystemRamBytes = os5.totalmem();
18321
+ var totalSystemRamMB = totalSystemRamBytes / (1024 * 1024);
18322
+ var SAFETY_MARGIN = 0.5;
18323
+ var calculatedLimit = Math.floor(totalSystemRamMB * SAFETY_MARGIN);
18324
+ var _rawArgs = process.argv.slice(2);
18325
+ var _allocIdx = _rawArgs.indexOf("--allocation");
18326
+ var _allocValue = _allocIdx !== -1 ? parseInt(_rawArgs[_allocIdx + 1], 10) : NaN;
18327
+ var _maxAllowed = Math.floor(totalSystemRamMB * 0.75);
18328
+ var HEAP_LIMIT = !isNaN(_allocValue) && _allocValue > 0 ? Math.min(_allocValue, _maxAllowed) : Math.max(1536, Math.min(32768, calculatedLimit));
18329
+ if (!Number.isNaN(_allocValue)) {
18330
+ console.log("\n[MEMORY] Using custom memory allocation: " + _allocValue + " MB" + (_allocValue > _maxAllowed ? " (Max allowed: " + _maxAllowed + "MB)" : ""));
18331
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
18332
+ } else {
18333
+ console.log("\n[MEMORY] Using auto-detected memory allocation: " + calculatedLimit + " MB");
18334
+ }
18011
18335
  var isBundled = fileURLToPath2(import.meta.url).endsWith(".js");
18012
18336
  if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-size"))) {
18013
18337
  const cp = spawn3(process.execPath, [
@@ -18042,6 +18366,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
18042
18366
  --thinking <Fast|Low|Medium|High|xHigh> Set startup thinking level
18043
18367
  --memory <on|off> Toggle memory system
18044
18368
  --resume <session_id> Resume a previous session
18369
+ --allocation <mb> Override Node.js max-old-space-size in MB (default: auto)
18045
18370
  --package <npm|pnpm|yarn|bun> Set package manager for updates
18046
18371
  --auto-del <1d|7d|30d> Set history auto-deletion timeframe
18047
18372
  --auto-exec <on|off> Toggle permission for autonomous command execution
@@ -18131,7 +18456,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
18131
18456
  }
18132
18457
  const promptPackageManager = async () => {
18133
18458
  const React17 = (await import("react")).default;
18134
- const { useState: useState14 } = React17;
18459
+ const { useState: useState15 } = React17;
18135
18460
  const { render: render2, Box: Box16, Text: Text17 } = await import("ink");
18136
18461
  const SelectInput3 = (await import("ink-select-input")).default;
18137
18462
  const TextInput5 = (await import("ink-text-input")).default;
@@ -18148,8 +18473,8 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
18148
18473
  };
18149
18474
  let unmountFn;
18150
18475
  const PromptComponent = () => {
18151
- const [step, setStep] = useState14("select");
18152
- const [customCommand2, setCustomCommand] = useState14("");
18476
+ const [step, setStep] = useState15("select");
18477
+ const [customCommand2, setCustomCommand] = useState15("");
18153
18478
  const handleSelect = (item) => {
18154
18479
  if (item.value === "custom") {
18155
18480
  setStep("custom");