fluxflow-cli 3.2.1 → 3.2.4

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 +139 -91
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -2138,7 +2138,8 @@ var init_text = __esm({
2138
2138
  if (currentVisibleLength + tokenVisibleLength > width) {
2139
2139
  if (currentLine.trim().length > 0) {
2140
2140
  finalLines.push(currentLine.trimEnd());
2141
- currentLine = indent + token;
2141
+ const cappedIndent = indent.substring(0, Math.min(indent.length, 8));
2142
+ currentLine = cappedIndent + token;
2142
2143
  currentVisibleLength = getVisibleLength(currentLine);
2143
2144
  } else {
2144
2145
  if (ansiRegex.test(token)) {
@@ -2227,36 +2228,20 @@ var init_text = __esm({
2227
2228
  };
2228
2229
  const adjustIndentation = (newText, originalMatch, leadingContext = "") => {
2229
2230
  if (!newText || originalMatch === void 0) return newText;
2230
- const getIndentStyle = (text) => {
2231
- const lines = text.split("\n").filter((l) => l.trim() !== "");
2232
- if (lines.length === 0) return { char: " ", size: 4 };
2233
- const firstIndent = lines[0].match(/^\s*/)[0];
2234
- if (firstIndent.includes(" ")) return { char: " ", size: 1 };
2235
- const indents = lines.map((l) => l.match(/^\s*/)[0].length).filter((l) => l > 0);
2236
- if (indents.length === 0) return { char: " ", size: firstIndent.length || 4 };
2237
- const gcd = (a, b) => b ? gcd(b, a % b) : a;
2238
- const step = indents.reduce((a, b) => gcd(a, b));
2239
- return { char: " ", size: step || 4 };
2240
- };
2241
- const fileStyle = getIndentStyle(originalMatch);
2242
- const modelStyle = getIndentStyle(newText);
2243
- const matchMinIndent = getMinIndent(originalMatch).length;
2244
- const leadingIndent = (leadingContext.match(/^\s*/) || [""])[0].length;
2245
- const targetBaseIndentRaw = leadingIndent + matchMinIndent;
2246
- const targetUnits = targetBaseIndentRaw / fileStyle.size;
2247
- const modelBaseUnits = getMinIndent(newText).length / modelStyle.size;
2248
- const deltaUnits = targetUnits - modelBaseUnits;
2231
+ const usesTabs = /^\t/m.test(originalMatch);
2232
+ const indentChar = usesTabs ? " " : " ";
2233
+ const firstNonEmpty = (text) => text.split("\n").find((l) => l.trim() !== "") ?? "";
2234
+ const origFirstIndent = firstNonEmpty(originalMatch).match(/^\s*/)[0].length;
2235
+ const newFirstIndent = firstNonEmpty(newText).match(/^\s*/)[0].length;
2236
+ const delta = origFirstIndent - newFirstIndent;
2237
+ const leadingLen = (leadingContext.match(/^\s*/) || [""])[0].length;
2249
2238
  const newLines = newText.split("\n");
2250
2239
  return newLines.map((line, i) => {
2251
2240
  if (line.trim() === "" && i !== 0) return "";
2252
- const currentLineUnits = line.match(/^\s*/)[0].length / modelStyle.size;
2253
- const finalUnits = Math.max(0, currentLineUnits + deltaUnits);
2254
- let unitCount = finalUnits;
2255
- if (i === 0) {
2256
- const leadingUnits = leadingIndent / fileStyle.size;
2257
- unitCount = Math.max(0, finalUnits - leadingUnits);
2258
- }
2259
- return fileStyle.char.repeat(unitCount * fileStyle.size) + line.trimStart();
2241
+ const currentIndent = line.match(/^\s*/)[0].length;
2242
+ let targetIndent = Math.max(0, currentIndent + delta);
2243
+ if (i === 0) targetIndent = Math.max(0, targetIndent - leadingLen);
2244
+ return indentChar.repeat(targetIndent) + line.trimStart();
2260
2245
  }).join("\n");
2261
2246
  };
2262
2247
  const patchMatches = [];
@@ -4311,12 +4296,12 @@ var init_ChatLayout = __esm({
4311
4296
  const renderInlineDiff = () => {
4312
4297
  if (isPureUnpairedBlock) {
4313
4298
  const blockColor = isRemoval ? "#ffdddd" : "#ddffdd";
4314
- const wrappedLines = wrapText(content, columns - 14).split("\n");
4299
+ const wrappedLines = wrapText(content, columns - 15).split("\n");
4315
4300
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, blockColor))));
4316
4301
  }
4317
4302
  if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
4318
4303
  const textColor = isRemoval ? "#885555" : isAddition ? "#558866" : "gray";
4319
- const wrappedLines = wrapText(content, columns - 14).split("\n");
4304
+ const wrappedLines = wrapText(content, columns - 15).split("\n");
4320
4305
  return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, textColor))));
4321
4306
  }
