fluxflow-cli 3.2.7 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/fluxflow.js +187 -48
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -326,7 +326,8 @@ var init_settings = __esm({
326
326
  useExternalData: false,
327
327
  externalDataPath: "",
328
328
  preserveThinking: true,
329
- loadingPhrases: true
329
+ loadingPhrases: true,
330
+ progressiveRendering: false
330
331
  },
331
332
  profileData: {
332
333
  name: null,
@@ -2562,7 +2563,7 @@ var init_text = __esm({
2562
2563
  };
2563
2564
  parseMessageToBlocks = (msg, columns) => {
2564
2565
  if (!msg) return { completed: [], active: [] };
2565
- const cacheKey = `${msg.id}-${msg.text?.length || 0}-${columns}-${msg.isStreaming}`;
2566
+ const cacheKey = `${msg.id}-${msg.text?.length || 0}-${columns}-${msg.isStreaming}-${msg.workedDuration || 0}`;
2566
2567
  if (!msg.isStreaming && blocksCache.has(cacheKey)) {
2567
2568
  return blocksCache.get(cacheKey);
2568
2569
  }
@@ -4124,10 +4125,10 @@ var init_ChatLayout = __esm({
4124
4125
  tokenCache.set(cacheKey, tokens);
4125
4126
  return tokens;
4126
4127
  };
4127
- renderHighlightedLine = (line, lang, defaultColor = void 0) => {
4128
- if (!line) return /* @__PURE__ */ React4.createElement(Text4, null, " ");
4128
+ renderHighlightedLine = (line, lang, defaultColor = void 0, defaultBgColor = void 0) => {
4129
+ if (!line) return /* @__PURE__ */ React4.createElement(Text4, { backgroundColor: defaultBgColor }, " ");
4129
4130
  const tokens = tokenizeLine(line, lang);
4130
- return /* @__PURE__ */ React4.createElement(Text4, { color: defaultColor }, tokens.map((token, idx) => /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: token.color || defaultColor, bold: token.bold }, token.text)));
4131
+ return /* @__PURE__ */ React4.createElement(Text4, { color: defaultColor, backgroundColor: defaultBgColor }, tokens.map((token, idx) => /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: token.color || defaultColor, backgroundColor: defaultBgColor, bold: token.bold }, token.text)));
4131
4132
  };
4132
4133
  renderLatexText = (content, key) => {
4133
4134
  if (!content) return null;
@@ -4257,7 +4258,7 @@ var init_ChatLayout = __esm({
4257
4258
  const level = headingMatch[1].length;
4258
4259
  const hText = headingMatch[2];
4259
4260
  result.push(
4260
- /* @__PURE__ */ React4.createElement(Box3, { key: i, marginTop: 1, marginBottom: 0, width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: level === 1 ? "cyan" : level === 2 ? "purple" : level === 3 ? "yellow" : level === 4 ? "green" : level === 5 ? "blue" : "white", underline: true }, hText.toUpperCase()))
4261
+ /* @__PURE__ */ React4.createElement(Box3, { key: i, marginTop: 1, marginBottom: 0, width: "100%" }, /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: level === 1 ? "cyan" : level === 2 ? "purple" : level === 3 ? "yellow" : level === 4 ? "green" : level === 5 ? "blue" : "white", underline: true }, hText))
4261
4262
  );
4262
4263
  return;
4263
4264
  }
@@ -4313,14 +4314,16 @@ var init_ChatLayout = __esm({
4313
4314
  const displayPrefix = isRemoval ? "-" : isAddition ? "+" : " ";
4314
4315
  const renderInlineDiff = () => {
4315
4316
  if (isPureUnpairedBlock) {
4316
- const blockColor = isRemoval ? "#ffdddd" : "#ddffdd";
4317
+ const blockColor = isRemoval ? "#ff3333" : "#33ff66";
4318
+ const textBgColor = isRemoval ? "#5a1818" : "#185a25";
4317
4319
  const wrappedLines = wrapText(content, columns - 15).split("\n");
4318
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, blockColor))));
4320
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, blockColor, textBgColor))));
4319
4321
  }
4320
4322
  if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
4321
4323
  const textColor = isRemoval ? "#885555" : isAddition ? "#558866" : "gray";
4324
+ const textBgColor = void 0;
4322
4325
  const wrappedLines = wrapText(content, columns - 15).split("\n");
4323
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, textColor))));
4326
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, textColor, textBgColor))));
4324
4327
  }
