fluxflow-cli 1.8.11 → 1.8.13

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 +78 -20
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -1301,7 +1301,7 @@ var init_web_search = __esm({
1301
1301
  const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
1302
1302
  await new Promise((r) => setTimeout(r, jitter));
1303
1303
  const searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
1304
- await page.goto(searchUrl, { waitUntil: "networkidle2" });
1304
+ await page.goto(searchUrl, { waitUntil: "networkidle2", timeout: 18e4 });
1305
1305
  const results = await page.$$eval(".result", (elements, maxLimit) => {
1306
1306
  return elements.slice(0, maxLimit).map((el, i) => {
1307
1307
  const titleEl = el.querySelector(".result__a");
@@ -1384,7 +1384,7 @@ var init_web_scrape = __esm({
1384
1384
  await page.setViewport({ width: 1366, height: 768 });
1385
1385
  const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
1386
1386
  await new Promise((r) => setTimeout(r, jitter));
1387
- await page.goto(url, { waitUntil: "networkidle2", timeout: 45e3 });
1387
+ await page.goto(url, { waitUntil: "networkidle2", timeout: 18e4 });
1388
1388
  await new Promise((r) => setTimeout(r, 5e3));
1389
1389
  let htmlContent = await page.evaluate(() => {
1390
1390
  const junk = document.querySelectorAll("script, style, nav, footer, header, noscript, svg, canvas, iframe, ad, .ads, link, meta, img");
@@ -2150,7 +2150,7 @@ var init_write_pdf = __esm({
2150
2150
  <div class="watermark">Generated by FluxFlow CLI (AI)</div>
2151
2151
  ${content}
2152
2152
  `;
2153
- await page.setContent(styledContent, { waitUntil: "networkidle0" });
2153
+ await page.setContent(styledContent, { waitUntil: "networkidle0", timeout: 18e4 });
2154
2154
  const pdfBytes = await page.pdf({
2155
2155
  format: "A4",
2156
2156
  landscape: orientation.toLowerCase() === "landscape",
@@ -2697,6 +2697,7 @@ var init_ai = __esm({
2697
2697
  try {
2698
2698
  if (isInitialAttempt) {
2699
2699
  yield { type: "turn_reset", content: true };
2700
+ yield { type: "spinner", content: true };
2700
2701
  isInitialAttempt = false;
2701
2702
  accumulatedContext = "";
2702
2703
  }
@@ -2775,20 +2776,24 @@ var init_ai = __esm({
2775
2776
  if (chunk.text) {
2776
2777
  if (isDedupeActive) {
2777
2778
  dedupeBuffer += chunk.text;
2778
- if (dedupeBuffer.length >= accumulatedContext.length) {
2779
- if (dedupeBuffer.startsWith(accumulatedContext)) {
2780
- const newText = dedupeBuffer.substring(accumulatedContext.length);
2781
- if (newText) {
2782
- turnText += newText;
2783
- yield { type: "text", content: newText };
2779
+ if (dedupeBuffer.length >= 100) {
2780
+ let overlapLen = 0;
2781
+ const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
2782
+ for (let len = maxPossibleOverlap; len > 0; len--) {
2783
+ if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
2784
+ overlapLen = len;
2785
+ break;
2784
2786
  }
2785
- isDedupeActive = false;
2786
- } else {
2787
- turnText += dedupeBuffer;
2788
- yield { type: "text", content: dedupeBuffer };
2789
- isDedupeActive = false;
2790
2787
  }
2788
+ const cleanText = dedupeBuffer.substring(overlapLen);
2789
+ if (cleanText) {
2790
+ turnText += cleanText;
2791
+ yield { type: "text", content: cleanText };
2792
+ }
2793
+ isDedupeActive = false;
2794
+ dedupeBuffer = "";
2791
2795
  }
2796
+ continue;
2792
2797
  } else {
2793
2798
  turnText += chunk.text;
2794
2799
  yield { type: "text", content: chunk.text };
@@ -2810,15 +2815,44 @@ var init_ai = __esm({
2810
2815
  const uniqueSentences = new Set(sentences);
2811
2816
  const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
2812
2817
  const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
2813
- let repetitionThreshold = 0.4;
2814
- let isOverVerbose = wordCount > 2500;
2815
- if (repetitionRatio > repetitionThreshold || isOverVerbose) {
2816
- const reason = repetitionRatio > repetitionThreshold ? "Thinking Loop Detected" : "Rambling Detected";
2818
+ let repetitionThresholdThinking = 0.4;
2819
+ let repetitionThresholdResponse = 0.6;
2820
+ let isOverVerboseThinking = wordCount > 2500;
2821
+ if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
2822
+ const reason = repetitionRatio > repetitionThresholdThinking ? "Thinking Loop Detected" : "Rambling Detected";
2817
2823
  yield { type: "status", content: `${reason}. Re-centering...` };
2818
2824
  isThinkingLoop = true;
2819
2825
  await new Promise((resolve) => setTimeout(resolve, 3e3));
2820
2826
  break;
2821
2827
  }
2828
+ const responseContent = signalSafeText2.trim();
2829
+ const respSentences = responseContent.split(/[.!?]\s+/);
2830
+ const uniqueRespSentences = new Set(respSentences);
2831
+ const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
2832
+ if (respRepetitionRatio > repetitionThresholdResponse) {
2833
+ yield { type: "status", content: `Response Loop Detected. Re-centering...` };
2834
+ isThinkingLoop = false;
2835
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
2836
+ break;
2837
+ }
2838
+ const allWords = contextSafeText.split(/\s+/).filter((w) => w.length > 0);
2839
+ if (allWords.length > 12) {
2840
+ let stutterDetected = false;
2841
+ for (let i = 0; i < allWords.length - 10; i++) {
2842
+ const sub = allWords.slice(i, i + 5).join(" ");
2843
+ const next = allWords.slice(i + 5, i + 10).join(" ");
2844
+ if (sub === next) {
2845
+ stutterDetected = true;
2846
+ break;
2847
+ }
2848
+ }
2849
+ if (stutterDetected) {
2850
+ yield { type: "status", content: `Stuttering Detected. Re-centering...` };
2851
+ isThinkingLoop = false;
2852
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
2853
+ break;
2854
+ }
2855
+ }
2822
2856
  const toolActionableText = turnText.replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "");
2823
2857
  const allToolsFound = detectToolCalls(toolActionableText);
2824
2858
  while (allToolsFound.length > toolCallPointer) {
@@ -2943,12 +2977,14 @@ ${boxBottom}
2943
2977
  }
2944
2978
  }
2945
2979
  const effectiveStart = lastToolEventTime || Date.now();
2980
+ yield { type: "spinner", content: false };
2946
2981
  let result = await dispatchTool(toolCall.toolName, toolCall.args, {
2947
2982
  chatId,
2948
2983
  history,
2949
2984
  onChunk: (chunk2) => settings.onExecChunk ? settings.onExecChunk(chunk2) : null,
2950
2985
  onAskUser: settings.onAskUser
2951
2986
  });
2987
+ yield { type: "spinner", content: true };
2952
2988
  const toolEnd = Date.now();
2953
2989
  yield { type: "tool_time", content: toolEnd - effectiveStart };
2954
2990
  lastToolEventTime = toolEnd;
@@ -2985,6 +3021,23 @@ ${boxBottom}
2985
3021
  yield { type: "liveTokens", content: lastUsage.totalTokenCount };
2986
3022
  }
2987
3023
  }
3024
+ if (isDedupeActive && dedupeBuffer.length > 0) {
3025
+ let overlapLen = 0;
3026
+ const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
3027
+ for (let len = maxPossibleOverlap; len > 0; len--) {
3028
+ if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
3029
+ overlapLen = len;
3030
+ break;
3031
+ }
3032
+ }
3033
+ const cleanText = dedupeBuffer.substring(overlapLen);
3034
+ if (cleanText) {
3035
+ turnText += cleanText;
3036
+ yield { type: "text", content: cleanText };
3037
+ }
3038
+ isDedupeActive = false;
3039
+ dedupeBuffer = "";
3040
+ }
2988
3041
  if (TERMINATION_SIGNAL) break;
2989
3042
  success = true;
2990
3043
  await incrementUsage("agent");
@@ -3568,6 +3621,7 @@ Check what's new using \`/changelog\` command.`,
3568
3621
  return formatDuration(Math.floor(ms / 1e3));
3569
3622
  };
3570
3623
  const [statusText, setStatusText] = useState7(null);
3624
+ const [isSpinnerActive, setIsSpinnerActive] = useState7(true);
3571
3625
  const [isProcessing, setIsProcessing] = useState7(false);
3572
3626
  const [escPressed, setEscPressed] = useState7(false);
3573
3627
  const [escTimer, setEscTimer] = useState7(null);
@@ -4242,6 +4296,10 @@ Selection: ${val}`,
4242
4296
  setStatusText(packet.content);
4243
4297
  continue;
4244
4298
  }
4299
+ if (packet.type === "spinner") {
4300
+ setIsSpinnerActive(packet.content);
4301
+ continue;
4302
+ }
4245
4303
  if (packet.type === "model_update") {
4246
4304
  setTempModelOverride(packet.content);
4247
4305
  continue;
@@ -4933,7 +4991,7 @@ Selection: ${val}`,
4933
4991
  }
4934
4992
  )));
4935
4993
  default:
4936
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, null, statusText && /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta" }, /* @__PURE__ */ React10.createElement(Spinner2, { type: "dots" })), /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", italic: true }, " ", statusText))), /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true }, "(", tempModelOverride || activeModel, ")")), suggestions.length > 0 && /* @__PURE__ */ React10.createElement(Box10, { paddingY: 0 }), /* @__PURE__ */ React10.createElement(Box10, { backgroundColor: "#333333", paddingX: 1, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, maxLines > 2 && !isExpanded ? /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "row", width: "100%", paddingY: 0, height: 1, overflow: "hidden" }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true }, "[Pasted ", maxLines, " Lines]")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React10.createElement(
4994
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, null, statusText && /* @__PURE__ */ React10.createElement(Box10, null, isSpinnerActive && /* @__PURE__ */ React10.createElement(Text10, { color: "magenta" }, /* @__PURE__ */ React10.createElement(Spinner2, { type: "dots" })), /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", italic: true }, isSpinnerActive ? " " : "", statusText))), /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true }, "(", tempModelOverride || activeModel, ")")), suggestions.length > 0 && /* @__PURE__ */ React10.createElement(Box10, { paddingY: 0 }), /* @__PURE__ */ React10.createElement(Box10, { backgroundColor: "#333333", paddingX: 1, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, maxLines > 2 && !isExpanded ? /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "row", width: "100%", paddingY: 0, height: 1, overflow: "hidden" }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true }, "[Pasted ", maxLines, " Lines]")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React10.createElement(
4937
4995
  MultilineInput,
4938
4996
  {
4939
4997
  value: "",
@@ -5055,7 +5113,7 @@ var init_app = __esm({
5055
5113
  init_text();
5056
5114
  SESSION_START_TIME = Date.now();
5057
5115
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5058
- versionFluxflow = "1.8.11";
5116
+ versionFluxflow = "1.8.13";
5059
5117
  updatedOn = "2026-05-09";
5060
5118
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent already finished the task before your hint was consumed."), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
5061
5119
  CommandMenu,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.8.11",
3
+ "version": "1.8.13",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",