fluxflow-cli 1.5.2 → 1.5.4
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 +93 -37
- package/package.json +1 -1
package/dist/fluxflow.js
CHANGED
|
@@ -257,6 +257,9 @@ var init_ChatLayout = __esm({
|
|
|
257
257
|
MessageItem = React2.memo(({ msg, showFullThinking, columns = 80 }) => {
|
|
258
258
|
const isDiffResult = msg.role === "system" && msg.text?.includes("[DIFF_START]");
|
|
259
259
|
const isTerminalRecord = msg.isTerminalRecord;
|
|
260
|
+
if (msg.isVisualFeedback) {
|
|
261
|
+
return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, msg.text));
|
|
262
|
+
}
|
|
260
263
|
if (msg.role === "system" && msg.text?.includes("[TOOL_RESULT]") && !isDiffResult && !isTerminalRecord) return null;
|
|
261
264
|
if (msg.isAskRecord) {
|
|
262
265
|
const selectionMatch = msg.text.match(/Selection: (.*)/);
|
|
@@ -612,7 +615,7 @@ ${mode === "Flux" ? `
|
|
|
612
615
|
3. Read Folder: tool:functions.read_folder(path="relative/path"). Detailed stats of a directory.
|
|
613
616
|
4. Write File: tool:functions.write_file(path="path", content="content"). Creates/Overwrites. NO CODE BLOCKS. RETURNS: Disk verification + original content (if overwritten) for 100% reversibility.
|
|
614
617
|
5. Update File: tool:functions.update_file(path="relative/path", content_to_replace="old", content_to_add="new"). Surgical patching. RETURNS: High-fidelity visual diff and old code block. You MUST verify that the change specifically matches your intent using the returned diff. PREFFER UPDATE FILE OVER WRITE FILE if file already exists for better reversal tracking (if a file has 500+ lines, try to stick with update_file over full-rewrite). DONT WRAP UPDATE FILE CALL CONTENT IN MARKDOWN CODE BLOCKS.
|
|
615
|
-
6. Write PDF: tool:functions.write_pdf(path="path", content="<html/css content>", orientation="portrait/landscape"). Generates a professional PDF document. Orientation are optional. A4 size page will be used. DO NOT ADD FOOTER MANUALLY, the system will handle it automatically. USE CSS TO VISUALLY BEAUTIFY THE DOCUMENT.
|
|
618
|
+
6. Write PDF: tool:functions.write_pdf(path="path", content="<html/css content>", orientation="portrait/landscape"). Generates a professional PDF document. Orientation are optional. A4 size page will be used, so any multi-page PDFs calculate your alightment and page breaks to not mess up A4 page layout . DO NOT ADD FOOTER MANUALLY, the system will handle it automatically. USE CSS TO VISUALLY BEAUTIFY THE DOCUMENT.
|
|
616
619
|
7. Execution: tool:functions.exec_command(command="terminal command"). Runs a shell command.
|
|
617
620
|
|
|
618
621
|
**NOTE:** WHEN WRITING/UPDATING FILES, USE ACTUAL NEW LINE CHARACTER FOR LINE BREAKS RATHER THAN STRING '\\n'`.trim() : `
|
|
@@ -741,7 +744,7 @@ Every ${isMemoryEnabled ? "Prompt, Responses & Memories" : "Prompt & Responses"}
|
|
|
741
744
|
- Use GFM tables for structured data to keep the terminal view organized. KEEP SENTENCES IN TABLE **SHORT & CONCISE**. AND MAX 3 COLUMNS. DO NOT OVERUSE TABLES.
|
|
742
745
|
- **CRITICAL**: NEVER USE LaTeX IN TERMINAL RESPONSES (exception: file content).
|
|
743
746
|
- Keep Poems & Literature in Code Block.
|
|
744
|
-
- Use emojis & Kaomojis.
|
|
747
|
+
- Use emojis & Kaomojis. Prefer Kaomojis more.
|
|
745
748
|
-- END FORMATTING RULES --
|
|
746
749
|
|
|
747
750
|
-- START REPONSE FINISH PROTOCOL --
|
|
@@ -763,7 +766,7 @@ Current date and Time is: ${dateTimeStr}
|
|
|
763
766
|
AGENT RAWS (responses from this turn):
|
|
764
767
|
${agentRes}
|
|
765
768
|
${userMemories ? `
|
|
766
|
-
|
|
769
|
+
|
|
767
770
|
-- CURRENT PERSISTENT USER MEMORIES --
|
|
768
771
|
${userMemories}
|
|
769
772
|
-------------------------------------------------
|
|
@@ -972,6 +975,9 @@ var init_arg_parser = __esm({
|
|
|
972
975
|
if (value === "true") value = true;
|
|
973
976
|
else if (value === "false") value = false;
|
|
974
977
|
else if (typeof value === "string" && !isNaN(value) && value.trim() !== "") value = Number(value);
|
|
978
|
+
if (typeof value === "string" && (key.toLowerCase().includes("path") || ["dest", "source", "to", "from"].includes(key.toLowerCase()))) {
|
|
979
|
+
value = value.replace(/\x0C/g, "\\f").replace(/\x0D/g, "\\r").replace(/\x0B/g, "\\v").replace(/\x08/g, "\\b");
|
|
980
|
+
}
|
|
975
981
|
args[key] = value;
|
|
976
982
|
}
|
|
977
983
|
return args;
|
|
@@ -1096,35 +1102,58 @@ var init_web_scrape = __esm({
|
|
|
1096
1102
|
await new Promise((r) => setTimeout(r, jitter));
|
|
1097
1103
|
await page.goto(url, { waitUntil: "networkidle2", timeout: 45e3 });
|
|
1098
1104
|
await new Promise((r) => setTimeout(r, 5e3));
|
|
1099
|
-
let
|
|
1100
|
-
const junk = document.querySelectorAll("script, style, nav, footer, header, noscript");
|
|
1105
|
+
let htmlContent = await page.evaluate(() => {
|
|
1106
|
+
const junk = document.querySelectorAll("script, style, nav, footer, header, noscript, svg, canvas, iframe, ad, .ads, link, meta, img");
|
|
1101
1107
|
junk.forEach((el) => el.remove());
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
+
const iterator = document.createNodeIterator(document.body, NodeFilter.SHOW_COMMENT);
|
|
1109
|
+
let currentNode;
|
|
1110
|
+
while (currentNode = iterator.nextNode()) {
|
|
1111
|
+
currentNode.remove();
|
|
1112
|
+
}
|
|
1113
|
+
const allElements = document.querySelectorAll("*");
|
|
1114
|
+
allElements.forEach((el) => {
|
|
1115
|
+
const attributes = el.attributes;
|
|
1116
|
+
for (let i = attributes.length - 1; i >= 0; i--) {
|
|
1117
|
+
const attrName = attributes[i].name;
|
|
1118
|
+
if (attrName !== "href" && attrName !== "src") {
|
|
1119
|
+
el.removeAttribute(attrName);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if ((el.tagName === "SPAN" || el.tagName === "DIV" || el.tagName === "SECTION") && el.attributes.length === 0) {
|
|
1123
|
+
if (el.tagName === "SPAN" || el.tagName === "DIV" && el.childNodes.length === 1 && el.childNodes[0].nodeType === Node.TEXT_NODE) {
|
|
1124
|
+
el.replaceWith(...el.childNodes);
|
|
1125
|
+
}
|
|
1108
1126
|
}
|
|
1109
1127
|
});
|
|
1110
|
-
|
|
1128
|
+
const pruneEmpty = () => {
|
|
1129
|
+
let found = false;
|
|
1130
|
+
document.querySelectorAll("*:not(br)").forEach((el) => {
|
|
1131
|
+
if (el.childNodes.length === 0 && !el.innerText.trim()) {
|
|
1132
|
+
el.remove();
|
|
1133
|
+
found = true;
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
if (found) pruneEmpty();
|
|
1137
|
+
};
|
|
1138
|
+
pruneEmpty();
|
|
1139
|
+
return document.body.innerHTML;
|
|
1111
1140
|
});
|
|
1112
|
-
if (!
|
|
1113
|
-
const
|
|
1141
|
+
if (!htmlContent) throw new Error("EMPTY_RENDER_RESULT");
|
|
1142
|
+
const cleanedHtml = htmlContent.replace(/\s+/g, " ").replace(/>\s+</g, "><").trim().substring(0, 3e4);
|
|
1114
1143
|
const toolLogDir = path7.join(LOGS_DIR, "tools");
|
|
1115
1144
|
if (!fs7.existsSync(toolLogDir)) fs7.mkdirSync(toolLogDir, { recursive: true });
|
|
1116
|
-
fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toISOString()} - URL: [${url}]. Length: ${
|
|
1145
|
+
fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toISOString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
|
|
1117
1146
|
Content:
|
|
1118
|
-
${
|
|
1147
|
+
${cleanedHtml}
|
|
1119
1148
|
|
|
1120
1149
|
--------------------------------------------------------
|
|
1121
1150
|
|
|
1122
1151
|
|
|
1123
1152
|
`);
|
|
1124
1153
|
await browser.close();
|
|
1125
|
-
return `
|
|
1154
|
+
return `CLEANED HTML FROM [${url}]:
|
|
1126
1155
|
|
|
1127
|
-
${
|
|
1156
|
+
${cleanedHtml}${htmlContent.length > 3e4 ? "\n\n[TRUNCATED AT 30K CHARS]" : ""}`;
|
|
1128
1157
|
} catch (err) {
|
|
1129
1158
|
lastError = err;
|
|
1130
1159
|
if (browser) await browser.close();
|
|
@@ -1710,16 +1739,33 @@ var init_write_pdf = __esm({
|
|
|
1710
1739
|
const page = await browser.newPage();
|
|
1711
1740
|
const styledContent = `
|
|
1712
1741
|
<style>
|
|
1713
|
-
@page {
|
|
1714
|
-
margin: ${margin};
|
|
1742
|
+
@page {
|
|
1743
|
+
margin: ${margin};
|
|
1715
1744
|
}
|
|
1716
|
-
body {
|
|
1717
|
-
margin: 0;
|
|
1745
|
+
body {
|
|
1746
|
+
margin: 0;
|
|
1718
1747
|
padding: 0;
|
|
1719
1748
|
font-family: system-ui, -apple-system, sans-serif;
|
|
1720
1749
|
}
|
|
1721
1750
|
* { box-sizing: border-box; }
|
|
1751
|
+
.watermark {
|
|
1752
|
+
position: fixed;
|
|
1753
|
+
top: 50%;
|
|
1754
|
+
left: 50%;
|
|
1755
|
+
transform: translate(-50%, -50%) rotate(-50deg);
|
|
1756
|
+
font-size: 52px;
|
|
1757
|
+
font-weight: bold;
|
|
1758
|
+
color: rgba(0, 0, 0, 0.005);
|
|
1759
|
+
pointer-events: none;
|
|
1760
|
+
z-index: 1000;
|
|
1761
|
+
text-align: center;
|
|
1762
|
+
width: 150%;
|
|
1763
|
+
white-space: nowrap;
|
|
1764
|
+
text-transform: uppercase;
|
|
1765
|
+
letter-spacing: 5px;
|
|
1766
|
+
}
|
|
1722
1767
|
</style>
|
|
1768
|
+
<div class="watermark">Generated by FluxFlow CLI (AI)</div>
|
|
1723
1769
|
${content}
|
|
1724
1770
|
`;
|
|
1725
1771
|
await page.setContent(styledContent, { waitUntil: "networkidle0" });
|
|
@@ -1730,17 +1776,9 @@ var init_write_pdf = __esm({
|
|
|
1730
1776
|
margin: {
|
|
1731
1777
|
top: margin,
|
|
1732
1778
|
right: margin,
|
|
1733
|
-
bottom:
|
|
1734
|
-
// Space for watermark
|
|
1779
|
+
bottom: margin,
|
|
1735
1780
|
left: margin
|
|
1736
1781
|
},
|
|
1737
|
-
displayHeaderFooter: true,
|
|
1738
|
-
headerTemplate: "<span></span>",
|
|
1739
|
-
footerTemplate: `
|
|
1740
|
-
<div style="font-size: 9px; color: rgba(0,0,0,0.2); width: 100%; text-align: right; padding-right: 15mm; font-family: system-ui, sans-serif; -webkit-print-color-adjust: exact;">
|
|
1741
|
-
FluxFlow CLI
|
|
1742
|
-
</div>
|
|
1743
|
-
`,
|
|
1744
1782
|
printBackground: true
|
|
1745
1783
|
});
|
|
1746
1784
|
const stats = await fs13.stat(absolutePath);
|
|
@@ -2051,7 +2089,16 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2051
2089
|
}
|
|
2052
2090
|
} catch (e) {
|
|
2053
2091
|
}
|
|
2054
|
-
|
|
2092
|
+
const pathLower = targetPath2.toLowerCase();
|
|
2093
|
+
const isPdf = pathLower.endsWith(".pdf");
|
|
2094
|
+
const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
|
|
2095
|
+
if (isPdf) {
|
|
2096
|
+
label = `\u{1F4C4} ANALYZING PDF: ${targetPath2}`.toUpperCase();
|
|
2097
|
+
} else if (isImage) {
|
|
2098
|
+
label = `\u{1F5BC}\uFE0F ANALYZING IMAGE: ${targetPath2}`.toUpperCase();
|
|
2099
|
+
} else {
|
|
2100
|
+
label = `\u{1F4C4} READING FILE: ${targetPath2}. LINES ${start_line} - ${actualEndLine} FROM ${totalLines}`.toUpperCase();
|
|
2101
|
+
}
|
|
2055
2102
|
} else if (toolCall.toolName === "list_files" || toolCall.toolName === "read_folder") {
|
|
2056
2103
|
const action = toolCall.toolName === "list_files" ? "LISTING" : "DISCOVERING";
|
|
2057
2104
|
label = `\u{1F4C2} ${action} DIRECTORY: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
|
|
@@ -2070,7 +2117,7 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2070
2117
|
const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
|
|
2071
2118
|
const boxMid = `\u2502 ${label.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
|
|
2072
2119
|
const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
|
|
2073
|
-
yield { type: "
|
|
2120
|
+
yield { type: "visual_feedback", content: `
|
|
2074
2121
|
|
|
2075
2122
|
${boxTop}
|
|
2076
2123
|
${boxMid}
|
|
@@ -3182,7 +3229,7 @@ ${timestamp}` };
|
|
|
3182
3229
|
setIsExpanded(false);
|
|
3183
3230
|
try {
|
|
3184
3231
|
const cleanHistoryForAI = [...messages, userMessage].filter(
|
|
3185
|
-
(m) => m.role !== "think" && !String(m.id).startsWith("welcome")
|
|
3232
|
+
(m) => m.role !== "think" && !m.isVisualFeedback && !String(m.id).startsWith("welcome")
|
|
3186
3233
|
).map((m) => ({
|
|
3187
3234
|
...m,
|
|
3188
3235
|
text: m.fullText || m.text
|
|
@@ -3309,6 +3356,15 @@ Selection: ${val}`,
|
|
|
3309
3356
|
});
|
|
3310
3357
|
continue;
|
|
3311
3358
|
}
|
|
3359
|
+
if (packet.type === "visual_feedback") {
|
|
3360
|
+
setMessages((prev) => [...prev, {
|
|
3361
|
+
id: "feedback-" + Date.now(),
|
|
3362
|
+
role: "system",
|
|
3363
|
+
text: packet.content,
|
|
3364
|
+
isVisualFeedback: true
|
|
3365
|
+
}]);
|
|
3366
|
+
continue;
|
|
3367
|
+
}
|
|
3312
3368
|
if (packet.type === "exec_start") {
|
|
3313
3369
|
continue;
|
|
3314
3370
|
}
|
|
@@ -3420,7 +3476,7 @@ Selection: ${val}`,
|
|
|
3420
3476
|
setActiveView("resolution");
|
|
3421
3477
|
}
|
|
3422
3478
|
setMessages((prev) => {
|
|
3423
|
-
const historyToSave = prev.filter((m) => !String(m.id).startsWith("welcome"));
|
|
3479
|
+
const historyToSave = prev.filter((m) => !String(m.id).startsWith("welcome") && !m.isVisualFeedback);
|
|
3424
3480
|
saveChat(chatId, null, historyToSave);
|
|
3425
3481
|
setCompletedIndex(prev.length);
|
|
3426
3482
|
return prev;
|
|
@@ -4089,8 +4145,8 @@ var init_app = __esm({
|
|
|
4089
4145
|
init_setup();
|
|
4090
4146
|
SESSION_START_TIME = Date.now();
|
|
4091
4147
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
4092
|
-
versionFluxflow = "1.5.
|
|
4093
|
-
updatedOn = "2026-05-
|
|
4148
|
+
versionFluxflow = "1.5.4";
|
|
4149
|
+
updatedOn = "2026-05-02";
|
|
4094
4150
|
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 (turn: finish) 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(
|
|
4095
4151
|
CommandMenu,
|
|
4096
4152
|
{
|