fluxflow-cli 1.1.1 → 1.1.2

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 +53 -46
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -410,7 +410,7 @@ tool:functions.tool_name(arguments)
410
410
  - WEB TOOLS (Available in Flux & Flow) -
411
411
  1. Web Search: tool:functions.web_search(query="<query>", limit=number). Find info. limit is optional (3-10, default 10). If user asks about something that is not in your training data, proactively use this tool to find the information.Winder search recomemded (limit = 10) when exploring a topic.
412
412
  2. Web Scrape: tool:functions.web_scrape(url="<url>"). provides detail from a URL.
413
- 3. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). Use this ONLY when you reach a decision point with multiple valid paths and need user preference to proceed / confirmation. This allows you to pause for guidance without ending your task loop. Format options as 'Short Label::Detailed Description'. You can provide 2 - 4 options (optionA, optionB, optionC, optionD). Tool can also return result as none of the 4 if user write custom one.
413
+ 3. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). You can use this tool if you hit a roadblock and need user direction on which path to continue. This allows you to pause for guidance without ending your task loop. Format options as 'Short Label::Detailed Description'. You can provide 2 - 4 options (optionA, optionB, optionC, optionD). Tool can also return result as none of the 4 if user write custom one. Example cases to use this tool: ask or user permission (Yes/No). Ask user to choose between two or more options. Ask user for any clarification needed to proceed with the task.
414
414
  ${mode === "Flux" ? `
415
415
  - DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
416
416
  1. View File: tool:functions.view_file(path="relative/path", start_line=number, end_line=number). Reads file content. Auto-truncates at 500 lines unless start_line and end_line are provided.
@@ -524,6 +524,7 @@ Every ${isMemoryEnabled ? "Prompt, Responses & Memories" : "Prompt & Responses"}
524
524
 
525
525
  -- START REPONSE FINISH PROTOCOL --
526
526
  WHEN YOU ARE DONE AND NEED NO LONGER AGENT LOOP FOR THE TASK, WRITE [turn: finish] AT VERY END OF YOUR RESPONSE TO AVOID AGENT LOOPS. IF YOU ARE NOT COMPLETED YET AND WANT NEXT LOOP WRITE [turn: continue] AT VERY END OF YOUR RESPONSE TO CONTINUE AGENT LOOPS. YOU CAN STACK MULTIPLE TOOLS AT ONCE BUT **HAVE TO** WRITE [turn: continue] AFTER WRITING ALL TOOL CALLS.
527
+ When you 'finish' an agentic loop, you will lose your previous turn 'thinking' data. So only write [turn: finish] when you are absolutely sure that you are done with the task. Or user has to prompt again and re-thinking again from scratch will use tokens that were already planned.
527
528
  -- END REPONSE FINISH PROTOCOL --
528
529
  Current date and Time is: ${dateTimeStr}
529
530
  --- END SYSTEM INSTRUCTION ---`.trim();
@@ -1229,7 +1230,7 @@ ${formatted}${footer}`;
1229
1230
  var ask_user = async (args, context) => {
1230
1231
  const parsed = parseArgs(args);
1231
1232
  const { question } = parsed;
1232
- if (!question) return 'ERROR: Missing "question" argument for ask_user.';
1233
+ if (!question) return 'ERROR: Missing "question" argument for ask.';
1233
1234
  if (!context.onAskUser) return "ERROR: onAskUser callback not provided in tool context.";
1234
1235
  const options = [];
1235
1236
  Object.keys(parsed).forEach((key) => {
@@ -1295,35 +1296,39 @@ var signalTermination = () => {
1295
1296
  };
1296
1297
  var detectToolCalls = (text) => {
1297
1298
  const results = [];
1298
- const trigger = "tool:functions.";
1299
- let searchIdx = 0;
1300
- while (true) {
1301
- const startIdx = text.indexOf(trigger, searchIdx);
1302
- if (startIdx === -1) break;
1303
- const openParenIdx = text.indexOf("(", startIdx + trigger.length);
1304
- if (openParenIdx === -1) {
1305
- searchIdx = startIdx + trigger.length;
1306
- continue;
1307
- }
1308
- const toolName = text.substring(startIdx + trigger.length, openParenIdx).trim();
1309
- let balance = 1;
1310
- let endIdx = -1;
1311
- for (let i = openParenIdx + 1; i < text.length; i++) {
1312
- if (text[i] === "(") balance++;
1313
- if (text[i] === ")") balance--;
1314
- if (balance === 0) {
1315
- endIdx = i;
1316
- break;
1299
+ const toolRegex = /(?:\[?\s*tool:functions\.)([a-z0-9_]+)\s*\(([\s\S]*?)\)(?:\s*\]?)/gi;
1300
+ let match;
1301
+ while ((match = toolRegex.exec(text)) !== null) {
1302
+ const fullMatch = match[0];
1303
+ const toolName = match[1];
1304
+ const args = match[2];
1305
+ let openCount = (args.match(/\(/g) || []).length;
1306
+ let closeCount = (args.match(/\)/g) || []).length;
1307
+ let finalArgs = args;
1308
+ let finalFullMatch = fullMatch;
1309
+ if (openCount > closeCount) {
1310
+ const startIdx = match.index + fullMatch.indexOf("(");
1311
+ let balance = 0;
1312
+ let endIdx = -1;
1313
+ for (let i = startIdx; i < text.length; i++) {
1314
+ if (text[i] === "(") balance++;
1315
+ if (text[i] === ")") balance--;
1316
+ if (balance === 0) {
1317
+ endIdx = i;
1318
+ break;
1319
+ }
1320
+ }
1321
+ if (endIdx !== -1) {
1322
+ finalArgs = text.substring(startIdx + 1, endIdx);
1323
+ finalFullMatch = text.substring(match.index, endIdx + 1);
1324
+ toolRegex.lastIndex = endIdx + 1;
1317
1325
  }
1318
1326
  }
1319
- if (endIdx === -1) {
1320
- searchIdx = openParenIdx + 1;
1321
- continue;
1322
- }
1323
- const fullMatch = text.substring(startIdx, endIdx + 1);
1324
- const args = text.substring(openParenIdx + 1, endIdx);
1325
- results.push({ fullMatch, toolName, args });
1326
- searchIdx = endIdx + 1;
1327
+ results.push({
1328
+ fullMatch: finalFullMatch,
1329
+ toolName: toolName.trim(),
1330
+ args: finalArgs.trim()
1331
+ });
1327
1332
  }
1328
1333
  return results;
1329
1334
  };
@@ -1375,7 +1380,7 @@ USER_PROMPT: ${agentText}`.trim();
1375
1380
  }
1376
1381
  }
1377
1382
  yield { type: "turn_reset", content: true };
1378
- const contents = modifiedHistory.filter((msg) => (msg.role === "user" || msg.role === "agent" || msg.role === "system") && !String(msg.id).startsWith("welcome")).map((msg) => ({
1383
+ const contents = modifiedHistory.filter((msg) => (msg.role === "user" || msg.role === "agent" || msg.role === "system") && !String(msg.id).startsWith("welcome") && !msg.isMeta).map((msg) => ({
1379
1384
  role: msg.role === "user" || msg.role === "system" ? "user" : "model",
1380
1385
  parts: [{ text: msg.text }]
1381
1386
  }));
@@ -1609,7 +1614,8 @@ ${boxBottom}
1609
1614
  yield { type: "status", content: "Working..." };
1610
1615
  }
1611
1616
  const cleanedTurnText = turnText.replace(/<think>[\s\S]*?<\/think>/g, "").replace(/\[?\s*(turn\s*:)?\s*(continue|finish)\s*\]?/gi, "").trim();
1612
- if (hasFinish || !shouldContinue && toolResults.length === 0) {
1617
+ const isActuallyFinished = hasFinish || !shouldContinue && toolResults.length === 0 && turnText.length < 5;
1618
+ if (isActuallyFinished) {
1613
1619
  const lateHint = await steeringCallback();
1614
1620
  if (lateHint) {
1615
1621
  toolResults.push(`[USER STEERING HINT]: ${lateHint}`);
@@ -1694,7 +1700,7 @@ ${timestamp}`;
1694
1700
  }
1695
1701
  break;
1696
1702
  }
1697
- if (!shouldContinue && toolResults.length === 0) break;
1703
+ if (isActuallyFinished) break;
1698
1704
  const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
1699
1705
  modifiedHistory.push({ role: "agent", text: nextAgentMsg });
1700
1706
  const nextUserMsg = toolResults.length > 0 ? `${toolResults.join("\n")}` : "";
@@ -1838,7 +1844,7 @@ function MemoryModal({ onClose }) {
1838
1844
  // src/app.jsx
1839
1845
  var SESSION_START_TIME = Date.now();
1840
1846
  var CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
1841
- var versionFluxflow = "1.1.1";
1847
+ var versionFluxflow = "1.1.2";
1842
1848
  var updatedOn = "2026-04-26";
1843
1849
  var ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "The agent already finished the task (turn: finish) before your hint was consumed."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
1844
1850
  CommandMenu,
@@ -1899,7 +1905,8 @@ function App() {
1899
1905
  text: `\u{1F680} **New version 'v${latestVersion}' is available!**
1900
1906
  Type \`npm i -g fluxflow-cli\` to update.
1901
1907
  Check what's new using \`/changelog\` command.`,
1902
- isUpdateNotification: true
1908
+ isUpdateNotification: true,
1909
+ isMeta: true
1903
1910
  });
1904
1911
  return newMsgs;
1905
1912
  });
@@ -2136,7 +2143,7 @@ ${hintText}`, color: "magenta" }];
2136
2143
  setMode(newMode);
2137
2144
  setMessages((prev) => {
2138
2145
  setCompletedIndex(prev.length + 1);
2139
- return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Mode switched to ${newMode}` }];
2146
+ return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Mode switched to ${newMode}`, isMeta: true }];
2140
2147
  });
2141
2148
  } else {
2142
2149
  setActiveView("mode");
@@ -2149,13 +2156,13 @@ ${hintText}`, color: "magenta" }];
2149
2156
  setShowFullThinking(true);
2150
2157
  setMessages((prev) => {
2151
2158
  setCompletedIndex(prev.length + 1);
2152
- return [...prev, { id: Date.now(), role: "system", text: "\u2699\uFE0F [SYSTEM] Full Thinking Process: VISIBLE" }];
2159
+ return [...prev, { id: Date.now(), role: "system", text: "\u2699\uFE0F [SYSTEM] Full Thinking Process: VISIBLE", isMeta: true }];
2153
2160
  });
2154
2161
  } else if (arg === "hide") {
2155
2162
  setShowFullThinking(false);
2156
2163
  setMessages((prev) => {
2157
2164
  setCompletedIndex(prev.length + 1);
2158
- return [...prev, { id: Date.now(), role: "system", text: "\u2699\uFE0F [SYSTEM] Full Thinking Process: HIDDEN (Headings only)" }];
2165
+ return [...prev, { id: Date.now(), role: "system", text: "\u2699\uFE0F [SYSTEM] Full Thinking Process: HIDDEN (Headings only)", isMeta: true }];
2159
2166
  });
2160
2167
  } else if (parts[1]) {
2161
2168
  let val = parts[1].toLowerCase();
@@ -2170,7 +2177,7 @@ ${hintText}`, color: "magenta" }];
2170
2177
  setThinkingLevel(formattedLevel);
2171
2178
  setMessages((prev) => {
2172
2179
  setCompletedIndex(prev.length + 1);
2173
- return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Thinking level set to ${formattedLevel}` }];
2180
+ return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Thinking level set to ${formattedLevel}`, isMeta: true }];
2174
2181
  });
2175
2182
  }
2176
2183
  } else {
@@ -2184,7 +2191,7 @@ ${hintText}`, color: "magenta" }];
2184
2191
  setActiveModel(mod);
2185
2192
  setMessages((prev) => {
2186
2193
  setCompletedIndex(prev.length + 1);
2187
- return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Model switched to ${mod}` }];
2194
+ return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Model switched to ${mod}`, isMeta: true }];
2188
2195
  });
