fluxflow-cli 1.5.0 → 1.5.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 +141 -91
  2. package/package.json +2 -3
package/dist/fluxflow.js CHANGED
@@ -754,28 +754,35 @@ Current date and Time is: ${dateTimeStr}
754
754
  --- END SYSTEM INSTRUCTION ---`.trim();
755
755
  };
756
756
  getJanitorInstruction = (originalText, agentRaws, userMemories = "", isMemoryEnabled = true, needTitle = false) => {
757
- return `ORIGINAL USER PROMPT: ${originalText.substring(0, 500)}
757
+ let agentRes = `${agentRaws.replace(/tool:functions\..*\n/g, "").replace(/<think>.*<\/think>/g, "").replace(/\[Prompted on:.*?\]/g, "").replace(/\[turn: continue\]/g, "").replace(/\[turn: finish\]/g, "").replace(/\[TOOL_RESULTS\]/g, "").replace(/\[tool_results\]/g, "").substring(0, 3500)}`;
758
+ if (agentRes.length > 3500) {
759
+ agentRes += "\n... (truncated) ...";
760
+ }
761
+ let originalTextProcessed = originalText.replace(/\[Prompted on:.*?\]/g, "");
762
+ return `USER PROMPT: ${originalTextProcessed.substring(0, 600)}${originalTextProcessed.length > 600 ? "\n... (truncated) ..." : ""}
758
763
  AGENT RAWS (responses from this turn):
759
- ${agentRaws.substring(0, 2e3).replace(/tool:functions\..*\n/g, "").replace(/<think>.*<\/think>/g, "").replace(/\[Prompted on:.*?\]/g, "").replace(/\[turn: continue\]/g, "").replace(/\[turn: finish\]/g, "")}${agentRaws.length > 1500 ? "\n... (truncated) ..." : ""}
764
+ ${agentRes}
765
+ ${userMemories ? `
766
+
767
+ -- CURRENT PERSISTENT USER MEMORIES --
768
+ ${userMemories}
769
+ -------------------------------------------------
770
+ ` : ""}
760
771
 
761
772
  --- START SYSTEM INSTRUCTION (STRICT HEADLESS LOGIC WORKER: ZERO USER-FACING TEXT POLICY) ---
762
- YOU ARE A SILENT BACKGROUND SYSTEM PROCESS. YOU HAVE NO MOUTH. YOUR ONLY OUTPUT MEDIUM IS VALID TOOL CALL SYNTAX.
773
+ YOU ARE A SILENT BACKGROUND SYSTEM PROCESS. YOU HAVE NO MOUTH. YOUR ONLY OUTPUT MEDIUM IS VALID TOOL CALLS.
763
774
  [CRITICAL RULES]
764
775
  1. OUTPUT ONLY 'tool:functions.xxx' CALLS.
765
- 2. DO NOT EXPLAIN. DO NOT SUMMARIZE AGENT RAWS. DO NOT TALK TO THE USER.
776
+ 2. DO NOT EXPLAIN. DO NOT TALK TO THE USER.
766
777
  3. NON-TOOL TEXT WILL BREAK THE SYSTEM.
767
- 4. DO NOT REPEAT AGENT RAWS IN YOUR RESPONSE.
768
- 5. IF YOU GET ONLY USER RESPONSE AND NO AGENT RAWS, THEN JUST USE TEMP MEMORY TO LOG THE SUMMARY OF USER QUERY.
778
+ 4. DO NOT REPEAT AGENT RAWS AND TOOL RESULTS IN YOUR RESPONSE.
779
+ 5. IF YOU GET ONLY USER QUERY AND NO AGENT RAWS, THEN JUST USE TEMP MEMORY TO LOG THE SUMMARY OF USER QUERY.
769
780
 
770
781
  YOUR JOB: Analyze the 'User prompt' and 'Agent Raws' to extract facts for long-term memory or handle system tasks.
771
782
  ${isMemoryEnabled ? `If user tell something that is important (like, hobbies, preferences, facts about user, hates, likes, etc) to know user better over time, use long term memory tools.` : ""}
772
783
 
773
784
  ${JANITOR_TOOLS_PROTOCOL(isMemoryEnabled, needTitle)}
774
785
 
775
- ${userMemories ? `-- CURRENT PERSISTENT USER MEMORIES --
776
- ${userMemories}
777
- -------------------------------------------------
778
- ` : ""}
779
786
  Current date and Time: ${(/* @__PURE__ */ new Date()).toLocaleString()}
780
787
 
781
788
  --- END SYSTEM INSTRUCTION ---`.trim();
