fluxflow-cli 2.9.0 → 2.10.1

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 +226 -29
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -1586,7 +1586,7 @@ var init_ChatLayout = __esm({
1586
1586
  }
1587
1587
  }
1588
1588
  }
1589
- return result.replace(/\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi, "").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(/\[\[END\]\]/gi, "").replace(/\[\s*turn\s*:?.*?$/gi, "").replace(/\n\s*turn\s*:?.*?$/gi, "").replace(/\[\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(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replace(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_docx|generate_image)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
1589
+ return result.replaceAll(/\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi, "").replaceAll(/<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi, "").replace(/\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi, "").replaceAll(/\[TOOL RESULT\]:?\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replaceAll(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replaceAll(/\[\[END\]\]/gi, "").replaceAll(/\[\s*turn\s*:?.*?$/gi, "").replaceAll(/\n\s*turn\s*:?.*?$/gi, "").replaceAll(/\[\s*$/gi, "").replaceAll(/\n\nResponded on .*/g, "").replaceAll(/\n\n\[Prompted on: .*\]/g, "").replaceAll(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replaceAll(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replaceAll(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replaceAll(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replaceAll(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replaceAll(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replaceAll(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_docx|generate_image)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
1590
1590
  };
1591
1591
  formatThinkText = (cleaned, columns = 80) => {
1592
1592
  if (!cleaned) return null;
@@ -1896,6 +1896,7 @@ var init_ChatLayout = __esm({
1896
1896
  { cmd: "/save", desc: "Force save current chat" },
1897
1897
  { cmd: "/export", desc: "Export current chat in a .txt file" },
1898
1898
  { cmd: "/chats", desc: "List all chat sessions" },
1899
+ { cmd: "/btw", desc: "Send raw inquiry mid-turn" },
1899
1900
  { cmd: "/image", desc: "Generate images" },
1900
1901
  { cmd: "/mode", desc: "Toggle Flux/Flow modes" },
1901
1902
  { cmd: "/thinking", desc: "Set AI reasoning depth" },
@@ -2462,6 +2463,7 @@ var init_exec_command = __esm({
2462
2463
  const looksLikePath = (str) => {
2463
2464
  if (!str.includes("/")) return false;
2464
2465
  if (/^(https?|file|ftp):\/\//i.test(str)) return false;
2466
+ if (str.startsWith("@")) return false;
2465
2467
  if (str.startsWith("/") && (str.match(/\//g) || []).length === 1) {
2466
2468
  return false;
2467
2469
  }
@@ -3448,8 +3450,7 @@ ${projectContextBlock}
3448
3450
 
3449
3451
  -- FORMATTING --
3450
3452
  - GFM Supported
3451
- - NO CHAT RESPONSE **AFTER** CALLING TOOLS IN SAME TURN
3452
- - ONE THINKING BLOCK PER TURN
3453
+ - NO CHAT **AFTER** FIRING TOOLS IN THIS TURN
3453
3454
  - Basic LaTeX${mode === "Flux" ? "" : ". Kaomojis"}
3454
3455
  === END SYSTEM PROMPT ===`.trim();
3455
3456
  };
@@ -8168,7 +8169,8 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
8168
8169
  let wasToolCalledInLastLoop = false;
8169
8170
  modifiedHistory.forEach((msg) => {
8170
8171
  if (msg.text && msg.role === "agent") {
8171
- msg.text = msg.text.replace(/(?:<(think|thought)>|\[(think|thought)\])[\s\S]*?(?:<\/(think|thought)>|\[\/(think|thought)\])/gi, "").trim();
8172
+ msg.text = msg.text.replace(/(?:<(think|thought)>|\[(think|thought)\])[\s\S]*?(?:<\/(think|thought)>|\[\/(think|thought)\])/gi, "");
8173
+ msg.text = msg.text.replace(/(?:<(think|thought)>|\[(think|thought)\])[^\[\n]*/gi, "").trim();
8172
8174
  }
8173
8175
  });
8174
8176
  for (let loop = 0; loop <= MAX_LOOPS; loop++) {
@@ -8187,14 +8189,25 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
8187
8189
  if (steeringCallback) {
8188
8190
  const hint = await steeringCallback();
8189
8191
  if (hint) {
8190
- if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "user") {
8191
- modifiedHistory[modifiedHistory.length - 1].text += `
8192
+ if (hint.startsWith("/btw")) {
8193
+ if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "user") {
8194
+ modifiedHistory[modifiedHistory.length - 1].text += `
8192
8195
 
8193
- [STEERING HINT]: ${hint}`;
8196
+ [SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY [/SYSTEM]
8197
+ [QUESTION] ${hint.replace("/btw", "").trim()} [/QUESTION]`;
8198
+ } else {
8199
+ 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]` });
8200
+ }
8194
8201
  } else {
8195
- 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}` });
8202
+ if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "user") {
8203
+ modifiedHistory[modifiedHistory.length - 1].text += `
8204
+
8205
+ [STEERING HINT] ${hint.trim()} [/STEERING HINT]`;
8206
+ } else {
8207
+ 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]` });
8208
+ }
8196
8209
  }
8197
- yield { type: "status", content: "Steering Hint Injected." };
8210
+ yield { type: "status", content: `${hint.startsWith("/btw") ? "Question Forwarded..." : "Steering Hint Injected..."}` };
8198
8211
  }
8199
8212
  }
8200
8213
  let stream;
@@ -8319,14 +8332,16 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
8319
8332
  }
8320
8333
  currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, isMultiModal);
8321
8334
  const lastUserMsg = contents[contents.length - 1];
8322
- if (isBridgeConnected()) {
8323
- await new Promise((resolve) => setTimeout(resolve, 2e3));
8335
+ if (isBridgeConnected() & loop > 0) {
8336
+ yield { type: "status", content: "Checking Code..." };
8337
+ await new Promise((resolve) => setTimeout(resolve, 2500));
8324
8338
  const ideCtxJIT = await getIDEContext();
8325
8339
  const ideErr = ideCtxJIT ? ideCtxJIT.diagnostics : null;
8326
8340
  if (ideErr && lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text) {
8327
8341
  lastUserMsg.parts[0].text += `
8328
8342
  ${ideErr} [/ERROR]`;
8329
8343
  }
8344
+ yield { type: "status", content: "Working..." };
8330
8345
  }
8331
8346
  const isGemma = modelName && modelName.toLowerCase().startsWith("gemma") && aiProvider === "Google";
8332
8347
  if (isGemma) {
@@ -8885,12 +8900,112 @@ ${ideErr} [/ERROR]`;
8885
8900
  if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
8886
8901
  const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
8887
8902
  const currentDrive = path19.resolve(process.cwd()).substring(0, 3).toLowerCase();
8888
- const isViolating = riskyPatterns.some((pattern) => {
8889
- if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
8890
- const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
8891
- return driveMatch && driveMatch[0].toLowerCase() !== currentDrive;
8903
+ const splitCommands = (cmdString) => {
8904
+ const commands = [];
8905
+ let current = "";
8906
+ let inQuote = null;
8907
+ for (let i = 0; i < cmdString.length; i++) {
8908
+ const char = cmdString[i];
8909
+ if (inQuote) {
8910
+ if (char === inQuote) inQuote = null;
8911
+ current += char;
8912
+ } else {
8913
+ if (char === '"' || char === "'") {
8914
+ inQuote = char;
8915
+ current += char;
8916
+ } else if (char === "&" && cmdString[i + 1] === "&" || char === "|" && cmdString[i + 1] === "|") {
8917
+ if (current.trim()) {
8918
+ commands.push(current.trim());
8919
+ current = "";
8920
+ }
8921
+ i++;
8922
+ } else if (char === ";" || char === "|" || char === "&") {
8923
+ if (current.trim()) {
8924
+ commands.push(current.trim());
8925
+ current = "";
8926
+ }
8927
+ } else {
8928
+ current += char;
8929
+ }
8930
+ }
8892
8931
  }
8893
- return pattern.test(command);
8932
+ if (current.trim()) {
8933
+ commands.push(current.trim());
8934
+ }
8935
+ return commands;
8936
+ };
8937
+ const tokenizeCommand = (cmd) => {
8938
+ const tokens = [];
8939
+ let current = "";
8940
+ let inQuote = null;
8941
+ for (let i = 0; i < cmd.length; i++) {
8942
+ const char = cmd[i];
8943
+ if (inQuote) {
8944
+ if (char === inQuote) {
8945
+ inQuote = null;
8946
+ current += char;
8947
+ } else {
8948
+ current += char;
8949
+ }
8950
+ } else {
8951
+ if (char === '"' || char === "'") {
8952
+ inQuote = char;
8953
+ current += char;
8954
+ } else if (/\s/.test(char)) {
8955
+ if (current) {
8956
+ tokens.push(current);
8957
+ current = "";
8958
+ }
8959
+ } else {
8960
+ current += char;
8961
+ }
8962
+ }
8963
+ }
8964
+ if (current) {
8965
+ tokens.push(current);
8966
+ }
8967
+ return tokens;
8968
+ };
8969
+ const checkToken = (token) => {
8970
+ const cleanToken = token.replace(/^['"]|['"]$/g, "").trim();
8971
+ if (!cleanToken) return false;
8972
+ if (process.platform === "win32" && /^\/[a-zA-Z0-9?]+$/.test(cleanToken)) {
8973
+ return false;
8974
+ }
8975
+ return riskyPatterns.some((pattern) => {
8976
+ if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
8977
+ const driveMatch = cleanToken.match(/[a-zA-Z]:[\\\/]/i);
8978
+ return driveMatch && driveMatch[0].toLowerCase() !== currentDrive;
8979
+ }
8980
+ return pattern.test(cleanToken);
8981
+ });
8982
+ };
8983
+ const commandParts = splitCommands(command);
8984
+ const isViolating = commandParts.some((cmdPart) => {
8985
+ const tokens = tokenizeCommand(cmdPart);
8986
+ if (tokens.length === 0) return false;
8987
+ const exe = tokens[0].replace(/^['"]|['"]$/g, "").toLowerCase();
8988
+ const isSafePrint = ["echo", "printf", "write-output"].includes(exe);
8989
+ if (isSafePrint) {
8990
+ let checkNext = false;
8991
+ return tokens.some((token) => {
8992
+ const clean = token.replace(/^['"]|['"]$/g, "");
8993
+ if (clean === ">" || clean === ">>" || clean === "<") {
8994
+ checkNext = true;
8995
+ return false;
8996
+ }
8997
+ if (clean.startsWith(">") || clean.startsWith("<")) {
8998
+ const pathPart = clean.replace(/^[><]+/, "");
8999
+ return checkToken(pathPart);
9000
+ }
9001
+ if (checkNext) {
9002
+ checkNext = false;
9003
+ return checkToken(token);
9004
+ }
9005
+ return false;
9006
+ });
9007
+ }
9008
+ return tokens.some((token) => checkToken(token));
8894
9009
  });
8895
9010
  if (isViolating) {
8896
9011
  const denyMsg = `Access Denied. Terminal is prohibited from accessing system drives (C://) or external directories while "External Workspace Access" is disabled.`;
@@ -9652,6 +9767,9 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9652
9767
  const cleanedTurnText = contextSafeReplace(turnText, /(\[\s*(turn\s*:)?\s*(continue|finish)\s*\]|\[\[END\]\])/gi, "").trim();
9653
9768
  let isActuallyFinished = (hasFinish || toolResults.length === 0) && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop;
9654
9769
  isActuallyFinished = toolResults.length === 0 ? isActuallyFinished : false;
9770
+ if (turnText && turnText.trim().endsWith('")]') && toolResults.length === 0) {
9771
+ isActuallyFinished = false;
9772
+ }
9655
9773
  if (isActuallyFinished) {
9656
9774
  const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
9657
9775
  const cleanedFullResponse = fullAgentTextRaw.replace(/(?:<think>|\[think\])[\s\S]*?(?:<\/think>|\[\/think\])/g, "").trim();
@@ -9681,7 +9799,7 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9681
9799
  }
9682
9800
  } else {
9683
9801
  if (wasToolCalledInLastLoop) {
9684
- modifiedHistory.push({ role: "user", text: `[SYSTEM] Failed to verify tool execution, Verify tool syntax, proper escaping or ask user if tool worked when unsure [/SYSTEM]` });
9802
+ modifiedHistory.push({ role: "user", text: `[SYSTEM] Failed to verify tool execution, MUST check if executed or failed. On failure try again [/SYSTEM]` });
9685
9803
  } else {
9686
9804
  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 execution/output" : "If you have finished your task use [[END]]"}`} [/SYSTEM]` });
9687
9805
  }
@@ -9694,6 +9812,13 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9694
9812
  modifiedHistory.forEach((msg) => {
9695
9813
  if (msg.role === "user" && msg.text) {
9696
9814
  msg.text = msg.text.replace(/\n\[COMPILE ERROR\][\s\S]*?\[\/ERROR\]/g, "");
9815
+ msg.text = msg.text.replace(`
9816
+
9817
+ [SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY [/SYSTEM]
9818
+ `, "").replace(`[SYSTEM] USER QUESTION. RESOLVE THIS SPECIFIC QUERY WITHIN '[ANSWER] ... [/ANSWER]' CONCISELY, NATURALLY
9819
+ **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]
9820
+ `, "").replace(`[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]
9821
+ `, "");
9697
9822
  if (modelName && modelName.toLowerCase().startsWith("gemma") && aiProvider === "Google" && msg.text.startsWith("[TOOL RESULT]")) {
9698
9823
  const jitInstructionFast = `
9699
9824
  [SYSTEM] Tool result received. Analyze output and proceed with your turn [/SYSTEM]`;
@@ -11041,6 +11166,28 @@ function App({ args = [] }) {
11041
11166
  return msgs;
11042
11167
  });
11043
11168
  const queuedPromptRef = useRef3(null);
11169
+ const [btwResponse, setBtwResponse] = useState11("");
11170
+ const [showBtwBox, setShowBtwBox] = useState11(false);
11171
+ const btwResponseRef = useRef3("");
11172
+ const btwClosedRef = useRef3(null);
11173
+ useEffect8(() => {
11174
+ if (messages.length === 0) return;
11175
+ const lastMsg = messages[messages.length - 1];
11176
+ if (lastMsg && (lastMsg.role === "agent" || lastMsg.role === "assistant")) {
11177
+ const text = lastMsg.text || "";
11178
+ const match = text.match(/\[ANSWER\]([\s\S]*?)(?:\[\/ANSWER\]|$)/i);
11179
+ if (match) {
11180
+ const content = match[1].trim();
11181
+ if (content && content !== btwResponseRef.current) {
11182
+ setBtwResponse(content);
11183
+ btwResponseRef.current = content;
11184
+ if (btwClosedRef.current !== lastMsg.id) {
11185
+ setShowBtwBox(true);
11186
+ }
11187
+ }
11188
+ }
11189
+ }
11190
+ }, [messages]);
11044
11191
  const [completedIndex, setCompletedIndex] = useState11(messages.length);
11045
11192
  const windowedHistory = useMemo2(() => {
11046
11193
  const MAX_HISTORY_LINES = 2e3;
@@ -11151,6 +11298,16 @@ function App({ args = [] }) {
11151
11298
  return;
11152
11299
  }
11153
11300
  if (key.escape) {
11301
+ if (showBtwBox) {
11302
+ setShowBtwBox(false);
11303
+ if (messages.length > 0) {
11304
+ const lastMsg = messages[messages.length - 1];
11305
+ if (lastMsg) {
11306
+ btwClosedRef.current = lastMsg.id;
11307
+ }
11308
+ }
11309
+ return;
11310
+ }
11154
11311
  if (suggestions.length > 0 && activeView === "chat") {
11155
11312
  setIsFilePickerDismissed(true);
11156
11313
  return;
@@ -11537,6 +11694,7 @@ function App({ args = [] }) {
11537
11694
  { cmd: "/save", desc: "Force save current chat" },
11538
11695
  { cmd: "/export", desc: "Export current chat in a .txt file" },
11539
11696
  { cmd: "/chats", desc: "List all chat sessions" },
11697
+ { cmd: "/btw", desc: "Ask a question without intefering with ongoing tasks" },
11540
11698
  // {
11541
11699
  // cmd: '/image', desc: 'Generate images using Pollinations', subs: [
11542
11700
  // {
@@ -11833,7 +11991,17 @@ function App({ args = [] }) {
11833
11991
  if (!absoluteClean.trim()) return;
11834
11992
  if (isProcessing) {
11835
11993
  const hintText = absoluteClean.trim();
11836
- if (hintText.startsWith("/")) {
11994
+ if (hintText.startsWith("/btw")) {
11995
+ const question = hintText.replace(/^\/btw\s*/, "").trim();
11996
+ if (question.length <= 3) {
11997
+ setMessages((prev) => {
11998
+ setCompletedIndex(prev.length + 1);
11999
+ return [...prev, { id: "hint-err-" + Date.now(), role: "system", text: "[RESTRICTED] Inquiry question must be more than 3 characters.", isMeta: true }];
12000
+ });
12001
+ setInput("");
12002
+ return;
12003
+ }
12004
+ } else if (hintText.startsWith("/")) {
11837
12005
  setMessages((prev) => {
11838
12006
  setCompletedIndex(prev.length + 1);
11839
12007
  return [...prev, { id: "hint-err-" + Date.now(), role: "system", text: "[RESTRICTED] Steering Hints cannot start with /", isMeta: true }];
@@ -11845,8 +12013,11 @@ function App({ args = [] }) {
11845
12013
  queuedPromptRef.current = hintText;
11846
12014
  setMessages((prev) => {
11847
12015
  setCompletedIndex(prev.length + 1);
11848
- return [...prev, { id: "hint-" + Date.now(), role: "user", text: `[STEERING HINT: QUEUED]
11849
- ${hintText}`, color: "magenta" }];
12016
+ const isBtw = hintText.startsWith("/btw");
12017
+ const cleanText = isBtw ? hintText.replace(/^\/btw\s*/, "") : hintText;
12018
+ const prefix = isBtw ? "[QUESTION: QUEUED]" : "[STEERING HINT: QUEUED]";
12019
+ return [...prev, { id: "hint-" + Date.now(), role: "user", text: `${prefix}
12020
+ ${cleanText}`, color: "magenta" }];
11850
12021
  });
11851
12022
  setInput("");
11852
12023
  return;
@@ -12619,13 +12790,19 @@ Selection: ${val}`,
12619
12790
  setQueuedPrompt(null);
12620
12791
  queuedPromptRef.current = null;
12621
12792
  setMessages((prev) => {
12622
- const index = [...prev].reverse().findIndex((m) => m.text?.includes("[STEERING HINT: QUEUED]"));
12793
+ const index = [...prev].reverse().findIndex((m) => m.text?.includes("[STEERING HINT: QUEUED]") || m.text?.includes("[QUESTION: QUEUED]"));
12623
12794
  if (index !== -1) {
12624
12795
  const actualIndex = prev.length - 1 - index;
12625
12796
  const newMsgs = [...prev];
12797
+ let text = newMsgs[actualIndex].text;
12798
+ if (text.includes("[STEERING HINT: QUEUED]")) {
12799
+ text = text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: INJECTED]");
12800
+ } else if (text.includes("[QUESTION: QUEUED]")) {
12801
+ text = text.replace("[QUESTION: QUEUED]", "[QUESTION: ASKED]");
12802
+ }
12626
12803
  newMsgs[actualIndex] = {
12627
12804
  ...newMsgs[actualIndex],
12628
- text: newMsgs[actualIndex].text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: INJECTED]"),
12805
+ text,
12629
12806
  color: "cyan"
12630
12807
  };
12631
12808
  return newMsgs;
@@ -12843,11 +13020,26 @@ Selection: ${val}`,
12843
13020
  const hasThinkTag = chunkLower.includes("<think") || chunkLower.includes("<thought");
12844
13021
  const canThink = !inThinkMode && !inCodeBlock && !inToolCall && !thinkConsumedInTurn;
12845
13022
  if (hasThinkTag && canThink) {
13023
+ const match = chunkText.match(/<(think|thought)/i);
13024
+ const tagIndex = match.index;
13025
+ const beforeText = chunkText.substring(0, tagIndex);
13026
+ const afterText = chunkText.substring(tagIndex);
13027
+ if (beforeText) {
13028
+ if (!currentAgentId) {
13029
+ currentAgentId = "agent-" + Date.now();
13030
+ setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: beforeText, isStreaming: true }]);
13031
+ } else {
13032
+ setMessages((prev) => prev.map(
13033
+ (m) => m.id === currentAgentId ? { ...m, text: m.text + beforeText, isStreaming: true } : m
13034
+ ));
13035
+ }
13036
+ }
12846
13037
  inThinkMode = true;
12847
13038
  thinkConsumedInTurn = true;
12848
- chunkText = chunkText.replace(/<(think|thought)>[\s\S]*?<\/(think|thought)>/gi, "").replace(/<(think|thought)>/gi, "");
13039
+ let thinkStartText = afterText.replace(/<(think|thought)>/gi, "");
12849
13040
  currentThinkId = "think-" + Date.now();
12850
- setMessages((prev) => [...prev, { id: currentThinkId, role: "think", text: "", isStreaming: true, startTime: Date.now() }]);
13041
+ setMessages((prev) => [...prev, { id: currentThinkId, role: "think", text: thinkStartText, isStreaming: true, startTime: Date.now() }]);
13042
+ continue;
12851
13043
  }
12852
13044
  if ((chunkLower.includes("</think>") || chunkLower.includes("</thought>")) && currentThinkId) {
12853
13045
  const parts = chunkText.split(/<\/(think|thought)>/gi);
@@ -12932,9 +13124,13 @@ Selection: ${val}`,
12932
13124
  queuedPromptRef.current = null;
12933
13125
  setMessages((prev) => {
12934
13126
  const newMsgs = [...prev];
12935
- const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]"));
13127
+ const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]") || m.text?.includes("[QUESTION: QUEUED]"));
12936
13128
  if (hintMsg) {
12937
- hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: FINISHED_TURN]");
13129
+ if (hintMsg.text.includes("[STEERING HINT: QUEUED]")) {
13130
+ hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: FINISHED_TURN]");
13131
+ } else if (hintMsg.text.includes("[QUESTION: QUEUED]")) {
13132
+ hintMsg.text = hintMsg.text.replace("[QUESTION: QUEUED]", "[QUESTION: FINISHED_TURN]");
13133
+ }
12938
13134
  }
12939
13135
  return newMsgs.reverse();
12940
13136
  });
@@ -13604,7 +13800,7 @@ Selection: ${val}`,
13604
13800
  }
13605
13801
  )));
13606
13802
  default:
13607
- return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, null, statusText ? /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true, italic: true }, statusText)) : /* @__PURE__ */ React14.createElement(Text14, { color: "gray", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : "Waiting for input...")), /* @__PURE__ */ React14.createElement(Box14, null, wittyPhrase && /* @__PURE__ */ React14.createElement(Text14, { color: "gray", italic: true }, wittyPhrase, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React14.createElement(Text14, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React14.createElement(
13803
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, showBtwBox && btwResponse && /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%", marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Box14, { justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "INQUIRY RESPONSE"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "[ ESC to Close ]")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React14.createElement(CodeRenderer, { text: btwResponse, columns: terminalSize.columns - 6 }))), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, null, statusText ? /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true, italic: true }, statusText)) : /* @__PURE__ */ React14.createElement(Text14, { color: "gray", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : "Waiting for input...")), /* @__PURE__ */ React14.createElement(Box14, null, wittyPhrase && /* @__PURE__ */ React14.createElement(Text14, { color: "gray", italic: true }, wittyPhrase, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React14.createElement(Text14, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React14.createElement(
13608
13804
  Box14,
13609
13805
  {
13610
13806
  backgroundColor: "#555555",
@@ -13880,7 +14076,7 @@ var init_app = __esm({
13880
14076
  height
13881
14077
  },
13882
14078
  /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1, width: Math.min(80, width - 4), justifyContent: "flex-start" }, /* @__PURE__ */ React14.createElement(Text14, null, getFluxLogo(versionFluxflow))),
13883
- /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "double", borderColor: "grey", paddingX: 3, paddingY: 1, width: Math.min(80, width - 4) }, /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white", textAlign: "center" }, "\u{1F680} UPGRADE YOUR WORKFLOW"), /* @__PURE__ */ React14.createElement(Box14, { marginY: 1, flexDirection: "column", alignItems: "left" }, /* @__PURE__ */ React14.createElement(Text14, null, "You're in ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "cyan" }, ideName), ", but the ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white" }, "FluxFlow-CLI Companion"), " is not installed."), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Real-time file & cursor tracking"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Auto-open files created by agent"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native DIFF viewer for AI edits"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Direct IDE context sharing"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Surgical Diagnostic Sync"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native Right-Click \u276F Chat integration"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Live Status in IDE"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Clickable terminal-to-code links"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, options.map((opt, i) => /* @__PURE__ */ React14.createElement(Box14, { key: i }, /* @__PURE__ */ React14.createElement(Text14, { color: selectedIndex === i ? "yellow" : "white", bold: selectedIndex === i }, selectedIndex === i ? " \u276F " : " ", opt.label)))), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React14.createElement(Text14, { dimColor: true, italic: true }, "(Use arrows to navigate, Enter to select)")))
14079
+ /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "double", borderColor: "grey", paddingX: 3, paddingY: 1, width: Math.min(80, width - 4) }, /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white", textAlign: "center" }, "\u{1F680} UPGRADE YOUR WORKFLOW"), /* @__PURE__ */ React14.createElement(Box14, { marginY: 1, flexDirection: "column", alignItems: "left" }, /* @__PURE__ */ React14.createElement(Text14, null, "You're in ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "cyan" }, ideName), ", but the ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white" }, "FluxFlow-CLI Companion"), " is not installed."), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Real-time IDE context & Error Resolution"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Auto-open files created by agent"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native DIFFing for AI edits"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Direct IDE context sharing"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Surgical Diagnostic Sync"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native Right-Click \u276F Chat integration"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Live Status in IDE"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Clickable terminal-to-code links"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, options.map((opt, i) => /* @__PURE__ */ React14.createElement(Box14, { key: i }, /* @__PURE__ */ React14.createElement(Text14, { color: selectedIndex === i ? "yellow" : "white", bold: selectedIndex === i }, selectedIndex === i ? " \u276F " : " ", opt.label)))), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React14.createElement(Text14, { dimColor: true, italic: true }, "(Use arrows to navigate, Enter to select)")))
13884
14080
  );
13885
14081
  };
13886
14082
  SESSION_START_TIME = Date.now();
@@ -13892,7 +14088,7 @@ var init_app = __esm({
13892
14088
  packageJson = JSON.parse(fs22.readFileSync(packageJsonPath, "utf8"));
13893
14089
  versionFluxflow = packageJson.version;
13894
14090
  updatedOn = packageJson.date || "2026-05-20";
13895
- ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 0 }, /* @__PURE__ */ React14.createElement(
14091
+ ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", padding: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, data.startsWith("/btw") ? "QUESTION" : "STEERING HINT", " RESOLUTION")), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, null, "The agent already finished the task before your ", data.startsWith("/btw") ? "question" : "hint", " was consumed.")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { italic: true, color: "gray" }, '"', data.replace("/btw", "").trim(), '"')), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "How would you like to proceed?")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 0 }, /* @__PURE__ */ React14.createElement(
13896
14092
  CommandMenu,
13897
14093
  {
13898
14094
  title: "Select Action",
@@ -14076,6 +14272,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
14076
14272
  /save Force save current chat
14077
14273
  /export Export current chat in a .txt file
14078
14274
  /chats List all chat sessions
14275
+ /btw <question> Send raw inquiry to the agent mid-turn
14079
14276
  /image setup key <default|custom> Configure image API key strategy
14080
14277
  /image setup quality <low...premium> Configure default image generation quality
14081
14278
  /image stats Show image quota stats
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.9.0",
4
- "date": "2026-06-19",
3
+ "version": "2.10.1",
4
+ "date": "2026-06-20",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",