4322
4307
  return /* @__PURE__ */ React4.createElement(Text4, { wrap: "anywhere" }, words.map((part, idx) => {
@@ -4340,7 +4325,7 @@ var init_ChatLayout = __esm({
4340
4325
  return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: "gray" }, part.value);
4341
4326
  }));
4342
4327
  };
4343
- return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 3, flexShrink: 0, justifyContent: "flex-end" }, /* @__PURE__ */ React4.createElement(Text4, { color: finalNumColor }, lineNum)), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: finalPrefixColor }, displayPrefix)), /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 1, backgroundColor: innerBgColor, flexShrink: 1 }, renderInlineDiff()));
4328
+ return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 4, flexShrink: 0, justifyContent: "flex-end" }, /* @__PURE__ */ React4.createElement(Text4, { color: finalNumColor }, lineNum)), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: finalPrefixColor }, displayPrefix)), /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 1, backgroundColor: innerBgColor, flexShrink: 1 }, renderInlineDiff()));
4344
4329
  });
4345
4330
  DiffBlock = React4.memo(({ text, columns = 80, extension }) => {
4346
4331
  const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
@@ -4530,12 +4515,8 @@ var init_ChatLayout = __esm({
4530
4515
  Box3,
4531
4516
  {
4532
4517
  flexDirection: "column",
4533
- borderStyle: "single",
4534
- borderLeft: true,
4535
- borderRight: false,
4536
- borderTop: false,
4537
- borderBottom: false,
4538
- borderColor: "#444444",
4518
+ borderStyle: "round",
4519
+ border: true,
4539
4520
  paddingLeft: 2,
4540
4521
  paddingRight: 0,
4541
4522
  paddingTop: 1,
@@ -4552,12 +4533,8 @@ var init_ChatLayout = __esm({
4552
4533
  Box3,
4553
4534
  {
4554
4535
  flexDirection: "column",
4555
- borderStyle: "single",
4556
- borderLeft: true,
4557
- borderRight: false,
4558
- borderTop: false,
4559
- borderBottom: false,
4560
- borderColor: "#444444",
4536
+ borderStyle: "round",
4537
+ border: true,
4561
4538
  paddingLeft: 2,
4562
4539
  paddingRight: 0,
4563
4540
  paddingTop: 1,
@@ -4744,7 +4721,7 @@ var init_ChatLayout = __esm({
4744
4721
  paddingLeft: 2,
4745
4722
  width: "100%"
4746
4723
  },
4747
- /* @__PURE__ */ React4.createElement(Box3, { width: 4, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(lineNum).padStart(3, " "), " ")),
4724
+ /* @__PURE__ */ React4.createElement(Box3, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, String(lineNum).padStart(4, " "), " ")),
4748
4725
  /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, renderHighlightedLine(text, lang, "#e1e4e8"))
4749
4726
  );
4750
4727
  }
@@ -4848,20 +4825,34 @@ var init_StatusBar = __esm({
4848
4825
  init_text();
4849
4826
  activeGetMemoryInfo = null;
4850
4827
  getLatencyColor = (delay) => {
4851
- if (delay <= 500) return "#00a564";
4828
+ if (delay <= 370) return "#00a564";
4852
4829
  if (delay >= 5e3) return "#ff0000";
4853
4830
  const points = [
4854
- { t: 500, r: 0, g: 165, b: 100 },
4855
- { t: 800, r: 120, g: 220, b: 80 },
4856
- { t: 1500, r: 250, g: 210, b: 40 },
4857
- { t: 3e3, r: 255, g: 120, b: 0 },
4831
+ { t: 370, r: 0, g: 165, b: 100 },
4832
+ // deep green
4833
+ { t: 550, r: 40, g: 195, b: 80 },
4834
+ // green
4835
+ { t: 800, r: 120, g: 220, b: 50 },
4836
+ // lime-green
4837
+ { t: 1100, r: 190, g: 225, b: 20 },
4838
+ // yellow-green
4839
+ { t: 1500, r: 250, g: 210, b: 15 },
4840
+ // yellow
4841
+ { t: 2e3, r: 255, g: 170, b: 0 },
4842
+ // amber
4843
+ { t: 2800, r: 255, g: 110, b: 0 },
4844
+ // orange
4845
+ { t: 3800, r: 255, g: 50, b: 0 },
4846
+ // deep orange
4858
4847
  { t: 5e3, r: 255, g: 0, b: 0 }
4848
+ // red
4859
4849
  ];
4860
4850
  for (let i = 0; i < points.length - 1; i++) {
4861
4851
  const p1 = points[i];
4862
4852
  const p2 = points[i + 1];
4863
4853
  if (delay >= p1.t && delay <= p2.t) {
4864
- const ratio = (delay - p1.t) / (p2.t - p1.t);
4854
+ let ratio = (delay - p1.t) / (p2.t - p1.t);
4855
+ ratio = ratio * ratio * (3 - 2 * ratio);
4865
4856
  const r = Math.round(p1.r + (p2.r - p1.r) * ratio);
4866
4857
  const g = Math.round(p1.g + (p2.g - p1.g) * ratio);
4867
4858
  const b = Math.round(p1.b + (p2.b - p1.b) * ratio);
@@ -4877,6 +4868,7 @@ var init_StatusBar = __esm({
4877
4868
  const [memoryUnit, setMemoryUnit] = useState5("MB");
4878
4869
  const [dotColor, setDotColor] = useState5("green");
4879
4870
  const chunkTimesRef = useRef3([]);
4871
+ const smoothedDelayRef = useRef3(370);
4880
4872
  useEffect4(() => {
4881
4873
  if (!isProcessing) {
4882
4874
  chunkTimesRef.current = [];
@@ -4886,7 +4878,7 @@ var init_StatusBar = __esm({
4886
4878
  const times = chunkTimesRef.current;
4887
4879
  if (times.length === 0 || times[times.length - 1] !== lastChunkTime) {
4888
4880
  times.push(lastChunkTime);
4889
- if (times.length > 5) {
4881
+ if (times.length > 10) {
4890
4882
  times.shift();
4891
4883
  }
4892
4884
  }
@@ -4906,8 +4898,13 @@ var init_StatusBar = __esm({
4906
4898
  averageInterval = sum / (times.length - 1);
4907
4899
  }
4908
4900
  const timeSinceLast = Date.now() - lastChunkTime;
4909
- const delay = Math.max(averageInterval, timeSinceLast);
4910
- setDotColor(getLatencyColor(delay));
4901
+ const STALL_THRESHOLD = 2500;
4902
+ const isStalled = timeSinceLast >= STALL_THRESHOLD;
4903
+ const cappedTimeSinceLast = !isStalled && averageInterval > 0 ? Math.min(timeSinceLast, averageInterval * 3) : timeSinceLast;
4904
+ const rawDelay = Math.max(averageInterval, cappedTimeSinceLast);
4905
+ const alpha = isStalled ? 0.4 : 0.2;
4906
+ smoothedDelayRef.current = smoothedDelayRef.current * (1 - alpha) + rawDelay * alpha;
4907
+ setDotColor(getLatencyColor(smoothedDelayRef.current));
4911
4908
  };
4912
4909
  checkLatency();
4913
4910
  const timer = setInterval(checkLatency, 100);
@@ -4941,7 +4938,7 @@ var init_StatusBar = __esm({
4941
4938
  let maxLimit = 262144;
4942
4939
  if (aiProvider === "NVIDIA" && (activeModel?.includes("glm") || activeModel?.includes("gpt") || activeModel?.includes("qwen"))) {
4943
4940
  maxLimit = 128e3;
4944
- } else if (aiProvider === "DeepSeek" || aiProvider === "Google" && apiTier === "Paid") {
4941
+ } else if (aiProvider === "DeepSeek" || aiProvider === "Google" && apiTier === "Paid" || aiProvider === "NVIDIA" && activeModel.includes("deepseek")) {
4945
4942
  maxLimit = 409600;
4946
4943
  }
4947
4944
  return /* @__PURE__ */ React5.createElement(
@@ -5200,11 +5197,11 @@ Info: 'initial' = user prompted for THIS active task, revert 'id' should be a tu
5200
5197
  1. [tool:functions.EmergencyRollback(method="getCheckpoint/forceRevert", id="...")]. Rollback workspace to a specific checkpoint in THIS agent loop. Usage: ONLY in catastrophic situations. Verify nothing catastrophic happened in codebase before ending agent loop. 'id' not needed with getCheckPoint
5201
5198
  ` : ""}
5202
5199
  - SUB AGENT TOOLS -
5203
- **PROACTIVE USE OF SUB AGENTS HIGHLY RECOMMENDED, PREFER USING FOR ALL TASK WHERE PLAUSIBLE & BENEFICIAL, EVEN WITHOUT EXPLICIT USER NUDGE**
5200
+ **PROACTIVE USE OF SUB AGENTS HIGHLY RECOMMENDED, PREFER USING FOR ALL TASK WHERE EVEN SLIGHTLY BENEFICIAL, EVEN WITHOUT EXPLICIT USER NUDGE**
5204
5201
  Invocation Types:
5205
5202
  - Invoke (async, background worker for parallel tasks, upto 7 parallel agents together). Usage: Benefits parallelism & speed. Can take long time, If invoked DO NOT REPEAT SAME TASK WHILE ACTIVE
5206
- - InvokeSync (sync, blocking main agent loop). Usage: Repeatetive work, Sequential tasks, Task delegation. Huge tokens/costs savings
5207
- 1. [agent:generalist.InvokeSync/Invoke(title="...", task="...")]. Task must me detailed, including exact file paths, imports/exports, dependency, folder structure
5203
+ - InvokeSync (sync, blocking main agent loop). Usage: Repeatetive work, Sequential tasks, Task delegation. Tokens/Costs savings
5204
+ 1. [agent:generalist.InvokeSync/Invoke(title="...", task="...")]. Task must me detailed, including exact file paths, imports/exports, dependency, folder structure. No terminal access
5208
5205
  2. [agent:generalist.GetProgress(id="...")]. Usage: Check progress of async subagent task, taking time? continue your task, MUST await (exponentially longer after 1st check) than spamming getProgress. NEVER FINISH WITHOUT 'AWAIT' WHILE SUBAGENT WORKING
5209
5206
  3. [agent:generalist.Cancel(id="...")]. Usage: Cancel async subagent task, LAST RESORT ONLY IF ITS STUCK FOR UNUSUALLY LONG (2m+) WITH NO PROGRESS`.trim() : `- CREATIVE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
5210
5207
  1. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
@@ -10763,7 +10760,7 @@ var init_ai = __esm({
10763
10760
  "openai/gpt-5.5-pro",
10764
10761
  "moonshotai/kimi-k2.6",
10765
10762
  // NVIDIA vision models
10766
- "moonshotai/kimi-k2.6",
10763
+ "moonshotai/kimi-k2.7",
10767
10764
  "stepfun-ai/step-3.7-flash",
10768
10765
  "google/gemma-4-31b-it",
10769
10766
  "mistralai/mistral-medium-3.5-128b",
@@ -11193,6 +11190,8 @@ var init_ai = __esm({
11193
11190
  push({ value: { type: "status", content: `Queue ${depth || 1}` }, done: false });
11194
11191
  }
11195
11192
  }
11193
+ } else if (!isStreamingStarted) {
11194
+ push({ value: { type: "status", content: `Queue '${res.status}'` }, done: false });
11196
11195
  }
11197
11196
  } catch (e) {
11198
11197
  }
@@ -12082,14 +12081,14 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
12082
12081
  return { text: fullText, usageMetadata };
12083
12082
  });
12084
12083
  };
12085
- consolidatePastMemories = async (currentChatId, settings) => {
12084
+ consolidatePastMemories = async (currentChatId, settings, tempStorage = null) => {
12086
12085
  try {
12087
12086
  const { aiProvider = "Google" } = settings;
12088
- const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
12089
- const totalMemoriesCount = Object.values(tempStorage).flat().length;
12090
- if (totalMemoriesCount <= 2) return;
12091
- const chatsToSummarize = Object.keys(tempStorage).filter((id) => {
12092
- return id !== currentChatId && Array.isArray(tempStorage[id]) && tempStorage[id].length > 2;
12087
+ const tempStorage2 = tempStorage2 || readEncryptedJson(TEMP_MEM_FILE, {});
12088
+ const totalMemoriesCount = Object.values(tempStorage2).flat().length;
12089
+ if (totalMemoriesCount <= 5) return;
12090
+ const chatsToSummarize = Object.keys(tempStorage2).filter((id) => {
12091
+ return id !== currentChatId && Array.isArray(tempStorage2[id]) && tempStorage2[id].length > 2;
12093
12092
  });
12094
12093
  if (chatsToSummarize.length === 0) return;
12095
12094
  let prompt = `You are a silent background process for the FluxFlow CLI Agent.
@@ -12110,7 +12109,7 @@ Chats to process:
12110
12109
  `;
12111
12110
  const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
12112
12111
  for (const id of chatsToSummarize) {
12113
- const rawMemories = tempStorage[id];
12112
+ const rawMemories = tempStorage2[id];
12114
12113
  const newMemoryListStr = rawMemories.map((m) => `- ${m}`).join("\n");
12115
12114
  const oldSummary = cacheStorage[id];
12116
12115
  prompt += `[Chat ID: ${id}]
@@ -12340,8 +12339,12 @@ Provide a consolidated summary of the entire session.`;
12340
12339
  }
12341
12340
  }
12342
12341
  if (isFirstPrompt && isMemoryEnabled) {
12343
- yield { type: "status", content: "Condensing past chat memories..." };
12344
- await consolidatePastMemories(chatId, settings);
12342
+ const tempStorage2 = readEncryptedJson(TEMP_MEM_FILE, {});
12343
+ const totalMemoriesCount = Object.values(tempStorage2).flat().length;
12344
+ if (totalMemoriesCount > 5) {
12345
+ yield { type: "status", content: "Condensing past chat memories" };
12346
+ await consolidatePastMemories(chatId, settings, tempStorage2);
12347
+ }
12345
12348
  }
12346
12349
  const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
12347
12350
  const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
@@ -14949,7 +14952,7 @@ Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
14949
14952
  "filemap": '- [tool:functions.FileMap(path="path/file")]. Shows file structure, functions, classes, imports/exports',
14950
14953
  "patchfile": '- [tool:functions.PatchFile(path="...", replaceContent1="...", newContent1="...")]. Surgical block replacement for editing files',
14951
14954
  "writefile": '- [tool:functions.WriteFile(path="...", content="...")]. Creates or overwrites a file',
14952
- "searchkeyword": '- [tool:functions.SearchKeyword(keyword="...", file="optional", subString="true/false")]. Global project text search',
14955
+ "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`,
14953
14956
  "websearch": '- [tool:functions.WebSearch(query="...", limit=number)]. Web Search',
14954
14957
  "webscrape": '- [tool:functions.WebScrape(url="...")]. Web Scrape',
14955
14958
  "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`
@@ -15849,7 +15852,7 @@ var init_witty_phrases = __esm({
15849
15852
  "Letting the thoughts marinate",
15850
15853
  "Just remembered where I put my keys",
15851
15854
  "Pondering the orb",
15852
- "I've seen things you people wouldn't believe\u2026 like a user who reads loading messages.",
15855
+ // "I've seen things you people wouldn't believe like a user who reads loading messages.",
15853
15856
  "Initiating thoughtful gaze",
15854
15857
  "What's a computer's favorite snack? Microchips.",
15855
15858
  "Why do Java developers wear glasses? Because they don't C#.",
@@ -15868,7 +15871,8 @@ var init_witty_phrases = __esm({
15868
15871
  "Pretty sure there's a cat walking on the keyboard somewhere",
15869
15872
  "Enhancing\u2026 Enhancing\u2026 Still loading.",
15870
15873
  "It's not a bug, it's a feature\u2026 of this loading screen.",
15871
- "Have you tried turning it off and on again? (The loading screen, not me.)",
15874
+ "Have you tried turning it off and on again?",
15875
+ // 'Have you tried turning it off and on again? (The loading screen, not me.)',
15872
15876
  "Constructing additional pylons",
15873
15877
  "New line? That\u2019s Ctrl+J.",
15874
15878
  "Releasing the HypnoDrones",
@@ -16011,9 +16015,9 @@ var init_GlintText = __esm({
16011
16015
  "src/components/GlintText.jsx"() {
16012
16016
  GlintText = ({
16013
16017
  text,
16014
- baseColor = "white",
16018
+ baseColor = "grey",
16015
16019
  glintColor = "gray",
16016
- speed = 150,
16020
+ speed = 200,
16017
16021
  glintWidth = 6,
16018
16022
  typeSpeed = 30,
16019
16023
  // 👈 New prop! How fast it backspaces and types! ⌨️
@@ -16028,7 +16032,7 @@ var init_GlintText = __esm({
16028
16032
  return () => clearInterval(timer);
16029
16033
  }, [displayedText.length, speed, glintWidth]);
16030
16034
  useEffect11(() => {
16031
- if (text && text.includes("Trying to reach")) {
16035
+ if (text && (text.includes("Trying to reach") && displayedText && displayedText.includes("Trying to reach") || text.includes("Error Occurred") && displayedText && displayedText.includes("Error Occurred"))) {
16032
16036
  setDisplayedText(text);
16033
16037
  return;
16034
16038
  }
@@ -17464,9 +17468,13 @@ function App({ args = [] }) {
17464
17468
  ] : aiProvider === "NVIDIA" ? [
17465
17469
  // --- Kimi (Moonshot AI) ---
17466
17470
  {
17467
- cmd: "moonshotai/kimi-k2.6",
17471
+ cmd: "moonshotai/kimi-k2.7",
17468
17472
  desc: "Multimodal"
17469
17473
  },
17474
+ {
17475
+ cmd: "moonshotai/kimi-k2.6",
17476
+ desc: "[DEPRICATED]"
17477
+ },
17470
17478
  // --- DeepSeek Family ---
17471
17479
  {
17472
17480
  cmd: "deepseek-ai/deepseek-v4-flash",
@@ -17505,10 +17513,6 @@ function App({ args = [] }) {
17505
17513
  desc: "Text Only"
17506
17514
  },
17507
17515
  // --- GLM (Zhipu AI) ---
17508
- {
17509
- cmd: "z-ai/glm-5.1",
17510
- desc: "Text Only [DEPRICATED]"
17511
- },
17512
17516
  {
17513
17517
  cmd: "z-ai/glm-5.2",
17514
17518
  desc: "Text Only"
@@ -19201,6 +19205,30 @@ Selection: ${val}`,
19201
19205
  useEffect12(() => {
19202
19206
  setSelectedIndex(0);
19203
19207
  }, [suggestions]);
19208
+ const [suggestionVisibleCount, setSuggestionVisibleCount] = useState15(0);
19209
+ const prevSuggestionsLenRef = useRef4(0);
19210
+ useEffect12(() => {
19211
+ const wasOpen = prevSuggestionsLenRef.current > 0;
19212
+ const isOpen = suggestions.length > 0;
19213
+ prevSuggestionsLenRef.current = suggestions.length;
19214
+ if (!isOpen) {
19215
+ setSuggestionVisibleCount(0);
19216
+ return;
19217
+ }
19218
+ if (!wasOpen) {
19219
+ setSuggestionVisibleCount(1);
19220
+ return;
19221
+ }
19222
+ setSuggestionVisibleCount(suggestions.length);
19223
+ }, [suggestions]);
19224
+ useEffect12(() => {
19225
+ if (suggestionVisibleCount > 0 && suggestionVisibleCount < suggestions.length) {
19226
+ const t = setTimeout(() => {
19227
+ setSuggestionVisibleCount((prev) => Math.min(prev + 1, suggestions.length));
19228
+ }, 5);
19229
+ return () => clearTimeout(t);
19230
+ }
19231
+ }, [suggestionVisibleCount, suggestions.length]);
19204
19232
  useEffect12(() => {
19205
19233
  if (activeView !== "providerBudgetSelect") return;
19206
19234
  const PBS_PROVIDERS = ["Google", "DeepSeek", "NVIDIA", "OpenRouter"];
@@ -20161,14 +20189,14 @@ Selection: ${val}`,
20161
20189
  GlintText_default,
20162
20190
  {
20163
20191
  text: statusText.trimEnd(),
20164
- baseColor: "#BFD2CA",
20165
- glintColor: "#D8D2C8",
20192
+ baseColor: "#B5B8D9",
20193
+ glintColor: "#BFD4DB",
20166
20194
  speed: 60,
20167
20195
  italic: true,
20168
20196
  glintWidth: 2,
20169
20197
  typeSpeed: 10
20170
20198
  }
20171
- ), /* @__PURE__ */ React16.createElement(Text16, { color: "gray" }, activeTime > 0 ? `(${activeTime.toFixed(0)}s)` : "")) : /* @__PURE__ */ React16.createElement(Text16, { color: "grey", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : hasPasteBlock ? "Press CTRL + O to expand" : "Waiting for input...")), /* @__PURE__ */ React16.createElement(Box14, null, isProcessing && Date.now() - lastChunkTime > 15e3 && !activeSubagents.some((sa) => sa.status === "running" && !statusText.toLowerCase().includes("waiting")) ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text16, { color: "white" }, "Waiting for API"), /* @__PURE__ */ React16.createElement(Text16, { color: "gray", dimColor: true }, " \u2503 ")) : wittyPhrase ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text16, { color: "gray", italic: true }, wittyPhrase), /* @__PURE__ */ React16.createElement(Text16, { color: "gray", dimColor: true }, " \u2503 ")) : null, /* @__PURE__ */ React16.createElement(GlintText_default, { text: tempModelOverride || activeModel, baseColor: "white", glintColor: "gray", glintWidth: 1 }))), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React16.createElement(Text16, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React16.createElement(
20199
+ ), /* @__PURE__ */ React16.createElement(Text16, { color: "gray" }, activeTime > 0 ? `(${activeTime.toFixed(0)}s)` : "")) : /* @__PURE__ */ React16.createElement(Text16, { color: "grey", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : hasPasteBlock ? "Press CTRL + O to expand" : "Waiting for input...")), /* @__PURE__ */ React16.createElement(Box14, null, isProcessing && Date.now() - lastChunkTime > 15e3 && !activeSubagents.some((sa) => sa.status === "running" && !statusText.toLowerCase().includes("waiting")) ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(GlintText_default, { text: "Waiting for API", baseColor: "white", glintColor: "gray", glintWidth: 4, speed: 80 }), /* @__PURE__ */ React16.createElement(Text16, { color: "gray", dimColor: true }, " \u2503 ")) : wittyPhrase ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(GlintText_default, { text: wittyPhrase, italic: true, speed: 80, typeSpeed: 15 }), /* @__PURE__ */ React16.createElement(Text16, { color: "gray", dimColor: true }, " \u2503 ")) : null, /* @__PURE__ */ React16.createElement(GlintText_default, { text: tempModelOverride || activeModel.split("/")[1] || activeModel, baseColor: "white", glintColor: "gray", glintWidth: 3 }))), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React16.createElement(Text16, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React16.createElement(
20172
20200
  Box14,
20173
20201
  {
20174
20202
  backgroundColor: "#555555",
@@ -20281,7 +20309,7 @@ Selection: ${val}`,
20281
20309
  }
20282
20310
  return /* @__PURE__ */ React16.createElement(Text16, { color: "gray", dimColor: true, italic: true }, "Paid API Strategy has more models. Configure ", /* @__PURE__ */ React16.createElement(Text16, { color: "cyan", underline: true }, `\x1B]8;;${url}\x07${label}\x1B]8;;\x07`), " & /settings");
20283
20311
  })() : null),
20284
- visible.map((s, i) => {
20312
+ visible.slice(0, suggestionVisibleCount).map((s, i) => {
20285
20313
  const actualIdx = startIdx + i;
20286
20314
  const isActive = actualIdx === selectedIndex;
20287
20315
  const isGemmaDisabled = s.cmd === "gemma-4-31b-it" && apiTier !== "Free";
@@ -20592,20 +20620,34 @@ var init_app = __esm({
20592
20620
  })();
20593
20621
  cachedShortcut = "Ctrl + Enter";
20594
20622
  getLatencyColor2 = (delay) => {
20595
- if (delay <= 500) return "#00a564";
20623
+ if (delay <= 370) return "#00a564";
20596
20624
  if (delay >= 5e3) return "#ff0000";
20597
20625
  const points = [
20598
- { t: 500, r: 0, g: 165, b: 100 },
20599
- { t: 800, r: 120, g: 220, b: 80 },
20600
- { t: 1500, r: 250, g: 210, b: 40 },
20601
- { t: 3e3, r: 255, g: 120, b: 0 },
20626
+ { t: 370, r: 0, g: 165, b: 100 },
20627
+ // deep green
20628
+ { t: 550, r: 40, g: 195, b: 80 },
20629
+ // green
20630
+ { t: 800, r: 120, g: 220, b: 50 },
20631
+ // lime-green
20632
+ { t: 1100, r: 190, g: 225, b: 20 },
20633
+ // yellow-green
20634
+ { t: 1500, r: 250, g: 210, b: 15 },
20635
+ // yellow
20636
+ { t: 2e3, r: 255, g: 170, b: 0 },
20637
+ // amber
20638
+ { t: 2800, r: 255, g: 110, b: 0 },
20639
+ // orange
20640
+ { t: 3800, r: 255, g: 50, b: 0 },
20641
+ // deep orange
20602
20642
  { t: 5e3, r: 255, g: 0, b: 0 }
20643
+ // red
20603
20644
  ];
20604
20645
  for (let i = 0; i < points.length - 1; i++) {
20605
20646
  const p1 = points[i];
20606
20647
  const p2 = points[i + 1];
20607
20648
  if (delay >= p1.t && delay <= p2.t) {
20608
- const ratio = (delay - p1.t) / (p2.t - p1.t);
20649
+ let ratio = (delay - p1.t) / (p2.t - p1.t);
20650
+ ratio = ratio * ratio * (3 - 2 * ratio);
20609
20651
  const r = Math.round(p1.r + (p2.r - p1.r) * ratio);
20610
20652
  const g = Math.round(p1.g + (p2.g - p1.g) * ratio);
20611
20653
  const b = Math.round(p1.b + (p2.b - p1.b) * ratio);
@@ -20617,6 +20659,7 @@ var init_app = __esm({
20617
20659
  SubagentRow = React16.memo(({ sa }) => {
20618
20660
  const [dotColor, setDotColor] = useState15("green");
20619
20661
  const chunkTimesRef = useRef4([]);
20662
+ const smoothedDelayRef = useRef4(370);
20620
20663
  useEffect12(() => {
20621
20664
  if (sa.status !== "running") {
20622
20665
  chunkTimesRef.current = [];
@@ -20627,7 +20670,7 @@ var init_app = __esm({
20627
20670
  const times = chunkTimesRef.current;
20628
20671
  if (times.length === 0 || times[times.length - 1] !== lastChunkTime) {
20629
20672
  times.push(lastChunkTime);
20630
- if (times.length > 5) {
20673
+ if (times.length > 10) {
20631
20674
  times.shift();
20632
20675
  }
20633
20676
  }
@@ -20647,8 +20690,13 @@ var init_app = __esm({
20647
20690
  averageInterval = sum / (times.length - 1);
20648
20691
  }
20649
20692
  const timeSinceLast = Date.now() - lastChunkTime;
20650
- const delay = Math.max(averageInterval, timeSinceLast);
20651
- setDotColor(getLatencyColor2(delay));
20693
+ const STALL_THRESHOLD = 2500;
20694
+ const isStalled = timeSinceLast >= STALL_THRESHOLD;
20695
+ const cappedTimeSinceLast = !isStalled && averageInterval > 0 ? Math.min(timeSinceLast, averageInterval * 3) : timeSinceLast;
20696
+ const rawDelay = Math.max(averageInterval, cappedTimeSinceLast);
20697
+ const alpha = isStalled ? 0.4 : 0.2;
20698
+ smoothedDelayRef.current = smoothedDelayRef.current * (1 - alpha) + rawDelay * alpha;
20699
+ setDotColor(getLatencyColor2(smoothedDelayRef.current));
20652
20700
  };
20653
20701
  checkLatency();
20654
20702
  const timer = setInterval(checkLatency, 100);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.2.1",
4
- "date": "2026-07-07",
3
+ "version": "3.2.4",
4
+ "date": "2026-07-08",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",