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.
Files changed (2) hide show
  1. package/dist/fluxflow.js +93 -37
  2. 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 text = await page.evaluate(() => {
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 links = document.querySelectorAll("a");
1103
- links.forEach((a) => {
1104
- const href = a.href;
1105
- const content = a.innerText.trim();
1106
- if (href && content && !href.startsWith("javascript:") && !href.startsWith("#")) {
1107
- a.innerText = ` [${content}](${href}) `;
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
- return document.body.innerText;
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 (!text) throw new Error("EMPTY_RENDER_RESULT");
1113
- const cleanedText = text.replace(/\s+/g, " ").trim().substring(0, 25e3);
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: ${cleanedText.length}.
1145
+ fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toISOString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
1117
1146
  Content:
1118
- ${cleanedText}
1147
+ ${cleanedHtml}
1119
1148
 
1120
1149
  --------------------------------------------------------
1121
1150
 
1122
1151
 
1123
1152
  `);
1124
1153
  await browser.close();
1125
- return `CONTENT FROM [${url}]:
1154
+ return `CLEANED HTML FROM [${url}]:
1126
1155
 
1127
- ${cleanedText}${text.length > 25e3 ? "\n\n[TRUNCATED AT 25K CHARS]" : ""}`;
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: "15mm",
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
- label = `\u{1F4C4} READING FILE: ${targetPath2}. LINES ${start_line} - ${actualEndLine} FROM ${totalLines}`.toUpperCase();
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: "text", content: `
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.2";
4093
- updatedOn = "2026-05-01";
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
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",