fluxflow-cli 3.2.5 → 3.2.7

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 +221 -445
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -326,8 +326,7 @@ var init_settings = __esm({
326
326
  useExternalData: false,
327
327
  externalDataPath: "",
328
328
  preserveThinking: true,
329
- loadingPhrases: true,
330
- progressiveRendering: false
329
+ loadingPhrases: true
331
330
  },
332
331
  profileData: {
333
332
  name: null,
@@ -2111,10 +2110,14 @@ var init_build = __esm({
2111
2110
 
2112
2111
  // src/utils/text.js
2113
2112
  import os2 from "os";
2114
- var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseLineInfo, getSimilarity, alignChangeGroup, blocksCache, streamingBlocksCache, MAX_CACHE_SIZE, CHUNK_SIZE, indexBlockIntoMap, parseMessageToBlocks, TOOL_LABELS, REGEX_INITIAL_THINK, REGEX_INITIAL_TOOL, REGEX_CLEAN_SIGNALS, REGEX_ARROWS_ALL, REGEX_TOOLS, cleanSignals, clearBlocksCache;
2113
+ var flattenString, wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseLineInfo, getSimilarity, alignChangeGroup, blocksCache, streamingBlocksCache, MAX_CACHE_SIZE, CHUNK_SIZE, indexBlockIntoMap, parseMessageToBlocks, TOOL_LABELS, REGEX_INITIAL_THINK, REGEX_INITIAL_TOOL, REGEX_CLEAN_SIGNALS, REGEX_ARROWS_ALL, REGEX_TOOLS, cleanSignals, clearBlocksCache;
2115
2114
  var init_text = __esm({
2116
2115
  "src/utils/text.js"() {
2117
2116
  init_paths();
2117
+ flattenString = (str) => {
2118
+ if (typeof str !== "string") return str;
2119
+ return str.length > 12 ? (str + "").replace("", "") : str;
2120
+ };
2118
2121
  wrapText = (text, width) => {
2119
2122
  if (!text) return "";
2120
2123
  const ansiRegex = /\x1B\[[0-?]*[ -/]*[@-~]/g;
@@ -2166,7 +2169,7 @@ var init_text = __esm({
2166
2169
  finalLines.push(currentLine.trimEnd());
2167
2170
  }
2168
2171
  });
2169
- return finalLines.join("\n");
2172
+ return flattenString(finalLines.join("\n"));
2170
2173
  };
2171
2174
  formatTokens = (tokens) => {
2172
2175
  if (!tokens && tokens !== 0) return "0.0k";
@@ -2181,9 +2184,9 @@ var init_text = __esm({
2181
2184
  truncatePath = (p, maxLength = 40) => {
2182
2185
  let data_dir = DATA_DIR.replaceAll("\\\\", "\\");
2183
2186
  p = p.replace(os2.homedir(), "~").replace(data_dir, "FluxFlow").replaceAll("\\", "/");
2184
- if (!p || p.length <= maxLength) return p;
2187
+ if (!p || p.length <= maxLength) return flattenString(p);
2185
2188
  const half = Math.floor((maxLength - 3) / 2);
2186
- return p.substring(0, half) + "..." + p.substring(p.length - half).replaceAll("\\", "/");
2189
+ return flattenString(p.substring(0, half) + "..." + p.substring(p.length - half).replaceAll("\\", "/"));
2187
2190
  };
2188
2191
  parsePatchPairs = (args) => {
2189
2192
  const patchPairs = [];
@@ -2438,7 +2441,7 @@ var init_text = __esm({
2438
2441
  }
2439
2442
  }
2440
2443
  diffText += `[DIFF_END]`;
2441
- return diffText;
2444
+ return flattenString(diffText);
2442
2445
  };
2443
2446
  parseLineInfo = (l) => {
2444
2447
  if (!l) return null;
@@ -2448,8 +2451,8 @@ var init_text = __esm({
2448
2451
  let rest = isR || isA ? clean.substring(1) : clean;
2449
2452
  rest = rest.trim();
2450
2453
  const splitIdx = rest.indexOf("|");
2451
- const num = splitIdx !== -1 ? rest.substring(0, splitIdx).trim() : "";
2452
- const content = splitIdx !== -1 ? rest.substring(splitIdx + 1) : rest;
2454
+ const num = splitIdx !== -1 ? flattenString(rest.substring(0, splitIdx).trim()) : "";
2455
+ const content = splitIdx !== -1 ? flattenString(rest.substring(splitIdx + 1)) : flattenString(rest);
2453
2456
  return { isR, isA, num, content };
2454
2457
  };
2455
2458
  getSimilarity = (s1, s2) => {
@@ -2457,21 +2460,35 @@ var init_text = __esm({
2457
2460
  if (!s1 || !s2) return 0;
2458
2461
  const l1 = s1.length;
2459
2462
  const l2 = s2.length;
2460
- const dp = Array.from({ length: l1 + 1 }, () => Array(l2 + 1).fill(0));
2461
- for (let i = 0; i <= l1; i++) dp[i][0] = i;
2462
- for (let j = 0; j <= l2; j++) dp[0][j] = j;
2463
- for (let i = 1; i <= l1; i++) {
2464
- for (let j = 1; j <= l2; j++) {
2465
- if (s1[i - 1] === s2[j - 1]) {
2466
- dp[i][j] = dp[i - 1][j - 1];
2463
+ let str1 = s1;
2464
+ let str2 = s2;
2465
+ if (l1 < l2) {
2466
+ str1 = s2;
2467
+ str2 = s1;
2468
+ }
2469
+ const n = str1.length;
2470
+ const m = str2.length;
2471
+ const prevRow = new Int32Array(m + 1);
2472
+ const currRow = new Int32Array(m + 1);
2473
+ for (let j = 0; j <= m; j++) {
2474
+ prevRow[j] = j;
2475
+ }
2476
+ for (let i = 1; i <= n; i++) {
2477
+ currRow[0] = i;
2478
+ const char1 = str1[i - 1];
2479
+ for (let j = 1; j <= m; j++) {
2480
+ if (char1 === str2[j - 1]) {
2481
+ currRow[j] = prevRow[j - 1];
2467
2482
  } else {
2468
- dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
2483
+ currRow[j] = Math.min(prevRow[j], currRow[j - 1], prevRow[j - 1]) + 1;
2469
2484
  }
2470
2485
  }
2486
+ prevRow.set(currRow);
2471
2487
  }
2488
+ const dist = prevRow[m];
2472
2489
  const maxLen = Math.max(l1, l2);
2473
2490
  if (maxLen === 0) return 1;
2474
- return 1 - dp[l1][l2] / maxLen;
2491
+ return 1 - dist / maxLen;
2475
2492
  };
2476
2493
  alignChangeGroup = (group) => {
2477
2494
  const removals = [];
@@ -2545,11 +2562,11 @@ var init_text = __esm({
2545
2562
  };
2546
2563
  parseMessageToBlocks = (msg, columns) => {
2547
2564
  if (!msg) return { completed: [], active: [] };
2548
- const cacheKey = `${msg.id}-${msg.text?.length || 0}-${columns}-${msg.isStreaming}-${msg.workedDuration || 0}-${msg.memoryUpdated ? 1 : 0}-${msg.color || ""}`;
2565
+ const cacheKey = `${msg.id}-${msg.text?.length || 0}-${columns}-${msg.isStreaming}`;
2549
2566
  if (!msg.isStreaming && blocksCache.has(cacheKey)) {
2550
2567
  return blocksCache.get(cacheKey);
2551
2568
  }
2552
- const text = cleanSignals(msg.text || "");
2569
+ const text = flattenString(cleanSignals(msg.text || ""));
2553
2570
  const streamCacheKey = `${msg.id}-${columns}`;
2554
2571
  let cachedBlocks = /* @__PURE__ */ new Map();
2555
2572
  if (msg.isStreaming) {
@@ -2563,13 +2580,13 @@ var init_text = __esm({
2563
2580
  if (existing && existing.text === textContent && existing.type === type && !!existing.isActiveBlock === !!extra.isActiveBlock && !!existing.isStreaming === !!extra.isStreaming && existing.pairContent === extra.pairContent) {
2564
2581
  return existing;
2565
2582
  }
2566
- const flatText = typeof textContent === "string" ? (" " + textContent).slice(1) : textContent;
2583
+ const flatText = flattenString(textContent);
2567
2584
  const flatExtra = { ...extra };
2568
2585
  if (typeof flatExtra.pairContent === "string") {
2569
- flatExtra.pairContent = (" " + flatExtra.pairContent).slice(1);
2586
+ flatExtra.pairContent = flattenString(flatExtra.pairContent);
2570
2587
  }
2571
2588
  if (Array.isArray(flatExtra.wrappedLines)) {
2572
- flatExtra.wrappedLines = flatExtra.wrappedLines.map((l) => typeof l === "string" ? (" " + l).slice(1) : l);
2589
+ flatExtra.wrappedLines = flatExtra.wrappedLines.map(flattenString);
2573
2590
  }
2574
2591
  return {
2575
2592
  key,
@@ -4003,7 +4020,7 @@ ${coloredArt[7]}`;
4003
4020
  import React4, { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
4004
4021
  import { Box as Box3, Text as Text4 } from "ink";
4005
4022
  import { diffWordsWithSpace } from "diff";
4006
- var useStreamingText, formatThinkText, REGEX_MD_TOKENS, REGEX_LATEX_FRAC, REGEX_LATEX_STYLE, parseMathSymbols, SYNTAX_KEYWORDS, SYNTAX_RULES, tokenCache, MAX_TOKEN_CACHE_SIZE, tokenizeLine, renderHighlightedLine, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
4023
+ var useStreamingText, formatThinkText, REGEX_MD_TOKENS, REGEX_LATEX_FRAC, REGEX_LATEX_STYLE, parseMathSymbols, SYNTAX_KEYWORDS, SYNTAX_RULES, REGEX_SYNTAX, tokenCache, MAX_TOKEN_CACHE_SIZE, tokenizeLine, renderHighlightedLine, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
4007
4024
  var init_ChatLayout = __esm({
4008
4025
  "src/components/ChatLayout.jsx"() {
4009
4026
  init_TerminalBox();
@@ -4059,6 +4076,7 @@ var init_ChatLayout = __esm({
4059
4076
  /\b(true|false|null|undefined|nil|None)\b/.source,
4060
4077
  /\b(\d+(?:\.\d+)?|0x[0-9a-fA-F]+)\b/.source
4061
4078
  ];
4079
+ REGEX_SYNTAX = new RegExp(SYNTAX_RULES.join("|"), "g");
4062
4080
  tokenCache = /* @__PURE__ */ new Map();
4063
4081
  MAX_TOKEN_CACHE_SIZE = 1e3;
4064
4082
  tokenizeLine = (line, lang) => {
@@ -4070,12 +4088,12 @@ var init_ChatLayout = __esm({
4070
4088
  let lastIndex = 0;
4071
4089
  const tokens = [];
4072
4090
  let match;
4073
- const localRegex = new RegExp(SYNTAX_RULES.join("|"), "g");
4074
- while ((match = localRegex.exec(line)) !== null) {
4091
+ REGEX_SYNTAX.lastIndex = 0;
4092
+ while ((match = REGEX_SYNTAX.exec(line)) !== null) {
4075
4093
  const matchText = match[0];
4076
4094
  const matchIndex = match.index;
4077
4095
  if (matchIndex > lastIndex) {
4078
- tokens.push({ text: line.substring(lastIndex, matchIndex) });
4096
+ tokens.push({ text: flattenString(line.substring(lastIndex, matchIndex)) });
4079
4097
  }
4080
4098
  let color = void 0;
4081
4099
  let bold = false;
@@ -4093,11 +4111,11 @@ var init_ChatLayout = __esm({
4093
4111
  } else if (match[7] || match[8]) {
4094
4112
  color = "#ff9e64";
4095
4113
  }
4096
- tokens.push({ text: matchText, color, bold });
4097
- lastIndex = localRegex.lastIndex;
4114
+ tokens.push({ text: flattenString(matchText), color, bold });
4115
+ lastIndex = REGEX_SYNTAX.lastIndex;
4098
4116
  }
4099
4117
  if (lastIndex < line.length) {
4100
- tokens.push({ text: line.substring(lastIndex) });
4118
+ tokens.push({ text: flattenString(line.substring(lastIndex)) });
4101
4119
  }
4102
4120
  if (tokenCache.size >= MAX_TOKEN_CACHE_SIZE) {
4103
4121
  const firstKey = tokenCache.keys().next().value;
@@ -5966,7 +5984,6 @@ function SettingsMenu({
5966
5984
  { label: "Key Strategy", value: "apiTier", status: apiTier === "Free" ? "Free" : quotas?.providerBudgets?.__useProvider ? "Paid" : "Paid" },
5967
5985
  { label: "Preserve Thinking", value: "preserveThinking", status: systemSettings.preserveThinking !== false ? "ON" : "OFF" },
5968
5986
  { label: "Loading Phrases", value: "loadingPhrases", status: systemSettings.loadingPhrases !== false ? "ON" : "OFF" },
5969
- { label: "Progressive Rendering [EXPERIMENTAL]", value: "progressiveRendering", status: systemSettings.progressiveRendering ? "ON" : "OFF" },
5970
5987
  { label: "Download Language Parsers", value: "parserDownload", status: "ACTION" }
5971
5988
  ];
5972
5989
  default:
@@ -6135,12 +6152,6 @@ function SettingsMenu({
6135
6152
  saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
6136
6153
  return newSysSettings;
6137
6154
  });
6138
- } else if (item.value === "progressiveRendering") {
6139
- setSystemSettings((s) => {
6140
- const newSysSettings = { ...s, progressiveRendering: !s.progressiveRendering };
6141
- saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
6142
- return newSysSettings;
6143
- });
6144
6155
  }
6145
6156
  };
6146
6157
  return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "white", padding: 0, width: "100%", minHeight: 32 }, /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, paddingY: 0, marginBottom: 0, borderStyle: "single", borderColor: "gray", width: "100%" }, /* @__PURE__ */ React7.createElement(Text7, { color: "white", bold: true }, "SYSTEM CONFIGURATION")), /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "row", width: "100%", minHeight: 26 }, /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", width: "30%", borderStyle: "round", borderColor: activeColumn === "categories" ? "white" : "grey", padding: 1, paddingY: 0 }, /* @__PURE__ */ React7.createElement(Box6, { marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: activeColumn === "categories" ? "white" : "grey", bold: true, underline: true }, "CATEGORIES")), CATEGORIES.map((cat, index) => {
@@ -6177,7 +6188,7 @@ function SettingsMenu({
6177
6188
  currentItems.forEach((item, index) => {
6178
6189
  const isSelected = activeColumn === "items" && selectedItemIndex === index;
6179
6190
  const labelLength = item.label.length;
6180
- const dotsCount = Math.max(2, 38 - labelLength);
6191
+ const dotsCount = Math.max(2, 35 - labelLength);
6181
6192
  const dots = ".".repeat(dotsCount);
6182
6193
  const getStatusColor = (item2) => {
6183
6194
  if (currentCatId === "security") {
@@ -6225,7 +6236,7 @@ function SettingsMenu({
6225
6236
  });
6226
6237
  if (currentCatId === "other") {
6227
6238
  elements.push(
6228
- /* @__PURE__ */ React7.createElement(Box6, { key: "pty-notice", marginTop: 14, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "white" }, isPtyAvailable ? "\u2713 Advance Interactive Terminal Supported" : "\u26A0 Interactive Terminal is Limited"))
6239
+ /* @__PURE__ */ React7.createElement(Box6, { key: "pty-notice", marginTop: 15, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "white" }, isPtyAvailable ? "\u2713 Advance Interactive Terminal Supported" : "\u26A0 Interactive Terminal is Limited"))
6229
6240
  );
6230
6241
  elements.push(
6231
6242
  /* @__PURE__ */ React7.createElement(Box6, { key: "memory-load-2026", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "Memory Load: ", currentMemory, "/", maxMemory, " ", memoryUnit))
@@ -11546,7 +11557,7 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
11546
11557
  } else if (aiProvider === "NVIDIA") {
11547
11558
  const stream = getNVIDIAStream(
11548
11559
  apiKey,
11549
- "moonshotai/kimi-k2.6",
11560
+ "deepseek-ai/deepseek-v4-flash",
11550
11561
  janitorContents,
11551
11562
  janitorPrompt,
11552
11563
  "Fast",
@@ -12141,7 +12152,7 @@ ${newMemoryListStr}
12141
12152
  let targetModel = "gemma-4-26b-a4b-it";
12142
12153
  if (aiProvider === "OpenRouter") targetModel = "google/gemma-4-26b-a4b-it:free";
12143
12154
  if (aiProvider === "DeepSeek") targetModel = "deepseek-v4-flash";
12144
- if (aiProvider === "NVIDIA") targetModel = "moonshotai/kimi-k2.6";
12155
+ if (aiProvider === "NVIDIA") targetModel = "deepseek-ai/deepseek-v4-flash";
12145
12156
  while (attempts <= maxAttempts && !success) {
12146
12157
  attempts++;
12147
12158
  try {
@@ -12208,7 +12219,7 @@ Provide a consolidated summary of the entire session.`;
12208
12219
  let targetModel = "gemma-4-26b-a4b-it";
12209
12220
  if (aiProvider === "OpenRouter") targetModel = "google/gemma-4-26b-a4b-it:free";
12210
12221
  if (aiProvider === "DeepSeek") targetModel = "deepseek-v4-flash";
12211
- if (aiProvider === "NVIDIA") targetModel = "moonshotai/kimi-k2.6";
12222
+ if (aiProvider === "NVIDIA") targetModel = "deepseek-ai/deepseek-v4-flash";
12212
12223
  let attempts = 0;
12213
12224
  let success = false;
12214
12225
  let response = null;
@@ -16084,7 +16095,7 @@ import TextInput4 from "ink-text-input";
16084
16095
  import SelectInput2 from "ink-select-input";
16085
16096
  import gradient2 from "gradient-string";
16086
16097
  function App({ args = [] }) {
16087
- let lastGCTime = 1;
16098
+ const lastGCTimeRef = useRef4(1);
16088
16099
  const [confirmExit, setConfirmExit] = useState15(false);
16089
16100
  const [exitCountdown, setExitCountdown] = useState15(10);
16090
16101
  const { stdout } = useStdout2();
@@ -16102,6 +16113,24 @@ function App({ args = [] }) {
16102
16113
  const [promoSelectedIndex, setPromoSelectedIndex] = useState15(0);
16103
16114
  const suggestionOffsetRef = useRef4(0);
16104
16115
  const persistedModelRef = useRef4(null);
16116
+ const activeStreamingMsgRef = useRef4(null);
16117
+ const [renderTick, setRenderTick] = useState15(0);
16118
+ const forceRender = () => setRenderTick((t) => t + 1);
16119
+ const commitActiveStreamingMessage = () => {
16120
+ if (activeStreamingMsgRef.current) {
16121
+ const msg = {
16122
+ ...activeStreamingMsgRef.current,
16123
+ text: flattenString(activeStreamingMsgRef.current.text),
16124
+ isStreaming: false
16125
+ };
16126
+ setMessages((prev) => {
16127
+ const next = [...prev, msg];
16128
+ setCompletedIndex(next.length);
16129
+ return next;
16130
+ });
16131
+ activeStreamingMsgRef.current = null;
16132
+ }
16133
+ };
16105
16134
  useEffect12(() => {
16106
16135
  const ideName = getIDEName();
16107
16136
  const isIDE = !["Terminal", "Windows Terminal"].includes(ideName) || !!process.env.VSC_TERMINAL_URL;
@@ -16115,10 +16144,10 @@ function App({ args = [] }) {
16115
16144
  setShowBridgePromo(false);
16116
16145
  }
16117
16146
  }, 1e3);
16118
- lastGCTime = Date.now();
16147
+ lastGCTimeRef.current = Date.now();
16119
16148
  const memInterval = setInterval(() => {
16120
- if (lastGCTime) {
16121
- const diff = Date.now() - lastGCTime || 0;
16149
+ if (lastGCTimeRef.current) {
16150
+ const diff = Date.now() - lastGCTimeRef.current || 0;
16122
16151
  if (diff > 3e4) {
16123
16152
  if (global.gc) {
16124
16153
  const gCAsync = async () => {
@@ -16126,7 +16155,7 @@ function App({ args = [] }) {
16126
16155
  global.gc();
16127
16156
  await new Promise((resolve) => setImmediate(resolve));
16128
16157
  }
16129
- lastGCTime = Date.now();
16158
+ lastGCTimeRef.current = Date.now();
16130
16159
  };
16131
16160
  gCAsync();
16132
16161
  }
@@ -16480,8 +16509,8 @@ function App({ args = [] }) {
16480
16509
  defaultModel = "deepseek-v4-flash";
16481
16510
  modelDisplayName = "DeepSeek Flash (Free default)";
16482
16511
  } else if (aiProvider === "NVIDIA") {
16483
- defaultModel = "stepfun-ai/step-3.7-flash";
16484
- modelDisplayName = "Step 3.7 Flash (NVIDIA)";
16512
+ defaultModel = "deepseek-ai/deepseek-v4-flash";
16513
+ modelDisplayName = "DeepSeek V4 Flash (NVIDIA)";
16485
16514
  } else {
16486
16515
  defaultModel = "google/gemma-4-31b-it:free";
16487
16516
  modelDisplayName = "Gemma 4 (Free default)";
@@ -16494,8 +16523,8 @@ function App({ args = [] }) {
16494
16523
  defaultModel = "deepseek-v4-flash";
16495
16524
  modelDisplayName = "DeepSeek Flash";
16496
16525
  } else if (aiProvider === "NVIDIA") {
16497
- defaultModel = "stepfun-ai/step-3.7-flash";
16498
- modelDisplayName = "Step 3.7 Flash (NVIDIA)";
16526
+ defaultModel = "deepseek-ai/deepseek-v4-flash";
16527
+ modelDisplayName = "DeepSeek V4 Flash (NVIDIA)";
16499
16528
  } else {
16500
16529
  defaultModel = "deepseek/deepseek-v4-flash";
16501
16530
  modelDisplayName = "DeepSeek Flash";
@@ -16556,7 +16585,7 @@ function App({ args = [] }) {
16556
16585
  const [wittyPhrase, setWittyPhrase] = useState15("");
16557
16586
  const [hasPasteBlock, setHasPasteBlock] = useState15(false);
16558
16587
  const [activeTime, setActiveTime] = useState15(0);
16559
- const activeTimeIntervalRef = useRef4(null);
16588
+ let interval_for_timer;
16560
16589
  useEffect12(() => {
16561
16590
  let interval;
16562
16591
  if (statusText && systemSettings.loadingPhrases !== false) {
@@ -16667,11 +16696,6 @@ function App({ args = [] }) {
16667
16696
  }, [messages]);
16668
16697
  const [completedIndex, setCompletedIndex] = useState15(messages.length);
16669
16698
  const [clearKey, setClearKey] = useState15(0);
16670
- const [activeStreamMessages, setActiveStreamMessages] = useState15([]);
16671
- const activeStreamMessagesRef = useRef4([]);
16672
- const typewriterQueueRef = useRef4([]);
16673
- const typewriterIntervalRef = useRef4(null);
16674
- const streamFinishedRef = useRef4(false);
16675
16699
  const lastCompletedBlocksRef = useRef4([]);
16676
16700
  const cachedHistoryRef = useRef4({
16677
16701
  completedIndex: 0,
@@ -16745,7 +16769,7 @@ function App({ args = [] }) {
16745
16769
  };
16746
16770
  }
16747
16771
  }
16748
- const activeMsgs = activeStreamMessages;
16772
+ const activeMsgs = messages.slice(completedIndex);
16749
16773
  const streamingCompletedBlocks = [];
16750
16774
  const activeBlocks = [];
16751
16775
  for (let i = 0; i < activeMsgs.length; i++) {
@@ -16761,15 +16785,12 @@ function App({ args = [] }) {
16761
16785
  for (let j = 0; j < parsed.completed.length; j++) streamingCompletedBlocks.push(parsed.completed[j]);
16762
16786
  for (let j = 0; j < parsed.active.length; j++) activeBlocks.push(parsed.active[j]);
16763
16787
  }
16764
- const finalCompleted = historicalBlocks.map((block) => {
16765
- if (block.type === "full-message" && block.msg) {
16766
- const latestMsg = messages.find((m) => m.id === block.msg.id);
16767
- if (latestMsg && latestMsg !== block.msg) {
16768
- return { ...block, msg: latestMsg };
16769
- }
16770
- }
16771
- return block;
16772
- });
16788
+ if (activeStreamingMsgRef.current) {
16789
+ const parsed = parseMessageToBlocks(activeStreamingMsgRef.current, columns);
16790
+ for (let j = 0; j < parsed.completed.length; j++) streamingCompletedBlocks.push(parsed.completed[j]);
16791
+ for (let j = 0; j < parsed.active.length; j++) activeBlocks.push(parsed.active[j]);
16792
+ }
16793
+ const finalCompleted = [...historicalBlocks];
16773
16794
  for (let j = 0; j < streamingCompletedBlocks.length; j++) {
16774
16795
  finalCompleted.push(streamingCompletedBlocks[j]);
16775
16796
  }
@@ -16789,7 +16810,7 @@ function App({ args = [] }) {
16789
16810
  completed: finalCompleted,
16790
16811
  active: activeBlocks
16791
16812
  };
16792
- }, [messages, activeStreamMessages, completedIndex, terminalSize.columns, clearKey, chatId]);
16813
+ }, [messages, completedIndex, terminalSize.columns, clearKey, chatId, renderTick]);
16793
16814
  const isTerminalWaitingForInput = useMemo2(() => {
16794
16815
  if (!activeCommand || !execOutput) return false;
16795
16816
  const lastChunk = execOutput.trim();
@@ -17087,7 +17108,7 @@ function App({ args = [] }) {
17087
17108
  } else if (startupProvider === "OpenRouter") {
17088
17109
  defaultModel = "google/gemma-4-31b-it:free";
17089
17110
  } else if (startupProvider === "NVIDIA") {
17090
- defaultModel = "stepfun-ai/step-3.7-flash";
17111
+ defaultModel = "deepseek-ai/deepseek-v4-flash";
17091
17112
  }
17092
17113
  } else {
17093
17114
  if (startupProvider === "Google") {
@@ -17097,7 +17118,7 @@ function App({ args = [] }) {
17097
17118
  } else if (startupProvider === "OpenRouter") {
17098
17119
  defaultModel = "deepseek/deepseek-v4-flash";
17099
17120
  } else if (startupProvider === "NVIDIA") {
17100
- defaultModel = "stepfun-ai/step-3.7-flash";
17121
+ defaultModel = "deepseek-ai/deepseek-v4-flash";
17101
17122
  }
17102
17123
  }
17103
17124
  setActiveModel(defaultModel);
@@ -17314,7 +17335,7 @@ function App({ args = [] }) {
17314
17335
  } else if (aiProvider === "DeepSeek") {
17315
17336
  defaultModel = "deepseek-v4-flash";
17316
17337
  } else if (aiProvider === "NVIDIA") {
17317
- defaultModel = "stepfun-ai/step-3.7-flash";
17338
+ defaultModel = "deepseek-ai/deepseek-v4-flash";
17318
17339
  }
17319
17340
  setActiveModel(defaultModel);
17320
17341
  setMessages((prev) => [...prev, { role: "system", text: `${aiProvider} API Key saved successfully! Model set to ${defaultModel}. Initialization complete.`, isMeta: true }]);
@@ -17491,10 +17512,6 @@ function App({ args = [] }) {
17491
17512
  cmd: "moonshotai/kimi-k2.7",
17492
17513
  desc: "Multimodal"
17493
17514
  },
17494
- {
17495
- cmd: "moonshotai/kimi-k2.6",
17496
- desc: "[DEPRICATED]"
17497
- },
17498
17515
  // --- DeepSeek Family ---
17499
17516
  {
17500
17517
  cmd: "deepseek-ai/deepseek-v4-flash",
@@ -17877,7 +17894,7 @@ ${cleanText}`, color: "magenta" }];
17877
17894
  global.gc();
17878
17895
  await new Promise((resolve) => setImmediate(resolve));
17879
17896
  }
17880
- lastGCTime = Date.now();
17897
+ lastGCTimeRef.current = Date.now();
17881
17898
  };
17882
17899
  gCAsync();
17883
17900
  }
@@ -17904,7 +17921,7 @@ ${cleanText}`, color: "magenta" }];
17904
17921
  global.gc();
17905
17922
  await new Promise((resolve) => setImmediate(resolve));
17906
17923
  }
17907
- lastGCTime = Date.now();
17924
+ lastGCTimeRef.current = Date.now();
17908
17925
  };
17909
17926
  gCAsync();
17910
17927
  }
@@ -18523,24 +18540,12 @@ ${timestamp}` };
18523
18540
  const appendCancelMessage = () => {
18524
18541
  if (didAppendCancel) return;
18525
18542
  didAppendCancel = true;
18526
- const dangling = activeStreamMessagesRef.current;
18527
- activeStreamMessagesRef.current = [];
18528
- setActiveStreamMessages([]);
18529
- if (typewriterIntervalRef.current) {
18530
- clearInterval(typewriterIntervalRef.current);
18531
- typewriterIntervalRef.current = null;
18532
- }
18533
- typewriterQueueRef.current = [];
18534
18543
  setMessages((prev) => {
18535
18544
  const lastMsg = prev[prev.length - 1];
18536
18545
  if (lastMsg && lastMsg.text && lastMsg.text.includes("Request Cancelled")) {
18537
18546
  return prev;
18538
18547
  }
18539
- const flushed = dangling.map((m) => {
18540
- const flatText = m.text ? (" " + m.text).slice(1) : m.text;
18541
- return { ...m, isStreaming: false, text: flatText };
18542
- });
18543
- const updatedPrev = [...prev, ...flushed].map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
18548
+ const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
18544
18549
  const newMsgs = [...updatedPrev, {
18545
18550
  id: "cancel-" + Date.now(),
18546
18551
  role: "system",
@@ -18551,159 +18556,6 @@ ${timestamp}` };
18551
18556
  return newMsgs;
18552
18557
  });
18553
18558
  };
18554
- const finalizeTurn = async (apiStartVal) => {
18555
- const dangling = activeStreamMessagesRef.current;
18556
- if (dangling.length > 0) {
18557
- activeStreamMessagesRef.current = [];
18558
- setActiveStreamMessages([]);
18559
- setMessages((prev) => {
18560
- const totalDuration = Date.now() - apiStartVal;
18561
- const flushed = dangling.map((m) => {
18562
- const flatText = m.text ? (" " + m.text).slice(1) : m.text;
18563
- return {
18564
- ...m,
18565
- isStreaming: false,
18566
- text: flatText,
18567
- workedDuration: m.role === "agent" ? totalDuration : m.workedDuration
18568
- };
18569
- });
18570
- const newMsgs = [...prev, ...flushed];
18571
- setCompletedIndex(newMsgs.length);
18572
- return newMsgs;
18573
- });
18574
- }
18575
- setIsProcessing(false);
18576
- setStatusText(null);
18577
- setActiveTime(0);
18578
- clearInterval(activeTimeIntervalRef.current);
18579
- if (didSignalTerminationRef.current) {
18580
- appendCancelMessage();
18581
- }
18582
- clearBlocksCache();
18583
- if (global.gc) {
18584
- try {
18585
- for (let i = 0; i < 3; i++) {
18586
- global.gc();
18587
- await new Promise((resolve) => setImmediate(resolve));
18588
- }
18589
- lastGCTime = Date.now();
18590
- } catch (e) {
18591
- }
18592
- }
18593
- if (!hasFiredJanitor) {
18594
- if (process.stdout.isTTY) {
18595
- process.stdout.write("\x1B]0;FluxFlow | Idle\x07");
18596
- process.stdout.write("\x1B]633;P;TerminalTitle=FluxFlow | Idle\x07");
18597
- }
18598
- }
18599
- if (queuedPromptRef.current) {
18600
- setResolutionData(queuedPromptRef.current);
18601
- setQueuedPrompt(null);
18602
- const hintToResolve = queuedPromptRef.current;
18603
- queuedPromptRef.current = null;
18604
- setMessages((prev) => {
18605
- const newMsgs = [...prev];
18606
- const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]") || m.text?.includes("[QUESTION: QUEUED]"));
18607
- if (hintMsg) {
18608
- if (hintMsg.text.includes("[STEERING HINT: QUEUED]")) {
18609
- hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: FINISHED_TURN]");
18610
- } else if (hintMsg.text.includes("[QUESTION: QUEUED]")) {
18611
- hintMsg.text = hintMsg.text.replace("[QUESTION: QUEUED]", "[QUESTION: FINISHED_TURN]");
18612
- }
18613
- }
18614
- return newMsgs.reverse();
18615
- });
18616
- setActiveView("resolution");
18617
- }
18618
- setMessages((prev) => {
18619
- const totalDuration = Date.now() - apiStartVal;
18620
- let foundLastAgent = false;
18621
- const newMsgs = [...prev].reverse().map((m) => {
18622
- let updated = m.isStreaming ? { ...m, isStreaming: false } : m;
18623
- if (updated.text) {
18624
- updated.text = (" " + updated.text).slice(1);
18625
- }
18626
- if (!foundLastAgent && updated.role === "agent") {
18627
- foundLastAgent = true;
18628
- updated = { ...updated, workedDuration: totalDuration };
18629
- }
18630
- return updated;
18631
- }).reverse();
18632
- const historyToSave = newMsgs.filter((m) => !String(m.id).startsWith("welcome") && (!m.isMeta || m.text && m.text.includes("Request Cancelled")));
18633
- saveChat(chatId, null, historyToSave);
18634
- setCompletedIndex(newMsgs.length);
18635
- return newMsgs;
18636
- });
18637
- };
18638
- const pushTokenText = (id, text) => {
18639
- if (systemSettings.progressiveRendering) {
18640
- const tokens = text.split(/(\s+)/).filter(Boolean);
18641
- for (const tok of tokens) {
18642
- typewriterQueueRef.current.push({ type: "text", id, text: tok });
18643
- }
18644
- }
18645
- };
18646
- const startTypewriter = (apiStartVal) => {
18647
- if (typewriterIntervalRef.current) {
18648
- clearInterval(typewriterIntervalRef.current);
18649
- }
18650
- streamFinishedRef.current = false;
18651
- typewriterQueueRef.current = [];
18652
- typewriterIntervalRef.current = setInterval(() => {
18653
- const queue = typewriterQueueRef.current;
18654
- if (queue.length > 0) {
18655
- let batchSize = 1;
18656
- if (queue.length > 35) batchSize = 5;
18657
- else if (queue.length > 15) batchSize = 3;
18658
- else if (queue.length > 5) batchSize = 2;
18659
- let changed = false;
18660
- const nextMsgs = [...activeStreamMessagesRef.current];
18661
- const clonedIndices = /* @__PURE__ */ new Set();
18662
- for (let i = 0; i < batchSize; i++) {
18663
- if (queue.length === 0) break;
18664
- const task = queue.shift();
18665
- if (task.type === "create") {
18666
- nextMsgs.push(task.msg);
18667
- changed = true;
18668
- } else if (task.type === "text") {
18669
- const idx = nextMsgs.findIndex((m) => m.id === task.id);
18670
- if (idx !== -1) {
18671
- if (!clonedIndices.has(idx)) {
18672
- nextMsgs[idx] = { ...nextMsgs[idx] };
18673
- clonedIndices.add(idx);
18674
- }
18675
- nextMsgs[idx].text += task.text;
18676
- changed = true;
18677
- }
18678
- } else if (task.type === "finalize-think") {
18679
- const idx = nextMsgs.findIndex((m) => m.id === task.id);
18680
- if (idx !== -1) {
18681
- if (!clonedIndices.has(idx)) {
18682
- nextMsgs[idx] = { ...nextMsgs[idx] };
18683
- clonedIndices.add(idx);
18684
- }
18685
- nextMsgs[idx].isStreaming = false;
18686
- nextMsgs[idx].duration = task.duration;
18687
- changed = true;
18688
- }
18689
- }
18690
- }
18691
- if (changed) {
18692
- activeStreamMessagesRef.current = nextMsgs;
18693
- setActiveStreamMessages(nextMsgs);
18694
- }
18695
- } else if (streamFinishedRef.current) {
18696
- clearInterval(typewriterIntervalRef.current);
18697
- typewriterIntervalRef.current = null;
18698
- finalizeTurn(apiStartVal);
18699
- }
18700
- }, 35);
18701
- };
18702
- const awaitTypewriter = async () => {
18703
- while (systemSettings.progressiveRendering && typewriterQueueRef.current.length > 0) {
18704
- await new Promise((resolve) => setTimeout(resolve, 10));
18705
- }
18706
- };
18707
18559
  let hasFiredJanitor = false;
18708
18560
  setIsProcessing(true);
18709
18561
  setLastChunkTime(Date.now());
@@ -18925,34 +18777,33 @@ Selection: ${val}`,
18925
18777
  let inToolCallString = null;
18926
18778
  const signalRegex = /\[?\s*turn\s*:\s*.*?\s*\]?/gi;
18927
18779
  for await (const packet of stream) {
18780
+ await new Promise((resolve) => setTimeout(resolve, 3));
18928
18781
  if (packet.type === "text") {
18929
18782
  setLastChunkTime(Date.now());
18930
18783
  }
18931
18784
  if (isFirstPacket && packet.type === "text") {
18932
18785
  apiStart = Date.now();
18933
18786
  isFirstPacket = false;
18934
- if (systemSettings.progressiveRendering) {
18935
- startTypewriter(apiStart);
18936
- }
18937
18787
  }
18938
18788
  if (packet.type === "status") {
18939
18789
  if (!packet.content?.includes("[start]")) {
18940
18790
  setStatusText(packet.content);
18941
18791
  }
18942
18792
  if (packet.content?.includes("[start]")) {
18943
- clearInterval(activeTimeIntervalRef.current);
18793
+ clearInterval(interval_for_timer);
18944
18794
  setActiveTime(0);
18945
- activeTimeIntervalRef.current = setInterval(() => {
18795
+ interval_for_timer = setInterval(() => {
18946
18796
  setActiveTime((prev) => prev + 1);
18947
18797
  }, 1e3);
18948
18798
  } else if (packet.content?.includes("[end]")) {
18949
18799
  setActiveTime(0);
18950
- clearInterval(activeTimeIntervalRef.current);
18800
+ clearInterval(interval_for_timer);
18951
18801
  }
18952
18802
  if (isBridgeConnected()) {
18953
18803
  sendStatus(packet.content);
18954
18804
  }
18955
18805
  if (packet.content === "Request Cancelled") {
18806
+ commitActiveStreamingMessage();
18956
18807
  appendCancelMessage();
18957
18808
  }
18958
18809
  continue;
@@ -18980,9 +18831,6 @@ Selection: ${val}`,
18980
18831
  continue;
18981
18832
  }
18982
18833
  if (packet.type === "turn_reset") {
18983
- if (systemSettings.progressiveRendering) {
18984
- await awaitTypewriter();
18985
- }
18986
18834
  currentThinkId = null;
18987
18835
  currentAgentId = null;
18988
18836
  inThinkMode = false;
@@ -18990,40 +18838,32 @@ Selection: ${val}`,
18990
18838
  inToolCall = false;
18991
18839
  toolCallEncounteredInTurn = false;
18992
18840
  thinkConsumedInTurn = false;
18993
- const streamingMsgs = activeStreamMessagesRef.current;
18994
- activeStreamMessagesRef.current = [];
18995
- setActiveStreamMessages([]);
18996
18841
  setMessages((prev) => {
18997
- const totalDuration = Date.now() - apiStart;
18998
- const flushed = streamingMsgs.map((m) => {
18999
- const flatText = m.text ? (" " + m.text).slice(1) : m.text;
19000
- const flatFullText = m.fullText ? (" " + m.fullText).slice(1) : m.fullText;
19001
- return {
19002
- ...m,
19003
- isStreaming: false,
19004
- text: flatText,
19005
- fullText: flatFullText,
19006
- workedDuration: m.role === "agent" ? totalDuration : m.workedDuration
19007
- };
18842
+ const newMsgs = prev.map((m) => {
18843
+ if (m.isStreaming) {
18844
+ const flatText = m.text ? flattenString(m.text) : m.text;
18845
+ const flatFullText = m.fullText ? flattenString(m.fullText) : m.fullText;
18846
+ return { ...m, isStreaming: false, text: flatText, fullText: flatFullText };
18847
+ }
18848
+ return m;
19008
18849
  });
19009
- const newMsgs = [...prev, ...flushed];
19010
18850
  setCompletedIndex(newMsgs.length);
19011
18851
  return newMsgs;
19012
18852
  });
19013
18853
  clearBlocksCache();
19014
18854
  if (global.gc) {
19015
- for (let i = 0; i < 1; i++) {
18855
+ for (let i = 0; i < 2; i++) {
19016
18856
  global.gc();
19017
18857
  await new Promise((resolve) => setImmediate(resolve));
19018
18858
  }
19019
- lastGCTime = Date.now();
18859
+ lastGCTimeRef.current = Date.now();
19020
18860
  }
19021
18861
  continue;
19022
18862
  }
19023
18863
  if (packet.type === "interactive_turn_finished") {
19024
18864
  setIsProcessing(false);
19025
18865
  setActiveTime(0);
19026
- clearInterval(activeTimeIntervalRef.current);
18866
+ clearInterval(interval_for_timer);
19027
18867
  if (isBridgeConnected()) {
19028
18868
  sendStatus(null);
19029
18869
  }
@@ -19046,18 +18886,12 @@ Selection: ${val}`,
19046
18886
  continue;
19047
18887
  }
19048
18888
  if (packet.type === "visual_feedback") {
19049
- if (systemSettings.progressiveRendering) {
19050
- await awaitTypewriter();
19051
- }
19052
- const streamingMsgs = activeStreamMessagesRef.current;
19053
- activeStreamMessagesRef.current = [];
19054
- setActiveStreamMessages([]);
18889
+ commitActiveStreamingMessage();
19055
18890
  setMessages((prev) => {
19056
- const flushed = streamingMsgs.map((m) => ({ ...m, isStreaming: false }));
19057
- const newMsgs = [...prev, ...flushed, {
18891
+ const newMsgs = [...prev, {
19058
18892
  id: "feedback-" + Date.now() + "-" + Math.random().toString(36).substring(2, 9),
19059
18893
  role: "system",
19060
- text: packet.content,
18894
+ text: flattenString(packet.content),
19061
18895
  isVisualFeedback: true
19062
18896
  }];
19063
18897
  setCompletedIndex(newMsgs.length);
@@ -19092,19 +18926,13 @@ Selection: ${val}`,
19092
18926
  continue;
19093
18927
  }
19094
18928
  if (packet.type === "tool_result") {
19095
- if (systemSettings.progressiveRendering) {
19096
- await awaitTypewriter();
19097
- }
19098
- const streamingMsgs = activeStreamMessagesRef.current;
19099
- activeStreamMessagesRef.current = [];
19100
- setActiveStreamMessages([]);
18929
+ commitActiveStreamingMessage();
19101
18930
  setMessages((prev) => {
19102
- const flushed = streamingMsgs.map((m) => ({ ...m, isStreaming: false }));
19103
- const newMsgs = [...prev, ...flushed, {
18931
+ const newMsgs = [...prev, {
19104
18932
  id: "tool-" + Date.now(),
19105
18933
  role: "system",
19106
- text: packet.content,
19107
- fullText: packet.aiContent,
18934
+ text: flattenString(packet.content),
18935
+ fullText: flattenString(packet.aiContent),
19108
18936
  // Preserve raw data for next turn
19109
18937
  binaryPart: packet.binaryPart,
19110
18938
  // v1.5.0 Multimodal Support
@@ -19170,7 +18998,7 @@ Selection: ${val}`,
19170
18998
  global.gc();
19171
18999
  await new Promise((resolve) => setImmediate(resolve));
19172
19000
  }
19173
- lastGCTime = Date.now();
19001
+ lastGCTimeRef.current = Date.now();
19174
19002
  }
19175
19003
  continue;
19176
19004
  }
@@ -19207,191 +19035,137 @@ Selection: ${val}`,
19207
19035
  const beforeText = chunkText.substring(0, tagIndex);
19208
19036
  const afterText = chunkText.substring(tagIndex);
19209
19037
  if (beforeText) {
19210
- if (!currentAgentId) {
19211
- currentAgentId = "agent-" + Date.now();
19212
- const newMsg = { id: currentAgentId, role: "agent", text: beforeText, isStreaming: true };
19213
- if (systemSettings.progressiveRendering) {
19214
- typewriterQueueRef.current.push({ type: "create", msg: { ...newMsg, text: "" } });
19215
- pushTokenText(currentAgentId, beforeText);
19216
- } else {
19217
- activeStreamMessagesRef.current = [...activeStreamMessagesRef.current, newMsg];
19218
- }
19038
+ if (!activeStreamingMsgRef.current || activeStreamingMsgRef.current.role !== "agent") {
19039
+ activeStreamingMsgRef.current = { id: "agent-" + Date.now(), role: "agent", text: flattenString(beforeText), isStreaming: true };
19219
19040
  } else {
19220
- if (systemSettings.progressiveRendering) {
19221
- pushTokenText(currentAgentId, beforeText);
19222
- } else {
19223
- activeStreamMessagesRef.current = activeStreamMessagesRef.current.map(
19224
- (m) => m.id === currentAgentId ? { ...m, text: m.text + beforeText, isStreaming: true } : m
19225
- );
19226
- }
19227
- }
19228
- if (!systemSettings.progressiveRendering) {
19229
- setActiveStreamMessages([...activeStreamMessagesRef.current]);
19041
+ activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + beforeText);
19230
19042
  }
19231
19043
  }
19044
+ commitActiveStreamingMessage();
19232
19045
  inThinkMode = true;
19233
19046
  thinkConsumedInTurn = true;
19234
19047
  let thinkStartText = afterText.replace(/<(think|thought)>/gi, "");
19235
19048
  currentThinkId = "think-" + Date.now();
19236
- const thinkMsg = { id: currentThinkId, role: "think", text: thinkStartText, isStreaming: true, startTime: Date.now() };
19237
- if (systemSettings.progressiveRendering) {
19238
- typewriterQueueRef.current.push({ type: "create", msg: { ...thinkMsg, text: "", startTime: Date.now() } });
19239
- if (thinkStartText) {
19240
- pushTokenText(currentThinkId, thinkStartText);
19241
- }
19242
- } else {
19243
- activeStreamMessagesRef.current = [...activeStreamMessagesRef.current, thinkMsg];
19244
- setActiveStreamMessages([...activeStreamMessagesRef.current]);
19245
- }
19049
+ activeStreamingMsgRef.current = { id: currentThinkId, role: "think", text: flattenString(thinkStartText), isStreaming: true, startTime: Date.now() };
19050
+ forceRender();
19246
19051
  continue;
19247
19052
  }
19248
- if ((chunkLower.includes("</think>") || chunkLower.includes("</thought>")) && currentThinkId) {
19053
+ if ((chunkLower.includes("</think>") || chunkLower.includes("</thought>")) && activeStreamingMsgRef.current?.role === "think") {
19249
19054
  const parts = chunkText.split(/<\/(think|thought)>/gi);
19250
19055
  const thinkPart = parts[0] || "";
19251
19056
  const agentPart = parts.slice(2).join("").replace(/<\/?(think|thought)>/gi, "");
19057
+ activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + thinkPart);
19058
+ const startTime = activeStreamingMsgRef.current.startTime || Date.now();
19059
+ activeStreamingMsgRef.current.duration = Date.now() - startTime;
19060
+ commitActiveStreamingMessage();
19252
19061
  inThinkMode = false;
19253
19062
  currentAgentId = "agent-" + Date.now();
19254
- if (systemSettings.progressiveRendering) {
19255
- if (thinkPart) {
19256
- pushTokenText(currentThinkId, thinkPart);
19257
- }
19258
- const startTime = parseInt(currentThinkId.split("-")[1]) || Date.now();
19259
- const duration = Date.now() - startTime;
19260
- typewriterQueueRef.current.push({ type: "finalize-think", id: currentThinkId, duration });
19261
- const newAgentMsg = { id: currentAgentId, role: "agent", text: "", isStreaming: true };
19262
- typewriterQueueRef.current.push({ type: "create", msg: newAgentMsg });
19263
- if (agentPart) {
19264
- pushTokenText(currentAgentId, agentPart);
19265
- }
19266
- } else {
19267
- activeStreamMessagesRef.current = activeStreamMessagesRef.current.map((m) => {
19268
- if (m.id === currentThinkId && typeof m.id === "string") {
19269
- const startTime = m.startTime || parseInt(m.id.split("-")[1]) || Date.now();
19270
- const duration = Date.now() - startTime;
19271
- return { ...m, text: m.text + thinkPart, isStreaming: false, duration };
19272
- }
19273
- return m;
19274
- });
19275
- activeStreamMessagesRef.current = [...activeStreamMessagesRef.current, { id: currentAgentId, role: "agent", text: agentPart, isStreaming: true }];
19276
- setActiveStreamMessages([...activeStreamMessagesRef.current]);
19277
- }
19063
+ activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: flattenString(agentPart), isStreaming: true };
19064
+ forceRender();
19278
19065
  continue;
19279
19066
  }
19280
- if (inThinkMode && currentThinkId) {
19281
- let transitioning = false;
19282
- let transitionContent = "";
19283
- if (systemSettings.progressiveRendering) {
19284
- if (chunkText.toLowerCase().includes("</think>")) {
19285
- transitioning = true;
19286
- const parts = chunkText.split(/<\/think>/gi);
19287
- const thinkPart = parts[0] || "";
19288
- transitionContent = parts.slice(1).join("</think>") || "";
19289
- if (thinkPart) pushTokenText(currentThinkId, thinkPart);
19290
- const startTime = parseInt(currentThinkId.split("-")[1]) || Date.now();
19291
- const duration = Date.now() - startTime;
19292
- typewriterQueueRef.current.push({ type: "finalize-think", id: currentThinkId, duration });
19293
- inThinkMode = false;
19294
- currentAgentId = "agent-" + Date.now();
19295
- typewriterQueueRef.current.push({ type: "create", msg: { id: currentAgentId, role: "agent", text: "", isStreaming: true } });
19296
- if (transitionContent) {
19297
- pushTokenText(currentAgentId, transitionContent.replace(/<\/?(think|thought)>/gi, ""));
19298
- }
19299
- } else {
19300
- pushTokenText(currentThinkId, chunkText);
19301
- }
19067
+ if (inThinkMode && activeStreamingMsgRef.current?.role === "think") {
19068
+ const newText = activeStreamingMsgRef.current.text + chunkText;
19069
+ if (newText.toLowerCase().includes("</think>")) {
19070
+ const parts = newText.split(/<\/think>/gi);
19071
+ const thinkPart = parts[0] || "";
19072
+ const agentPart = parts.slice(1).join("</think>") || "";
19073
+ activeStreamingMsgRef.current.text = flattenString(thinkPart);
19074
+ const startTime = activeStreamingMsgRef.current.startTime || Date.now();
19075
+ activeStreamingMsgRef.current.duration = Date.now() - startTime;
19076
+ commitActiveStreamingMessage();
19077
+ inThinkMode = false;
19078
+ currentAgentId = "agent-" + Date.now();
19079
+ activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: flattenString(agentPart.replace(/<\/?(think|thought)>/gi, "")), isStreaming: true };
19302
19080
  } else {
19303
- activeStreamMessagesRef.current = activeStreamMessagesRef.current.map((m) => {
19304
- if (m.id === currentThinkId) {
19305
- const newText = m.text + chunkText;
19306
- if (newText.toLowerCase().includes("</think>")) {
19307
- transitioning = true;
19308
- const parts = newText.split(/<\/think>/gi);
19309
- transitionContent = parts.slice(1).join("</think>") || "";
19310
- const startTime = m.startTime || parseInt(String(m.id).split("-")[1]) || Date.now();
19311
- const duration = Date.now() - startTime;
19312
- return { ...m, text: parts[0], isStreaming: false, duration };
19313
- }
19314
- return { ...m, text: newText, isStreaming: true };
19315
- }
19316
- return m;
19317
- });
19318
- if (transitioning) {
19319
- inThinkMode = false;
19320
- currentAgentId = "agent-" + Date.now();
19321
- activeStreamMessagesRef.current = [...activeStreamMessagesRef.current, { id: currentAgentId, role: "agent", text: transitionContent.replace(/<\/?(think|thought)>/gi, ""), isStreaming: true }];
19322
- }
19323
- setActiveStreamMessages([...activeStreamMessagesRef.current]);
19081
+ activeStreamingMsgRef.current.text = flattenString(newText);
19324
19082
  }
19083
+ forceRender();
19325
19084
  } else if (!inThinkMode) {
19326
19085
  const chunkLower2 = chunkText.toLowerCase();
19327
19086
  if (!toolCallEncounteredInTurn && (chunkLower2.includes("tool:functions.") || chunkLower2.includes("agent:generalist."))) {
19328
19087
  toolCallEncounteredInTurn = true;
19329
19088
  }
19330
- if (!currentAgentId) {
19089
+ if (!activeStreamingMsgRef.current || activeStreamingMsgRef.current.role !== "agent") {
19331
19090
  currentAgentId = "agent-" + Date.now();
19332
- const newMsg = { id: currentAgentId, role: "agent", text: chunkText, isStreaming: true };
19333
- if (systemSettings.progressiveRendering) {
19334
- typewriterQueueRef.current.push({ type: "create", msg: { ...newMsg, text: "" } });
19335
- pushTokenText(currentAgentId, chunkText);
19336
- } else {
19337
- activeStreamMessagesRef.current = [...activeStreamMessagesRef.current, newMsg];
19338
- setActiveStreamMessages([...activeStreamMessagesRef.current]);
19339
- }
19091
+ activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: flattenString(chunkText), isStreaming: true };
19340
19092
  } else {
19341
- if (systemSettings.progressiveRendering) {
19342
- pushTokenText(currentAgentId, chunkText);
19343
- } else {
19344
- const next = [...activeStreamMessagesRef.current];
19345
- for (let i = next.length - 1; i >= 0; i--) {
19346
- if (next[i].id === currentAgentId) {
19347
- next[i] = { ...next[i], text: next[i].text + chunkText, isStreaming: true };
19348
- break;
19349
- }
19350
- }
19351
- activeStreamMessagesRef.current = next;
19352
- setActiveStreamMessages([...activeStreamMessagesRef.current]);
19353
- }
19093
+ activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + chunkText);
19354
19094
  }
19095
+ forceRender();
19355
19096
  }
19356
19097
  }
19357
- if (systemSettings.progressiveRendering) {
19358
- streamFinishedRef.current = true;
19359
- } else {
19360
- await finalizeTurn(apiStart);
19361
- }
19362
19098
  const apiEnd = Date.now();
19363
19099
  setSessionApiTime((prev) => prev + (apiEnd - apiStart));
19364
19100
  } catch (err) {
19365
- if (typewriterIntervalRef.current) {
19366
- clearInterval(typewriterIntervalRef.current);
19367
- typewriterIntervalRef.current = null;
19368
- }
19369
- typewriterQueueRef.current = [];
19370
19101
  setMessages((prev) => {
19371
19102
  setCompletedIndex(prev.length + 1);
19372
19103
  return [...prev, { id: "error-" + Date.now(), role: "system", text: `\u274C ERROR: ${err.message}` }];
19373
19104
  });
19374
19105
  } finally {
19375
- if (!systemSettings.progressiveRendering) {
19376
- setIsProcessing(false);
19377
- setStatusText(null);
19378
- setActiveTime(0);
19379
- clearInterval(activeTimeIntervalRef.current);
19380
- if (didSignalTerminationRef.current) {
19381
- appendCancelMessage();
19106
+ setIsProcessing(false);
19107
+ setStatusText(null);
19108
+ setActiveTime(0);
19109
+ clearInterval(interval_for_timer);
19110
+ commitActiveStreamingMessage();
19111
+ if (didSignalTerminationRef.current) {
19112
+ appendCancelMessage();
19113
+ }
19114
+ clearBlocksCache();
19115
+ if (global.gc) {
19116
+ try {
19117
+ for (let i = 0; i < 3; i++) {
19118
+ global.gc();
19119
+ await new Promise((resolve) => setImmediate(resolve));
19120
+ }
19121
+ lastGCTimeRef.current = Date.now();
19122
+ } catch (e) {
19382
19123
  }
19383
- clearBlocksCache();
19384
- if (global.gc) {
19385
- try {
19386
- for (let i = 0; i < 3; i++) {
19387
- global.gc();
19388
- await new Promise((resolve) => setImmediate(resolve));
19124
+ }
19125
+ if (!hasFiredJanitor) {
19126
+ if (process.stdout.isTTY) {
19127
+ process.stdout.write("\x1B]0;FluxFlow | Idle\x07");
19128
+ process.stdout.write("\x1B]633;P;TerminalTitle=FluxFlow | Idle\x07");
19129
+ }
19130
+ }
19131
+ if (queuedPromptRef.current) {
19132
+ setResolutionData(queuedPromptRef.current);
19133
+ setQueuedPrompt(null);
19134
+ const hintToResolve = queuedPromptRef.current;
19135
+ queuedPromptRef.current = null;
19136
+ setMessages((prev) => {
19137
+ const newMsgs = [...prev];
19138
+ const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]") || m.text?.includes("[QUESTION: QUEUED]"));
19139
+ if (hintMsg) {
19140
+ if (hintMsg.text.includes("[STEERING HINT: QUEUED]")) {
19141
+ hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: FINISHED_TURN]");
19142
+ } else if (hintMsg.text.includes("[QUESTION: QUEUED]")) {
19143
+ hintMsg.text = hintMsg.text.replace("[QUESTION: QUEUED]", "[QUESTION: FINISHED_TURN]");
19389
19144
  }
19390
- lastGCTime = Date.now();
19391
- } catch (e) {
19392
19145
  }
19393
- }
19146
+ return newMsgs.reverse();
19147
+ });
19148
+ setActiveView("resolution");
19394
19149
  }
19150
+ setMessages((prev) => {
19151
+ const totalDuration = Date.now() - apiStart;
19152
+ let foundLastAgent = false;
19153
+ const newMsgs = [...prev].reverse().map((m) => {
19154
+ let updated = m.isStreaming ? { ...m, isStreaming: false } : m;
19155
+ if (updated.text) {
19156
+ updated.text = (" " + updated.text).slice(1);
19157
+ }
19158
+ if (!foundLastAgent && updated.role === "agent") {
19159
+ foundLastAgent = true;
19160
+ updated = { ...updated, workedDuration: totalDuration };
19161
+ }
19162
+ return updated;
19163
+ }).reverse();
19164
+ const historyToSave = newMsgs.filter((m) => !String(m.id).startsWith("welcome") && (!m.isMeta || m.text && m.text.includes("Request Cancelled")));
19165
+ saveChat(chatId, null, historyToSave);
19166
+ setCompletedIndex(newMsgs.length);
19167
+ return newMsgs;
19168
+ });
19395
19169
  }
19396
19170
  };
19397
19171
  streamChat();
@@ -19625,7 +19399,7 @@ Selection: ${val}`,
19625
19399
  } else if (selectedProvider === "DeepSeek") {
19626
19400
  defaultModel = "deepseek-v4-flash";
19627
19401
  } else if (selectedProvider === "NVIDIA") {
19628
- defaultModel = "stepfun-ai/step-3.7-flash";
19402
+ defaultModel = "deepseek-ai/deepseek-v4-flash";
19629
19403
  }
19630
19404
  setActiveModel(defaultModel);
19631
19405
  const targetTier = (quotas.providerTiers || {})[selectedProvider] || "Free";
@@ -19953,7 +19727,7 @@ Selection: ${val}`,
19953
19727
  } else if (prov === "DeepSeek") {
19954
19728
  defaultModel = "deepseek-v4-flash";
19955
19729
  } else if (prov === "NVIDIA") {
19956
- defaultModel = "stepfun-ai/step-3.7-flash";
19730
+ defaultModel = "moonshotai/kimi-k2.6";
19957
19731
  }
19958
19732
  setActiveModel(defaultModel);
19959
19733
  const targetTier = (quotas.providerTiers || {})[prov] || "Free";
@@ -20798,15 +20572,15 @@ var init_app = __esm({
20798
20572
  }
20799
20573
  }
20800
20574
  if (endIdx !== -1) {
20801
- const beforeText = text.substring(lastIdx, match.index);
20575
+ const beforeText = flattenString(text.substring(lastIdx, match.index));
20802
20576
  if (beforeText.trim()) {
20803
20577
  blocks.push({ type: "output", content: beforeText });
20804
20578
  }
20805
- const finalArgsText = text.substring(startIdx + 1, closingParenIdx);
20579
+ const finalArgsText = flattenString(text.substring(startIdx + 1, closingParenIdx));
20806
20580
  blocks.push({
20807
20581
  type: "tool",
20808
- toolName: toolName.trim(),
20809
- args: finalArgsText.trim()
20582
+ toolName: flattenString(toolName.trim()),
20583
+ args: flattenString(finalArgsText.trim())
20810
20584
  });
20811
20585
  lastIdx = endIdx + 1;
20812
20586
  toolRegex.lastIndex = lastIdx;
@@ -20815,7 +20589,7 @@ var init_app = __esm({
20815
20589
  }
20816
20590
  }
20817
20591
  if (lastIdx < text.length) {
20818
- const remainingText = text.substring(lastIdx);
20592
+ const remainingText = flattenString(text.substring(lastIdx));
20819
20593
  if (remainingText.trim()) {
20820
20594
  blocks.push({ type: "output", content: remainingText });
20821
20595
  }
@@ -20827,14 +20601,16 @@ var init_app = __esm({
20827
20601
  let lastScanTime = 0;
20828
20602
  return (dir) => {
20829
20603
  const now = Date.now();
20830
- if (cachedFiles && now - lastScanTime < 5e3) {
20604
+ if (cachedFiles && now - lastScanTime < 1e4) {
20831
20605
  return cachedFiles;
20832
20606
  }
20833
20607
  const fileList = [];
20834
20608
  const scan = (currentDir) => {
20609
+ if (fileList.length >= 2e3) return;
20835
20610
  try {
20836
20611
  const files = fs24.readdirSync(currentDir);
20837
20612
  for (const file of files) {
20613
+ if (fileList.length >= 2e3) return;
20838
20614
  if (["node_modules", ".git", ".gemini", "dist", "build", ".next", ".cache", "out"].includes(file)) {
20839
20615
  continue;
20840
20616
  }
@@ -20844,8 +20620,8 @@ var init_app = __esm({
20844
20620
  scan(filePath);
20845
20621
  } else {
20846
20622
  fileList.push({
20847
- name: file,
20848
- relativePath: path22.relative(process.cwd(), filePath)
20623
+ name: flattenString(file),
20624
+ relativePath: flattenString(path22.relative(process.cwd(), filePath))
20849
20625
  });
20850
20626
  }
20851
20627
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.2.5",
3
+ "version": "3.2.7",
4
4
  "date": "2026-07-08",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [