fluxflow-cli 1.8.32 → 1.8.33

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 +72 -18
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -173,7 +173,7 @@ var init_ChatLayout = __esm({
173
173
  }
174
174
  }
175
175
  }
176
- return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*(turn\s*:)?\s*(continue|finish)?\s*$/gi, "").replace(/\n\s*turn\s*:\s*(continue|finish)\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/\[\/n\]/g, "\\\\n").trim();
176
+ return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*(turn\s*:)?\s*(continue|finish)?\s*$/gi, "").replace(/\n\s*turn\s*:\s*(continue|finish)\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/\[\/n\]?/g, "\\\\n").trim();
177
177
  };
178
178
  formatThinkText = (cleaned, columns = 80) => {
179
179
  if (!cleaned) return null;
@@ -1805,7 +1805,7 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
1805
1805
  fs10.mkdirSync(parentDir, { recursive: true });
1806
1806
  }
1807
1807
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
1808
- const processedContent = strip(content).replace(/\\n/g, "\n").replace(/\[\/n\]/g, "\\n");
1808
+ const processedContent = strip(content).replace(/\\n/g, "\n").replace(/\[\/n\]?/g, "\\n");
1809
1809
  const lineCount = processedContent.split(/\r?\n/).length;
1810
1810
  const originalSize = Buffer.byteLength(processedContent, "utf8");
1811
1811
  fs10.writeFileSync(absolutePath, processedContent, "utf8");
@@ -1858,7 +1858,7 @@ var init_update_file = __esm({
1858
1858
  if (content_to_add === void 0) return 'ERROR: Missing "content_to_add" argument.';
1859
1859
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
1860
1860
  const unescapeContent = (content) => {
1861
- return content.replace(/\\n/g, "\n").replace(/\[\/n\]/g, "\\n");
1861
+ return content.replace(/\\n/g, "\n").replace(/\[\/n\]?/g, "\\n");
1862
1862
  };
1863
1863
  content_to_replace = unescapeContent(strip(content_to_replace));
1864
1864
  content_to_add = unescapeContent(strip(content_to_add));
@@ -2529,7 +2529,7 @@ var init_terminal = __esm({
2529
2529
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
2530
2530
  import path16 from "path";
2531
2531
  import fs16 from "fs";
2532
- var client, TERMINATION_SIGNAL, signalTermination, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
2532
+ var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
2533
2533
  var init_ai = __esm({
2534
2534
  "src/utils/ai.js"() {
2535
2535
  init_prompts();
@@ -2545,6 +2545,27 @@ var init_ai = __esm({
2545
2545
  signalTermination = () => {
2546
2546
  TERMINATION_SIGNAL = true;
2547
2547
  };
2548
+ TOOL_LABELS = {
2549
+ "write_file": "Writing File",
2550
+ "update_file": "Updating File",
2551
+ "read_folder": "Listing Directory",
2552
+ "view_file": "Reading File",
2553
+ "exec_command": "Running Command",
2554
+ "web_search": "Searching Web",
2555
+ "web_scrape": "Reading Site",
2556
+ "memory": "Updating Memory",
2557
+ "search_keyword": "Finding Files",
2558
+ "ask": "Asking User"
2559
+ };
2560
+ getToolDetail = (toolName, argsStr) => {
2561
+ try {
2562
+ const pArgs = parseArgs(argsStr);
2563
+ const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
2564
+ return filePath ? path16.basename(filePath.replace(/[\\"]/g, "")) : null;
2565
+ } catch (e) {
2566
+ return null;
2567
+ }
2568
+ };
2548
2569
  runJanitorTask = async (settings, agentText, fullAgentTextRaw, history, callbacks = {}) => {
2549
2570
  const { onStatus, onMemoryUpdated, onBackgroundIncrement } = callbacks;
2550
2571
  const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats } = settings;
@@ -2706,7 +2727,7 @@ DEBUG [${date}]: ${finalSynthesis}
2706
2727
  else isEscaped = false;
2707
2728
  }
2708
2729
  if (!closed) {
2709
- return { inside: true, toolName: match[1], startIndex: match.index };
2730
+ return { inside: true, toolName: match[1], startIndex: match.index, args: text.substring(match.index + match[0].length) };
2710
2731
  }
2711
2732
  }
2712
2733
  return { inside: false };
@@ -2884,14 +2905,14 @@ DEBUG [${date}]: ${finalSynthesis}
2884
2905
  const agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
2885
2906
  let modifiedHistory = [...history.slice(0, -1)];
2886
2907
  if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 254e3) {
2887
- modifiedHistory = getTruncatedHistory(modifiedHistory, 4);
2908
+ modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
2888
2909
  }
2889
2910
  const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
2890
2911
  const otherMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems).map((mem) => `- ${mem}`).join("\n");
2891
2912
  const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
2892
2913
  const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
2893
2914
  const janitorUserMemories = persistentStorage.map((m) => `- [${m.id}]: ${m.memory}`).join("\n");
2894
- const firstUserMsg = `[SYSTEM] MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGH PRIORITY FOR THIS PROMPT. DO NOT FORGET.
2915
+ const firstUserMsg = `[SYSTEM] **MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGHEST PRIORITY**.
2895
2916
 
2896
2917
  USER_PROMPT: "${agentText}"`.trim();
2897
2918
  modifiedHistory.push({ role: "user", text: firstUserMsg });
@@ -2934,6 +2955,7 @@ USER_PROMPT: "${agentText}"`.trim();
2934
2955
  let inStreamRetryCount = 1;
2935
2956
  let turnText = "";
2936
2957
  let lastToolSniffed = null;
2958
+ let lastToolDetail = null;
2937
2959
  let lastToolEventTime = null;
2938
2960
  let toolResults = [];
2939
2961
  let toolCallPointer = 0;
@@ -2974,12 +2996,21 @@ USER_PROMPT: "${agentText}"`.trim();
2974
2996
  }
2975
2997
  const isContext32k = (sessionStats.tokens || 0) >= 32e3;
2976
2998
  const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, otherMemories, mainUserMemories, isMemoryEnabled, isContext32k, MAX_LOOPS, loop + 1);
2999
+ const jitInstruction = `
3000
+
3001
+ [SYSTEM] **MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGHEST PRIORITY**.`;
3002
+ const lastUserMsg = contents[contents.length - 1];
3003
+ let addedMarker = false;
3004
+ if (lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text?.startsWith("[TOOL_RESULT]")) {
3005
+ lastUserMsg.parts[0].text += jitInstruction;
3006
+ addedMarker = true;
3007
+ }
2977
3008
  stream = await client.models.generateContentStream({
2978
3009
  model: targetModel || "gemma-4-31b-it",
2979
3010
  contents,
2980
3011
  config: {
2981
3012
  systemInstruction: currentSystemInstruction,
2982
- temperature: mode === "Flux" ? 1.05 : 1.4,
3013
+ temperature: mode === "Flux" ? 0.98 : 1.4,
2983
3014
  maxOutputTokens: 32768,
2984
3015
  mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
2985
3016
  safetySettings: [
@@ -2991,6 +3022,9 @@ USER_PROMPT: "${agentText}"`.trim();
2991
3022
  thinkingConfig: { includeThoughts: false, thinkingLevel: targetModel.includes("pro") ? ThinkingLevel.HIGH : ThinkingLevel.MINIMAL }
2992
3023
  }
2993
3024
  });
3025
+ if (addedMarker && contents[contents.length - 1]?.parts?.[0]) {
3026
+ contents[contents.length - 1].parts[0].text = contents[contents.length - 1].parts[0].text.replace(jitInstruction, "").trim();
3027
+ }
2994
3028
  turnText = "";
2995
3029
  lastToolSniffed = null;
2996
3030
  lastToolEventTime = null;
@@ -3036,9 +3070,23 @@ USER_PROMPT: "${agentText}"`.trim();
3036
3070
  if (toolContext.inside) {
3037
3071
  if (!lastToolEventTime) lastToolEventTime = Date.now();
3038
3072
  const potentialTool = toolContext.toolName;
3039
- if (potentialTool && /^[a-z_]+$/.test(potentialTool) && potentialTool !== lastToolSniffed) {
3073
+ const partialArgs = toolContext.args || "";
3074
+ let detail = null;
3075
+ if (["write_file", "update_file", "view_file", "read_folder"].includes(potentialTool)) {
3076
+ const pArgs = parseArgs(partialArgs);
3077
+ const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
3078
+ if (filePath) {
3079
+ detail = path16.basename(filePath.replace(/[\\"]/g, ""));
3080
+ } else {
3081
+ const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory)\s*=\s*\\?["']?([^\\"' \),]+)/);
3082
+ if (m) detail = path16.basename(m[1].replace(/[\\"]/g, ""));
3083
+ }
3084
+ }
3085
+ const currentLabel = `${TOOL_LABELS[potentialTool] || potentialTool}${detail ? ` (${detail})` : ""}`;
3086
+ if (potentialTool !== lastToolSniffed || detail !== lastToolDetail) {
3040
3087
  lastToolSniffed = potentialTool;
3041
- yield { type: "status", content: `Working (${potentialTool})...` };
3088
+ lastToolDetail = detail;
3089
+ yield { type: "status", content: `${currentLabel}...` };
3042
3090
  }
3043
3091
  }
3044
3092
  const contextSafeText = getContextSafeText(turnText, false);
@@ -3098,7 +3146,9 @@ USER_PROMPT: "${agentText}"`.trim();
3098
3146
  const allToolsFound = detectToolCalls(toolActionableText);
3099
3147
  while (allToolsFound.length > toolCallPointer) {
3100
3148
  const toolCall = allToolsFound[toolCallPointer];
3101
- yield { type: "status", content: `Working (${toolCall.toolName})...` };
3149
+ const displayLabel = TOOL_LABELS[toolCall.toolName] || toolCall.toolName;
3150
+ const detail = getToolDetail(toolCall.toolName, toolCall.args);
3151
+ yield { type: "status", content: `${displayLabel}${detail ? ` (${detail})` : ""}...` };
3102
3152
  let label = "";
3103
3153
  if (toolCall.toolName === "web_search") {
3104
3154
  const { query, limit = 10 } = parseArgs(toolCall.args);
@@ -3197,7 +3247,9 @@ ${boxBottom}
3197
3247
  const absoluteCwd = path16.resolve(process.cwd());
3198
3248
  if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
3199
3249
  const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace. To enable this, ask the user to turn on "External Workspace Access" in /settings.`;
3200
- toolResults.push({ role: "user", text: `[TOOL_RESULT]: ERROR: ${denyMsg}` });
3250
+ toolResults.push({ role: "user", text: `[TOOL_RESULT]: ERROR: ${denyMsg}
3251
+
3252
+ [SYSTEM] **MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGHEST PRIORITY**.` });
3201
3253
  yield { type: "tool_result", content: `[TOOL_RESULT]: ERROR: ${denyMsg}` };
3202
3254
  toolCallPointer++;
3203
3255
  continue;
@@ -3210,7 +3262,9 @@ ${boxBottom}
3210
3262
  if (approval === "deny") {
3211
3263
  if (toolCall.toolName === "exec_command" && settings.onExecEnd) settings.onExecEnd();
3212
3264
  const denyMsg = `Permission Denied: User rejected the ${toolCall.toolName === "exec_command" ? "terminal execution" : "file edit"}.`;
3213
- toolResults.push({ role: "user", text: `[TOOL_RESULT]: DENIED: ${denyMsg}` });
3265
+ toolResults.push({ role: "user", text: `[TOOL_RESULT]: DENIED: ${denyMsg}
3266
+
3267
+ [SYSTEM] **MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGHEST PRIORITY**.` });
3214
3268
  yield { type: "tool_result", content: `[TOOL_RESULT]: DENIED: ${denyMsg}` };
3215
3269
  await incrementUsage("toolDenied");
3216
3270
  if (settings.onToolResult) settings.onToolResult("denied");
@@ -3305,7 +3359,7 @@ ${boxBottom}
3305
3359
  if (toolResults.length > 0) {
3306
3360
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3307
3361
  }
3308
- modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly from the EXACT word it left off and DON'T repeat what you already said! IF you were in a thinking block, complete the thinking and close the thinking with proper </think> then respond. PICK UP FROM TE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF." });
3362
+ modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly from the EXACT word it left off and DON'T repeat what you already said! IF you were in a thinking block, complete the thinking and close the thinking with proper </think> then respond. PICK UP FROM TE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF. Rules:\n- Do not reuse <think> if the thinking already started just continue and end it properly.\n- If the cutoff was in middle of a tool call, start the tool call from start as the system won't pick half tool formats.\n- Visually the new pickup and continuation should look natual sentence flow." });
3309
3363
  accumulatedContext += turnText;
3310
3364
  for (let i = waitTime / 1e3; i > 0; i--) {
3311
3365
  yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
@@ -3378,7 +3432,7 @@ ${timestamp}`;
3378
3432
  if (toolResults.length > 0) {
3379
3433
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3380
3434
  } else {
3381
- modifiedHistory.push({ role: "user", text: `[SYSTEM]: ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? "OVER-THINKING " : ""}LOOP DETECTED by Internal System${isThinkingLoop && " for current EFFORT_LEVEL"}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
3435
+ modifiedHistory.push({ role: "user", text: `[SYSTEM] ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? " OVER-THINKING" : " LOOP"} DETECTED by Internal System${isThinkingLoop && " for current EFFORT_LEVEL"}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
3382
3436
  isThinkingLoop = false;
3383
3437
  isStutteringLoop = false;
3384
3438
  }
@@ -5109,9 +5163,9 @@ Selection: ${val}`,
5109
5163
  const oldVal = args.TargetContent || args.content_to_replace || null;
5110
5164
  const newVal = args.content || args.ReplacementContent || args.content_to_add || args.replacementContent || null;
5111
5165
  if (oldVal && newVal) {
5112
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal.replace(/\[\/n\]/g, "\\n"))));
5166
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal.replace(/\[\/n\]?/g, "\\n"))));
5113
5167
  }
5114
- return /* @__PURE__ */ React10.createElement(Text10, { color: "white", wrap: "anywhere" }, newVal.replace(/\[\/n\]/g, "\\n") || "Updating file content...");
5168
+ return /* @__PURE__ */ React10.createElement(Text10, { color: "white", wrap: "anywhere" }, newVal.replace(/\[\/n\]?/g, "\\n") || "Updating file content...");
5115
5169
  })()), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
5116
5170
  CommandMenu,
5117
5171
  {
@@ -5341,7 +5395,7 @@ var init_app = __esm({
5341
5395
  init_text();
5342
5396
  SESSION_START_TIME = Date.now();
5343
5397
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5344
- versionFluxflow = "1.8.32";
5398
+ versionFluxflow = "1.8.33";
5345
5399
  updatedOn = "2026-05-12";
5346
5400
  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(
5347
5401
  CommandMenu,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.8.32",
3
+ "version": "1.8.33",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",