@@ -973,7 +980,7 @@ var init_arg_parser = __esm({
973
980
  });
974
981
 
975
982
  // src/tools/web_search.js
976
- import * as cuimp from "cuimp";
983
+ import puppeteer from "puppeteer";
977
984
  import fs6 from "fs";
978
985
  import path6 from "path";
979
986
  var web_search;
@@ -984,67 +991,83 @@ var init_web_search = __esm({
984
991
  web_search = async (argsString) => {
985
992
  const { query, limit = 10 } = parseArgs(argsString);
986
993
  if (!query) return 'ERROR: Missing "query" argument for web_search.';
987
- try {
988
- await new Promise((r) => setTimeout(r, Math.random() * 1e3 + 500));
989
- const response = await cuimp.get(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`, {
990
- headers: {
991
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
992
- }
993
- });
994
- const html = response.data;
995
- const results = [];
996
- const resultRegex = /<a[^>]*class="result__a"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
997
- let match;
998
- let count = 0;
999
- while ((match = resultRegex.exec(html)) !== null && count < limit) {
1000
- let url = match[1];
1001
- if (url.includes("uddg=")) {
1002
- url = decodeURIComponent(url.split("uddg=")[1].split("&")[0]);
1003
- }
1004
- const title = match[2].replace(/<[^>]*>/g, "").trim();
1005
- const snippet = match[3].replace(/<[^>]*>/g, "").trim();
1006
- results.push(`${count + 1}. ${title}
994
+ const maxRetries = 3;
995
+ let lastError = null;
996
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
997
+ let browser = null;
998
+ try {
999
+ browser = await puppeteer.launch({
1000
+ headless: true,
1001
+ args: [
1002
+ "--no-sandbox",
1003
+ "--disable-setuid-sandbox",
1004
+ "--disable-gpu",
1005
+ "--disable-dev-shm-usage"
1006
+ ]
1007
+ });
1008
+ const page = await browser.newPage();
1009
+ await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36");
1010
+ await page.setViewport({ width: 1280, height: 800 });
1011
+ const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
1012
+ await new Promise((r) => setTimeout(r, jitter));
1013
+ const searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
1014
+ await page.goto(searchUrl, { waitUntil: "networkidle2" });
1015
+ const results = await page.$$eval(".result", (elements, maxLimit) => {
1016
+ return elements.slice(0, maxLimit).map((el, i) => {
1017
+ const titleEl = el.querySelector(".result__a");
1018
+ const snippetEl = el.querySelector(".result__snippet");
1019
+ let url = titleEl ? titleEl.href : "";
1020
+ if (url.includes("uddg=")) {
1021
+ url = decodeURIComponent(url.split("uddg=")[1].split("&")[0]);
1022
+ }
1023
+ const title = titleEl ? titleEl.innerText.trim() : "No Title";
1024
+ const snippet = snippetEl ? snippetEl.innerText.trim() : "No Snippet";
1025
+ return `${i + 1}. ${title}
1007
1026
  Source: ${url}
1008
- Snippet: ${snippet}`);
1009
- count++;
1010
- }
1011
- const toolLogDir = path6.join(LOGS_DIR, "tools");
1012
- if (!fs6.existsSync(toolLogDir)) {
1013
- fs6.mkdirSync(toolLogDir, { recursive: true });
1014
- }
1015
- fs6.appendFileSync(path6.join(toolLogDir, "search-results.log"), `RESULTS ${(/* @__PURE__ */ new Date()).toISOString()} -
1016
- Query: [${query}]. Results Count: ${results.length}.
1017
- Results: ${results}
1027
+ Snippet: ${snippet}`;
1028
+ });
1029
+ }, limit);
1030
+ if (results.length === 0) {
1031
+ const bodyText = await page.evaluate(() => document.body.innerText);
1032
+ if (bodyText.includes("anomaly")) {
1033
+ throw new Error("ANOMALY_DETECTED");
1034
+ }
1035
+ await browser.close();
1036
+ return `No results found for query: [${query}].`;
1037
+ }
1038
+ const finalResults = results.join("\n\n");
1039
+ const toolLogDir = path6.join(LOGS_DIR, "tools");
1040
+ if (!fs6.existsSync(toolLogDir)) fs6.mkdirSync(toolLogDir, { recursive: true });
1041
+ fs6.appendFileSync(path6.join(toolLogDir, "search-results.log"), `SEARCH ${(/* @__PURE__ */ new Date()).toISOString()} - Query: [${query}]. Count: ${results.length}.
1042
+ Content:
1043
+ ${finalResults}
1044
+
1045
+ --------------------------------------------------------
1018
1046
 
1019
1047
 
1020
1048
  `);
1021
- if (results.length === 0) {
1022
- if (html.includes("anomaly")) {
1023
- const toolErrDir = path6.join(LOGS_DIR, "tools");
1024
- if (!fs6.existsSync(toolErrDir)) {
1025
- fs6.mkdirSync(toolErrDir, { recursive: true });
1026
- }
1027
- fs6.appendFileSync(path6.join(toolErrDir, "error.log"), `ERROR ${(/* @__PURE__ */ new Date()).toISOString()} - DDG detected unusual activity. Cuimp impersonation might need adjustment.
1028
- `);
1029
- throw new Error("DDG detected unusual activity. Cuimp impersonation might need adjustment.");
1030
- }
1031
- return `No results found for query: [${query}].`;
1032
- }
1033
- const finalResults = results.join("\n\n");
1034
- return `Search results for [${query}]:
1049
+ await browser.close();
1050
+ return `Search results for [${query}]:
1035
1051
 
1036
1052
  ${finalResults}`;
1037
- } catch (err) {
1038
- return `ERROR: Search failed. Unable to read.`;
1053
+ } catch (err) {
1054
+ lastError = err;
1055
+ if (browser) await browser.close();
1056
+ if (attempt < maxRetries) {
1057
+ const backoff = Math.pow(2, attempt) * 1e3;
1058
+ await new Promise((r) => setTimeout(r, backoff));
1059
+ }
1060
+ }
1039
1061
  }
1062
+ return `ERROR: Search failed after ${maxRetries + 1} attempts. Last error: ${lastError.message}`;
1040
1063
  };
1041
1064
  }
1042
1065
  });
1043
1066
 
1044
1067
  // src/tools/web_scrape.js
1068
+ import puppeteer2 from "puppeteer";
1045
1069
  import fs7 from "fs";
1046
1070
  import path7 from "path";
1047
- import * as cuimp2 from "cuimp";
1048
1071
  var web_scrape;
1049
1072
  var init_web_scrape = __esm({
1050
1073
  "src/tools/web_scrape.js"() {
@@ -1052,39 +1075,66 @@ var init_web_scrape = __esm({
1052
1075
  web_scrape = async (args) => {
1053
1076
  const urlMatch = args.match(/url\s*=\s*["'](.*)["']/);
1054
1077
  const url = urlMatch ? urlMatch[1] : args;
1055
- try {
1056
- const response = await cuimp2.get(url, {
1057
- headers: {
1058
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
1059
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
1060
- "Accept-Language": "en-US,en;q=0.5"
1061
- }
1062
- });
1063
- let html = response.data;
1064
- if (!html) throw new Error("No content received from URL.");
1065
- html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
1066
- html = html.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "");
1067
- html = html.replace(/<nav\b[^<]*(?:(?!<\/nav>)<[^<]*)*<\/nav>/gi, "");
1068
- html = html.replace(/<footer\b[^<]*(?:(?!<\/footer>)<[^<]*)*<\/footer>/gi, "");
1069
- html = html.replace(/<header\b[^<]*(?:(?!<\/header>)<[^<]*)*<\/header>/gi, "");
1070
- let text = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
1071
- const finalContent = text.substring(0, 2e4);
1072
- const toolLogDir = path7.join(LOGS_DIR, "tools");
1073
- if (!fs7.existsSync(toolLogDir)) {
1074
- fs7.mkdirSync(toolLogDir, { recursive: true });
1075
- }
1076
- fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `RESULTS ${(/* @__PURE__ */ new Date()).toISOString()} -
1077
- Query: [${url}].
1078
- Results: ${finalContent}
1078
+ const maxRetries = 3;
1079
+ let lastError = null;
1080
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1081
+ let browser = null;
1082
+ try {
1083
+ browser = await puppeteer2.launch({
1084
+ headless: true,
1085
+ args: [
1086
+ "--no-sandbox",
1087
+ "--disable-setuid-sandbox",
1088
+ "--disable-gpu",
1089
+ "--disable-dev-shm-usage"
1090
+ ]
1091
+ });
1092
+ const page = await browser.newPage();
1093
+ await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36");
1094
+ await page.setViewport({ width: 1280, height: 1600 });
1095
+ const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
1096
+ await new Promise((r) => setTimeout(r, jitter));
1097
+ await page.goto(url, { waitUntil: "networkidle2", timeout: 45e3 });
1098
+ await new Promise((r) => setTimeout(r, 5e3));
1099
+ let text = await page.evaluate(() => {
1100
+ const junk = document.querySelectorAll("script, style, nav, footer, header, noscript");
1101
+ 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
+ }
1109
+ });
1110
+ return document.body.innerText;
1111
+ });
1112
+ if (!text) throw new Error("EMPTY_RENDER_RESULT");
1113
+ const cleanedText = text.replace(/\s+/g, " ").trim().substring(0, 25e3);
1114
+ const toolLogDir = path7.join(LOGS_DIR, "tools");
1115
+ 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}.
1117
+ Content:
1118
+ ${cleanedText}
1119
+
1120
+ --------------------------------------------------------
1079
1121
 
1080
1122
 
1081
1123
  `);
1082
- return `CONTENT FROM [${url}]:
1124
+ await browser.close();
1125
+ return `CONTENT FROM [${url}]:
1083
1126
 
1084
- ${finalContent}${text.length > 2e4 ? "\n\n[TRUNCATED AT 20K CHARS]" : ""}`;
1085
- } catch (err) {
1086
- return `ERROR: Failed to read page at ${url}. Unable to read.`;
1127
+ ${cleanedText}${text.length > 25e3 ? "\n\n[TRUNCATED AT 25K CHARS]" : ""}`;
1128
+ } catch (err) {
1129
+ lastError = err;
1130
+ if (browser) await browser.close();
1131
+ if (attempt < maxRetries) {
1132
+ const backoff = Math.pow(2, attempt) * 1e3;
1133
+ await new Promise((r) => setTimeout(r, backoff));
1134
+ }
1135
+ }
1087
1136
  }
1137
+ return `ERROR: Scrape failed after ${maxRetries + 1} attempts. Last error: ${lastError.message}`;
1088
1138
  };
1089
1139
  }
1090
1140
  });
@@ -1633,7 +1683,7 @@ var init_ask_user = __esm({
1633
1683
  });
1634
1684
 
1635
1685
  // src/tools/write_pdf.js
1636
- import puppeteer from "puppeteer";
1686
+ import puppeteer3 from "puppeteer";
1637
1687
  import path13 from "path";
1638
1688
  import fs13 from "fs-extra";
1639
1689
  var write_pdf;
@@ -1648,7 +1698,7 @@ var init_write_pdf = __esm({
1648
1698
  let browser = null;
1649
1699
  try {
1650
1700
  await fs13.ensureDir(path13.dirname(absolutePath));
1651
- browser = await puppeteer.launch({
1701
+ browser = await puppeteer3.launch({
1652
1702
  headless: true,
1653
1703
  args: [
1654
1704
  "--no-sandbox",
@@ -2461,7 +2511,7 @@ var init_UpdateProcessor = __esm({
2461
2511
  });
2462
2512
 
2463
2513
  // src/utils/setup.js
2464
- import puppeteer2 from "puppeteer";
2514
+ import puppeteer4 from "puppeteer";
2465
2515
  import { exec as exec2 } from "child_process";
2466
2516
  import { promisify } from "util";
2467
2517
  import fs16 from "fs";
@@ -2471,7 +2521,7 @@ var init_setup = __esm({
2471
2521
  execAsync = promisify(exec2);
2472
2522
  checkPuppeteerReady = () => {
2473
2523
  try {
2474
- const exePath = puppeteer2.executablePath();
2524
+ const exePath = puppeteer4.executablePath();
2475
2525
  const exists = exePath && fs16.existsSync(exePath);
2476
2526
  if (exists) return true;
2477
2527
  } catch (e) {
@@ -4039,7 +4089,7 @@ var init_app = __esm({
4039
4089
  init_setup();
4040
4090
  SESSION_START_TIME = Date.now();
4041
4091
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
4042
- versionFluxflow = "1.5.0";
4092
+ versionFluxflow = "1.5.2";
4043
4093
  updatedOn = "2026-05-01";
4044
4094
  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(
4045
4095
  CommandMenu,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",
@@ -34,12 +34,11 @@
34
34
  },
35
35
  "scripts": {
36
36
  "start": "tsx ./src/cli.jsx",
37
- "build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:ink-spinner --external:ink-multiline-input --external:@google/genai --external:zod --external:duck-duck-scrape --external:nanoid --external:cuimp --external:puppeteer --external:typescript"
37
+ "build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:ink-spinner --external:ink-multiline-input --external:@google/genai --external:zod --external:nanoid --external:puppeteer --external:typescript"
38
38
  },
39
39
  "dependencies": {
40
40
  "@google/genai": "^1.50.1",
41
41
  "chalk": "^5.6.2",
42
- "cuimp": "^1.10.0",
43
42
  "fs-extra": "^11.3.4",
44
43
  "gradient-string": "^3.0.0",
45
44
  "ink": "^7.0.1",