4325
4328
  return /* @__PURE__ */ React4.createElement(Text4, { wrap: "anywhere" }, words.map((part, idx) => {
4326
4329
  const isWhitespace = /^\s+$/.test(part.value);
@@ -4969,7 +4972,11 @@ var init_StatusBar = __esm({
4969
4972
  },
4970
4973
  /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Box4, { marginRight: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white", bold: true }, 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", bold: true }, "MEM: "), /* @__PURE__ */ React5.createElement(Text5, { color: "white", bold: true }, isMemoryEnabled ? "ON" : "OFF"))),
4971
4974
  /* @__PURE__ */ React5.createElement(Box4, { flexGrow: 1, justifyContent: "center", paddingX: 2 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white", italic: true }, truncatePath(process.cwd(), 35))),
4972
- /* @__PURE__ */ React5.createElement(Box4, null, isProcessing ? /* @__PURE__ */ React5.createElement(Box4, { marginRight: 0 }, /* @__PURE__ */ React5.createElement(Text5, { color: dotColor }, "\u25CF")) : /* @__PURE__ */ React5.createElement(Text5, null, " "), /* @__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", bold: true }, chatId), (apiTier === "Custom" || apiTier === "Paid") && /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, " \u2503 "), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", bold: true }, "PAID"))))
4975
+ /* @__PURE__ */ React5.createElement(Box4, null, isProcessing ? /* @__PURE__ */ React5.createElement(Box4, { marginRight: 0 }, /* @__PURE__ */ React5.createElement(Text5, { color: dotColor }, "\u25CF")) : /* @__PURE__ */ React5.createElement(Text5, null, " "), /* @__PURE__ */ React5.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "white" }, formatTokens(tokensTotal), " ", (() => {
4976
+ const pct = tokens / maxLimit * 100;
4977
+ const color = pct < 60 ? "white" : pct < 80 ? "yellow" : "red";
4978
+ return /* @__PURE__ */ React5.createElement(Text5, { color, dimColor: true }, pct.toFixed(0), "%");
4979
+ })())), /* @__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", bold: true }, chatId), (apiTier === "Custom" || apiTier === "Paid") && /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true }, " \u2503 "), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", bold: true }, "PAID"))))
4973
4980
  );
4974
4981
  });
4975
4982
  StatusBar_default = StatusBar;
@@ -5205,7 +5212,7 @@ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST A
5205
5212
  3. [tool:functions.FileMap(path="path/file")]. Shows file structure, functions, class, import/export, variable
5206
5213
  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**
5207
5214
  5. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
5208
- 6. [tool:functions.SearchKeyword(keyword="...", file="optional", subString="true/false optional", regex="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. Optional parameters default to false
5215
+ 6. [tool:functions.SearchKeyword(keyword="...", file="optional", subString="true/false optional", regex="optional, false for keyword")]. 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. defaults subString: false, regex: auto-detect
5209
5216
  7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL ONLY` : `WINDOWS CMD ONLY` : `BASH`} command. Destructive/Irreversible ops \u2192 Ask user
5210
5217
  8. [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASK STRINGS])]. Task List, NO Markdown IN ARRAY. 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. **EVERY TURN UPDATE POLICY**
5211
5218
  9. [tool:functions.Await(time="seconds")]. For waiting without exiting agent loop, 15s - 180s
@@ -5984,6 +5991,7 @@ function SettingsMenu({
5984
5991
  { label: "Key Strategy", value: "apiTier", status: apiTier === "Free" ? "Free" : quotas?.providerBudgets?.__useProvider ? "Paid" : "Paid" },
5985
5992
  { label: "Preserve Thinking", value: "preserveThinking", status: systemSettings.preserveThinking !== false ? "ON" : "OFF" },
5986
5993
  { label: "Loading Phrases", value: "loadingPhrases", status: systemSettings.loadingPhrases !== false ? "ON" : "OFF" },
5994
+ { label: "Progressive Rendering [EXPERIMENTAL]", value: "progressiveRendering", status: systemSettings.progressiveRendering ? "ON" : "OFF" },
5987
5995
  { label: "Download Language Parsers", value: "parserDownload", status: "ACTION" }
5988
5996
  ];
5989
5997
  default:
@@ -6152,6 +6160,12 @@ function SettingsMenu({
6152
6160
  saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
6153
6161
  return newSysSettings;
6154
6162
  });
6163
+ } else if (item.value === "progressiveRendering") {
6164
+ setSystemSettings((s) => {
6165
+ const newSysSettings = { ...s, progressiveRendering: !s.progressiveRendering };
6166
+ saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
6167
+ return newSysSettings;
6168
+ });
6155
6169
  }
6156
6170
  };
6157
6171
  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) => {
@@ -6188,7 +6202,7 @@ function SettingsMenu({
6188
6202
  currentItems.forEach((item, index) => {
6189
6203
  const isSelected = activeColumn === "items" && selectedItemIndex === index;
6190
6204
  const labelLength = item.label.length;
6191
- const dotsCount = Math.max(2, 35 - labelLength);
6205
+ const dotsCount = Math.max(2, 38 - labelLength);
6192
6206
  const dots = ".".repeat(dotsCount);
6193
6207
  const getStatusColor = (item2) => {
6194
6208
  if (currentCatId === "security") {
@@ -6236,7 +6250,7 @@ function SettingsMenu({
6236
6250
  });
6237
6251
  if (currentCatId === "other") {
6238
6252
  elements.push(
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"))
6253
+ /* @__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"))
6240
6254
  );
6241
6255
  elements.push(
6242
6256
  /* @__PURE__ */ React7.createElement(Box6, { key: "memory-load-2026", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "Memory Load: ", currentMemory, "/", maxMemory, " ", memoryUnit))
@@ -8923,8 +8937,15 @@ var init_search_keyword = __esm({
8923
8937
  const { keyword, file, subString, regex } = parseArgs(args);
8924
8938
  if (!keyword) return 'ERROR: Missing "keyword" argument.';
8925
8939
  const toBool = (v) => v === true || v === "true" || v === 1 || v === "1" || v === "yes";
8926
- const matchRegex = toBool(regex);
8927
- const matchSubstring = !matchRegex && toBool(subString);
8940
+ const regexExplicitlyFalse = regex === false || regex === "false" || regex === 0 || regex === "0" || regex === "no";
8941
+ let matchRegex = toBool(regex);
8942
+ let matchSubstring = !matchRegex && toBool(subString);
8943
+ const hasRegexIndicators = /[|]/.test(keyword) || /\\([*+?{}()|[\]\^$])/.test(keyword);
8944
+ let isAutoRegex = false;
8945
+ if (!matchRegex && !regexExplicitlyFalse && hasRegexIndicators) {
8946
+ matchRegex = true;
8947
+ isAutoRegex = true;
8948
+ }
8928
8949
  let regexPattern;
8929
8950
  let wordRegex;
8930
8951
  if (matchRegex) {
@@ -9001,7 +9022,7 @@ var init_search_keyword = __esm({
9001
9022
  if (typeof global.gc === "function") {
9002
9023
  global.gc();
9003
9024
  }
9004
- const modeLabel = matchRegex ? "(regex mode)" : matchSubstring ? "(subString mode)" : "";
9025
+ const modeLabel = matchRegex ? isAutoRegex ? "(regex mode)" : "(keyword mode)" : matchSubstring ? "(subString mode)" : "";
9005
9026
  if (fileGroups.length === 0) {
9006
9027
  return `Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ". Try to specify files"} ${modeLabel}`;
9007
9028
  }
@@ -10820,10 +10841,18 @@ var init_ai = __esm({
10820
10841
  throw new DOMException("The user aborted a request.", "AbortError");
10821
10842
  }
10822
10843
  try {
10823
- const response = await fetch(url, options);
10824
- if (response.ok) return response;
10825
- if (response.status !== 429 && response.status < 500) return response;
10844
+ const response2 = await fetch(url, options);
10845
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
10846
+ performance.clearMeasures();
10847
+ performance.clearMarks();
10848
+ }
10849
+ if (response2.ok) return response2;
10850
+ if (response2.status !== 429 && response2.status < 500) return response2;
10826
10851
  } catch (e) {
10852
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
10853
+ performance.clearMeasures();
10854
+ performance.clearMarks();
10855
+ }
10827
10856
  if (e.name === "AbortError" || signal?.aborted) throw e;
10828
10857
  if (i === retries - 1) throw e;
10829
10858
  }
@@ -10846,7 +10875,12 @@ var init_ai = __esm({
10846
10875
  if (signal?.aborted) {
10847
10876
  throw new DOMException("The user aborted a request.", "AbortError");
10848
10877
  }
10849
- return fetch(url, options);
10878
+ const response = await fetch(url, options);
10879
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
10880
+ performance.clearMeasures();
10881
+ performance.clearMarks();
10882
+ }
10883
+ return response;
10850
10884
  };
10851
10885
  getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.99) {
10852
10886
  const messages = [];
@@ -11995,6 +12029,32 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
11995
12029
  if (!apiKey) return null;
11996
12030
  globalSettings = settings;
11997
12031
  client = new GoogleGenAI({ apiKey });
12032
+ if (!globalThis.__perfCleanupInstalled) {
12033
+ globalThis.__perfCleanupInstalled = true;
12034
+ setInterval(() => {
12035
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
12036
+ performance.clearMeasures();
12037
+ performance.clearMarks();
12038
+ }
12039
+ }, 6e4);
12040
+ const originalFetch = globalThis.fetch;
12041
+ globalThis.fetch = async (...args) => {
12042
+ try {
12043
+ const response = await originalFetch(...args);
12044
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
12045
+ performance.clearMeasures();
12046
+ performance.clearMarks();
12047
+ }
12048
+ return response;
12049
+ } catch (e) {
12050
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
12051
+ performance.clearMeasures();
12052
+ performance.clearMarks();
12053
+ }
12054
+ throw e;
12055
+ }
12056
+ };
12057
+ }
11998
12058
  return client;
11999
12059
  };
12000
12060
  generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast", temperature = 0.75, usageKey = "agent") => {
@@ -12911,7 +12971,7 @@ ${boxMid}
12911
12971
  }
12912
12972
  let taggedContextStr = "";
12913
12973
  if (taggedContextBlocks.length > 0) {
12914
- taggedContextStr = "[TAGGED CONTEXT]\n" + taggedContextBlocks.join("\n\n") + "\n[/TAGGED CONTEXT]\n";
12974
+ taggedContextStr = "[TAGGED FILE CONTENTS] Auto Read, System Provided Context\n" + taggedContextBlocks.join("\n\n") + "\n[/TAGGED FILE CONTENTS]\n";
12915
12975
  }
12916
12976
  const osDetected = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
12917
12977
  const firstUserMsg = `[SYSTEM METADATA (PRIORITY: DYNAMIC), Chat Context >> Metadata] Time: ${dateTimeStr}
@@ -12919,7 +12979,7 @@ OS: ${osDetected}
12919
12979
  CWD: ${process.cwd()}${isPlayground ? " [PLAYGROUND MODE]" : ""}${cwdMismatch ? ` (WARNING: CWD Mismatch! Previous Path: ${lastCwd})` : ""}
12920
12980
  **DIRECTORY STRUCTURE**
12921
12981
  ${dirStructure}${memoryPrompt}${ideBlock}
12922
- ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}${taggedContextStr}[USER] ${cleanAgentText.trim()} [/USER]`.trim();
12982
+ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGH PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : "\n"}${taggedContextStr}[USER PROMPT] ${cleanAgentText.trim()} [/USER PROMPT]`.trim();
12923
12983
  const userMsgObj = { role: "user", text: firstUserMsg };
12924
12984
  if (attachedBinaryPart) {
12925
12985
  userMsgObj.binaryPart = attachedBinaryPart;
@@ -12965,7 +13025,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
12965
13025
  [SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY [/SYSTEM]
12966
13026
  [QUESTION] ${hint.replace("/btw", "").trim()} [/QUESTION]`;