2189
2196
  } else {
2190
2197
  setActiveView("model");
@@ -2217,7 +2224,7 @@ ${hintText}`, color: "magenta" }];
2217
2224
  saveChat(chatId, name, messages);
2218
2225
  setMessages((prev) => {
2219
2226
  setCompletedIndex(prev.length + 1);
2220
- return [...prev, { id: Date.now(), role: "system", text: `\u{1F4BE} [MEMORY] Chat saved as "${name}" (ID: ${chatId})` }];
2227
+ return [...prev, { id: Date.now(), role: "system", text: `\u{1F4BE} [MEMORY] Chat saved as "${name}" (ID: ${chatId})`, isMeta: true }];
2221
2228
  });
2222
2229
  break;
2223
2230
  }
@@ -2228,7 +2235,7 @@ ${hintText}`, color: "magenta" }];
2228
2235
  setMessages((prev) => {
2229
2236
  setCompletedIndex(prev.length + 1);
2230
2237
  return [...prev, { id: Date.now(), role: "system", text: `\u{1F5C3}\uFE0F [HISTORY] Saved Chats:
2231
- ${list || "No saved chats found."}` }];
2238
+ ${list || "No saved chats found."}`, isMeta: true }];
2232
2239
  });
2233
2240
  };
2234
2241
  run();
@@ -2243,7 +2250,7 @@ ${list || "No saved chats found."}` }];
2243
2250
  try {
2244
2251
  setMessages((prev) => {
2245
2252
  setCompletedIndex(prev.length + 1);
2246
- return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset..." }];
2253
+ return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
2247
2254
  });
2248
2255
  if (fs14.existsSync(LOGS_DIR)) fs14.removeSync(LOGS_DIR);
2249
2256
  if (fs14.existsSync(SECRET_DIR)) fs14.removeSync(SECRET_DIR);
@@ -2274,7 +2281,7 @@ ${list || "No saved chats found."}` }];
2274
2281
  \u{1F4C5} **Updated on:** ${updatedOn}`;
2275
2282
  setMessages((prev) => {
2276
2283
  setCompletedIndex(prev.length + 1);
2277
- return [...prev, { id: Date.now(), role: "system", text: aboutText }];
2284
+ return [...prev, { id: Date.now(), role: "system", text: aboutText, isMeta: true }];
2278
2285
  });
2279
2286
  break;
2280
2287
  }
@@ -2284,21 +2291,21 @@ ${list || "No saved chats found."}` }];
2284
2291
  exec(`${command} ${CHANGELOG_URL}`);
2285
2292
  setMessages((prev) => {
2286
2293
  setCompletedIndex(prev.length + 1);
2287
- return [...prev, { id: Date.now(), role: "system", text: `\u{1F310} [BROWSER] Opening changelog: ${CHANGELOG_URL}` }];
2294
+ return [...prev, { id: Date.now(), role: "system", text: `\u{1F310} [BROWSER] Opening changelog: ${CHANGELOG_URL}`, isMeta: true }];
2288
2295
  });
2289
2296
  break;
2290
2297
  }
2291
2298
  case "/help": {
2292
2299
  setMessages((prev) => {
2293
2300
  setCompletedIndex(prev.length + 1);
2294
- return [...prev, { id: Date.now(), role: "system", text: "\u2699\uFE0F [SYSTEM] Available commands: " + COMMANDS.join(", ") }];
2301
+ return [...prev, { id: Date.now(), role: "system", text: "\u2699\uFE0F [SYSTEM] Available commands: " + COMMANDS.join(", "), isMeta: true }];
2295
2302
  });
2296
2303
  break;
2297
2304
  }
2298
2305
  default:
2299
2306
  setMessages((prev) => {
2300
2307
  setCompletedIndex(prev.length + 1);
2301
- return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Unknown command: ${cmd}` }];
2308
+ return [...prev, { id: Date.now(), role: "system", text: `\u2699\uFE0F [SYSTEM] Unknown command: ${cmd}`, isMeta: true }];
2302
2309
  });
2303
2310
  }
2304
2311
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",