fluxflow-cli 1.8.10 → 1.8.11
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.
- package/dist/fluxflow.js +148 -14
- package/package.json +1 -1
package/dist/fluxflow.js
CHANGED
|
@@ -2430,7 +2430,7 @@ var init_terminal = __esm({
|
|
|
2430
2430
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
2431
2431
|
import path16 from "path";
|
|
2432
2432
|
import fs16 from "fs";
|
|
2433
|
-
var client, TERMINATION_SIGNAL, signalTermination, detectToolCalls, initAI, getAIStream;
|
|
2433
|
+
var client, TERMINATION_SIGNAL, signalTermination, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
|
|
2434
2434
|
var init_ai = __esm({
|
|
2435
2435
|
"src/utils/ai.js"() {
|
|
2436
2436
|
init_prompts();
|
|
@@ -2446,6 +2446,138 @@ var init_ai = __esm({
|
|
|
2446
2446
|
signalTermination = () => {
|
|
2447
2447
|
TERMINATION_SIGNAL = true;
|
|
2448
2448
|
};
|
|
2449
|
+
getActiveToolContext = (text) => {
|
|
2450
|
+
const toolRegex = /(?:\[?\s*tool:functions\.)([a-z0-9_]+)\s*\(/gi;
|
|
2451
|
+
let match;
|
|
2452
|
+
while ((match = toolRegex.exec(text)) !== null) {
|
|
2453
|
+
const startIdx = match.index + match[0].length - 1;
|
|
2454
|
+
let balance = 0;
|
|
2455
|
+
let inString = null;
|
|
2456
|
+
let isEscaped = false;
|
|
2457
|
+
let closed = false;
|
|
2458
|
+
for (let i = startIdx; i < text.length; i++) {
|
|
2459
|
+
const char = text[i];
|
|
2460
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
2461
|
+
inString = char;
|
|
2462
|
+
isEscaped = false;
|
|
2463
|
+
} else if (inString && char === inString && !isEscaped) {
|
|
2464
|
+
inString = null;
|
|
2465
|
+
}
|
|
2466
|
+
if (!inString) {
|
|
2467
|
+
if (char === "(") balance++;
|
|
2468
|
+
else if (char === ")") balance--;
|
|
2469
|
+
if (balance === 0) {
|
|
2470
|
+
closed = true;
|
|
2471
|
+
toolRegex.lastIndex = i + 1;
|
|
2472
|
+
break;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
if (char === "\\") isEscaped = !isEscaped;
|
|
2476
|
+
else isEscaped = false;
|
|
2477
|
+
}
|
|
2478
|
+
if (!closed) {
|
|
2479
|
+
return { inside: true, toolName: match[1], startIndex: match.index };
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
return { inside: false };
|
|
2483
|
+
};
|
|
2484
|
+
getContextSafeText = (text, stripThoughts = true) => {
|
|
2485
|
+
const toolRegex = /(?:\[?\s*tool:functions\.)([a-z0-9_]+)\s*\(/gi;
|
|
2486
|
+
let result = "";
|
|
2487
|
+
let lastIdx = 0;
|
|
2488
|
+
let match;
|
|
2489
|
+
while ((match = toolRegex.exec(text)) !== null) {
|
|
2490
|
+
const before = text.substring(lastIdx, match.index);
|
|
2491
|
+
result += stripThoughts ? before.replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "") : before;
|
|
2492
|
+
const startIdx = match.index + match[0].length - 1;
|
|
2493
|
+
let balance = 0;
|
|
2494
|
+
let inString = null;
|
|
2495
|
+
let isEscaped = false;
|
|
2496
|
+
let endIdx = -1;
|
|
2497
|
+
for (let i = startIdx; i < text.length; i++) {
|
|
2498
|
+
const char = text[i];
|
|
2499
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
2500
|
+
inString = char;
|
|
2501
|
+
isEscaped = false;
|
|
2502
|
+
} else if (inString && char === inString && !isEscaped) {
|
|
2503
|
+
inString = null;
|
|
2504
|
+
}
|
|
2505
|
+
if (!inString) {
|
|
2506
|
+
if (char === "(") balance++;
|
|
2507
|
+
else if (char === ")") balance--;
|
|
2508
|
+
if (balance === 0) {
|
|
2509
|
+
endIdx = i;
|
|
2510
|
+
break;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
if (char === "\\") isEscaped = !isEscaped;
|
|
2514
|
+
else isEscaped = false;
|
|
2515
|
+
}
|
|
2516
|
+
if (endIdx !== -1) {
|
|
2517
|
+
result += "tool:functions." + match[1] + "()";
|
|
2518
|
+
lastIdx = endIdx + 1;
|
|
2519
|
+
toolRegex.lastIndex = lastIdx;
|
|
2520
|
+
} else {
|
|
2521
|
+
result += "tool:functions." + match[1] + "(";
|
|
2522
|
+
lastIdx = text.length;
|
|
2523
|
+
break;
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
if (lastIdx < text.length) {
|
|
2527
|
+
result += stripThoughts ? text.substring(lastIdx).replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "") : text.substring(lastIdx);
|
|
2528
|
+
}
|
|
2529
|
+
return result;
|
|
2530
|
+
};
|
|
2531
|
+
contextSafeReplace = (text, regex, replacement) => {
|
|
2532
|
+
const toolRegex = /(?:\[?\s*tool:functions\.)([a-z0-9_]+)\s*\(/gi;
|
|
2533
|
+
let result = "";
|
|
2534
|
+
let lastIdx = 0;
|
|
2535
|
+
let match;
|
|
2536
|
+
while ((match = toolRegex.exec(text)) !== null) {
|
|
2537
|
+
const before = text.substring(lastIdx, match.index);
|
|
2538
|
+
result += before.replace(regex, replacement);
|
|
2539
|
+
const startIdx = match.index + match[0].length - 1;
|
|
2540
|
+
let balance = 0;
|
|
2541
|
+
let inString = null;
|
|
2542
|
+
let isEscaped = false;
|
|
2543
|
+
let endIdx = -1;
|
|
2544
|
+
for (let i = startIdx; i < text.length; i++) {
|
|
2545
|
+
const char = text[i];
|
|
2546
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
2547
|
+
inString = char;
|
|
2548
|
+
isEscaped = false;
|
|
2549
|
+
} else if (inString && char === inString && !isEscaped) {
|
|
2550
|
+
inString = null;
|
|
2551
|
+
}
|
|
2552
|
+
if (!inString) {
|
|
2553
|
+
if (char === "(") balance++;
|
|
2554
|
+
else if (char === ")") balance--;
|
|
2555
|
+
if (balance === 0) {
|
|
2556
|
+
endIdx = i;
|
|
2557
|
+
break;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
if (char === "\\") isEscaped = !isEscaped;
|
|
2561
|
+
else isEscaped = false;
|
|
2562
|
+
}
|
|
2563
|
+
if (endIdx !== -1) {
|
|
2564
|
+
result += text.substring(match.index, endIdx + 1);
|
|
2565
|
+
lastIdx = endIdx + 1;
|
|
2566
|
+
toolRegex.lastIndex = lastIdx;
|
|
2567
|
+
} else {
|
|
2568
|
+
result += text.substring(match.index);
|
|
2569
|
+
lastIdx = text.length;
|
|
2570
|
+
break;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
if (lastIdx < text.length) {
|
|
2574
|
+
result += text.substring(lastIdx).replace(regex, replacement);
|
|
2575
|
+
}
|
|
2576
|
+
return result;
|
|
2577
|
+
};
|
|
2578
|
+
getSanitizedText = (text) => {
|
|
2579
|
+
return getContextSafeText(text, true);
|
|
2580
|
+
};
|
|
2449
2581
|
detectToolCalls = (text) => {
|
|
2450
2582
|
const results = [];
|
|
2451
2583
|
const toolRegex = /(?:\[?\s*tool:functions\.)([a-z0-9_]+)\s*\(/gi;
|
|
@@ -2661,17 +2793,18 @@ var init_ai = __esm({
|
|
|
2661
2793
|
turnText += chunk.text;
|
|
2662
2794
|
yield { type: "text", content: chunk.text };
|
|
2663
2795
|
}
|
|
2664
|
-
const
|
|
2665
|
-
|
|
2796
|
+
const signalSafeText2 = getSanitizedText(turnText);
|
|
2797
|
+
const toolContext = getActiveToolContext(turnText);
|
|
2798
|
+
if (toolContext.inside) {
|
|
2666
2799
|
if (!lastToolEventTime) lastToolEventTime = Date.now();
|
|
2667
|
-
const
|
|
2668
|
-
const potentialTool = parts[parts.length - 1].split("(")[0].trim();
|
|
2800
|
+
const potentialTool = toolContext.toolName;
|
|
2669
2801
|
if (potentialTool && /^[a-z_]+$/.test(potentialTool) && potentialTool !== lastToolSniffed) {
|
|
2670
2802
|
lastToolSniffed = potentialTool;
|
|
2671
2803
|
yield { type: "status", content: `Working (${potentialTool})...` };
|
|
2672
2804
|
}
|
|
2673
2805
|
}
|
|
2674
|
-
const
|
|
2806
|
+
const contextSafeText = getContextSafeText(turnText, false);
|
|
2807
|
+
const thinkBlocks = contextSafeText.match(/<think>([\s\S]*?)(?:<\/think>|$)/gi) || [];
|
|
2675
2808
|
const thinkContent = thinkBlocks.join("").trim();
|
|
2676
2809
|
const sentences = thinkContent.split(/[.!?]\s+/);
|
|
2677
2810
|
const uniqueSentences = new Set(sentences);
|
|
@@ -2686,7 +2819,8 @@ var init_ai = __esm({
|
|
|
2686
2819
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
2687
2820
|
break;
|
|
2688
2821
|
}
|
|
2689
|
-
const
|
|
2822
|
+
const toolActionableText = turnText.replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "");
|
|
2823
|
+
const allToolsFound = detectToolCalls(toolActionableText);
|
|
2690
2824
|
while (allToolsFound.length > toolCallPointer) {
|
|
2691
2825
|
const toolCall = allToolsFound[toolCallPointer];
|
|
2692
2826
|
yield { type: "status", content: `Working (${toolCall.toolName})...` };
|
|
@@ -2893,11 +3027,11 @@ ${boxBottom}
|
|
|
2893
3027
|
if (thinkMatch) {
|
|
2894
3028
|
textToProcess = turnText.replace(/<think>[\s\S]*?<\/think>/i, "");
|
|
2895
3029
|
}
|
|
2896
|
-
const
|
|
2897
|
-
const hasFinish = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(
|
|
3030
|
+
const signalSafeText = getSanitizedText(turnText);
|
|
3031
|
+
const hasFinish = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText.toLowerCase());
|
|
2898
3032
|
const shouldContinue = toolCallPointer > 0;
|
|
2899
3033
|
yield { type: "status", content: "Working..." };
|
|
2900
|
-
const cleanedTurnText = turnText
|
|
3034
|
+
const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
|
|
2901
3035
|
let isActuallyFinished = hasFinish && !shouldContinue;
|
|
2902
3036
|
if (isActuallyFinished) {
|
|
2903
3037
|
yield { type: "status", content: "Finalizing..." };
|
|
@@ -4693,7 +4827,7 @@ Selection: ${val}`,
|
|
|
4693
4827
|
}
|
|
4694
4828
|
));
|
|
4695
4829
|
case "approval":
|
|
4696
|
-
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true, underline: true }, "\u{
|
|
4830
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true, underline: true }, "\u{1F510} SECURITY GATE: FILE WRITE PERMISSION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent is attempting to modify: ", /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, parseArgs(pendingApproval?.args || "{}").path || "Unknown File")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, borderStyle: "single", borderColor: "#333", paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, "--- PROPOSED CONTENT / DIFF ---"), (() => {
|
|
4697
4831
|
const args = parseArgs(pendingApproval?.args || "{}");
|
|
4698
4832
|
const oldVal = args.TargetContent || args.content_to_replace || null;
|
|
4699
4833
|
const newVal = args.content || args.ReplacementContent || args.content_to_add || args.replacementContent || null;
|
|
@@ -4707,7 +4841,7 @@ Selection: ${val}`,
|
|
|
4707
4841
|
title: "Action Required",
|
|
4708
4842
|
items: [
|
|
4709
4843
|
{ label: "\u2705 Accept this time", value: "allow" },
|
|
4710
|
-
{ label: "\u{
|
|
4844
|
+
{ label: "\u{1F510} Accept for this session", value: "always" },
|
|
4711
4845
|
{ label: "\u274C Don't accept", value: "deny" }
|
|
4712
4846
|
],
|
|
4713
4847
|
onSelect: (item) => {
|
|
@@ -4783,7 +4917,7 @@ Selection: ${val}`,
|
|
|
4783
4917
|
}
|
|
4784
4918
|
);
|
|
4785
4919
|
case "terminalApproval":
|
|
4786
|
-
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "red", bold: true, underline: true }, "\u{
|
|
4920
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "red", bold: true, underline: true }, "\u{1F510} SECURITY GATE: TERMINAL COMMAND OVERSIGHT"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "Agent requested to run: ", /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true }, parseArgs(pendingApproval?.args || "{}").command || "Unknown Command"))), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
|
|
4787
4921
|
CommandMenu,
|
|
4788
4922
|
{
|
|
4789
4923
|
title: "Risk Assessment Required",
|
|
@@ -4921,7 +5055,7 @@ var init_app = __esm({
|
|
|
4921
5055
|
init_text();
|
|
4922
5056
|
SESSION_START_TIME = Date.now();
|
|
4923
5057
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
4924
|
-
versionFluxflow = "1.8.
|
|
5058
|
+
versionFluxflow = "1.8.11";
|
|
4925
5059
|
updatedOn = "2026-05-09";
|
|
4926
5060
|
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(
|
|
4927
5061
|
CommandMenu,
|