fluxflow-cli 2.13.5 → 2.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/fluxflow.js +1074 -666
  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, CHUNK_SIZE, indexBlockIntoMap, parseMessageToBlocks, TOOL_LABELS, REGEX_INITIAL_THINK, REGEX_INITIAL_TOOL, REGEX_SYSTEM, REGEX_THINK, REGEX_ANSWER, REGEX_TOOL_RES, REGEX_SUCCESS_ERROR, REGEX_TURN_1, REGEX_END, REGEX_TURN_2, REGEX_TURN_3, REGEX_OPEN_BRACKET, REGEX_RESPONDED, REGEX_PROMPTED, REGEX_ARROWS, REGEX_ARROWS_L, REGEX_ARROWS_U, REGEX_ARROWS_D, REGEX_ARROWS_LR, REGEX_TERMINAL, REGEX_TOOLS, cleanSignals, clearBlocksCache;
2093
2095
  var init_text = __esm({
2094
2096
  "src/utils/text.js"() {
2095
2097
  init_paths();
@@ -2433,223 +2435,348 @@ 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;
2536
+ CHUNK_SIZE = 6;
2537
+ indexBlockIntoMap = (b, map) => {
2538
+ map.set(b.key, b);
2539
+ if (b.type === "chunk" && b.blocks) b.blocks.forEach((sub) => indexBlockIntoMap(sub, map));
2540
+ };
2436
2541
  parseMessageToBlocks = (msg, columns) => {
2542
+ if (!msg) return { completed: [], active: [] };
2543
+ const cacheKey = `${msg.id}-${msg.text?.length || 0}-${columns}-${msg.isStreaming}`;
2544
+ if (!msg.isStreaming && blocksCache.has(cacheKey)) {
2545
+ return blocksCache.get(cacheKey);
2546
+ }
2437
2547
  const text = cleanSignals(msg.text || "");
2548
+ const streamCacheKey = `${msg.id}-${columns}`;
2549
+ let cachedBlocks = /* @__PURE__ */ new Map();
2550
+ if (msg.isStreaming) {
2551
+ const cached = streamingBlocksCache.get(streamCacheKey);
2552
+ if (cached && text.startsWith(cached.text)) {
2553
+ cachedBlocks = cached.blocksMap;
2554
+ }
2555
+ }
2556
+ const getBlock = (key, type, textContent, extra = {}) => {
2557
+ const existing = cachedBlocks.get(key);
2558
+ if (existing && existing.text === textContent && existing.type === type && !!existing.isActiveBlock === !!extra.isActiveBlock && !!existing.isStreaming === !!extra.isStreaming && existing.pairContent === extra.pairContent) {
2559
+ return existing;
2560
+ }
2561
+ return {
2562
+ key,
2563
+ msg,
2564
+ type,
2565
+ text: textContent,
2566
+ ...extra
2567
+ };
2568
+ };
2438
2569
  if (text.includes("- Content Preview:")) {
2439
2570
  const mainParts = text.split("- Content Preview:");
2440
- const headerText = mainParts[0] || "";
2441
2571
  const contentPart = mainParts[1] || "";
2442
2572
  const footerMarker = "[SYSTEM] Check the content preview for verification [/SYSTEM]";
2443
- const contentAndFooter = contentPart.split(footerMarker);
2444
- const content = contentAndFooter[0]?.trim() || "";
2445
- const footer = contentAndFooter[1] ? `${footerMarker}${contentAndFooter[1]}` : "";
2573
+ const content = contentPart.split(footerMarker)[0]?.trim() || "";
2446
2574
  const codeLines = content.split("\n").map((l) => l.replace(/\r$/, ""));
2447
2575
  const gutterWidth = String(codeLines.length).length;
2448
2576
  const completedBlocks2 = [];
2449
2577
  let activeBlock2 = null;
2578
+ let writeChunk = [];
2579
+ const flushWrite = () => {
2580
+ if (!writeChunk.length) return;
2581
+ const batch = writeChunk;
2582
+ writeChunk = [];
2583
+ completedBlocks2.push(batch.length === 1 ? batch[0] : {
2584
+ key: `${batch[0].key}-chunk`,
2585
+ msg,
2586
+ type: "chunk",
2587
+ blocks: batch
2588
+ });
2589
+ };
2450
2590
  codeLines.forEach((line, idx) => {
2451
2591
  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,
2592
+ const block = getBlock(`${msg.id || Date.now()}-write-line-${idx}`, "write-line", line, {
2457
2593
  gutterWidth,
2458
2594
  lineNum: idx + 1,
2459
2595
  isFirstLine: idx === 0,
2460
2596
  isLastLine: isLast
2461
- };
2597
+ });
2462
2598
  if (isLast && msg.isStreaming) {
2599
+ flushWrite();
2463
2600
  activeBlock2 = block;
2464
2601
  } else {
2465
- completedBlocks2.push(block);
2602
+ writeChunk.push(block);
2603
+ if (writeChunk.length >= CHUNK_SIZE) flushWrite();
2466
2604
  }
2467
2605
  });
2468
- return {
2469
- completed: completedBlocks2,
2470
- active: activeBlock2 ? [activeBlock2] : []
2471
- };
2606
+ flushWrite();
2607
+ return { completed: completedBlocks2, active: activeBlock2 ? [activeBlock2] : [] };
2472
2608
  }
2473
2609
  if (text.includes("[DIFF_START]")) {
2474
2610
  const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
2475
2611
  const diffBody = match ? match[1].trim() : "";
2476
2612
  const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
2613
+ const parsedLines = diffLines.map((line) => ({ line, parsed: parseLineInfo(line), pairContent: null }));
2614
+ let currentGroup = [];
2615
+ for (let i = 0; i < parsedLines.length; i++) {
2616
+ const item = parsedLines[i];
2617
+ if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
2618
+ currentGroup.push(item);
2619
+ } else {
2620
+ if (currentGroup.length > 0) {
2621
+ alignChangeGroup(currentGroup);
2622
+ currentGroup = [];
2623
+ }
2624
+ }
2625
+ }
2626
+ if (currentGroup.length > 0) alignChangeGroup(currentGroup);
2477
2627
  const completedBlocks2 = [];
2478
2628
  let activeBlock2 = null;
2629
+ let diffChunk = [];
2630
+ const flushDiff = () => {
2631
+ if (!diffChunk.length) return;
2632
+ const batch = diffChunk;
2633
+ diffChunk = [];
2634
+ completedBlocks2.push(batch.length === 1 ? batch[0] : {
2635
+ key: `${batch[0].key}-chunk`,
2636
+ msg,
2637
+ type: "chunk",
2638
+ blocks: batch
2639
+ });
2640
+ };
2479
2641
  diffLines.forEach((line, i) => {
2480
2642
  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,
2643
+ const block = getBlock(`${msg.id || Date.now()}-diff-${i}`, "diff-line", line, {
2486
2644
  isFirstLine: i === 0,
2487
- isLastLine: isLast
2488
- };
2645
+ isLastLine: isLast,
2646
+ pairContent: parsedLines[i].pairContent
2647
+ });
2489
2648
  if (isLast && msg.isStreaming) {
2649
+ flushDiff();
2490
2650
  activeBlock2 = block;
2491
2651
  } else {
2492
- completedBlocks2.push(block);
2652
+ diffChunk.push(block);
2653
+ if (diffChunk.length >= CHUNK_SIZE) flushDiff();
2493
2654
  }
2494
2655
  });
2495
- return {
2496
- completed: completedBlocks2,
2497
- active: activeBlock2 ? [activeBlock2] : []
2498
- };
2656
+ flushDiff();
2657
+ return { completed: completedBlocks2, active: activeBlock2 ? [activeBlock2] : [] };
2499
2658
  }
2500
2659
  if (msg.role === "system" || msg.isLogo || msg.isHelpRecord || msg.isTerminalRecord || msg.isHomeWarning || msg.isImageStats || msg.isAskRecord || msg.isAboutRecord || msg.isUpdateNotification || msg.role === "user") {
2501
2660
  return {
2502
- completed: [{
2503
- key: `${msg.id || Date.now()}-full`,
2504
- msg,
2505
- type: "full-message",
2506
- text
2507
- }],
2661
+ completed: [getBlock(`${msg.id || Date.now()}-full`, "full-message", text)],
2508
2662
  active: []
2509
2663
  };
2510
2664
  }
2511
2665
  const completedBlocks = [];
2512
2666
  let activeBlock = null;
2513
- if (msg.role === "think") {
2514
- completedBlocks.push({
2515
- key: `${msg.id}-header`,
2667
+ let pendingChunk = [];
2668
+ let pendingChunkType = null;
2669
+ const flushPending = () => {
2670
+ if (!pendingChunk.length) return;
2671
+ const batch = pendingChunk;
2672
+ pendingChunk = [];
2673
+ pendingChunkType = null;
2674
+ completedBlocks.push(batch.length === 1 ? batch[0] : {
2675
+ key: `${msg.id || "x"}-chunk-${batch[0].key}`,
2516
2676
  msg,
2517
- type: "think-header",
2518
- text: ""
2677
+ type: "chunk",
2678
+ blocks: batch
2519
2679
  });
2680
+ };
2681
+ const enqueue = (block) => {
2682
+ if (pendingChunkType !== null && pendingChunkType !== block.type) flushPending();
2683
+ pendingChunk.push(block);
2684
+ pendingChunkType = block.type;
2685
+ if (pendingChunk.length >= CHUNK_SIZE) flushPending();
2686
+ };
2687
+ if (msg.role === "think") {
2688
+ completedBlocks.push(getBlock(`${msg.id}-header`, "think-header", ""));
2520
2689
  const lines = text.split("\n");
2521
2690
  lines.forEach((line, idx) => {
2522
- const isLast = idx === lines.length - 1;
2523
- const block = {
2524
- key: `${msg.id}-${idx}`,
2525
- msg,
2526
- type: "think-line",
2527
- text: line
2528
- };
2529
- if (isLast && msg.isStreaming) {
2530
- block.isActiveBlock = true;
2531
- activeBlock = block;
2532
- } else {
2533
- completedBlocks.push(block);
2534
- }
2691
+ enqueue(getBlock(`${msg.id}-${idx}`, "think-line", line, {}));
2535
2692
  });
2536
2693
  if (!msg.isStreaming) {
2537
- completedBlocks.push({
2538
- key: `${msg.id}-footer-padding`,
2539
- msg,
2540
- type: "think-footer-padding",
2541
- text: ""
2542
- });
2694
+ flushPending();
2695
+ completedBlocks.push({ key: `${msg.id}-footer-padding`, msg, type: "think-footer-padding", text: "" });
2543
2696
  }
2544
2697
  } else {
2545
2698
  const lines = text.split("\n");
2546
2699
  let inTable = false;
2547
2700
  let tableLines = [];
2548
2701
  let inCodeBlock = false;
2549
- let codeLines = [];
2702
+ let codeLineNum = 0;
2703
+ let codeStartIdx = 0;
2550
2704
  lines.forEach((line, idx) => {
2551
2705
  const isLast = idx === lines.length - 1;
2552
2706
  const isTableRow = line.trim().startsWith("|");
2553
2707
  const isCodeBlockMarker = line.trim().startsWith("```");
2554
2708
  if (inCodeBlock) {
2555
- codeLines.push(line);
2556
- if (isCodeBlockMarker || isLast) {
2557
- inCodeBlock = !isCodeBlockMarker;
2558
- if (!inCodeBlock || isLast) {
2559
- const block = {
2560
- key: `${msg.id}-code-${idx}`,
2561
- msg,
2562
- type: "agent-line",
2563
- text: codeLines.join("\n")
2564
- };
2565
- if (isLast && msg.isStreaming && inCodeBlock) {
2566
- block.isActiveBlock = true;
2567
- activeBlock = block;
2568
- } else {
2569
- completedBlocks.push(block);
2570
- }
2571
- codeLines = [];
2572
- }
2709
+ if (isCodeBlockMarker) {
2710
+ inCodeBlock = false;
2711
+ enqueue(getBlock(`${msg.id}-code-close-${codeStartIdx}`, "code-fence-close", "", {}));
2712
+ } else {
2713
+ codeLineNum++;
2714
+ enqueue(getBlock(`${msg.id}-code-line-${idx}`, "code-line", line, { lineNum: codeLineNum }));
2573
2715
  }
2574
2716
  } else if (isCodeBlockMarker) {
2575
2717
  inCodeBlock = true;
2576
- codeLines.push(line);
2577
- if (isLast) {
2578
- const block = {
2579
- key: `${msg.id}-code-${idx}`,
2580
- msg,
2581
- type: "agent-line",
2582
- text: codeLines.join("\n")
2583
- };
2584
- if (msg.isStreaming) {
2585
- block.isActiveBlock = true;
2586
- activeBlock = block;
2587
- } else {
2588
- completedBlocks.push(block);
2589
- }
2590
- }
2718
+ codeStartIdx = idx;
2719
+ codeLineNum = 0;
2720
+ const lang = line.trim().replace(/^```/, "").trim();
2721
+ enqueue(getBlock(`${msg.id}-code-open-${idx}`, "code-fence-open", lang, {}));
2591
2722
  } else if (isTableRow) {
2592
2723
  inTable = true;
2593
2724
  tableLines.push(line);
2594
2725
  if (isLast) {
2726
+ flushPending();
2595
2727
  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
- };
2728
+ activeBlock = getBlock(`${msg.id}-table-${idx}`, "table", tableLines.join("\n"), { isStreaming: true });
2604
2729
  } else {
2605
- completedBlocks.push({
2606
- key: `${msg.id}-table-${idx}`,
2607
- msg,
2608
- type: "table",
2609
- text: tableLines.join("\n"),
2610
- isStreaming: false
2611
- });
2730
+ completedBlocks.push(getBlock(`${msg.id}-table-${idx}`, "table", tableLines.join("\n"), { isStreaming: false }));
2612
2731
  }
2613
2732
  }
2614
2733
  } else {
2615
2734
  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
- });
2735
+ flushPending();
2736
+ completedBlocks.push(getBlock(`${msg.id}-table-${idx}`, "table", tableLines.join("\n"), { isStreaming: false }));
2623
2737
  inTable = false;
2624
2738
  tableLines = [];
2625
2739
  }
2626
- const block = {
2627
- key: `${msg.id}-${idx}`,
2628
- msg,
2629
- type: "agent-line",
2630
- text: line
2631
- };
2632
- if (isLast && msg.isStreaming) {
2633
- block.isActiveBlock = true;
2634
- activeBlock = block;
2635
- } else {
2636
- completedBlocks.push(block);
2637
- }
2740
+ enqueue(getBlock(`${msg.id}-${idx}`, "agent-line", line, {}));
2638
2741
  }
2639
2742
  });
2640
2743
  if (!msg.isStreaming && msg.workedDuration) {
2641
- completedBlocks.push({
2642
- key: `${msg.id}-worked-duration`,
2643
- msg,
2644
- type: "worked-duration",
2645
- text: ""
2646
- });
2744
+ flushPending();
2745
+ completedBlocks.push(getBlock(`${msg.id}-worked-duration`, "worked-duration", ""));
2647
2746
  }
2648
2747
  }
2649
- return {
2748
+ if (msg.isStreaming && pendingChunk.length > 0) {
2749
+ activeBlock = pendingChunk.length === 1 ? pendingChunk[0] : {
2750
+ key: `${msg.id || "x"}-chunk-active-${pendingChunk[0].key}`,
2751
+ msg,
2752
+ type: "chunk",
2753
+ blocks: pendingChunk
2754
+ };
2755
+ } else {
2756
+ flushPending();
2757
+ }
2758
+ const result = {
2650
2759
  completed: completedBlocks,
2651
2760
  active: activeBlock ? [activeBlock] : []
2652
2761
  };
2762
+ if (!msg.isStreaming) {
2763
+ blocksCache.set(cacheKey, result);
2764
+ if (blocksCache.size > MAX_CACHE_SIZE) {
2765
+ const firstKey = blocksCache.keys().next().value;
2766
+ blocksCache.delete(firstKey);
2767
+ }
2768
+ streamingBlocksCache.delete(streamCacheKey);
2769
+ } else {
2770
+ const blocksMap = /* @__PURE__ */ new Map();
2771
+ completedBlocks.forEach((b) => indexBlockIntoMap(b, blocksMap));
2772
+ if (activeBlock) indexBlockIntoMap(activeBlock, blocksMap);
2773
+ streamingBlocksCache.set(streamCacheKey, { text, blocksMap });
2774
+ if (streamingBlocksCache.size > MAX_CACHE_SIZE) {
2775
+ const firstKey = streamingBlocksCache.keys().next().value;
2776
+ streamingBlocksCache.delete(firstKey);
2777
+ }
2778
+ }
2779
+ return result;
2653
2780
  };
2654
2781
  TOOL_LABELS = {
2655
2782
  "write_file": "WriteFile",
@@ -2678,61 +2805,88 @@ var init_text = __esm({
2678
2805
  "Chat": "Chat",
2679
2806
  "GenerateImage": "GenerateImage"
2680
2807
  };
2808
+ REGEX_INITIAL_THINK = /<\/think>(\r?\n){2}/gi;
2809
+ REGEX_INITIAL_TOOL = /(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi;
2810
+ REGEX_SYSTEM = /\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi;
2811
+ REGEX_THINK = /<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi;
2812
+ REGEX_ANSWER = /\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi;
2813
+ REGEX_TOOL_RES = /\[TOOL RESULT\]:?\s*/gi;
2814
+ REGEX_SUCCESS_ERROR = /^\s*(SUCCESS|ERROR):.*(\r?\n)?/gm;
2815
+ REGEX_TURN_1 = /\[\s*turn\s*:\s*(continue|finish)\s*\]/gi;
2816
+ REGEX_END = /\[\[END\]\]/gi;
2817
+ REGEX_TURN_2 = /\[\s*turn\s*:?.*?$/gi;
2818
+ REGEX_TURN_3 = /\n\s*turn\s*:?.*?$/gi;
2819
+ REGEX_OPEN_BRACKET = /\[\s*$/gi;
2820
+ REGEX_RESPONDED = /\n\nResponded on .*/g;
2821
+ REGEX_PROMPTED = /\n\n\[Prompted on: .*\]/g;
2822
+ REGEX_ARROWS = /(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi;
2823
+ REGEX_ARROWS_L = /(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi;
2824
+ REGEX_ARROWS_U = /(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi;
2825
+ REGEX_ARROWS_D = /(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi;
2826
+ REGEX_ARROWS_LR = /(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi;
2827
+ REGEX_TERMINAL = /@\[TerminalName:.*?, ProcessId:.*?\]/gi;
2828
+ 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
2829
  cleanSignals = (text) => {
2682
2830
  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, "");
2831
+ let result = text.replace(REGEX_INITIAL_THINK, "</think>").replace(REGEX_INITIAL_TOOL, "");
2684
2832
  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;
2833
+ if (result.toLowerCase().includes(trigger)) {
2834
+ while (true) {
2835
+ const lowerResult = result.toLowerCase();
2836
+ let triggerIdx = lowerResult.indexOf(trigger);
2837
+ if (triggerIdx === -1) break;
2838
+ let startIdx = triggerIdx;
2839
+ let hasOuterBracket = false;
2840
+ let k = triggerIdx - 1;
2841
+ while (k >= 0 && /\s/.test(result[k])) k--;
2842
+ if (k >= 0 && result[k] === "[") {
2843
+ startIdx = k;
2844
+ hasOuterBracket = true;
2707
2845
  }
2708
- if (!inString) {
2709
- if (char === "(") {
2710
- balance++;
2711
- foundStart = true;
2712
- } else if (char === ")") {
2713
- balance--;
2846
+ let balance = 0;
2847
+ let foundStart = false;
2848
+ let inString = null;
2849
+ let j = triggerIdx;
2850
+ while (j < result.length) {
2851
+ const char = result[j];
2852
+ if (!inString && (char === "'" || char === '"' || char === "`")) {
2853
+ inString = char;
2854
+ } else if (inString && char === inString && result[j - 1] !== "\\") {
2855
+ inString = null;
2714
2856
  }
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;
2857
+ if (!inString) {
2858
+ if (char === "(") {
2859
+ balance++;
2860
+ foundStart = true;
2861
+ } else if (char === ")") {
2862
+ balance--;
2723
2863
  }
2724
2864
  }
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;
2865
+ if (foundStart && balance === 0 && !inString) {
2866
+ let endIdx = j;
2867
+ if (hasOuterBracket) {
2868
+ let m = j + 1;
2869
+ while (m < result.length && /\s/.test(result[m])) m++;
2870
+ if (m < result.length && result[m] === "]") {
2871
+ endIdx = m;
2872
+ }
2873
+ }
2874
+ result = result.substring(0, startIdx) + result.substring(endIdx + 1);
2875
+ break;
2876
+ }
2877
+ j++;
2878
+ if (j === result.length) {
2879
+ result = result.substring(0, startIdx);
2880
+ return result;
2881
+ }
2732
2882
  }
2733
2883
  }
2734
2884
  }
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();
2885
+ 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();
2886
+ };
2887
+ clearBlocksCache = () => {
2888
+ blocksCache.clear();
2889
+ streamingBlocksCache.clear();
2736
2890
  };
2737
2891
  }
2738
2892
  });
@@ -3812,75 +3966,14 @@ ${coloredArt[7]}`;
3812
3966
  import React4, { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
3813
3967
  import { Box as Box3, Text as Text4 } from "ink";
3814
3968
  import { diffWordsWithSpace } from "diff";
3815
- var useStreamingText, formatThinkText, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, parseLineInfo, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
3969
+ 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
3970
  var init_ChatLayout = __esm({
3817
3971
  "src/components/ChatLayout.jsx"() {
3818
3972
  init_TerminalBox();
3819
3973
  init_text();
3820
3974
  init_terminal();
3821
3975
  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;
3976
+ return targetText;
3884
3977
  };
3885
3978
  formatThinkText = (cleaned, columns = 80) => {
3886
3979
  if (!cleaned) return null;
@@ -3908,14 +4001,17 @@ var init_ChatLayout = __esm({
3908
4001
  return /* @__PURE__ */ React4.createElement(MarkdownText, { key: i, text: cleanPart, color: "gray", columns: availableWidth, italic: true });
3909
4002
  }));
3910
4003
  };
4004
+ REGEX_MD_TOKENS = /(```[\s\S]*?```|`[^`]+`|@\[.*?\]|\*\*.*?\*\*|\*.*?\*|\$.*?\$|\[.*?\]\s*\(.*?\)|\[.*?\]\s*\[.*?\]|https?:\/\/[^\s]+)/g;
4005
+ REGEX_LATEX_FRAC = /\\frac\s*\{([^{}]*)\}\s*\{([^{}]*)\}/g;
4006
+ REGEX_LATEX_STYLE = /(\\(?:mathbf|textbf|textit|underline|texttt)\{[^{}]*\})/g;
3911
4007
  parseMathSymbols = (content) => {
3912
4008
  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
4009
  };
3914
4010
  renderLatexText = (content, key) => {
3915
4011
  if (!content) return null;
3916
- let formatted = content.replace(/\\frac\s*\{([^{}]*)\}\s*\{([^{}]*)\}/g, "($1/$2)");
4012
+ let formatted = content.replace(REGEX_LATEX_FRAC, "($1/$2)");
3917
4013
  formatted = parseMathSymbols(formatted);
3918
- const parts = formatted.split(/(\\(?:mathbf|textbf|textit|underline|texttt)\{[^{}]*\})/g);
4014
+ const parts = formatted.split(REGEX_LATEX_STYLE);
3919
4015
  return /* @__PURE__ */ React4.createElement(React4.Fragment, { key }, parts.map((p, idx) => {
3920
4016
  if (p.startsWith("\\")) {
3921
4017
  const match = p.match(/\\(\w+)\{([^{}]*)\}/);
@@ -3934,7 +4030,7 @@ var init_ChatLayout = __esm({
3934
4030
  };
3935
4031
  InlineMarkdown = React4.memo(({ text, color, italic }) => {
3936
4032
  if (!text) return null;
3937
- const parts = text.split(/(```[\s\S]*?```|`[^`]+`|@\[.*?\]|\*\*.*?\*\*|\*.*?\*|\$.*?\$|\[.*?\]\s*\(.*?\)|\[.*?\]\s*\[.*?\]|https?:\/\/[^\s]+)/g);
4033
+ const parts = text.split(REGEX_MD_TOKENS);
3938
4034
  return /* @__PURE__ */ React4.createElement(Text4, { color, wrap: "anywhere", italic }, parts.map((part, j) => {
3939
4035
  if (!part) return null;
3940
4036
  if (part.startsWith("```") && part.endsWith("```")) {
@@ -4065,40 +4161,47 @@ var init_ChatLayout = __esm({
4065
4161
  flushBuffers("final");
4066
4162
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: columns - 2 }, result);
4067
4163
  });
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
4164
  DiffLine = React4.memo(({ line, pairContent, parentText, columns = 80 }) => {
4081
4165
  const isContext = line.includes("[UI_CONTEXT]");
4082
4166
  const cleanLine = line.replace("[UI_CONTEXT]", "");
4083
4167
  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))));
4168
+ 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
4169
  }
4086
4170
  const parsedCurrent = parseLineInfo(line);
4087
4171
  if (!parsedCurrent) {
4088
4172
  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
4173
  }
4090
4174
  const { isR: isRemoval, isA: isAddition, num: lineNum, content } = parsedCurrent;
4091
- const innerBgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : void 0;
4092
4175
  let finalPairContent = pairContent;
4093
4176
  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;
4177
+ const match = parentText.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
4178
+ const diffBody = match ? match[1].trim() : "";
4179
+ const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
4180
+ const parsedLines = diffLines.map((l) => {
4181
+ return {
4182
+ line: l,
4183
+ parsed: parseLineInfo(l),
4184
+ pairContent: null
4185
+ };
4099
4186
  });
4100
- if (pairLine) {
4101
- finalPairContent = parseLineInfo(pairLine).content;
4187
+ let currentGroup = [];
4188
+ for (let idx = 0; idx < parsedLines.length; idx++) {
4189
+ const item = parsedLines[idx];
4190
+ if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
4191
+ currentGroup.push(item);
4192
+ } else {
4193
+ if (currentGroup.length > 0) {
4194
+ alignChangeGroup(currentGroup);
4195
+ currentGroup = [];
4196
+ }
4197
+ }
4198
+ }
4199
+ if (currentGroup.length > 0) {
4200
+ alignChangeGroup(currentGroup);
4201
+ }
4202
+ const matchedItem = parsedLines.find((item) => item.parsed && item.parsed.num === lineNum && item.parsed.isR === isRemoval);
4203
+ if (matchedItem) {
4204
+ finalPairContent = matchedItem.pairContent;
4102
4205
  }
4103
4206
  }
4104
4207
  let words = [];
@@ -4113,7 +4216,7 @@ var init_ChatLayout = __esm({
4113
4216
  }
4114
4217
  const hasInlineChange = words.some((part) => isRemoval && part.removed || isAddition && part.added);
4115
4218
  const isPureUnpairedBlock = !finalPairContent && (isRemoval || isAddition);
4116
- const hasRealChange = hasInlineChange || isPureUnpairedBlock;
4219
+ const innerBgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : void 0;
4117
4220
  const finalNumColor = isRemoval || isAddition ? isRemoval ? "#d96868" : "#68d98c" : "gray";
4118
4221
  const finalPrefixColor = isRemoval ? "#ff4d4d" : "#4dff88";
4119
4222
  const displayPrefix = isRemoval ? "-" : isAddition ? "+" : " ";
@@ -4123,7 +4226,7 @@ var init_ChatLayout = __esm({
4123
4226
  return /* @__PURE__ */ React4.createElement(Text4, { color: blockColor }, wrapText(content, columns - 14));
4124
4227
  }
4125
4228
  if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
4126
- const textColor = isRemoval ? "#b34d4d" : isAddition ? "#4db36b" : "gray";
4229
+ const textColor = isRemoval ? "#885555" : isAddition ? "#558866" : "gray";
4127
4230
  return /* @__PURE__ */ React4.createElement(Text4, { color: textColor }, wrapText(content, columns - 14));
4128
4231
  }
4129
4232
  return /* @__PURE__ */ React4.createElement(Text4, { wrap: "anywhere" }, words.map((part, idx) => {
@@ -4134,7 +4237,7 @@ var init_ChatLayout = __esm({
4134
4237
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#ff3333" }, part.value);
4135
4238
  }
4136
4239
  if (part.added) return null;
4137
- return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#b34d4d" }, part.value);
4240
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#885555" }, part.value);
4138
4241
  }
4139
4242
  if (isAddition) {
4140
4243
  const isSurroundedByAddition = words[idx - 1]?.added || words[idx + 1]?.added;
@@ -4142,7 +4245,7 @@ var init_ChatLayout = __esm({
4142
4245
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#33ff66" }, part.value);
4143
4246
  }
4144
4247
  if (part.removed) return null;
4145
- return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#4db36b" }, part.value);
4248
+ return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "#558866" }, part.value);
4146
4249
  }
4147
4250
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "gray" }, part.value);
4148
4251
  }));
@@ -4153,7 +4256,37 @@ var init_ChatLayout = __esm({
4153
4256
  const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
4154
4257
  const diffBody = match ? match[1].trim() : "";
4155
4258
  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, " ")))));
4259
+ const parsedLines = diffLines.map((line) => {
4260
+ return {
4261
+ line,
4262
+ parsed: parseLineInfo(line),
4263
+ pairContent: null
4264
+ };
4265
+ });
4266
+ let currentGroup = [];
4267
+ for (let i = 0; i < parsedLines.length; i++) {
4268
+ const item = parsedLines[i];
4269
+ if (item.parsed && (item.parsed.isR || item.parsed.isA)) {
4270
+ currentGroup.push(item);
4271
+ } else {
4272
+ if (currentGroup.length > 0) {
4273
+ alignChangeGroup(currentGroup);
4274
+ currentGroup = [];
4275
+ }
4276
+ }
4277
+ }
4278
+ if (currentGroup.length > 0) {
4279
+ alignChangeGroup(currentGroup);
4280
+ }
4281
+ 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(
4282
+ DiffLine,
4283
+ {
4284
+ key: i,
4285
+ line: item.line,
4286
+ pairContent: item.pairContent,
4287
+ columns: columns - 3
4288
+ }
4289
+ )), /* @__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
4290
  });
4158
4291
  CodeRenderer = React4.memo(({ text, columns = 80 }) => {
4159
4292
  if (!text) return null;
@@ -4408,6 +4541,19 @@ var init_ChatLayout = __esm({
4408
4541
  });
4409
4542
  BlockItem = React4.memo(({ block, columns = 80, showFullThinking, aiProvider, version }) => {
4410
4543
  const { msg, type, text, isStreaming } = block;
4544
+ if (type === "chunk") {
4545
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: "100%" }, block.blocks.map((b) => /* @__PURE__ */ React4.createElement(
4546
+ BlockItem,
4547
+ {
4548
+ key: b.key,
4549
+ block: b,
4550
+ columns,
4551
+ showFullThinking,
4552
+ aiProvider,
4553
+ version
4554
+ }
4555
+ )));
4556
+ }
4411
4557
  if (type === "full-message") {
4412
4558
  return /* @__PURE__ */ React4.createElement(
4413
4559
  MessageItem,
@@ -4471,6 +4617,56 @@ var init_ChatLayout = __esm({
4471
4617
  }
4472
4618
  ), isLastLine && renderPaddingLine(true));
4473
4619
  }
4620
+ if (type === "code-fence-open") {
4621
+ const borderProps = {
4622
+ borderStyle: "single",
4623
+ borderLeft: true,
4624
+ borderRight: false,
4625
+ borderTop: false,
4626
+ borderBottom: false,
4627
+ borderColor: "#444444",
4628
+ paddingLeft: 2,
4629
+ width: "100%"
4630
+ };
4631
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", ...borderProps }, /* @__PURE__ */ React4.createElement(Text4, null, " ")), /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "row", ...borderProps }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "\u25B6_ ", (text || "CODE").toUpperCase())));
4632
+ }
4633
+ if (type === "code-line") {
4634
+ const { lineNum } = block;
4635
+ return /* @__PURE__ */ React4.createElement(
4636
+ Box3,
4637
+ {
4638
+ flexDirection: "row",
4639
+ borderStyle: "single",
4640
+ borderLeft: true,
4641
+ borderRight: false,
4642
+ borderTop: false,
4643
+ borderBottom: false,
4644
+ borderColor: "#444444",
4645
+ paddingLeft: 2,
4646
+ width: "100%"
4647
+ },
4648
+ /* @__PURE__ */ React4.createElement(Box3, { width: 4, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(lineNum).padStart(3, " "), " ")),
4649
+ /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "#fcfca4ff" }, text))
4650
+ );
4651
+ }
4652
+ if (type === "code-fence-close") {
4653
+ return /* @__PURE__ */ React4.createElement(
4654
+ Box3,
4655
+ {
4656
+ flexDirection: "row",
4657
+ borderStyle: "single",
4658
+ borderLeft: true,
4659
+ borderRight: false,
4660
+ borderTop: false,
4661
+ borderBottom: false,
4662
+ borderColor: "#444444",
4663
+ paddingLeft: 2,
4664
+ marginBottom: 1,
4665
+ width: "100%"
4666
+ },
4667
+ /* @__PURE__ */ React4.createElement(Text4, null, " ")
4668
+ );
4669
+ }
4474
4670
  if (type === "write-header") {
4475
4671
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(MarkdownText, { text, columns }));
4476
4672
  }
@@ -4541,12 +4737,35 @@ var init_ChatLayout = __esm({
4541
4737
  // src/components/StatusBar.jsx
4542
4738
  import React5 from "react";
4543
4739
  import { Box as Box4, Text as Text5 } from "ink";
4740
+ import { useState as useState5, useEffect as useEffect4 } from "react";
4544
4741
  var StatusBar, StatusBar_default;
4545
4742
  var init_StatusBar = __esm({
4546
4743
  "src/components/StatusBar.jsx"() {
4547
4744
  init_text();
4548
4745
  StatusBar = React5.memo(({ mode, thinkingLevel, tokens = "0.0k", tokensTotal = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true, apiTier = "Free", aiProvider = "Google" }) => {
4549
4746
  const modeIcon = mode === "Flux" ? "" : "";
4747
+ const [memoryUsage, setMemoryUsage] = useState5(0);
4748
+ const [memoryLimit, setMemoryLimit] = useState5(0);
4749
+ const [memoryUnit, setMemoryUnit] = useState5("MB");
4750
+ useEffect4(() => {
4751
+ const getMemoryInfo = () => {
4752
+ const usage = process.memoryUsage();
4753
+ const isGB = usage.heapTotal / (1024 * 1024) >= 1024;
4754
+ const currentUnit = isGB ? "GB" : "MB";
4755
+ const formatToNumber = (bytes, toGB) => {
4756
+ const converted = bytes / (1024 * 1024 * (toGB ? 1024 : 1));
4757
+ return toGB ? parseFloat(converted.toFixed(2)) : Math.round(converted);
4758
+ };
4759
+ setMemoryUnit(currentUnit);
4760
+ setMemoryLimit(formatToNumber(usage.heapTotal, isGB));
4761
+ setMemoryUsage(formatToNumber(usage.heapUsed, isGB));
4762
+ };
4763
+ getMemoryInfo();
4764
+ const interval = setInterval(() => {
4765
+ getMemoryInfo();
4766
+ }, 3e3);
4767
+ return () => clearInterval(interval);
4768
+ }, []);
4550
4769
  let maxLimit = 256e3;
4551
4770
  if (aiProvider === "DeepSeek" || aiProvider === "Google" && apiTier === "Paid") {
4552
4771
  maxLimit = 4e5;
@@ -4561,7 +4780,7 @@ var init_StatusBar = __esm({
4561
4780
  },
4562
4781
  /* @__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
4782
  /* @__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"))))
4783
+ /* @__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
4784
  );
4566
4785
  });
4567
4786
  StatusBar_default = StatusBar;
@@ -4797,7 +5016,7 @@ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST A
4797
5016
  3. [tool:functions.FileMap(path="path/file")]. Shows file structure, functions, class, import/export, variable
4798
5017
  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
5018
  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
5019
+ 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
5020
  7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL ONLY` : `WINDOWS CMD ONLY` : `BASH`} command. Destructive/Irreversible ops -> Ask user
4802
5021
  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
5022
  1. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
@@ -5456,9 +5675,10 @@ ${finalOutput}`);
5456
5675
  });
5457
5676
 
5458
5677
  // src/components/SettingsMenu.jsx
5459
- import React7, { useState as useState5 } from "react";
5678
+ import React7, { useState as useState6, useEffect as useEffect5 } from "react";
5460
5679
  import { Box as Box6, Text as Text7, useInput as useInput3 } from "ink";
5461
5680
  import TextInput from "ink-text-input";
5681
+ import v8 from "v8";
5462
5682
  function SettingsMenu({
5463
5683
  systemSettings,
5464
5684
  setSystemSettings,
@@ -5470,11 +5690,34 @@ function SettingsMenu({
5470
5690
  setMessages,
5471
5691
  aiProvider
5472
5692
  }) {
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("");
5693
+ const [activeColumn, setActiveColumn] = useState6("categories");
5694
+ const [selectedCategoryIndex, setSelectedCategoryIndex] = useState6(0);
5695
+ const [selectedItemIndex, setSelectedItemIndex] = useState6(0);
5696
+ const [editingItem, setEditingItem] = useState6(null);
5697
+ const [editValue, setEditValue] = useState6("");
5698
+ const [currentMemory, setCurrentMemory] = useState6(0);
5699
+ const [maxMemory, setMaxMemory] = useState6(0);
5700
+ const [memoryUnit, setMemoryUnit] = useState6("MB");
5701
+ useEffect5(() => {
5702
+ const maxLimitBytes = v8.getHeapStatistics().heap_size_limit;
5703
+ const isGB = maxLimitBytes >= 1024 * 1024 * 1024;
5704
+ const unitLabel = isGB ? "GB" : "MB";
5705
+ const divisor = isGB ? 1024 * 1024 * 1024 : 1024 * 1024;
5706
+ setMaxMemory(parseFloat((maxLimitBytes / divisor).toFixed(2)));
5707
+ setMemoryUnit(unitLabel);
5708
+ const getMemoryStats = () => {
5709
+ const usage = process.memoryUsage();
5710
+ const targetBytes = usage.rss;
5711
+ const converted = targetBytes / divisor;
5712
+ const formattedCurrent = isGB ? parseFloat(converted.toFixed(2)) : Math.round(converted);
5713
+ setCurrentMemory(formattedCurrent);
5714
+ };
5715
+ getMemoryStats();
5716
+ const interval = setInterval(() => {
5717
+ getMemoryStats();
5718
+ }, 5e3);
5719
+ return () => clearInterval(interval);
5720
+ }, []);
5478
5721
  const getCategoryItems = (catId) => {
5479
5722
  switch (catId) {
5480
5723
  case "memory":
@@ -5734,7 +5977,10 @@ function SettingsMenu({
5734
5977
  });
5735
5978
  if (currentCatId === "other") {
5736
5979
  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"))
5980
+ /* @__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"))
5981
+ );
5982
+ elements.push(
5983
+ /* @__PURE__ */ React7.createElement(Box6, { key: "memory-load-2026", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "Memory Load: ", currentMemory, "/", maxMemory, " ", memoryUnit))
5738
5984
  );
5739
5985
  }
5740
5986
  if (hasConflict) {
@@ -5777,13 +6023,13 @@ var init_SettingsMenu = __esm({
5777
6023
  });
5778
6024
 
5779
6025
  // src/components/ProfileForm.jsx
5780
- import React8, { useState as useState6, useEffect as useEffect4 } from "react";
6026
+ import React8, { useState as useState7, useEffect as useEffect6 } from "react";
5781
6027
  import { Box as Box7, Text as Text8 } from "ink";
5782
6028
  import TextInput2 from "ink-text-input";
5783
6029
  function ProfileForm({ initialData, onSave, onCancel }) {
5784
- const [step, setStep] = useState6(0);
5785
- const [currentInput, setCurrentInput] = useState6("");
5786
- const [profile, setProfile] = useState6(() => ({
6030
+ const [step, setStep] = useState7(0);
6031
+ const [currentInput, setCurrentInput] = useState7("");
6032
+ const [profile, setProfile] = useState7(() => ({
5787
6033
  name: initialData?.name || "",
5788
6034
  nickname: initialData?.nickname || "",
5789
6035
  instructions: initialData?.instructions || ""
@@ -5793,7 +6039,7 @@ function ProfileForm({ initialData, onSave, onCancel }) {
5793
6039
  { key: "nickname", label: "Enter a Nickname (Agent will use this): " },
5794
6040
  { key: "instructions", label: "System Instructions (Persona overrides): " }
5795
6041
  ];
5796
- useEffect4(() => {
6042
+ useEffect6(() => {
5797
6043
  const currentKey = steps[step].key;
5798
6044
  setCurrentInput(profile[currentKey] || "");
5799
6045
  }, [step, profile]);
@@ -5841,7 +6087,7 @@ var init_ProfileForm = __esm({
5841
6087
  });
5842
6088
 
5843
6089
  // src/components/AskUserModal.jsx
5844
- import React9, { useState as useState7 } from "react";
6090
+ import React9, { useState as useState8 } from "react";
5845
6091
  import { Box as Box8, Text as Text9, useInput as useInput4 } from "ink";
5846
6092
  import TextInput3 from "ink-text-input";
5847
6093
  var AskUserModal, AskUserModal_default;
@@ -5849,9 +6095,9 @@ var init_AskUserModal = __esm({
5849
6095
  "src/components/AskUserModal.jsx"() {
5850
6096
  init_terminal();
5851
6097
  AskUserModal = ({ question, options, onResolve }) => {
5852
- const [isSuggestingElse, setIsSuggestingElse] = useState7(false);
5853
- const [customInput, setCustomInput] = useState7("");
5854
- const [selectedIndex, setSelectedIndex] = useState7(0);
6098
+ const [isSuggestingElse, setIsSuggestingElse] = useState8(false);
6099
+ const [customInput, setCustomInput] = useState8("");
6100
+ const [selectedIndex, setSelectedIndex] = useState8(0);
5855
6101
  const allOptions = [...options, { id: "CUSTOM", label: "Suggest something else...", description: "Provide a custom response" }];
5856
6102
  useInput4((input, key) => {
5857
6103
  if (isSuggestingElse) return;
@@ -6084,6 +6330,7 @@ ${projectContextBlock}
6084
6330
  -- FORMATTING --
6085
6331
  - GFM Supported
6086
6332
  - NO CHAT **AFTER** FIRING TOOLS IN CURRENT TURN
6333
+ - Short headsup about actions before firing tools
6087
6334
  - Task Complete & Results Verified? End response with summary of changes made and files edited
6088
6335
  - Basic LaTeX${mode === "Flux" ? "" : ". Kaomojis"}
6089
6336
  === END SYSTEM PROMPT ===`.trim();
@@ -6322,27 +6569,61 @@ var init_history = __esm({
6322
6569
  return nextLock;
6323
6570
  };
6324
6571
  loadHistory = async () => {
6572
+ await fs7.ensureDir(HISTORY_DIR);
6573
+ let history = {};
6325
6574
  if (await fs7.pathExists(HISTORY_FILE)) {
6326
6575
  try {
6327
- return readEncryptedJson(HISTORY_FILE, {});
6576
+ history = readEncryptedJson(HISTORY_FILE, {});
6328
6577
  } catch (e) {
6329
- return {};
6578
+ history = {};
6330
6579
  }
6331
6580
  }
6332
- return {};
6581
+ for (const id in history) {
6582
+ const chatFile = path6.join(HISTORY_DIR, `${id}.json`);
6583
+ Object.defineProperty(history[id], "messages", {
6584
+ get: () => {
6585
+ if (fs7.existsSync(chatFile)) {
6586
+ try {
6587
+ return readEncryptedJson(chatFile, []);
6588
+ } catch (e) {
6589
+ return [];
6590
+ }
6591
+ }
6592
+ return [];
6593
+ },
6594
+ set: (msgs) => {
6595
+ try {
6596
+ writeEncryptedJson(chatFile, msgs);
6597
+ } catch (e) {
6598
+ }
6599
+ },
6600
+ enumerable: false,
6601
+ configurable: true
6602
+ });
6603
+ }
6604
+ return history;
6333
6605
  };
6334
6606
  saveChat = async (id, name, messages) => {
6335
6607
  return withLock(async () => {
6608
+ await fs7.ensureDir(HISTORY_DIR);
6336
6609
  const history = await loadHistory();
6337
6610
  const existingChat = history[id];
6338
6611
  const persistentMessages = (messages || []).filter((m) => !m.isUpdateNotification && !m.isMeta);
6339
6612
  const finalName = name || (existingChat ? existingChat.name : `Session ${id.slice(-6)}`);
6613
+ const chatFile = path6.join(HISTORY_DIR, `${id}.json`);
6614
+ writeEncryptedJson(chatFile, persistentMessages);
6340
6615
  history[id] = {
6341
6616
  name: finalName,
6342
- messages: persistentMessages,
6343
6617
  updatedAt: Date.now()
6344
6618
  };
6345
- writeEncryptedJson(HISTORY_FILE, history);
6619
+ const indexHistory = {};
6620
+ for (const chatId in history) {
6621
+ indexHistory[chatId] = {
6622
+ name: history[chatId].name,
6623
+ updatedAt: history[chatId].updatedAt
6624
+ };
6625
+ }
6626
+ writeEncryptedJson(HISTORY_FILE, indexHistory);
6346
6627
  });
6347
6628
  };
6348
6629
  saveChatTitle = async (id, title) => {
@@ -6352,16 +6633,30 @@ var init_history = __esm({
6352
6633
  history[id].name = title;
6353
6634
  history[id].updatedAt = Date.now();
6354
6635
  } else {
6355
- history[id] = { name: title, messages: [], updatedAt: Date.now() };
6636
+ history[id] = { name: title, updatedAt: Date.now() };
6356
6637
  }
6357
- writeEncryptedJson(HISTORY_FILE, history);
6638
+ const indexHistory = {};
6639
+ for (const chatId in history) {
6640
+ indexHistory[chatId] = {
6641
+ name: history[chatId].name,
6642
+ updatedAt: history[chatId].updatedAt
6643
+ };
6644
+ }
6645
+ writeEncryptedJson(HISTORY_FILE, indexHistory);
6358
6646
  });
6359
6647
  };
6360
6648
  deleteChat = async (id) => {
6361
6649
  return withLock(async () => {
6362
6650
  const history = await loadHistory();
6363
6651
  delete history[id];
6364
- writeEncryptedJson(HISTORY_FILE, history);
6652
+ const indexHistory = {};
6653
+ for (const chatId in history) {
6654
+ indexHistory[chatId] = {
6655
+ name: history[chatId].name,
6656
+ updatedAt: history[chatId].updatedAt
6657
+ };
6658
+ }
6659
+ writeEncryptedJson(HISTORY_FILE, indexHistory);
6365
6660
  if (await fs7.pathExists(CONTEXT_FILE)) {
6366
6661
  try {
6367
6662
  const contextData = readEncryptedJson(CONTEXT_FILE, []);
@@ -6383,6 +6678,13 @@ var init_history = __esm({
6383
6678
  writeEncryptedJson(TEMP_MEM_CHAT_FILE, cache);
6384
6679
  }
6385
6680
  await RevertManager.deleteChatBackups(id);
6681
+ const chatFile = path6.join(HISTORY_DIR, `${id}.json`);
6682
+ if (await fs7.pathExists(chatFile)) {
6683
+ try {
6684
+ await fs7.remove(chatFile);
6685
+ } catch (e) {
6686
+ }
6687
+ }
6386
6688
  return history;
6387
6689
  });
6388
6690
  };
@@ -8085,8 +8387,10 @@ var init_search_keyword = __esm({
8085
8387
  "src/tools/search_keyword.js"() {
8086
8388
  init_arg_parser();
8087
8389
  search_keyword = async (args) => {
8088
- const { keyword, file } = parseArgs(args);
8390
+ const { keyword, file, subString } = parseArgs(args);
8089
8391
  if (!keyword) return 'ERROR: Missing "keyword" argument.';
8392
+ const matchSubstring = subString === true || subString === "true" || subString === 1 || subString === "1" || subString === "true";
8393
+ const wordRegex = new RegExp(`(?<![\\w])${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w])`, "i");
8090
8394
  const excludes = [
8091
8395
  "node_modules",
8092
8396
  ".git",
@@ -8126,7 +8430,8 @@ var init_search_keyword = __esm({
8126
8430
  const lines = content.split(/\r?\n/);
8127
8431
  const fileMatches = [];
8128
8432
  for (let i = 0; i < lines.length; i++) {
8129
- if (lines[i].includes(keyword)) {
8433
+ const matched = matchSubstring ? lines[i].toLowerCase().includes(keyword.toLowerCase()) : wordRegex.test(lines[i]);
8434
+ if (matched) {
8130
8435
  const displayPath = fileObj.relativePath.replace(/\\/g, "/");
8131
8436
  fileMatches.push(`${displayPath} \u2192 ${i + 1}`);
8132
8437
  }
@@ -8142,9 +8447,9 @@ var init_search_keyword = __esm({
8142
8447
  global.gc();
8143
8448
  }
8144
8449
  if (matches.length === 0) {
8145
- return `Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ". Try to specify files"}`;
8450
+ return `Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ". Try to specify files"} ${matchSubstring ? "(subString mode)" : ""}`;
8146
8451
  }
8147
- let output = `Found ${matches.length} matches:
8452
+ let output = `Found ${matches.length} matches ${matchSubstring ? "(subString mode)" : ""}:
8148
8453
 
8149
8454
  `;
8150
8455
  output += matches.join("\n");
@@ -9142,7 +9447,7 @@ var init_ai = __esm({
9142
9447
  colorMainWords = (label2) => {
9143
9448
  if (!label2) return label2;
9144
9449
  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`;
9450
+ return `${ansiBefore || ""}${icon}${ansiAfter || ""} \x1B[95m${word}\x1B[0m`;
9146
9451
  });
9147
9452
  };
9148
9453
  TERMINATION_SIGNAL = false;
@@ -9162,13 +9467,11 @@ var init_ai = __esm({
9162
9467
  "moonshotai/kimi-k2.6",
9163
9468
  // NVIDIA vision models
9164
9469
  "moonshotai/kimi-k2.6",
9470
+ "stepfun-ai/step-3.7-flash",
9471
+ "google/gemma-4-31b-it",
9472
+ "mistralai/mistral-medium-3.5-128b"
9165
9473
  // 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"
9474
+ // No need. All models on Gemini API is Multimodal
9172
9475
  ];
9173
9476
  isModelMultimodal = (model) => {
9174
9477
  if (!model) return false;
@@ -9232,7 +9535,7 @@ var init_ai = __esm({
9232
9535
  }
9233
9536
  return fetch(url, options);
9234
9537
  };
9235
- getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.85) {
9538
+ getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.99) {
9236
9539
  const messages = [];
9237
9540
  if (systemInstruction) {
9238
9541
  messages.push({ role: "system", content: systemInstruction });
@@ -9364,7 +9667,7 @@ var init_ai = __esm({
9364
9667
  }
9365
9668
  }
9366
9669
  };
9367
- getNVIDIAStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal = false, signal, temperature = 0.7) {
9670
+ getNVIDIAStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal = false, signal, temperature = 0.99) {
9368
9671
  const messages = [];
9369
9672
  if (systemInstruction) {
9370
9673
  messages.push({ role: "system", content: systemInstruction });
@@ -9380,7 +9683,7 @@ var init_ai = __esm({
9380
9683
  const mimeType = part.inlineData.mimeType;
9381
9684
  const data = part.inlineData.data;
9382
9685
  const isImage = mimeType.startsWith("image/");
9383
- if (isImage) {
9686
+ if (isImage && MULTIMODAL_MODELS.includes(model)) {
9384
9687
  msgContent.push({
9385
9688
  type: "image_url",
9386
9689
  image_url: {
@@ -9404,7 +9707,7 @@ var init_ai = __esm({
9404
9707
  "High": "High",
9405
9708
  "xHigh": "High"
9406
9709
  };
9407
- const apiLevel = thinkingLevelMap[thinkingLevel] || "Standard";
9710
+ const apiLevel = thinkingLevelMap[thinkingLevel] || "High";
9408
9711
  const isThinking = apiLevel !== "Fast";
9409
9712
  const isKimi = model.includes("kimi");
9410
9713
  const isGemma = model.includes("gemma");
@@ -9412,6 +9715,15 @@ var init_ai = __esm({
9412
9715
  const isGlm = model.includes("glm");
9413
9716
  const isMistral = model.includes("mistral");
9414
9717
  const isMinimax = model.includes("minimax");
9718
+ const isGPT = model.includes("gpt");
9719
+ const GPT_THINKING_LEVELS = {
9720
+ "Fast": "low",
9721
+ "Low": "low",
9722
+ "Medium": "medium",
9723
+ "Standard": "medium",
9724
+ "High": "high",
9725
+ "xHigh": "high"
9726
+ };
9415
9727
  const maxTokens = isMinimax || isDeepSeek ? 16384 : 32768;
9416
9728
  const body = {
9417
9729
  model,
@@ -9419,7 +9731,8 @@ var init_ai = __esm({
9419
9731
  max_tokens: maxTokens,
9420
9732
  stream: true,
9421
9733
  stream_options: { include_usage: true },
9422
- temperature
9734
+ temperature,
9735
+ ...isGPT && { thinking: GPT_THINKING_LEVELS[thinkingLevel] || "high" }
9423
9736
  };
9424
9737
  if (isKimi) {
9425
9738
  body.chat_template_kwargs = { thinking: isThinking };
@@ -9516,7 +9829,7 @@ var init_ai = __esm({
9516
9829
  }
9517
9830
  }
9518
9831
  };
9519
- getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.45) {
9832
+ getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.95) {
9520
9833
  const messages = [];
9521
9834
  if (systemInstruction) {
9522
9835
  messages.push({ role: "system", content: systemInstruction });
@@ -9763,7 +10076,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9763
10076
  mode,
9764
10077
  false,
9765
10078
  null,
9766
- 0.4
10079
+ 0.75
9767
10080
  );
9768
10081
  const iterator2 = stream[Symbol.asyncIterator]();
9769
10082
  const firstResult2 = await iterator2.next();
@@ -9779,7 +10092,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9779
10092
  mode,
9780
10093
  false,
9781
10094
  null,
9782
- 0.4
10095
+ 0.75
9783
10096
  );
9784
10097
  const iterator2 = stream[Symbol.asyncIterator]();
9785
10098
  const firstResult2 = await iterator2.next();
@@ -9795,7 +10108,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9795
10108
  mode,
9796
10109
  false,
9797
10110
  null,
9798
- 0.4
10111
+ 0.75
9799
10112
  );
9800
10113
  const iterator2 = stream[Symbol.asyncIterator]();
9801
10114
  const firstResult2 = await iterator2.next();
@@ -9807,7 +10120,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9807
10120
  config: {
9808
10121
  systemInstruction: janitorPrompt,
9809
10122
  maxOutputTokens: 512,
9810
- temperature: 0.4,
10123
+ temperature: 0.75,
9811
10124
  safetySettings: [
9812
10125
  { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
9813
10126
  { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
@@ -10227,7 +10540,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
10227
10540
  client = new GoogleGenAI({ apiKey });
10228
10541
  return client;
10229
10542
  };
10230
- generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast", temperature = 0.4) => {
10543
+ generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast", temperature = 0.75) => {
10231
10544
  const { aiProvider = "Google", apiKey, mode } = settings;
10232
10545
  let fullText = "";
10233
10546
  let usageMetadata = null;
@@ -10245,7 +10558,6 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
10245
10558
  contents: normalizedContents,
10246
10559
  config: {
10247
10560
  systemInstruction,
10248
- maxOutputTokens: 2048,
10249
10561
  temperature,
10250
10562
  thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MINIMAL }
10251
10563
  }
@@ -11162,6 +11474,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
11162
11474
  let isStutteringLoop = false;
11163
11475
  let isGeneralLoop = false;
11164
11476
  let isInitialAttempt = true;
11477
+ let lastLoopCheckLen = 0;
11165
11478
  let accumulatedContext = "";
11166
11479
  let dedupeBuffer = "";
11167
11480
  let isDedupeActive = false;
@@ -11266,7 +11579,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
11266
11579
  } else if (retryCount > 0) {
11267
11580
  yield { type: "model_update", content: null };
11268
11581
  }
11269
- currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, isMultiModal);
11582
+ currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, aiProvider === "Google" ? true : isMultiModal);
11270
11583
  const lastUserMsg = contents[contents.length - 1];
11271
11584
  if (isBridgeConnected() & loop > 0) {
11272
11585
  yield { type: "status", content: "Checking Code..." };
@@ -11314,7 +11627,7 @@ ${ideErr} [/ERROR]`;
11314
11627
  mode,
11315
11628
  isMultiModal,
11316
11629
  abortController.signal,
11317
- 0.45
11630
+ 0.95
11318
11631
  );
11319
11632
  } else if (aiProvider === "DeepSeek") {
11320
11633
  stream = getDeepSeekStream(
@@ -11326,7 +11639,7 @@ ${ideErr} [/ERROR]`;
11326
11639
  mode,
11327
11640
  isMultiModal,
11328
11641
  abortController.signal,
11329
- 0.85
11642
+ 0.99
11330
11643
  );
11331
11644
  } else if (aiProvider === "NVIDIA") {
11332
11645
  stream = getNVIDIAStream(
@@ -11338,7 +11651,7 @@ ${ideErr} [/ERROR]`;
11338
11651
  mode,
11339
11652
  isMultiModal,
11340
11653
  abortController.signal,
11341
- 0.7
11654
+ 0.99
11342
11655
  );
11343
11656
  } else {
11344
11657
  const apiCallPromise = client.models.generateContentStream({
@@ -11347,7 +11660,7 @@ ${ideErr} [/ERROR]`;
11347
11660
  config: {
11348
11661
  systemInstruction: currentSystemInstruction,
11349
11662
  mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
11350
- temperature: 1.05,
11663
+ temperature: 1,
11351
11664
  safetySettings: [
11352
11665
  { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
11353
11666
  { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
@@ -11641,7 +11954,6 @@ ${ideErr} [/ERROR]`;
11641
11954
  for (const m of msgs) yield m;
11642
11955
  }
11643
11956
  }
11644
- const signalSafeText3 = getSanitizedText(turnText);
11645
11957
  const toolContext = getActiveToolContext(turnText);
11646
11958
  if (toolContext.inside) {
11647
11959
  if (!lastToolEventTime) lastToolEventTime = Date.now();
@@ -11712,78 +12024,60 @@ ${ideErr} [/ERROR]`;
11712
12024
  }
11713
12025
  }
11714
12026
  }
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
- }
12027
+ if (turnText.length - lastLoopCheckLen > 150) {
12028
+ lastLoopCheckLen = turnText.length;
12029
+ const contextSafeText = getContextSafeText(turnText, false);
12030
+ const thinkBlocks = contextSafeText.match(/(?:<think>|\[think\])([\s\S]*?)(?:<\/think>|\[\/think\]|$)/gi) || [];
12031
+ const thinkContent = thinkBlocks.join("").trim();
12032
+ const sentences = thinkContent.split(/[.!?]\s+/);
12033
+ const uniqueSentences = new Set(sentences);
12034
+ const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
12035
+ const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
12036
+ let repetitionThresholdThinking = 0.4;
12037
+ let repetitionThresholdResponse = 0.6;
12038
+ let isOverVerboseThinking = false;
12039
+ if ((targetModel || "").toLowerCase().startsWith("gemma")) {
12040
+ const thinkingCaps = {
12041
+ "low": 256,
12042
+ "medium": 768,
12043
+ "high": 2048,
12044
+ "max": 4096,
12045
+ "xhigh": 4096
12046
+ };
12047
+ const cap = thinkingCaps[thinkingLevel?.toLowerCase()] || 2500;
12048
+ isOverVerboseThinking = wordCount > cap;
11774
12049
  }
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);
12050
+ if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
12051
+ const reason = repetitionRatio > repetitionThresholdThinking ? "Reasoning Loop Detected" : "Thinking Budget Exceeded";
12052
+ yield { type: "status", content: `${reason}. Re-centering...` };
12053
+ isThinkingLoop = true;
12054
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
12055
+ break;
12056
+ }
12057
+ const signalSafeText3 = getSanitizedText(turnText);
12058
+ const responseContent = signalSafeText3.trim();
12059
+ const respSentences = responseContent.split(/[.!?]\s+/);
12060
+ const uniqueRespSentences = new Set(respSentences);
12061
+ const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
12062
+ if (respRepetitionRatio > repetitionThresholdResponse) {
12063
+ yield { type: "status", content: `Response Loop Detected. Re-centering...` };
12064
+ isThinkingLoop = false;
12065
+ isGeneralLoop = true;
12066
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
12067
+ break;
12068
+ }
12069
+ const allWords = contextSafeText.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
12070
+ let stutterDetected = false;
12071
+ if (allWords.length > 5) {
12072
+ for (let p = 1; p <= 15; p++) {
12073
+ const R = Math.max(3, Math.ceil(8 / p));
12074
+ if (allWords.length < p * R) continue;
11783
12075
  let isRepeating = true;
12076
+ const pattern = allWords.slice(allWords.length - p);
12077
+ const patternStr = pattern.join(" ");
11784
12078
  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) {
12079
+ const prevPattern = allWords.slice(allWords.length - p * (r + 1), allWords.length - p * r);
12080
+ if (prevPattern.join(" ") !== patternStr) {
11787
12081
  isRepeating = false;
11788
12082
  break;
11789
12083
  }
@@ -11794,13 +12088,35 @@ ${ideErr} [/ERROR]`;
11794
12088
  }
11795
12089
  }
11796
12090
  }
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;
12091
+ if (!stutterDetected) {
12092
+ const cleanChars = contextSafeText.toLowerCase().replace(/[^a-z0-9]/gi, "");
12093
+ if (cleanChars.length >= 10) {
12094
+ for (let p = 1; p <= 10; p++) {
12095
+ const R = Math.max(4, Math.ceil(12 / p));
12096
+ if (cleanChars.length < p * R) continue;
12097
+ const pattern = cleanChars.substring(cleanChars.length - p);
12098
+ let isRepeating = true;
12099
+ for (let r = 1; r < R; r++) {
12100
+ const prevPattern = cleanChars.substring(cleanChars.length - p * (r + 1), cleanChars.length - p * r);
12101
+ if (prevPattern !== pattern) {
12102
+ isRepeating = false;
12103
+ break;
12104
+ }
12105
+ }
12106
+ if (isRepeating) {
12107
+ stutterDetected = true;
12108
+ break;
12109
+ }
12110
+ }
12111
+ }
12112
+ }
12113
+ if (stutterDetected) {
12114
+ yield { type: "status", content: `Stuttering Detected. Re-centering...` };
12115
+ isThinkingLoop = false;
12116
+ isStutteringLoop = true;
12117
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
12118
+ break;
12119
+ }
11804
12120
  }
11805
12121
  const toolActionableText = turnText.replace(/(?:<(think|thought|thoughts)>|\[(think|thought|thoughts)\])[\s\S]*?(?:<\/(think|thought|thoughts)>|\[\/(think|thought|thoughts)\]|$)/gi, "");
11806
12122
  const allToolsFound = detectToolCalls(toolActionableText);
@@ -12952,13 +13268,13 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
12952
13268
  });
12953
13269
 
12954
13270
  // src/components/ResumeModal.jsx
12955
- import React10, { useState as useState8, useEffect as useEffect5 } from "react";
13271
+ import React10, { useState as useState9, useEffect as useEffect7 } from "react";
12956
13272
  import { Box as Box9, Text as Text10, useInput as useInput5 } from "ink";
12957
13273
  function ResumeModal({ onSelect, onDelete, onClose }) {
12958
- const [history, setHistory] = useState8({});
12959
- const [keys, setKeys] = useState8([]);
12960
- const [selectedIndex, setSelectedIndex] = useState8(0);
12961
- useEffect5(() => {
13274
+ const [history, setHistory] = useState9({});
13275
+ const [keys, setKeys] = useState9([]);
13276
+ const [selectedIndex, setSelectedIndex] = useState9(0);
13277
+ useEffect7(() => {
12962
13278
  const fetchHistory = async () => {
12963
13279
  const h = await loadHistory();
12964
13280
  setHistory(h);
@@ -13044,14 +13360,14 @@ var init_ResumeModal = __esm({
13044
13360
  });
13045
13361
 
13046
13362
  // src/components/MemoryModal.jsx
13047
- import React11, { useState as useState9, useEffect as useEffect6 } from "react";
13363
+ import React11, { useState as useState10, useEffect as useEffect8 } from "react";
13048
13364
  import { Box as Box10, Text as Text11, useInput as useInput6, useStdout } from "ink";
13049
13365
  function MemoryModal({ onClose }) {
13050
13366
  const { stdout } = useStdout();
13051
13367
  const columns = stdout?.columns || 80;
13052
- const [memories, setMemories] = useState9([]);
13053
- const [selectedIndex, setSelectedIndex] = useState9(0);
13054
- const [isMemoryOn, setIsMemoryOn] = useState9(true);
13368
+ const [memories, setMemories] = useState10([]);
13369
+ const [selectedIndex, setSelectedIndex] = useState10(0);
13370
+ const [isMemoryOn, setIsMemoryOn] = useState10(true);
13055
13371
  const loadMemories = () => {
13056
13372
  const data = readEncryptedJson(MEMORIES_FILE, []);
13057
13373
  setMemories(data);
@@ -13063,7 +13379,7 @@ function MemoryModal({ onClose }) {
13063
13379
  setIsMemoryOn(true);
13064
13380
  }
13065
13381
  };
13066
- useEffect6(() => {
13382
+ useEffect8(() => {
13067
13383
  loadMemories();
13068
13384
  }, []);
13069
13385
  useInput6((input, key) => {
@@ -13165,7 +13481,7 @@ var init_MemoryModal = __esm({
13165
13481
  });
13166
13482
 
13167
13483
  // src/components/UpdateProcessor.jsx
13168
- import React12, { useState as useState10, useEffect as useEffect7 } from "react";
13484
+ import React12, { useState as useState11, useEffect as useEffect9 } from "react";
13169
13485
  import { Box as Box11, Text as Text12 } from "ink";
13170
13486
  import { spawn as spawn2 } from "child_process";
13171
13487
  var pty2, SPINNER_FRAMES, UpdateProcessor, UpdateProcessor_default;
@@ -13180,17 +13496,17 @@ var init_UpdateProcessor = __esm({
13180
13496
  }
13181
13497
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
13182
13498
  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(() => {
13499
+ const [status, setStatus] = useState11("initializing");
13500
+ const [log, setLog] = useState11("");
13501
+ const [error, setError] = useState11(null);
13502
+ const [tick, setTick] = useState11(0);
13503
+ useEffect9(() => {
13188
13504
  const interval = setInterval(() => {
13189
13505
  setTick((t) => (t + 1) % 1e3);
13190
13506
  }, 33);
13191
13507
  return () => clearInterval(interval);
13192
13508
  }, []);
13193
- useEffect7(() => {
13509
+ useEffect9(() => {
13194
13510
  let child;
13195
13511
  const runUpdate = async () => {
13196
13512
  const manager = settings.updateManager || "npm";
@@ -13323,12 +13639,12 @@ var init_UpdateProcessor = __esm({
13323
13639
  });
13324
13640
 
13325
13641
  // src/components/ParserDownloadModal.jsx
13326
- import React13, { useState as useState11, useEffect as useEffect8 } from "react";
13642
+ import React13, { useState as useState12, useEffect as useEffect10 } from "react";
13327
13643
  import { Box as Box12, Text as Text13, useInput as useInput7 } from "ink";
13328
13644
  function ParserDownloadModal({ onClose }) {
13329
- const [selectedIndex, setSelectedIndex] = useState11(0);
13330
- const [status, setStatus] = useState11({});
13331
- useEffect8(() => {
13645
+ const [selectedIndex, setSelectedIndex] = useState12(0);
13646
+ const [status, setStatus] = useState12({});
13647
+ useEffect10(() => {
13332
13648
  const initialStatus = {};
13333
13649
  EXTENSIONS.forEach((item) => {
13334
13650
  if (isParserInstalled(item.file)) {
@@ -13829,10 +14145,10 @@ var init_dist = __esm({
13829
14145
  });
13830
14146
 
13831
14147
  // src/components/RevertModal.jsx
13832
- import React14, { useState as useState12 } from "react";
14148
+ import React14, { useState as useState13 } from "react";
13833
14149
  import { Box as Box14, Text as Text15, useInput as useInput8 } from "ink";
13834
14150
  function RevertModal({ prompts, onSelect, onClose }) {
13835
- const [selectedIndex, setSelectedIndex] = useState12(0);
14151
+ const [selectedIndex, setSelectedIndex] = useState13(0);
13836
14152
  useInput8((input, key) => {
13837
14153
  if (key.escape) onClose();
13838
14154
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
@@ -13955,7 +14271,7 @@ __export(app_exports, {
13955
14271
  default: () => App
13956
14272
  });
13957
14273
  import os4 from "os";
13958
- import React15, { useState as useState13, useEffect as useEffect9, useRef as useRef3, useMemo as useMemo2 } from "react";
14274
+ import React15, { useState as useState14, useEffect as useEffect11, useRef as useRef3, useMemo as useMemo2 } from "react";
13959
14275
  import { Box as Box15, Text as Text16, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
13960
14276
  import fs22 from "fs-extra";
13961
14277
  import path20 from "path";
@@ -13965,24 +14281,24 @@ import TextInput4 from "ink-text-input";
13965
14281
  import SelectInput2 from "ink-select-input";
13966
14282
  import gradient2 from "gradient-string";
13967
14283
  function App({ args = [] }) {
13968
- const [confirmExit, setConfirmExit] = useState13(false);
13969
- const [exitCountdown, setExitCountdown] = useState13(10);
14284
+ const [confirmExit, setConfirmExit] = useState14(false);
14285
+ const [exitCountdown, setExitCountdown] = useState14(10);
13970
14286
  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({
14287
+ const [input, setInput] = useState14("");
14288
+ const [inputKey, setInputKey] = useState14(0);
14289
+ const [isExpanded, setIsExpanded] = useState14(false);
14290
+ const [mode, setMode] = useState14("Flux");
14291
+ const [terminalSize, setTerminalSize] = useState14({
13976
14292
  columns: stdout?.columns || 80,
13977
14293
  rows: stdout?.rows || 24
13978
14294
  });
13979
- const [selectedIndex, setSelectedIndex] = useState13(0);
13980
- const [isFilePickerDismissed, setIsFilePickerDismissed] = useState13(false);
13981
- const [showBridgePromo, setShowBridgePromo] = useState13(false);
13982
- const [promoSelectedIndex, setPromoSelectedIndex] = useState13(0);
14295
+ const [selectedIndex, setSelectedIndex] = useState14(0);
14296
+ const [isFilePickerDismissed, setIsFilePickerDismissed] = useState14(false);
14297
+ const [showBridgePromo, setShowBridgePromo] = useState14(false);
14298
+ const [promoSelectedIndex, setPromoSelectedIndex] = useState14(0);
13983
14299
  const suggestionOffsetRef = useRef3(0);
13984
14300
  const persistedModelRef = useRef3(null);
13985
- useEffect9(() => {
14301
+ useEffect11(() => {
13986
14302
  const ideName = getIDEName();
13987
14303
  const isIDE = !["Terminal", "Windows Terminal"].includes(ideName) || !!process.env.VSC_TERMINAL_URL;
13988
14304
  const graceTimer = setTimeout(() => {
@@ -14157,7 +14473,7 @@ function App({ args = [] }) {
14157
14473
  }
14158
14474
  }
14159
14475
  };
14160
- useEffect9(() => {
14476
+ useEffect11(() => {
14161
14477
  const handleResize = () => {
14162
14478
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
14163
14479
  setTerminalSize({
@@ -14170,18 +14486,18 @@ function App({ args = [] }) {
14170
14486
  stdout.off("resize", handleResize);
14171
14487
  };
14172
14488
  }, [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);
14489
+ const [thinkingLevel, setThinkingLevel] = useState14("Medium");
14490
+ const [aiProvider, setAiProvider] = useState14("Google");
14491
+ const [setupStep, setSetupStep] = useState14(0);
14492
+ const [latestVer, setLatestVer] = useState14(null);
14493
+ const [showFullThinking, setShowFullThinking] = useState14(false);
14494
+ const [activeModel, setActiveModel] = useState14("gemma-4-31b-it");
14495
+ const [janitorModel, setJanitorModel] = useState14("gemma-4-26b-a4b-it");
14496
+ const [isInitializing, setIsInitializing] = useState14(true);
14497
+ const [isAppFocused, setIsAppFocused] = useState14(true);
14182
14498
  const lastFocusEventTime = useRef3(0);
14183
- const [apiKey, setApiKey] = useState13(null);
14184
- const [tempKey, setTempKey] = useState13("");
14499
+ const [apiKey, setApiKey] = useState14(null);
14500
+ const [tempKey, setTempKey] = useState14("");
14185
14501
  const addShiftEnterBinding = async (ideName) => {
14186
14502
  const kbPath = getKeybindingsPath(ideName);
14187
14503
  if (!kbPath) return;
@@ -14232,35 +14548,35 @@ function App({ args = [] }) {
14232
14548
  });
14233
14549
  }
14234
14550
  };
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);
14551
+ const [activeView, setActiveView] = useState14("chat");
14552
+ const [apiTier, setApiTier] = useState14("Free");
14553
+ const [quotas, setQuotas] = useState14({ limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
14554
+ const [inputConfig, setInputConfig] = useState14(null);
14555
+ const [systemSettings, setSystemSettings] = useState14({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
14556
+ const [profileData, setProfileData] = useState14({ name: null, nickname: null, instructions: null });
14557
+ const [imageSettings, setImageSettings] = useState14({ keyType: "Default", quality: "Low-High", apiKey: "" });
14558
+ const [sessionStats, setSessionStats] = useState14({ tokens: 0 });
14559
+ const [sessionAgentCalls, setSessionAgentCalls] = useState14(0);
14560
+ const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState14(0);
14561
+ const [sessionTotalTokens, setSessionTotalTokens] = useState14(0);
14562
+ const [chatTokens, setChatTokens] = useState14(0);
14247
14563
  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");
14564
+ const [sessionTotalCachedTokens, setSessionTotalCachedTokens] = useState14(0);
14565
+ const [sessionTotalCandidateTokens, setSessionTotalCandidateTokens] = useState14(0);
14566
+ const [sessionToolSuccess, setSessionToolSuccess] = useState14(0);
14567
+ const [sessionToolFailure, setSessionToolFailure] = useState14(0);
14568
+ const [sessionToolDenied, setSessionToolDenied] = useState14(0);
14569
+ const [sessionApiTime, setSessionApiTime] = useState14(0);
14570
+ const [sessionToolTime, setSessionToolTime] = useState14(0);
14571
+ const [sessionImageCount, setSessionImageCount] = useState14(0);
14572
+ const [sessionImageCredits, setSessionImageCredits] = useState14(0);
14573
+ const [dailyUsage, setDailyUsage] = useState14(null);
14574
+ const [monthlyUsage, setMonthlyUsage] = useState14(null);
14575
+ const [customPeriodUsage, setCustomPeriodUsage] = useState14(null);
14576
+ const [statsMode, setStatsMode] = useState14("daily");
14261
14577
  const PLAYGROUND_CHAT_ID = "flow-playground";
14262
- const [chatId, setChatId] = useState13(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
14263
- useEffect9(() => {
14578
+ const [chatId, setChatId] = useState14(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
14579
+ useEffect11(() => {
14264
14580
  const nextTokens = sessionTotalTokens - chatTokenStartRef.current;
14265
14581
  setChatTokens(nextTokens);
14266
14582
  if (chatId) {
@@ -14268,7 +14584,7 @@ function App({ args = [] }) {
14268
14584
  });
14269
14585
  }
14270
14586
  }, [sessionTotalTokens, chatId, sessionStats.tokens]);
14271
- useEffect9(() => {
14587
+ useEffect11(() => {
14272
14588
  if (activeView === "apiTier") {
14273
14589
  const load = async () => {
14274
14590
  const d = await getDailyUsage();
@@ -14281,17 +14597,17 @@ function App({ args = [] }) {
14281
14597
  load();
14282
14598
  }
14283
14599
  }, [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);
14600
+ const [activeCommand, setActiveCommand] = useState14(null);
14601
+ const [execOutput, setExecOutput] = useState14("");
14602
+ const [isTerminalFocused, setIsTerminalFocused] = useState14(false);
14603
+ const [tick, setTick] = useState14(0);
14288
14604
  const isFirstRender = useRef3(true);
14289
14605
  const isSecondRender = useRef3(true);
14290
14606
  const isThirdRender = useRef3(true);
14291
14607
  const prevProviderRef = useRef3(aiProvider);
14292
14608
  const originalAllowExternalAccessRef = useRef3(false);
14293
14609
  const originalMemoryRef = useRef3(true);
14294
- useEffect9(() => {
14610
+ useEffect11(() => {
14295
14611
  if (prevProviderRef.current !== aiProvider) {
14296
14612
  prevProviderRef.current = aiProvider;
14297
14613
  const hasStandard = aiProvider === "DeepSeek" || aiProvider === "NVIDIA";
@@ -14304,7 +14620,7 @@ function App({ args = [] }) {
14304
14620
  }
14305
14621
  }
14306
14622
  }, [aiProvider, activeModel, thinkingLevel]);
14307
- useEffect9(() => {
14623
+ useEffect11(() => {
14308
14624
  if (!apiKey) return;
14309
14625
  if (isFirstRender.current) {
14310
14626
  isFirstRender.current = false;
@@ -14378,15 +14694,15 @@ function App({ args = [] }) {
14378
14694
  }, []);
14379
14695
  const activeCommandRef = useRef3(null);
14380
14696
  const execOutputRef = useRef3("");
14381
- useEffect9(() => {
14697
+ useEffect11(() => {
14382
14698
  activeCommandRef.current = activeCommand;
14383
14699
  }, [activeCommand]);
14384
- useEffect9(() => {
14700
+ useEffect11(() => {
14385
14701
  execOutputRef.current = execOutput;
14386
14702
  }, [execOutput]);
14387
- const [autoAcceptWrites, setAutoAcceptWrites] = useState13(false);
14388
- const [pendingApproval, setPendingApproval] = useState13(null);
14389
- const [pendingAsk, setPendingAsk] = useState13(null);
14703
+ const [autoAcceptWrites, setAutoAcceptWrites] = useState14(false);
14704
+ const [pendingApproval, setPendingApproval] = useState14(null);
14705
+ const [pendingAsk, setPendingAsk] = useState14(null);
14390
14706
  const resetPendingApproval = (decision) => {
14391
14707
  setPendingApproval(null);
14392
14708
  setActiveView("chat");
@@ -14405,10 +14721,10 @@ function App({ args = [] }) {
14405
14721
  if (ms < 1e3) return `${ms}ms`;
14406
14722
  return formatDuration(Math.floor(ms / 1e3));
14407
14723
  };
14408
- const [statusText, setStatusText] = useState13(null);
14409
- const [wittyPhrase, setWittyPhrase] = useState13("");
14410
- const [hasPasteBlock, setHasPasteBlock] = useState13(false);
14411
- useEffect9(() => {
14724
+ const [statusText, setStatusText] = useState14(null);
14725
+ const [wittyPhrase, setWittyPhrase] = useState14("");
14726
+ const [hasPasteBlock, setHasPasteBlock] = useState14(false);
14727
+ useEffect11(() => {
14412
14728
  let interval;
14413
14729
  if (statusText) {
14414
14730
  const updatePhrase = () => {
@@ -14422,20 +14738,20 @@ function App({ args = [] }) {
14422
14738
  }
14423
14739
  return () => clearInterval(interval);
14424
14740
  }, [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([]);
14741
+ const [isSpinnerActive, setIsSpinnerActive] = useState14(true);
14742
+ const [isProcessing, setIsProcessing] = useState14(false);
14743
+ const [isCompressing, setIsCompressing] = useState14(false);
14744
+ const [escPressed, setEscPressed] = useState14(false);
14745
+ const [escTimer, setEscTimer] = useState14(null);
14746
+ const [escPressCount, setEscPressCount] = useState14(0);
14747
+ const [recentPrompts, setRecentPrompts] = useState14([]);
14432
14748
  const escDoubleTimerRef = useRef3(null);
14433
14749
  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(() => {
14750
+ const [queuedPrompt, setQueuedPrompt] = useState14(null);
14751
+ const [resolutionData, setResolutionData] = useState14(null);
14752
+ const [tempModelOverride, setTempModelOverride] = useState14(null);
14753
+ useEffect11(() => setEscPressCount(0), [input]);
14754
+ const [messages, rawSetMessages] = useState14(() => {
14439
14755
  const logoMsg = { id: "logo-" + Date.now(), role: "system", isLogo: true, isMeta: true };
14440
14756
  const isHomeDir = process.cwd() === os4.homedir();
14441
14757
  const isSystemDir = (() => {
@@ -14473,24 +14789,22 @@ function App({ args = [] }) {
14473
14789
  const setMessages = (value) => {
14474
14790
  rawSetMessages((prev) => {
14475
14791
  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;
14792
+ if (next.length > 1) {
14793
+ const last = next[next.length - 1];
14794
+ const secondLast = next[next.length - 2];
14795
+ if (last?.text?.includes("Request Cancelled") && secondLast?.text?.includes("Request Cancelled")) {
14796
+ return next.slice(0, -1);
14482
14797
  }
14483
- cleaned.push(msg);
14484
14798
  }
14485
- return cleaned;
14799
+ return next;
14486
14800
  });
14487
14801
  };
14488
14802
  const queuedPromptRef = useRef3(null);
14489
- const [btwResponse, setBtwResponse] = useState13("");
14490
- const [showBtwBox, setShowBtwBox] = useState13(false);
14803
+ const [btwResponse, setBtwResponse] = useState14("");
14804
+ const [showBtwBox, setShowBtwBox] = useState14(false);
14491
14805
  const btwResponseRef = useRef3("");
14492
14806
  const btwClosedRef = useRef3(null);
14493
- useEffect9(() => {
14807
+ useEffect11(() => {
14494
14808
  if (messages.length === 0) return;
14495
14809
  const lastMsg = messages[messages.length - 1];
14496
14810
  if (lastMsg && (lastMsg.role === "agent" || lastMsg.role === "assistant")) {
@@ -14508,59 +14822,105 @@ function App({ args = [] }) {
14508
14822
  }
14509
14823
  }
14510
14824
  }, [messages]);
14511
- const [completedIndex, setCompletedIndex] = useState13(messages.length);
14512
- const [clearKey, setClearKey] = useState13(0);
14825
+ const [completedIndex, setCompletedIndex] = useState14(messages.length);
14826
+ const [clearKey, setClearKey] = useState14(0);
14827
+ const lastCompletedBlocksRef = useRef3([]);
14828
+ const cachedHistoryRef = useRef3({
14829
+ completedIndex: 0,
14830
+ columns: 0,
14831
+ historicalBlocks: [],
14832
+ seenSelections: /* @__PURE__ */ new Set()
14833
+ });
14513
14834
  const parsedBlocks = useMemo2(() => {
14514
- const completed = [];
14515
- const active = [];
14516
14835
  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
- }
14836
+ const SELECTION_REGEX = /Selection: (.*)/;
14837
+ let historicalBlocks = [];
14838
+ let seenAskSelections = /* @__PURE__ */ new Set();
14839
+ const isResize = cachedHistoryRef.current.columns !== columns;
14840
+ const isClear = completedIndex < cachedHistoryRef.current.completedIndex;
14841
+ if (isResize || isClear) {
14842
+ const completedMsgs = messages.slice(0, completedIndex);
14843
+ for (let i = 0; i < completedMsgs.length; i++) {
14844
+ const msg = completedMsgs[i];
14845
+ if (msg.isAskRecord && msg.text) {
14846
+ const match = msg.text.match(SELECTION_REGEX);
14847
+ if (match && match[1].trim()) {
14848
+ const selection = match[1].trim();
14849
+ if (seenAskSelections.has(selection)) continue;
14529
14850
  seenAskSelections.add(selection);
14530
14851
  }
14531
14852
  }
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) => {
14853
+ const parsed = parseMessageToBlocks(msg, columns);
14854
+ for (let j = 0; j < parsed.completed.length; j++) historicalBlocks.push(parsed.completed[j]);
14855
+ for (let j = 0; j < parsed.active.length; j++) historicalBlocks.push(parsed.active[j]);
14856
+ }
14857
+ cachedHistoryRef.current = {
14858
+ completedIndex,
14859
+ columns,
14860
+ historicalBlocks,
14861
+ seenSelections: new Set(seenAskSelections)
14862
+ };
14863
+ } else {
14864
+ historicalBlocks = cachedHistoryRef.current.historicalBlocks;
14865
+ seenAskSelections = cachedHistoryRef.current.seenSelections;
14866
+ if (completedIndex > cachedHistoryRef.current.completedIndex) {
14867
+ historicalBlocks = [...historicalBlocks];
14868
+ seenAskSelections = new Set(seenAskSelections);
14869
+ const newMsgs = messages.slice(cachedHistoryRef.current.completedIndex, completedIndex);
14870
+ for (let i = 0; i < newMsgs.length; i++) {
14871
+ const msg = newMsgs[i];
14872
+ if (msg.isAskRecord && msg.text) {
14873
+ const match = msg.text.match(SELECTION_REGEX);
14874
+ if (match && match[1].trim()) {
14875
+ const selection = match[1].trim();
14876
+ if (seenAskSelections.has(selection)) continue;
14877
+ seenAskSelections.add(selection);
14878
+ }
14879
+ }
14880
+ const parsed = parseMessageToBlocks(msg, columns);
14881
+ for (let j = 0; j < parsed.completed.length; j++) historicalBlocks.push(parsed.completed[j]);
14882
+ for (let j = 0; j < parsed.active.length; j++) historicalBlocks.push(parsed.active[j]);
14883
+ }
14884
+ cachedHistoryRef.current = {
14885
+ completedIndex,
14886
+ columns,
14887
+ historicalBlocks,
14888
+ seenSelections: seenAskSelections
14889
+ };
14890
+ }
14891
+ }
14892
+ const activeMsgs = messages.slice(completedIndex);
14893
+ const streamingCompletedBlocks = [];
14894
+ const activeBlocks = [];
14895
+ for (let i = 0; i < activeMsgs.length; i++) {
14896
+ const msg = activeMsgs[i];
14897
+ if (msg.isAskRecord && msg.text) {
14898
+ const match = msg.text.match(SELECTION_REGEX);
14899
+ if (match && match[1].trim()) {
14900
+ const selection = match[1].trim();
14901
+ if (seenAskSelections.has(selection)) continue;
14902
+ }
14903
+ }
14543
14904
  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",
14905
+ for (let j = 0; j < parsed.completed.length; j++) streamingCompletedBlocks.push(parsed.completed[j]);
14906
+ for (let j = 0; j < parsed.active.length; j++) activeBlocks.push(parsed.active[j]);
14907
+ }
14908
+ const finalCompleted = historicalBlocks.concat(streamingCompletedBlocks);
14909
+ if (finalCompleted.length >= 75e3) {
14910
+ finalCompleted.push({
14911
+ key: `memory-warning-block-${finalCompleted.length}`,
14552
14912
  msg: {
14553
14913
  role: "system",
14554
14914
  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.`,
14915
+ 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
14916
  isHomeWarning: true
14557
14917
  },
14558
14918
  type: "full-message"
14559
14919
  });
14560
14920
  }
14561
14921
  return {
14562
- completed: slicedCompleted,
14563
- active
14922
+ completed: finalCompleted,
14923
+ active: activeBlocks
14564
14924
  };
14565
14925
  }, [messages, completedIndex, terminalSize.columns]);
14566
14926
  const isTerminalWaitingForInput = useMemo2(() => {
@@ -14749,7 +15109,7 @@ function App({ args = [] }) {
14749
15109
  setInput((prev) => prev.replace(/\\\r?$/, "").replace(/\r?$/, "") + "\n");
14750
15110
  }
14751
15111
  });
14752
- useEffect9(() => {
15112
+ useEffect11(() => {
14753
15113
  process.stdout.write("\x1B[?1004h");
14754
15114
  const onData = (data) => {
14755
15115
  const str = data.toString();
@@ -14767,7 +15127,7 @@ function App({ args = [] }) {
14767
15127
  process.stdin.off("data", onData);
14768
15128
  };
14769
15129
  }, []);
14770
- useEffect9(() => {
15130
+ useEffect11(() => {
14771
15131
  async function init() {
14772
15132
  try {
14773
15133
  const pkg = JSON.parse(fs22.readFileSync(path20.join(process.cwd(), "package.json"), "utf8"));
@@ -14986,7 +15346,7 @@ function App({ args = [] }) {
14986
15346
  }
14987
15347
  init();
14988
15348
  }, []);
14989
- useEffect9(() => {
15349
+ useEffect11(() => {
14990
15350
  let timer;
14991
15351
  if (confirmExit) {
14992
15352
  setExitCountdown(10);
@@ -15004,7 +15364,7 @@ function App({ args = [] }) {
15004
15364
  if (timer) clearInterval(timer);
15005
15365
  };
15006
15366
  }, [confirmExit]);
15007
- useEffect9(() => {
15367
+ useEffect11(() => {
15008
15368
  if (!isInitializing) {
15009
15369
  const modelToSave = parsedArgs.model && activeModel === parsedArgs.model ? persistedModelRef.current : activeModel;
15010
15370
  let settingsToSave = systemSettings;
@@ -15054,7 +15414,7 @@ function App({ args = [] }) {
15054
15414
  }
15055
15415
  };
15056
15416
  const lastSavedTimeRef = useRef3(SESSION_START_TIME);
15057
- useEffect9(() => {
15417
+ useEffect11(() => {
15058
15418
  if (activeView === "exit") {
15059
15419
  const flush = async () => {
15060
15420
  const now = Date.now();
@@ -15072,7 +15432,7 @@ function App({ args = [] }) {
15072
15432
  return () => clearTimeout(timer);
15073
15433
  }
15074
15434
  }, [activeView]);
15075
- useEffect9(() => {
15435
+ useEffect11(() => {
15076
15436
  const interval = setInterval(async () => {
15077
15437
  if (!isInitializing) {
15078
15438
  const now = Date.now();
@@ -15082,7 +15442,7 @@ function App({ args = [] }) {
15082
15442
  lastSavedTimeRef.current += deltaSecs * 1e3;
15083
15443
  }
15084
15444
  }
15085
- }, 1500);
15445
+ }, 2e3);
15086
15446
  return () => clearInterval(interval);
15087
15447
  }, [isInitializing]);
15088
15448
  const COMMANDS = [
@@ -15098,32 +15458,6 @@ function App({ args = [] }) {
15098
15458
  { cmd: "/export", desc: "Export current chat in a .txt file" },
15099
15459
  { cmd: "/chats", desc: "List all chat sessions" },
15100
15460
  { 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
15461
  {
15128
15462
  cmd: "/mode",
15129
15463
  desc: "Toggle Flux/Flow modes",
@@ -15142,7 +15476,7 @@ function App({ args = [] }) {
15142
15476
  ] : aiProvider === "NVIDIA" ? [
15143
15477
  { cmd: "Fast", desc: "Reasoning Disabled" },
15144
15478
  { cmd: "Standard", desc: "Balanced Reasoning" },
15145
- { cmd: "High", desc: "Reasoning Enabled" }
15479
+ { cmd: "High", desc: "Deep Reasoning" }
15146
15480
  ] : aiProvider === "OpenRouter" ? [
15147
15481
  { cmd: "Fast", desc: "Fastest" },
15148
15482
  { cmd: "Low", desc: "Quick Reasoning" },
@@ -15165,7 +15499,7 @@ function App({ args = [] }) {
15165
15499
  },
15166
15500
  {
15167
15501
  cmd: "/model",
15168
- desc: "Switch Model for Agent",
15502
+ desc: "Select Agent Model",
15169
15503
  subs: aiProvider === "OpenRouter" ? apiTier === "Free" ? [
15170
15504
  {
15171
15505
  cmd: "google/gemma-4-31b-it:free",
@@ -15177,11 +15511,11 @@ function App({ args = [] }) {
15177
15511
  },
15178
15512
  {
15179
15513
  cmd: "qwen/qwen3-coder:free",
15180
- desc: ""
15514
+ desc: "Text Only"
15181
15515
  },
15182
15516
  {
15183
15517
  cmd: "z-ai/glm-4.5-air:free",
15184
- desc: ""
15518
+ desc: "Text Only"
15185
15519
  }
15186
15520
  ] : [
15187
15521
  {
@@ -15210,19 +15544,19 @@ function App({ args = [] }) {
15210
15544
  },
15211
15545
  {
15212
15546
  cmd: "deepseek/deepseek-v4-pro",
15213
- desc: ""
15547
+ desc: "Text Only"
15214
15548
  },
15215
15549
  {
15216
15550
  cmd: "deepseek/deepseek-v4-flash",
15217
- desc: ""
15551
+ desc: "Text Only"
15218
15552
  },
15219
15553
  {
15220
15554
  cmd: "xiaomi/mimo-v2.5-pro",
15221
- desc: ""
15555
+ desc: "Text Only"
15222
15556
  },
15223
15557
  {
15224
15558
  cmd: "z-ai/glm-5",
15225
- desc: ""
15559
+ desc: "Text Only"
15226
15560
  },
15227
15561
  {
15228
15562
  cmd: "openai/gpt-5.2-codex",
@@ -15243,106 +15577,122 @@ function App({ args = [] }) {
15243
15577
  ] : aiProvider === "DeepSeek" ? [
15244
15578
  {
15245
15579
  cmd: "deepseek-v4-flash",
15246
- desc: "Fast & Efficient"
15580
+ desc: "Fast & Efficient (Text Only)"
15247
15581
  },
15248
15582
  {
15249
15583
  cmd: "deepseek-v4-pro",
15250
- desc: "High-Intelligence Reasoning"
15584
+ desc: "High-Intelligence Reasoning (Text Only)"
15251
15585
  }
15252
15586
  ] : aiProvider === "NVIDIA" ? [
15587
+ // --- Kimi (Moonshot AI) ---
15253
15588
  {
15254
15589
  cmd: "moonshotai/kimi-k2.6",
15255
15590
  desc: "Multimodal"
15256
15591
  },
15592
+ // --- DeepSeek Family ---
15257
15593
  {
15258
- cmd: "google/gemma-4-31b-it",
15259
- desc: ""
15594
+ cmd: "deepseek-ai/deepseek-v4-flash",
15595
+ desc: "Text Only"
15260
15596
  },
15261
15597
  {
15262
- cmd: "stepfun-ai/step-3.7-flash",
15263
- desc: ""
15598
+ cmd: "deepseek-ai/deepseek-v4-pro",
15599
+ desc: "Text Only"
15264
15600
  },
15601
+ // --- StepFun ---
15265
15602
  {
15266
- cmd: "minimaxai/minimax-m2.7",
15267
- desc: ""
15603
+ cmd: "stepfun-ai/step-3.7-flash",
15604
+ desc: "Multimodal"
15268
15605
  },
15606
+ // --- Gemma Family (Google) ---
15269
15607
  {
15270
- cmd: "deepseek-ai/deepseek-v4-flash",
15271
- desc: ""
15608
+ cmd: "google/gemma-4-31b-it",
15609
+ desc: "Multimodal"
15272
15610
  },
15273
15611
  {
15274
- cmd: "deepseek-ai/deepseek-v4-pro",
15275
- desc: ""
15612
+ cmd: "google/diffusiongemma-26b-a4b-it",
15613
+ desc: "Mega Fast [Experimental]"
15276
15614
  },
15615
+ // --- Mistral ---
15277
15616
  {
15278
15617
  cmd: "mistralai/mistral-medium-3.5-128b",
15279
- desc: ""
15618
+ desc: "Multimodal"
15619
+ },
15620
+ // --- GPT Open Source Series (OpenAI) ---
15621
+ {
15622
+ cmd: "openai/gpt-oss-20b",
15623
+ desc: "Text Only"
15624
+ },
15625
+ {
15626
+ cmd: "openai/gpt-oss-120b",
15627
+ desc: "Text Only"
15280
15628
  },
15629
+ // --- GLM (Zhipu AI) ---
15281
15630
  {
15282
15631
  cmd: "z-ai/glm-5.1",
15283
- desc: ""
15632
+ desc: "Text Only"
15284
15633
  },
15634
+ // --- MiniMax Family ---
15285
15635
  {
15286
- cmd: "google/diffusiongemma-26b-a4b-it",
15287
- desc: "Mega Fast [Experimental]"
15636
+ cmd: "minimaxai/minimax-m2.7",
15637
+ desc: "Text Only"
15288
15638
  },
15289
15639
  {
15290
15640
  cmd: "minimaxai/minimax-m3",
15291
- desc: ""
15641
+ desc: "Text Only"
15292
15642
  }
15293
15643
  ] : apiTier === "Free" ? [
15294
15644
  {
15295
15645
  cmd: "gemma-4-26b-a4b-it",
15296
- desc: "Standard & Faster"
15646
+ desc: "Standard & Faster (Multimodal)"
15297
15647
  },
15298
15648
  {
15299
15649
  cmd: "gemma-4-31b-it",
15300
- desc: "Standard Default"
15650
+ desc: "Standard Default (Multimodal)"
15301
15651
  },
15302
15652
  {
15303
15653
  cmd: "gemini-2.5-flash-lite",
15304
- desc: "Fast & Cheap (Limited Free Quota)"
15654
+ desc: "Fast & Cheap (Multimodal) [Limited Free Quota]"
15305
15655
  },
15306
15656
  {
15307
15657
  cmd: "gemini-2.5-flash",
15308
- desc: "Fast & Reliable (Limited Free Quota)"
15658
+ desc: "Fast & Reliable (Multimodal) [Limited Free Quota]"
15309
15659
  },
15310
15660
  {
15311
15661
  cmd: "gemini-3-flash-preview",
15312
- desc: "Fast & Lightweight (Limited Free Quota)"
15662
+ desc: "Fast & Lightweight (Multimodal) [Limited Free Quota]"
15313
15663
  },
15314
15664
  {
15315
15665
  cmd: "gemini-3.5-flash",
15316
- desc: "Flash Latest (Limited Free Quota) [Instability Issues]"
15666
+ desc: "Flash Latest (Multimodal) [Limited Free Quota] Instability Issues"
15317
15667
  }
15318
15668
  ] : [
15319
15669
  {
15320
15670
  cmd: "gemini-2.5-flash-lite",
15321
- desc: "Fast & Cheap"
15671
+ desc: "Fast & Cheap (Multimodal)"
15322
15672
  },
15323
15673
  {
15324
15674
  cmd: "gemini-2.5-flash",
15325
- desc: "Fast & Reliable"
15675
+ desc: "Fast & Reliable (Multimodal)"
15326
15676
  },
15327
15677
  {
15328
15678
  cmd: "gemini-2.5-pro",
15329
- desc: "Last gen Pro reasoning"
15679
+ desc: "Last gen Pro reasoning (Multimodal)"
15330
15680
  },
15331
15681
  {
15332
15682
  cmd: "gemini-3.1-flash-lite",
15333
- desc: "Ultra-Fast & Lite"
15683
+ desc: "Ultra-Fast & Lite (Multimodal)"
15334
15684
  },
15335
15685
  {
15336
15686
  cmd: "gemini-3-flash-preview",
15337
- desc: "Default, Fast & Lightweight"
15687
+ desc: "Default, Fast & Lightweight (Multimodal)"
15338
15688
  },
15339
15689
  {
15340
15690
  cmd: "gemini-3.5-flash",
15341
- desc: "Flash Latest [Instability Issues]"
15691
+ desc: "Flash Latest (Multimodal) [Instability Issues]"
15342
15692
  },
15343
15693
  {
15344
15694
  cmd: "gemini-3.1-pro-preview",
15345
- desc: "Pro Reasoning"
15695
+ desc: "Pro Reasoning (Multimodal)"
15346
15696
  }
15347
15697
  ]
15348
15698
  },
@@ -15359,7 +15709,7 @@ function App({ args = [] }) {
15359
15709
  cmd: "/fluxflow",
15360
15710
  desc: "Project management",
15361
15711
  subs: [
15362
- { cmd: "init", desc: "Create FluxFlow.md template" }
15712
+ { cmd: "init", desc: "Create empty FluxFlow.md template" }
15363
15713
  ]
15364
15714
  },
15365
15715
  {
@@ -15374,8 +15724,8 @@ function App({ args = [] }) {
15374
15724
  cmd: "/update",
15375
15725
  desc: "Check/Install updates",
15376
15726
  subs: [
15377
- { cmd: "check", desc: "Check for new version" },
15378
- { cmd: "latest", desc: "Install latest release" }
15727
+ { cmd: "latest", desc: "Install latest release" },
15728
+ { cmd: "check", desc: "Check for new version" }
15379
15729
  ]
15380
15730
  }
15381
15731
  ];
@@ -15455,6 +15805,7 @@ ${cleanText}`, color: "magenta" }];
15455
15805
  const target = h[targetId] || Object.values(h).find((h2) => h2.name.toLowerCase() === targetId.toLowerCase());
15456
15806
  if (target) {
15457
15807
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
15808
+ clearBlocksCache();
15458
15809
  setChatId(targetId);
15459
15810
  const savedData = await loadChatContext(targetId);
15460
15811
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
@@ -15538,6 +15889,7 @@ ${cleanText}`, color: "magenta" }];
15538
15889
  ]);
15539
15890
  setCompletedIndex(1);
15540
15891
  setClearKey((prev) => prev + 1);
15892
+ clearBlocksCache();
15541
15893
  if (parsedArgs.playground) {
15542
15894
  parsedArgs.playground = false;
15543
15895
  deleteChat(PLAYGROUND_CHAT_ID).catch(() => {
@@ -15583,6 +15935,14 @@ ${cleanText}`, color: "magenta" }];
15583
15935
  setIsExpanded(false);
15584
15936
  setChatTokens(0);
15585
15937
  chatTokenStartRef.current = sessionTotalTokens;
15938
+ setTimeout(() => {
15939
+ if (global.gc) {
15940
+ try {
15941
+ global.gc();
15942
+ } catch (e) {
15943
+ }
15944
+ }
15945
+ }, 500);
15586
15946
  break;
15587
15947
  }
15588
15948
  case "/revert": {
@@ -15598,6 +15958,14 @@ ${cleanText}`, color: "magenta" }];
15598
15958
  });
15599
15959
  }
15600
15960
  });
15961
+ setTimeout(() => {
15962
+ if (global.gc) {
15963
+ try {
15964
+ global.gc();
15965
+ } catch (e) {
15966
+ }
15967
+ }
15968
+ }, 500);
15601
15969
  break;
15602
15970
  }
15603
15971
  case "/mode": {
@@ -16205,24 +16573,24 @@ ${timestamp}` };
16205
16573
  });
16206
16574
  const streamChat = async () => {
16207
16575
  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
- }
16576
+ const appendCancelMessage = () => {
16577
+ if (didAppendCancel) return;
16216
16578
  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;
16579
+ setMessages((prev) => {
16580
+ const lastMsg = prev[prev.length - 1];
16581
+ if (lastMsg && lastMsg.text && lastMsg.text.includes("Request Cancelled")) {
16582
+ return prev;
16583
+ }
16584
+ const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
16585
+ const newMsgs = [...updatedPrev, {
16586
+ id: "cancel-" + Date.now(),
16587
+ role: "system",
16588
+ text: "\n\n\x1B[33m\u2139 Request Cancelled\x1B[0m",
16589
+ isMeta: true
16590
+ }];
16591
+ setCompletedIndex(newMsgs.length);
16592
+ return newMsgs;
16593
+ });
16226
16594
  };
16227
16595
  let hasFiredJanitor = false;
16228
16596
  setIsProcessing(true);
@@ -16416,7 +16784,14 @@ Selection: ${val}`,
16416
16784
  let toolCallBalance = 0;
16417
16785
  let inToolCallString = null;
16418
16786
  const signalRegex = /\[?\s*turn\s*:\s*.*?\s*\]?/gi;
16787
+ const bullyTheBug = path20.join(DATA_DIR, "padding");
16419
16788
  for await (const packet of stream) {
16789
+ if (packet.type === "interactive_turn_finished") {
16790
+ fs22.writeFileSync(bullyTheBug, "pad_0xa\n");
16791
+ } else {
16792
+ fs22.appendFileSync(bullyTheBug, "\r");
16793
+ parsedBlocks.completed = [];
16794
+ }
16420
16795
  if (isFirstPacket && packet.type === "text") {
16421
16796
  apiStart = Date.now();
16422
16797
  isFirstPacket = false;
@@ -16427,7 +16802,7 @@ Selection: ${val}`,
16427
16802
  sendStatus(packet.content);
16428
16803
  }
16429
16804
  if (packet.content === "Request Cancelled") {
16430
- setMessages((prev) => appendCancelMessage(prev));
16805
+ appendCancelMessage();
16431
16806
  }
16432
16807
  continue;
16433
16808
  }
@@ -16466,6 +16841,14 @@ Selection: ${val}`,
16466
16841
  setCompletedIndex(newMsgs.length);
16467
16842
  return newMsgs;
16468
16843
  });
16844
+ setTimeout(() => {
16845
+ if (global.gc) {
16846
+ try {
16847
+ global.gc();
16848
+ } catch (e) {
16849
+ }
16850
+ }
16851
+ }, 100);
16469
16852
  continue;
16470
16853
  }
16471
16854
  if (packet.type === "interactive_turn_finished") {
@@ -16674,29 +17057,31 @@ Selection: ${val}`,
16674
17057
  }
16675
17058
  if (inThinkMode && currentThinkId) {
16676
17059
  setMessages((prev) => {
17060
+ const next = [...prev];
16677
17061
  let transitioning = false;
16678
17062
  let transitionContent = "";
16679
- const newMsgs = prev.map((m) => {
16680
- if (m.id === currentThinkId) {
16681
- const newText = m.text + chunkText;
17063
+ for (let i = next.length - 1; i >= 0; i--) {
17064
+ if (next[i].id === currentThinkId) {
17065
+ const newText = next[i].text + chunkText;
16682
17066
  if (newText.toLowerCase().includes("</think>")) {
16683
17067
  transitioning = true;
16684
17068
  const parts = newText.split(/<\/think>/gi);
16685
17069
  transitionContent = parts.slice(1).join("</think>") || "";
16686
- const startTime = m.startTime || parseInt(m.id.split("-")[1]) || Date.now();
17070
+ const startTime = next[i].startTime || parseInt(String(next[i].id).split("-")[1]) || Date.now();
16687
17071
  const duration = Date.now() - startTime;
16688
- return { ...m, text: parts[0], isStreaming: false, duration };
17072
+ next[i] = { ...next[i], text: parts[0], isStreaming: false, duration };
17073
+ } else {
17074
+ next[i] = { ...next[i], text: newText, isStreaming: true };
16689
17075
  }
16690
- return { ...m, text: newText, isStreaming: true };
17076
+ break;
16691
17077
  }
16692
- return m;
16693
- });
17078
+ }
16694
17079
  if (transitioning) {
16695
17080
  inThinkMode = false;
16696
17081
  currentAgentId = "agent-" + Date.now();
16697
- return [...newMsgs, { id: currentAgentId, role: "agent", text: transitionContent.replace(/<\/?(think|thought)>/gi, ""), isStreaming: true }];
17082
+ next.push({ id: currentAgentId, role: "agent", text: transitionContent.replace(/<\/?(think|thought)>/gi, ""), isStreaming: true });
16698
17083
  }
16699
- return newMsgs;
17084
+ return next;
16700
17085
  });
16701
17086
  } else if (!inThinkMode) {
16702
17087
  const chunkLower2 = chunkText.toLowerCase();
@@ -16707,9 +17092,16 @@ Selection: ${val}`,
16707
17092
  currentAgentId = "agent-" + Date.now();
16708
17093
  setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: chunkText, isStreaming: true }]);
16709
17094
  } else {
16710
- setMessages((prev) => prev.map(
16711
- (m) => m.id === currentAgentId ? { ...m, text: m.text + chunkText, isStreaming: true } : m
16712
- ));
17095
+ setMessages((prev) => {
17096
+ const next = [...prev];
17097
+ for (let i = next.length - 1; i >= 0; i--) {
17098
+ if (next[i].id === currentAgentId) {
17099
+ next[i] = { ...next[i], text: next[i].text + chunkText, isStreaming: true };
17100
+ break;
17101
+ }
17102
+ }
17103
+ return next;
17104
+ });
16713
17105
  }
16714
17106
  }
16715
17107
  }
@@ -16724,7 +17116,7 @@ Selection: ${val}`,
16724
17116
  setIsProcessing(false);
16725
17117
  setStatusText(null);
16726
17118
  if (didSignalTerminationRef.current) {
16727
- setMessages((prev) => appendCancelMessage(prev));
17119
+ appendCancelMessage();
16728
17120
  }
16729
17121
  if (!hasFiredJanitor) {
16730
17122
  if (process.stdout.isTTY) {
@@ -16817,7 +17209,7 @@ Selection: ${val}`,
16817
17209
  }
16818
17210
  return [];
16819
17211
  }, [input, isFilePickerDismissed]);
16820
- useEffect9(() => {
17212
+ useEffect11(() => {
16821
17213
  setSelectedIndex(0);
16822
17214
  }, [suggestions]);
16823
17215
  const CustomMenuItem = ({ label: label2, isSelected }) => {
@@ -17314,6 +17706,7 @@ Selection: ${val}`,
17314
17706
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
17315
17707
  }
17316
17708
  setClearKey((prev) => prev + 1);
17709
+ clearBlocksCache();
17317
17710
  const targetIdx = messages.findLastIndex(
17318
17711
  (m) => m.role === "user" && m.text && (m.text.startsWith(targetPrompt) || m.text.includes(targetPrompt))
17319
17712
  );
@@ -17366,6 +17759,7 @@ Selection: ${val}`,
17366
17759
  const h = await loadHistory();
17367
17760
  if (h[id]) {
17368
17761
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
17762
+ clearBlocksCache();
17369
17763
  setChatId(id);
17370
17764
  const savedData = await loadChatContext(id);
17371
17765
  chatTokenStartRef.current = sessionTotalTokens - savedData.total;
@@ -18007,9 +18401,22 @@ var init_app = __esm({
18007
18401
  // src/cli.jsx
18008
18402
  import { spawn as spawn3 } from "child_process";
18009
18403
  import { fileURLToPath as fileURLToPath2 } from "url";
18010
- var HEAP_LIMIT = 6144;
18404
+ import os5 from "os";
18405
+ var totalSystemRamBytes = os5.totalmem();
18406
+ var totalSystemRamMB = totalSystemRamBytes / (1024 * 1024);
18407
+ var SAFETY_MARGIN = 0.5;
18408
+ var calculatedLimit = Math.floor(totalSystemRamMB * SAFETY_MARGIN);
18409
+ var _rawArgs = process.argv.slice(2);
18410
+ var _allocIdx = _rawArgs.indexOf("--allocation");
18411
+ var _allocValue = _allocIdx !== -1 ? parseInt(_rawArgs[_allocIdx + 1], 10) : NaN;
18412
+ var _maxAllowed = Math.floor(totalSystemRamMB * 0.75);
18413
+ var HEAP_LIMIT = !isNaN(_allocValue) && _allocValue > 0 ? Math.min(_allocValue, _maxAllowed) : Math.max(1536, Math.min(32768, calculatedLimit));
18011
18414
  var isBundled = fileURLToPath2(import.meta.url).endsWith(".js");
18012
18415
  if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-size"))) {
18416
+ if (!Number.isNaN(_allocValue)) {
18417
+ console.log("\n[MEMORY] Using custom memory allocation: " + _allocValue + " MB" + (_allocValue > _maxAllowed ? " (Max allowed: " + _maxAllowed + "MB)" : ""));
18418
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
18419
+ }
18013
18420
  const cp = spawn3(process.execPath, [
18014
18421
  `--max-old-space-size=${HEAP_LIMIT}`,
18015
18422
  fileURLToPath2(import.meta.url),
@@ -18042,6 +18449,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
18042
18449
  --thinking <Fast|Low|Medium|High|xHigh> Set startup thinking level
18043
18450
  --memory <on|off> Toggle memory system
18044
18451
  --resume <session_id> Resume a previous session
18452
+ --allocation <mb> Override Node.js max-old-space-size in MB (default: auto)
18045
18453
  --package <npm|pnpm|yarn|bun> Set package manager for updates
18046
18454
  --auto-del <1d|7d|30d> Set history auto-deletion timeframe
18047
18455
  --auto-exec <on|off> Toggle permission for autonomous command execution
@@ -18131,7 +18539,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
18131
18539
  }
18132
18540
  const promptPackageManager = async () => {
18133
18541
  const React17 = (await import("react")).default;
18134
- const { useState: useState14 } = React17;
18542
+ const { useState: useState15 } = React17;
18135
18543
  const { render: render2, Box: Box16, Text: Text17 } = await import("ink");
18136
18544
  const SelectInput3 = (await import("ink-select-input")).default;
18137
18545
  const TextInput5 = (await import("ink-text-input")).default;
@@ -18148,8 +18556,8 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
18148
18556
  };
18149
18557
  let unmountFn;
18150
18558
  const PromptComponent = () => {
18151
- const [step, setStep] = useState14("select");
18152
- const [customCommand2, setCustomCommand] = useState14("");
18559
+ const [step, setStep] = useState15("select");
18560
+ const [customCommand2, setCustomCommand] = useState15("");
18153
18561
  const handleSelect = (item) => {
18154
18562
  if (item.value === "custom") {
18155
18563
  setStep("custom");