12967
13027
  } else {
12968
- modifiedHistory.push({ role: "user", text: `${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY\n**STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}[QUESTION] ${hint.replace("/btw", "").trim()} [/QUESTION]` });
13028
+ modifiedHistory.push({ role: "user", text: `${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY\n**STRICTLY FOLLOW THINKING POLICY AS HIGH PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}[QUESTION] ${hint.replace("/btw", "").trim()} [/QUESTION]` });
12969
13029
  }
12970
13030
  } else {
12971
13031
  if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "user") {
@@ -12973,7 +13033,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
12973
13033
 
12974
13034
  [STEERING HINT] ${hint.trim()} [/STEERING HINT]`;
12975
13035
  } else {
12976
- modifiedHistory.push({ role: "user", text: `${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}[STEERING HINT] ${hint.trim()} [/STEERING HINT]` });
13036
+ modifiedHistory.push({ role: "user", text: `${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGH PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}[STEERING HINT] ${hint.trim()} [/STEERING HINT]` });
12977
13037
  }
12978
13038
  }
12979
13039
  yield { type: "status", content: `${hint.startsWith("/btw") ? "Question Forwarded..." : "Steering Hint Injected..."}` };
@@ -14915,8 +14975,8 @@ Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
14915
14975
 
14916
14976
  [SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY [/SYSTEM]
14917
14977
  `, "").replace(`[SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY
14918
- **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]
14919
- `, "").replace(`[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]
14978
+ **STRICTLY FOLLOW THINKING POLICY AS HIGH PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]
14979
+ `, "").replace(`[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGH PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]
14920
14980
  `, "");
