fluxflow-cli 3.0.10 → 3.0.12

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 +137 -49
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -4829,36 +4829,78 @@ var init_ChatLayout = __esm({
4829
4829
  // src/components/StatusBar.jsx
4830
4830
  import React5 from "react";
4831
4831
  import { Box as Box4, Text as Text5 } from "ink";
4832
- import { useState as useState5, useEffect as useEffect4 } from "react";
4832
+ import { useState as useState5, useEffect as useEffect4, useRef as useRef3 } from "react";
4833
4833
  function getMemoryInfo() {
4834
4834
  if (activeGetMemoryInfo) {
4835
4835
  activeGetMemoryInfo();
4836
4836
  }
4837
4837
  }
4838
- var activeGetMemoryInfo, StatusBar, StatusBar_default;
4838
+ var activeGetMemoryInfo, getLatencyColor, StatusBar, StatusBar_default;
4839
4839
  var init_StatusBar = __esm({
4840
4840
  "src/components/StatusBar.jsx"() {
4841
4841
  init_text();
4842
4842
  activeGetMemoryInfo = null;
4843
+ getLatencyColor = (delay) => {
4844
+ if (delay <= 400) return "#00a564";
4845
+ if (delay >= 5e3) return "#ff0000";
4846
+ const points = [
4847
+ { t: 400, r: 0, g: 165, b: 100 },
4848
+ { t: 800, r: 120, g: 220, b: 80 },
4849
+ { t: 1500, r: 250, g: 210, b: 40 },
4850
+ { t: 3e3, r: 255, g: 120, b: 0 },
4851
+ { t: 5e3, r: 255, g: 0, b: 0 }
4852
+ ];
4853
+ for (let i = 0; i < points.length - 1; i++) {
4854
+ const p1 = points[i];
4855
+ const p2 = points[i + 1];
4856
+ if (delay >= p1.t && delay <= p2.t) {
4857
+ const ratio = (delay - p1.t) / (p2.t - p1.t);
4858
+ const r = Math.round(p1.r + (p2.r - p1.r) * ratio);
4859
+ const g = Math.round(p1.g + (p2.g - p1.g) * ratio);
4860
+ const b = Math.round(p1.b + (p2.b - p1.b) * ratio);
4861
+ return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
4862
+ }
4863
+ }
4864
+ return "#ff0000";
4865
+ };
4843
4866
  StatusBar = React5.memo(({ mode, thinkingLevel, tokens = "0.0k", tokensTotal = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true, apiTier = "Free", aiProvider = "Google", activeModel = "", isProcessing = false, lastChunkTime = 0 }) => {
4844
4867
  const modeIcon = mode === "Flux" ? "" : "";
4845
4868
  const [memoryUsage, setMemoryUsage] = useState5(0);
4846
4869
  const [memoryLimit, setMemoryLimit] = useState5(0);
4847
4870
  const [memoryUnit, setMemoryUnit] = useState5("MB");
4848
4871
  const [dotColor, setDotColor] = useState5("green");
4872
+ const chunkTimesRef = useRef3([]);
4849
4873
  useEffect4(() => {
4850
- if (!isProcessing) return;
4874
+ if (!isProcessing) {
4875
+ chunkTimesRef.current = [];
4876
+ return;
4877
+ }
4878
+ if (lastChunkTime > 0) {
4879
+ const times = chunkTimesRef.current;
4880
+ if (times.length === 0 || times[times.length - 1] !== lastChunkTime) {
4881
+ times.push(lastChunkTime);
4882
+ if (times.length > 5) {
4883
+ times.shift();
4884
+ }
4885
+ }
4886
+ }
4851
4887
  const checkLatency = () => {
4852
- const delay = Date.now() - lastChunkTime;
4853
- if (delay < 700) {
4854
- setDotColor("green");
4855
- } else if (delay <= 1200) {
4856
- setDotColor("yellow");
4857
- } else if (delay <= 2e3) {
4858
- setDotColor("#ff9f43");
4859
- } else {
4860
- setDotColor("#d63031");
4888
+ if (!lastChunkTime) {
4889
+ setDotColor("#00a564");
4890
+ return;
4891
+ }
4892
+ const times = chunkTimesRef.current;
4893
+ let averageInterval = 0;
4894
+ if (times.length > 1) {
4895
+ let sum = 0;
4896
+ for (let i = 1; i < times.length; i++) {
4897
+ sum += times[i] - times[i - 1];
4898
+ }
4899
+ averageInterval = sum / (times.length - 1);
4861
4900
  }
4901
+ const timeSinceLast = Date.now() - lastChunkTime;
4902
+ const delay = Math.max(averageInterval, timeSinceLast);
4903
+ setDotColor(getLatencyColor(delay));
4862
4904
  };
4863
4905
  checkLatency();
4864
4906
  const timer = setInterval(checkLatency, 100);
@@ -5156,7 +5198,7 @@ Invocation Types:
5156
5198
  2. [agent:generalist.getProgress(id="...")]. Usage: Check progress of async subagent task, taking time? continue your task, MUST await (exponentially longer after 1st check, eg. 15s, 30s, 45s ...) than spamming getProgress. NEVER FINISH WITHOUT 'AWAIT' WHILE SUBAGENT WORKING`.trim() : `- CREATIVE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
5157
5199
  1. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
5158
5200
  2. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word document
5159
- - WORKSPACE TOOLS ARE NOT AVAILABLE IN FLOW`.trim()}
5201
+ - WORKSPACE & SUB AGENT TOOLS ARE NOT AVAILABLE IN FLOW`.trim()}
5160
5202
 
5161
5203
  - VERIFY TOOL RESULT CONTENTS. Fix errors. No hallucinations
5162
5204
  - Escape quotes: \\" for code strings
@@ -12040,7 +12082,8 @@ ${boxMid}`) };
12040
12082
  const boxMid = boxLines.map((line) => `${line.padEnd(boxWidth - 2).substring(0, boxWidth - 2)}`).join("\n");
12041
12083
  const boxBottom = `${" ".repeat(boxWidth)}`;
12042
12084
  yield { type: "visual_feedback", content: colorMainWords(`${boxBottom}
12043
- ${boxMid}`) };
12085
+ ${boxMid}
12086
+ `) };
12044
12087
  }
12045
12088
  }
12046
12089
  }
@@ -12899,9 +12942,11 @@ ${ideErr} [/ERROR]`;
12899
12942
  const action = normToolName === "write_file" ? "Created" : "Edited";
12900
12943
  label2 = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
12901
12944
  } else if (normToolName === "write_pdf") {
12902
- label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}`;
12945
+ label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}
12946
+ `;
12903
12947
  } else if (normToolName === "write_docx") {
12904
- label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}`;
12948
+ label2 = `\u2714 Created: ${parseArgs(toolCall.args).path || "..."}
12949
+ `;
12905
12950
  } else if (normToolName === "file_map") {
12906
12951
  label2 = `\u2714 Get Map: ${parseArgs(toolCall.args).path || "..."}`;
12907
12952
  } else if (normToolName.toLowerCase() === "search_keyword" || normToolName.toLowerCase() === "todo") {
@@ -14998,7 +15043,7 @@ __export(app_exports, {
14998
15043
  default: () => App
14999
15044
  });
15000
15045
  import os4 from "os";
15001
- import React15, { useState as useState14, useEffect as useEffect11, useRef as useRef3, useMemo as useMemo2 } from "react";
15046
+ import React15, { useState as useState14, useEffect as useEffect11, useRef as useRef4, useMemo as useMemo2 } from "react";
15002
15047
  import { Box as Box14, Text as Text15, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
15003
15048
  import fs22 from "fs-extra";
15004
15049
  import path20 from "path";
@@ -15024,8 +15069,8 @@ function App({ args = [] }) {
15024
15069
  const [isFilePickerDismissed, setIsFilePickerDismissed] = useState14(false);
15025
15070
  const [showBridgePromo, setShowBridgePromo] = useState14(false);
15026
15071
  const [promoSelectedIndex, setPromoSelectedIndex] = useState14(0);
15027
- const suggestionOffsetRef = useRef3(0);
15028
- const persistedModelRef = useRef3(null);
15072
+ const suggestionOffsetRef = useRef4(0);
15073
+ const persistedModelRef = useRef4(null);
15029
15074
  useEffect11(() => {
15030
15075
  const ideName = getIDEName();
15031
15076
  const isIDE = !["Terminal", "Windows Terminal"].includes(ideName) || !!process.env.VSC_TERMINAL_URL;
@@ -15239,7 +15284,7 @@ function App({ args = [] }) {
15239
15284
  const [janitorModel, setJanitorModel] = useState14("gemma-4-26b-a4b-it");
15240
15285
  const [isInitializing, setIsInitializing] = useState14(true);
15241
15286
  const [isAppFocused, setIsAppFocused] = useState14(true);
15242
- const lastFocusEventTime = useRef3(0);
15287
+ const lastFocusEventTime = useRef4(0);
15243
15288
  const [apiKey, setApiKey] = useState14(null);
15244
15289
  const [tempKey, setTempKey] = useState14("");
15245
15290
  const addShiftEnterBinding = async (ideName) => {
@@ -15310,7 +15355,7 @@ function App({ args = [] }) {
15310
15355
  const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState14(0);
15311
15356
  const [sessionTotalTokens, setSessionTotalTokens] = useState14(0);
15312
15357
  const [chatTokens, setChatTokens] = useState14(0);
15313
- const chatTokenStartRef = useRef3(0);
15358
+ const chatTokenStartRef = useRef4(0);
15314
15359
  const [sessionTotalCachedTokens, setSessionTotalCachedTokens] = useState14(0);
15315
15360
  const [sessionTotalCandidateTokens, setSessionTotalCandidateTokens] = useState14(0);
15316
15361
  const [sessionToolSuccess, setSessionToolSuccess] = useState14(0);
@@ -15353,12 +15398,12 @@ function App({ args = [] }) {
15353
15398
  const [isTerminalFocused, setIsTerminalFocused] = useState14(false);
15354
15399
  const [activeSubagents, setActiveSubagents] = useState14([]);
15355
15400
  const [tick, setTick] = useState14(0);
15356
- const isFirstRender = useRef3(true);
15357
- const isSecondRender = useRef3(true);
15358
- const isThirdRender = useRef3(true);
15359
- const prevProviderRef = useRef3(aiProvider);
15360
- const originalAllowExternalAccessRef = useRef3(false);
15361
- const originalMemoryRef = useRef3(true);
15401
+ const isFirstRender = useRef4(true);
15402
+ const isSecondRender = useRef4(true);
15403
+ const isThirdRender = useRef4(true);
15404
+ const prevProviderRef = useRef4(aiProvider);
15405
+ const originalAllowExternalAccessRef = useRef4(false);
15406
+ const originalMemoryRef = useRef4(true);
15362
15407
  useEffect11(() => {
15363
15408
  if (prevProviderRef.current !== aiProvider) {
15364
15409
  prevProviderRef.current = aiProvider;
@@ -15444,8 +15489,8 @@ function App({ args = [] }) {
15444
15489
  }
15445
15490
  };
15446
15491
  }, []);
15447
- const activeCommandRef = useRef3(null);
15448
- const execOutputRef = useRef3("");
15492
+ const activeCommandRef = useRef4(null);
15493
+ const execOutputRef = useRef4("");
15449
15494
  useEffect11(() => {
15450
15495
  activeCommandRef.current = activeCommand;
15451
15496
  }, [activeCommand]);
@@ -15501,8 +15546,8 @@ function App({ args = [] }) {
15501
15546
  const [escTimer, setEscTimer] = useState14(null);
15502
15547
  const [escPressCount, setEscPressCount] = useState14(0);
15503
15548
  const [recentPrompts, setRecentPrompts] = useState14([]);
15504
- const escDoubleTimerRef = useRef3(null);
15505
- const chatLoadingRef = useRef3(false);
15549
+ const escDoubleTimerRef = useRef4(null);
15550
+ const chatLoadingRef = useRef4(false);
15506
15551
  useEffect11(() => {
15507
15552
  return () => {
15508
15553
  if (escDoubleTimerRef.current) {
@@ -15510,7 +15555,7 @@ function App({ args = [] }) {
15510
15555
  }
15511
15556
  };
15512
15557
  }, []);
15513
- const didSignalTerminationRef = useRef3(false);
15558
+ const didSignalTerminationRef = useRef4(false);
15514
15559
  const [queuedPrompt, setQueuedPrompt] = useState14(null);
15515
15560
  const [resolutionData, setResolutionData] = useState14(null);
15516
15561
  const [tempModelOverride, setTempModelOverride] = useState14(null);
@@ -15563,11 +15608,11 @@ function App({ args = [] }) {
15563
15608
  return next;
15564
15609
  });
15565
15610
  };
15566
- const queuedPromptRef = useRef3(null);
15611
+ const queuedPromptRef = useRef4(null);
15567
15612
  const [btwResponse, setBtwResponse] = useState14("");
15568
15613
  const [showBtwBox, setShowBtwBox] = useState14(false);
15569
- const btwResponseRef = useRef3("");
15570
- const btwClosedRef = useRef3(null);
15614
+ const btwResponseRef = useRef4("");
15615
+ const btwClosedRef = useRef4(null);
15571
15616
  useEffect11(() => {
15572
15617
  if (messages.length === 0) return;
15573
15618
  const lastMsg = messages[messages.length - 1];
@@ -15588,8 +15633,8 @@ function App({ args = [] }) {
15588
15633
  }, [messages]);
15589
15634
  const [completedIndex, setCompletedIndex] = useState14(messages.length);
15590
15635
  const [clearKey, setClearKey] = useState14(0);
15591
- const lastCompletedBlocksRef = useRef3([]);
15592
- const cachedHistoryRef = useRef3({
15636
+ const lastCompletedBlocksRef = useRef4([]);
15637
+ const cachedHistoryRef = useRef4({
15593
15638
  completedIndex: 0,
15594
15639
  columns: 0,
15595
15640
  historicalBlocks: [],
@@ -16231,7 +16276,7 @@ function App({ args = [] }) {
16231
16276
  setTempKey("");
16232
16277
  }
16233
16278
  };
16234
- const lastSavedTimeRef = useRef3(SESSION_START_TIME);
16279
+ const lastSavedTimeRef = useRef4(SESSION_START_TIME);
16235
16280
  useEffect11(() => {
16236
16281
  if (activeView === "exit") {
16237
16282
  const flush = async () => {
@@ -19240,7 +19285,7 @@ Selection: ${val}`,
19240
19285
  return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "grey", width: Math.min(100, (stdout?.columns || 100) - 2), marginTop: 0, marginBottom: 0 }, /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text15, { bold: true }, gradient2(["blue", "purple"])("Agent powering down. Goodbye!"))), /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Text15, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, chatId)), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( ", /* @__PURE__ */ React15.createElement(Text15, { color: "green" }, "\u2713 ", sessionToolSuccess), " ", /* @__PURE__ */ React15.createElement(Text15, { color: "yellow" }, "\u2298 ", sessionToolDenied), " ", /* @__PURE__ */ React15.createElement(Text15, { color: "red" }, "\u2715 ", sessionToolFailure), " )")), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, successRate, "%")), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Code Changes:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, /* @__PURE__ */ React15.createElement(Text15, { color: "green" }, "+", linesAdded), " ", /* @__PURE__ */ React15.createElement(Text15, { color: "red" }, "-", linesRemoved))), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatTokens(sessionTotalTokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React15.createElement(Box14, { width: 18 }, /* @__PURE__ */ React15.createElement(Text15, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React15.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React15.createElement(Box14, { width: 16 }, /* @__PURE__ */ React15.createElement(Text15, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React15.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React15.createElement(Box14, { width: 18 }, /* @__PURE__ */ React15.createElement(Text15, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, sessionImageCount)), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits")))), /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text15, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Box14, { width: 20 }, /* @__PURE__ */ React15.createElement(Text15, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React15.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React15.createElement(Box14, { width: 18 }, /* @__PURE__ */ React15.createElement(Text15, { color: "grey" }, "\xBB API Time:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React15.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React15.createElement(Box14, { width: 18 }, /* @__PURE__ */ React15.createElement(Text15, { color: "grey" }, "\xBB Tool Time:")), /* @__PURE__ */ React15.createElement(Text15, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
19241
19286
  })())));
19242
19287
  }
19243
- var shouldClearValue, getPrefilledValue, getIDEName, getIDEDirName, getKeybindingsPath, parseJsonc, hasShiftEnterBinding, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles, cachedShortcut, SubagentRow;
19288
+ var shouldClearValue, getPrefilledValue, getIDEName, getIDEDirName, getKeybindingsPath, parseJsonc, hasShiftEnterBinding, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles, cachedShortcut, getLatencyColor2, SubagentRow;
19244
19289
  var init_app = __esm({
19245
19290
  async "src/app.jsx"() {
19246
19291
  init_build();
@@ -19496,21 +19541,64 @@ var init_app = __esm({
19496
19541
  };
19497
19542
  })();
19498
19543
  cachedShortcut = "\\ + Enter";
19544
+ getLatencyColor2 = (delay) => {
19545
+ if (delay <= 400) return "#00a564";
19546
+ if (delay >= 5e3) return "#ff0000";
19547
+ const points = [
19548
+ { t: 400, r: 0, g: 165, b: 100 },
19549
+ { t: 800, r: 120, g: 220, b: 80 },
19550
+ { t: 1500, r: 250, g: 210, b: 40 },
19551
+ { t: 3e3, r: 255, g: 120, b: 0 },
19552
+ { t: 5e3, r: 255, g: 0, b: 0 }
19553
+ ];
19554
+ for (let i = 0; i < points.length - 1; i++) {
19555
+ const p1 = points[i];
19556
+ const p2 = points[i + 1];
19557
+ if (delay >= p1.t && delay <= p2.t) {
19558
+ const ratio = (delay - p1.t) / (p2.t - p1.t);
19559
+ const r = Math.round(p1.r + (p2.r - p1.r) * ratio);
19560
+ const g = Math.round(p1.g + (p2.g - p1.g) * ratio);
19561
+ const b = Math.round(p1.b + (p2.b - p1.b) * ratio);
19562
+ return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
19563
+ }
19564
+ }
19565
+ return "#ff0000";
19566
+ };
19499
19567
  SubagentRow = React15.memo(({ sa }) => {
19500
19568
  const [dotColor, setDotColor] = useState14("green");
19569
+ const chunkTimesRef = useRef4([]);
19501
19570
  useEffect11(() => {
19502
- if (sa.status !== "running") return;
19571
+ if (sa.status !== "running") {
19572
+ chunkTimesRef.current = [];
19573
+ return;
19574
+ }
19575
+ const lastChunkTime = sa.lastChunkTime;
19576
+ if (lastChunkTime > 0) {
19577
+ const times = chunkTimesRef.current;
19578
+ if (times.length === 0 || times[times.length - 1] !== lastChunkTime) {
19579
+ times.push(lastChunkTime);
19580
+ if (times.length > 5) {
19581
+ times.shift();
19582
+ }
19583
+ }
19584
+ }
19503
19585
  const checkLatency = () => {
19504
- const delay = Date.now() - (sa.lastChunkTime || Date.now());
19505
- if (delay < 700) {
19506
- setDotColor("green");
19507
- } else if (delay <= 1200) {
19508
- setDotColor("yellow");
19509
- } else if (delay <= 2e3) {
19510
- setDotColor("#ff9f43");
19511
- } else {
19512
- setDotColor("#d63031");
19586
+ if (!lastChunkTime) {
19587
+ setDotColor("#00a564");
19588
+ return;
19589
+ }
19590
+ const times = chunkTimesRef.current;
19591
+ let averageInterval = 0;
19592
+ if (times.length > 1) {
19593
+ let sum = 0;
19594
+ for (let i = 1; i < times.length; i++) {
19595
+ sum += times[i] - times[i - 1];
19596
+ }
19597
+ averageInterval = sum / (times.length - 1);
19513
19598
  }
19599
+ const timeSinceLast = Date.now() - lastChunkTime;
19600
+ const delay = Math.max(averageInterval, timeSinceLast);
19601
+ setDotColor(getLatencyColor2(delay));
19514
19602
  };
19515
19603
  checkLatency();
19516
19604
  const timer = setInterval(checkLatency, 100);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.0.10",
4
- "date": "2026-07-03",
3
+ "version": "3.0.12",
4
+ "date": "2026-07-04",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",