14921
14981
  if (modelName && modelName.toLowerCase().startsWith("gemma") && aiProvider === "Google" && msg.text.startsWith("[TOOL RESULT]")) {
14922
14982
  const jitInstructionFast = `
@@ -14953,6 +15013,10 @@ Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
14953
15013
  clearInterval(connectionPollInterval);
14954
15014
  connectionPollInterval = null;
14955
15015
  }
15016
+ if (typeof performance !== "undefined" && performance.clearMeasures) {
15017
+ performance.clearMeasures();
15018
+ performance.clearMarks();
15019
+ }
14956
15020
  await RevertManager.commitTransaction();
14957
15021
  if (systemSettings?.advanceRollback) {
14958
15022
  await AdvanceRevertManager.cleanup(chatId);
@@ -14970,7 +15034,7 @@ Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
14970
15034
  "filemap": '- [tool:functions.FileMap(path="path/file")]. Shows file structure, functions, classes, imports/exports',
14971
15035
  "patchfile": '- [tool:functions.PatchFile(path="...", replaceContent1="...", newContent1="...")]. Surgical block replacement for editing files',
14972
15036
  "writefile": '- [tool:functions.WriteFile(path="...", content="...")]. Creates or overwrites a file',
14973
- "searchkeyword": `- [tool:functions.SearchKeyword(keyword="...", file="optional", subString="true/false optional", regex="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. Optional parameters default to false`,
15037
+ "searchkeyword": `- [tool:functions.SearchKeyword(keyword="...", file="optional", subString="true/false optional", regex="optional, false for keyword")]. 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. defaults subString: false, regex: auto-detect`,
14974
15038
  "websearch": '- [tool:functions.WebSearch(query="...", limit=number)]. Web Search',
14975
15039
  "webscrape": '- [tool:functions.WebScrape(url="...")]. Web Scrape',
14976
15040
  "ask": `- [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish/guess. Suggest best options; don't ask for preferences. 'option' SHOULD be short`
@@ -15062,17 +15126,20 @@ ${cleanResponse}
15062
15126
  } else if (normalizedToolName === "web_scrape" || normalizedToolName === "webscrape") {
15063
15127
  label = `\u2714 \x1B[95mScraped\x1B[0m`;
15064
15128
  } else if (normalizedToolName === "view_file" || normalizedToolName === "viewfile" || normalizedToolName === "readfile") {
15065
- label = `\u2714 \x1B[95mRead File\x1B[0m`;
15129
+ const path23 = parseArgs(toolCall.args).path || "";
15130
+ label = `\u2714 \x1B[95mRead File\x1B[0m: ${path23}`;
15066
15131
  } else if (normalizedToolName === "list_files" || normalizedToolName === "read_folder" || normalizedToolName === "readfolder") {
15067
- label = `\u2714 \x1B[95mBrowsed Folder\x1B[0m`;
15132
+ const path23 = parseArgs(toolCall.args).path || "";
15133
+ label = `\u2714 \x1B[95mBrowsed Folder\x1B[0m: ${path23}`;
15068
15134
  } else if (normalizedToolName === "write_file" || normalizedToolName === "writefile") {
15069
- const path23 = parseArgs(toolCall.args).path || "...";
15135
+ const path23 = parseArgs(toolCall.args).path || "";
15070
15136
  label = `\u2714 \x1B[95mFile Created\x1B[0m: ${path23}`;
15071
15137
  } else if (normalizedToolName === "update_file" || normalizedToolName === "updatefile" || normalizedToolName === "patchfile" || normalizedToolName === "patch_file" || normalizedToolName === "patchfile" || normalizedToolName === "updatefile") {
15072
- const path23 = parseArgs(toolCall.args).path || "...";
15138
+ const path23 = parseArgs(toolCall.args).path || "";
15073
15139
  label = `\u2714 \x1B[95mFile Edited\x1B[0m: ${path23}`;
15074
15140
  } else if (normalizedToolName === "file_map" || normalizedToolName === "filemap") {
15075
- label = `\u2714 \x1B[95mIndexed\x1B[0m`;
15141
+ const path23 = parseArgs(toolCall.args).path || "";
15142
+ label = `\u2714 \x1B[95mIndexed\x1B[0m: ${path23}`;
15076
15143
  } else if (normalizedToolName === "await") {
15077
15144
  const { time } = parseArgs(toolCall.args);
15078
15145
  let sec = parseFloat(time) || 0;
@@ -16116,6 +16183,8 @@ function App({ args = [] }) {
16116
16183
  const activeStreamingMsgRef = useRef4(null);
16117
16184
  const [renderTick, setRenderTick] = useState15(0);
16118
16185
  const forceRender = () => setRenderTick((t) => t + 1);
16186
+ const typewriterQueueRef = useRef4([]);
16187
+ const typewriterTickRef = useRef4(null);
16119
16188
  const commitActiveStreamingMessage = () => {
16120
16189
  if (activeStreamingMsgRef.current) {
16121
16190
  const msg = {
@@ -16131,6 +16200,58 @@ function App({ args = [] }) {
16131
16200
  activeStreamingMsgRef.current = null;
16132
16201
  }
16133
16202
  };
16203
+ const startTypewriter = () => {
16204
+ if (typewriterTickRef.current) {
16205
+ clearInterval(typewriterTickRef.current);
16206
+ }
16207
+ typewriterQueueRef.current = [];
16208
+ typewriterTickRef.current = setInterval(() => {
16209
+ const queue = typewriterQueueRef.current;
16210
+ if (queue.length > 0 && activeStreamingMsgRef.current) {
16211
+ let batchSize = 2;
16212
+ if (queue.length > 65) batchSize = 16;
16213
+ else if (queue.length > 50) batchSize = 12;
16214
+ else if (queue.length > 35) batchSize = 8;
16215
+ else if (queue.length > 15) batchSize = 6;
16216
+ else if (queue.length > 5) batchSize = 4;
16217
+ let batchedText = "";
16218
+ for (let i = 0; i < batchSize && queue.length > 0; i++) {
16219
+ batchedText += queue.shift();
16220
+ }
16221
+ activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + batchedText);
16222
+ forceRender();
16223
+ }
16224
+ }, 100);
16225
+ };
16226
+ const awaitTypewriter = async () => {
16227
+ while (systemSettings.progressiveRendering && typewriterQueueRef.current.length > 0) {
16228
+ await new Promise((resolve) => setTimeout(resolve, 10));
16229
+ }
16230
+ };
16231
+ const flushTypewriterNow = () => {
16232
+ const queue = typewriterQueueRef.current;
16233
+ if (queue.length > 0 && activeStreamingMsgRef.current) {
16234
+ const remaining = queue.join("");
16235
+ queue.length = 0;
16236
+ activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + remaining);
16237
+ forceRender();
16238
+ }
16239
+ };
16240
+ const appendStreamText = (chunkText) => {
16241
+ if (systemSettings.progressiveRendering && typewriterTickRef.current) {
16242
+ const tokens = chunkText.split(/(\s+)/).filter(Boolean);
16243
+ for (const tok of tokens) {
16244
+ typewriterQueueRef.current.push(tok);
16245
+ }
16246
+ } else {
16247
+ if (!activeStreamingMsgRef.current) {
16248
+ activeStreamingMsgRef.current = { id: "agent-" + Date.now(), role: "agent", text: flattenString(chunkText), isStreaming: true };
16249
+ } else {
16250
+ activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + chunkText);
16251
+ }
16252
+ forceRender();
16253
+ }
16254
+ };
16134
16255
  useEffect12(() => {
16135
16256
  const ideName = getIDEName();
16136
16257
  const isIDE = !["Terminal", "Windows Terminal"].includes(ideName) || !!process.env.VSC_TERMINAL_URL;
@@ -16790,11 +16911,9 @@ function App({ args = [] }) {
16790
16911
  for (let j = 0; j < parsed.completed.length; j++) streamingCompletedBlocks.push(parsed.completed[j]);
16791
16912
  for (let j = 0; j < parsed.active.length; j++) activeBlocks.push(parsed.active[j]);
16792
16913
  }
16793
- const finalCompleted = [...historicalBlocks];
16794
- for (let j = 0; j < streamingCompletedBlocks.length; j++) {
16795
- finalCompleted.push(streamingCompletedBlocks[j]);
16796
- }
16914
+ let finalCompleted = streamingCompletedBlocks.length === 0 ? historicalBlocks : historicalBlocks.concat(streamingCompletedBlocks);
16797
16915
  if (finalCompleted.length >= 75e3) {
16916
+ finalCompleted = [...finalCompleted];
16798
16917
  finalCompleted.push({
16799
16918
  key: `memory-warning-block-${finalCompleted.length}`,
16800
16919
  msg: {
@@ -18548,7 +18667,7 @@ ${timestamp}` };
18548
18667
  const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
18549
18668
  const newMsgs = [...updatedPrev, {
18550
18669
  id: "cancel-" + Date.now(),
18551
- role: "system",
18670
+ role: "agent",
18552
18671
  text: "\n\n\x1B[33m\u24D8 Request Cancelled\x1B[0m",
18553
18672
  isMeta: false
18554
18673
  }];
@@ -18647,6 +18766,8 @@ ${timestamp}` };
18647
18766
  setActiveCommand(null);
18648
18767
  setIsTerminalFocused(false);
18649
18768
  setExecOutput("");
18769
+ activeCommandRef.current = null;
18770
+ execOutputRef.current = "";
18650
18771
  },
18651
18772
  onToolResult: (status, toolName) => {
18652
18773
  if (status === "success") {
@@ -18784,6 +18905,9 @@ Selection: ${val}`,
18784
18905
  if (isFirstPacket && packet.type === "text") {
18785
18906
  apiStart = Date.now();
18786
18907
  isFirstPacket = false;
18908
+ if (systemSettings.progressiveRendering) {
18909
+ startTypewriter();
18910
+ }
18787
18911
  }
18788
18912
  if (packet.type === "status") {
18789
18913
  if (!packet.content?.includes("[start]")) {
@@ -18803,6 +18927,7 @@ Selection: ${val}`,
18803
18927
  sendStatus(packet.content);
18804
18928
  }
18805
18929
  if (packet.content === "Request Cancelled") {
18930
+ flushTypewriterNow();
18806
18931
  commitActiveStreamingMessage();
18807
18932
  appendCancelMessage();
18808
18933
  }
@@ -18831,6 +18956,7 @@ Selection: ${val}`,
18831
18956
  continue;
18832
18957
  }
18833
18958
  if (packet.type === "turn_reset") {
18959
+ flushTypewriterNow();
18834
18960
  currentThinkId = null;
18835
18961
  currentAgentId = null;
18836
18962
  inThinkMode = false;
@@ -18886,6 +19012,7 @@ Selection: ${val}`,
18886
19012
  continue;
18887
19013
  }
18888
19014
  if (packet.type === "visual_feedback") {
19015
+ flushTypewriterNow();
18889
19016
  commitActiveStreamingMessage();
18890
19017
  setMessages((prev) => {
18891
19018
  const newMsgs = [...prev, {
@@ -19041,13 +19168,14 @@ Selection: ${val}`,
19041
19168
  activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + beforeText);
19042
19169
  }
19043
19170
  }
19171
+ flushTypewriterNow();
19044
19172
  commitActiveStreamingMessage();
19045
19173
  inThinkMode = true;
19046
19174
  thinkConsumedInTurn = true;
19047
19175
  let thinkStartText = afterText.replace(/<(think|thought)>/gi, "");
19048
19176
  currentThinkId = "think-" + Date.now();
19049
- activeStreamingMsgRef.current = { id: currentThinkId, role: "think", text: flattenString(thinkStartText), isStreaming: true, startTime: Date.now() };
19050
- forceRender();
19177
+ activeStreamingMsgRef.current = { id: currentThinkId, role: "think", text: "", isStreaming: true, startTime: Date.now() };
19178
+ appendStreamText(thinkStartText);
19051
19179
  continue;
19052
19180
  }
19053
19181
  if ((chunkLower.includes("</think>") || chunkLower.includes("</thought>")) && activeStreamingMsgRef.current?.role === "think") {
@@ -19057,11 +19185,12 @@ Selection: ${val}`,
19057
19185
  activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + thinkPart);
19058
19186
  const startTime = activeStreamingMsgRef.current.startTime || Date.now();
19059
19187
  activeStreamingMsgRef.current.duration = Date.now() - startTime;
19188
+ flushTypewriterNow();
19060
19189
  commitActiveStreamingMessage();
19061
19190
  inThinkMode = false;
19062
19191
  currentAgentId = "agent-" + Date.now();
19063
- activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: flattenString(agentPart), isStreaming: true };
19064
- forceRender();
19192
+ activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: "", isStreaming: true };
19193
+ appendStreamText(agentPart);
19065
19194
  continue;
19066
19195
  }
19067
19196
  if (inThinkMode && activeStreamingMsgRef.current?.role === "think") {
@@ -19073,14 +19202,15 @@ Selection: ${val}`,
19073
19202
  activeStreamingMsgRef.current.text = flattenString(thinkPart);
19074
19203
  const startTime = activeStreamingMsgRef.current.startTime || Date.now();
19075
19204
  activeStreamingMsgRef.current.duration = Date.now() - startTime;
19205
+ flushTypewriterNow();
19076
19206
  commitActiveStreamingMessage();
19077
19207
  inThinkMode = false;
19078
19208
  currentAgentId = "agent-" + Date.now();
19079
- activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: flattenString(agentPart.replace(/<\/?(think|thought)>/gi, "")), isStreaming: true };
19209
+ activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: "", isStreaming: true };
19210
+ appendStreamText(agentPart.replace(/<\/?(think|thought)>/gi, ""));
19080
19211
  } else {
19081
- activeStreamingMsgRef.current.text = flattenString(newText);
19212
+ appendStreamText(chunkText);
19082
19213
  }
19083
- forceRender();
19084
19214
  } else if (!inThinkMode) {
19085
19215
  const chunkLower2 = chunkText.toLowerCase();
19086
19216
  if (!toolCallEncounteredInTurn && (chunkLower2.includes("tool:functions.") || chunkLower2.includes("agent:generalist."))) {
@@ -19089,10 +19219,10 @@ Selection: ${val}`,
19089
19219
  if (!activeStreamingMsgRef.current || activeStreamingMsgRef.current.role !== "agent") {
19090
19220
  currentAgentId = "agent-" + Date.now();
19091
19221
  activeStreamingMsgRef.current = { id: currentAgentId, role: "agent", text: flattenString(chunkText), isStreaming: true };
19222
+ forceRender();
19092
19223
  } else {
19093
- activeStreamingMsgRef.current.text = flattenString(activeStreamingMsgRef.current.text + chunkText);
19224
+ appendStreamText(chunkText);
19094
19225
  }
19095
- forceRender();
19096
19226
  }
19097
19227
  }
19098
19228
  const apiEnd = Date.now();
@@ -19103,6 +19233,15 @@ Selection: ${val}`,
19103
19233
  return [...prev, { id: "error-" + Date.now(), role: "system", text: `\u274C ERROR: ${err.message}` }];
19104
19234
  });
19105
19235
  } finally {
19236
+ const totalDuration = Date.now() - apiStart;
19237
+ if (activeStreamingMsgRef.current) {
19238
+ activeStreamingMsgRef.current.workedDuration = totalDuration;
19239
+ }
19240
+ if (typewriterTickRef.current) {
19241
+ await awaitTypewriter();
19242
+ clearInterval(typewriterTickRef.current);
19243
+ typewriterTickRef.current = null;
19244
+ }
19106
19245
  setIsProcessing(false);
19107
19246
  setStatusText(null);
19108
19247
  setActiveTime(0);
@@ -19148,7 +19287,7 @@ Selection: ${val}`,
19148
19287
  setActiveView("resolution");
19149
19288
  }
19150
19289
  setMessages((prev) => {
19151
- const totalDuration = Date.now() - apiStart;
19290
+ const totalDuration2 = Date.now() - apiStart;
19152
19291
  let foundLastAgent = false;
19153
19292
  const newMsgs = [...prev].reverse().map((m) => {
19154
19293
  let updated = m.isStreaming ? { ...m, isStreaming: false } : m;
@@ -19157,7 +19296,7 @@ Selection: ${val}`,
19157
19296
  }
19158
19297
  if (!foundLastAgent && updated.role === "agent") {
19159
19298
  foundLastAgent = true;
19160
- updated = { ...updated, workedDuration: totalDuration };
19299
+ updated = { ...updated, workedDuration: totalDuration2 };
19161
19300
  }
19162
19301
  return updated;
19163
19302
  }).reverse();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.2.7",
4
- "date": "2026-07-08",
3
+ "version": "3.3.0",
4
+ "date": "2026-07-09",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",