fluxflow-cli 1.9.18 → 1.9.20

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 +73 -146
  2. package/package.json +1 -3
package/dist/fluxflow.js CHANGED
@@ -154,7 +154,6 @@ var init_ChatLayout = __esm({
154
154
  "web_scrape": "ReadSite",
155
155
  "search_keyword": "FindFiles",
156
156
  "write_pdf": "CreatePDF",
157
- "write_pptx": "CreatePresentation",
158
157
  "write_docx": "CreateDocument"
159
158
  };
160
159
  cleanSignals = (text) => {
@@ -211,7 +210,7 @@ var init_ChatLayout = __esm({
211
210
  }
212
211
  }
213
212
  }
214
- return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*turn\s*:?.*?$/gi, "").replace(/\n\s*turn\s*:?.*?$/gi, "").replace(/\[\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replace(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_pptx|write_docx)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
213
+ return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*turn\s*:?.*?$/gi, "").replace(/\n\s*turn\s*:?.*?$/gi, "").replace(/\[\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replace(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_docx)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
215
214
  };
216
215
  formatThinkText = (cleaned, columns = 80) => {
217
216
  if (!cleaned) return null;
@@ -875,32 +874,29 @@ Access to internal tools. To call a tool, MUST use the exact syntax on a new lin
875
874
  [tool:functions.tool_name(arguments)]
876
875
 
877
876
  - COMMUNICATION TOOLS -
878
- 1. Ask User: [tool:functions.ask(question="...", optionA="...", ...)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish
877
+ 1. Ask User: [tool:functions.ask(question="...", optionA="<option>::<description>", ...MAX 4)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish
879
878
  Suggest best options; don't ask for preferences. System handles the rest
880
879
 
881
880
  - WEB TOOLS -
882
881
  1. Web Search: [tool:functions.web_search(query="...", limit=number)]. Find info (limit 3-10). Proactive use for unknown topics${mode === "Flux" ? " or docs" : ""}
883
- 2. Web Scrape: [tool:functions.web_scrape(url="<url>")]. Provides detail from a URL
882
+ 2. Web Scrape: [tool:functions.web_scrape(url="...")]. Visit URL
884
883
 
885
884
  ${mode === "Flux" ? `- DEV TOOLS (path = relative to CWD) -
886
885
  1. View File: [tool:functions.view_file(path="...", start_line=N, end_line=N)]. Reads contents. Supports images/docs. User gives image/doc: VIEW FIRST
887
886
  2. Read Folder: [tool:functions.read_folder(path="...")]. Detailed DIR stats
888
- 3. Write File: [tool:functions.write_file(path="...", content="content to write")]. Creates/Overwrites. File Exist? -> update_file > write_file
889
- 4. Update File: [tool:functions.update_file(path="...", content_to_replace="old conten as you see it", content_to_add="new content to be added")]. Surgical patching. Unsure content_to_replace? -> use view_file >> guessing.
890
- 5. Write PDF: [tool:functions.write_pdf(path="...", content="html", orientation="...")]. A4 PDF. Use CSS for layout (100vh/vw). Handle page breaks pro-actively; no manual footers
891
- 6. Write DOCX: [tool:functions.write_docx(path="...", content="html")]. A4 Word doc. Use proper margins and page breaks
892
- 7. PPTX: [tool:functions.write_pptx(path="...", content="html")]. 4:3 PPTX. '---' for slides
893
- Tags: a,b,br,del,font,h1-h6,i,ol,ul,li,p,pre,s,sub,sup,u
894
- CSS: background-color,color,font-family,font-size(pt),font-style,font-weight,margin,text-align,text-shadow
895
- 8. Execution: [tool:functions.exec_command(command="command")]. Runs a shell command. Destructive/Irreversible ops -> ask user
896
- 9. Search: [tool:functions.search_keyword(keyword="...")]. Global search. Finds definitions/logic without reading every file
887
+ 3. Write File: [tool:functions.write_file(path="...", content="...")]. Creates/Overwrites. File Exist? -> update_file > write_file
888
+ 4. Update File: [tool:functions.update_file(path="...", content_to_replace="old content", content_to_add="new content")]. Surgical patching. Unsure content_to_replace? -> view_file >> guessing.
889
+ 5. Write PDF: [tool:functions.write_pdf(path="...", content="...", orientation="...")]. A4 PDF. Use CSS for layout (100vh/vw). Handle page breaks; no manual footers
890
+ 6. Write DOCX: [tool:functions.write_docx(path="...", content="...")]. A4 Word doc. Proper margins and page breaks
891
+ 7. Execution: [tool:functions.exec_command(command="...")]. Runs a shell command. Destructive/Irreversible ops -> ask user
892
+ 8. Search: [tool:functions.search_keyword(keyword="...")]. Global search. Finds definitions/logic without reading every file
897
893
 
898
- - VERIFY SUCCESS CONTENTS. Fix errors. No hallucinations
894
+ - VERIFY RESULT CONTENTS. Fix errors. No hallucinations
899
895
  - File tools > code chat
900
896
 
901
897
  - Escape quotes: Use \\" inside code strings
902
898
  - Literal escapes: Double-escape sequences (e.g., \\\\n, \\\\t)
903
- - File structure: Use real newlines for code formatting`.trim() : `
899
+ - File structure: Real newlines for code formatting`.trim() : `
904
900
  - DEV TOOLS ARE NOT AVAILABLE IN FLOW MODE. If you need to access files, tell the user to switch to FLUX`.trim()}
905
901
 
906
902
  - Results: Passed as [TOOL_RESULT] SYSTEM
@@ -949,7 +945,9 @@ Refinement: Iterate on the chosen path until it is bulletproof.
949
945
  RULES:
950
946
  - NO HEADINGS. Just a solid, stable analytical monologue.
951
947
  - Be thorough and exhaustive. Explore the 'why' behind every decision, depth and nuances.
952
- - Use internal critique: Question your own logic as you go.
948
+ Question your own logic as you go,
949
+
950
+ DO NOT GET STUCK IN RE-VERIFICATION LOOP.
953
951
  - MANDATORY THINKING: You MUST engage in full reasoning regardless of perceived simplicity.`,
954
952
  High: "EFFORT_LEVEL: HIGH\nThink in a stable, analytical monologue within the <think>...</think> block. Avoid headings or structured formatting. Your thinking should be a continuous stream of logical deduction:\nAnalyze the immediate task and its dependencies.\nMentally simulate the execution to identify potential failure points.\nStructure a precise plan that addresses both primary goals and secondary constraints.\nRULES:\n- NO HEADINGS. Maintain a fluid monologue style.\n- Be detailed and rigorous in your self-questioning.\n- Focus on accuracy, technical correctness, depth and nuances.\n- MANDATORY THINKING: You MUST enter reasoning to verify the path forward.",
955
953
  Medium: "EFFORT_LEVEL: MEDIUM\nThink in a concise, stable monologue within the <think>...</think> block. No headings needed. Focus on the core logic required to solve the task efficiently:\nIdentify the most direct path to the solution.\nBriefly consider and discard obvious alternatives.\nConfirm the plan meets the user's immediate requirements.\nRULES:\n- NO HEADINGS. Keep it as a simple, logical stream.\n- Be efficient. Spend energy only on what matters for the task.\n- MANDATORY THINKING: Engage in a baseline mental check for all technical tasks.",
@@ -1027,10 +1025,10 @@ Protocol: [SYSTEM] and [STEERING HINT] are high-priority
1027
1025
 
1028
1026
  -- THINKING INSTRUCTIONS --
1029
1027
  ${thinkingConfig}
1030
- ***CRITICAL THINKING POLICY***
1031
- - Always use <think> ... </think> before answering or using any tool
1028
+ ***THINKING POLICY***
1029
+ - Always use <think> ... </think> before responding
1032
1030
  - Never skip thinking, even for simple tasks, code, or greetings
1033
- - Never jump to responses directly, regardless of task complexity or speed
1031
+ - Never jump to responses directly, regardless of task complexity
1034
1032
 
1035
1033
  ${TOOL_PROTOCOL(mode)}
1036
1034
  ${projectContextBlock}
@@ -1051,10 +1049,10 @@ ${projectContextBlock}
1051
1049
  -- RESPONSE PROTOCOL --
1052
1050
  - End with [turn: continue] for more steps or [turn: finish] when done
1053
1051
  - Multi-tool: Stack tools if needed, but always end with [turn: continue] if called any tools
1054
- TO END THE LOOP YOU **MUST** WRITE [turn: finish] AT VERY END OF YOUR RESPONSE
1052
+ TO END THE LOOP, **MUST** WRITE [turn: finish] AT END OF RESPONSE
1055
1053
 
1056
- [METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v1.9.18 | Turn Progress: ${currentLoop}/${maxLoops} steps (Prompt user if reached)
1057
- === END SYSTEM PROMPT ===`.trim();
1054
+ [METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v1.9.20 | Turn Progress: ${currentLoop}/${maxLoops} steps (Prompt user if reached)
1055
+ === SYSTEM PROMPT ===`.trim();
1058
1056
  };
1059
1057
  getJanitorInstruction = (originalText, agentRaws, userMemories = "", isMemoryEnabled = true, needTitle = true) => {
1060
1058
  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)}`;
@@ -2416,72 +2414,6 @@ var init_write_docx = __esm({
2416
2414
  }
2417
2415
  });
2418
2416
 
2419
- // src/tools/write_pptx.js
2420
- import fs16 from "fs-extra";
2421
- import path15 from "path";
2422
- import pptxgen from "pptxgenjs";
2423
- import html2pptxgenjs from "html2pptxgenjs";
2424
- var write_pptx;
2425
- var init_write_pptx = __esm({
2426
- "src/tools/write_pptx.js"() {
2427
- init_arg_parser();
2428
- write_pptx = async (args) => {
2429
- let {
2430
- path: targetPath,
2431
- content = "",
2432
- title = "Autonomous Agent Report"
2433
- } = parseArgs(args);
2434
- if (!targetPath) return 'ERROR: Missing "path" argument for write_pptx.';
2435
- if (!content) return 'ERROR: No "content" (HTML) provided for write_pptx.';
2436
- const absolutePath = path15.resolve(process.cwd(), targetPath);
2437
- try {
2438
- await fs16.ensureDir(path15.dirname(absolutePath));
2439
- const PptxConstructor = typeof pptxgen === "function" ? pptxgen : pptxgen.default;
2440
- if (!PptxConstructor) throw new Error("Could not find PptxGenJS constructor in module");
2441
- const pres = new PptxConstructor();
2442
- pres.layout = "LAYOUT_4x3";
2443
- pres.title = title;
2444
- pres.author = "FluxFlow CLI";
2445
- pres.company = "Generated with Agentic AI System";
2446
- const slideBlocks = content.split(/---/).filter((s) => s.trim().length > 0);
2447
- if (slideBlocks.length === 0) {
2448
- slideBlocks.push(content);
2449
- }
2450
- for (let i = 0; i < slideBlocks.length; i++) {
2451
- const slide = pres.addSlide();
2452
- const htmlSnippet = slideBlocks[i].trim();
2453
- try {
2454
- const items = html2pptxgenjs.htmlToPptxText(htmlSnippet);
2455
- slide.addText(items, {
2456
- x: 0.5,
2457
- y: 0.5,
2458
- w: "90%",
2459
- h: "90%",
2460
- valign: "top",
2461
- fontSize: 18,
2462
- color: "363636"
2463
- });
2464
- } catch (err) {
2465
- slide.addText(htmlSnippet.replace(/<[^>]*>/g, ""), {
2466
- x: 0.5,
2467
- y: 0.5,
2468
- w: "90%",
2469
- h: "90%",
2470
- fontSize: 14
2471
- });
2472
- }
2473
- }
2474
- const buffer = await pres.write({ outputType: "nodebuffer" });
2475
- await fs16.writeFile(absolutePath, buffer);
2476
- return `SUCCESS: Native HTML-to-PPTX [${targetPath}] generated with ${slideBlocks.length} slides.
2477
- - Size: ${(buffer.length / 1024).toFixed(1)} KB`;
2478
- } catch (err) {
2479
- return `ERROR: Failed to generate native HTML-to-PPTX [${targetPath}]: ${err.message}`;
2480
- }
2481
- };
2482
- }
2483
- });
2484
-
2485
2417
  // src/tools/search_keyword.js
2486
2418
  import { exec } from "child_process";
2487
2419
  var search_keyword;
@@ -2555,7 +2487,6 @@ var init_tools = __esm({
2555
2487
  init_ask_user();
2556
2488
  init_write_pdf();
2557
2489
  init_write_docx();
2558
- init_write_pptx();
2559
2490
  init_search_keyword();
2560
2491
  TOOL_MAP = {
2561
2492
  web_search,
@@ -2570,7 +2501,6 @@ var init_tools = __esm({
2570
2501
  read_folder,
2571
2502
  write_pdf,
2572
2503
  write_docx,
2573
- write_pptx,
2574
2504
  search_keyword,
2575
2505
  ask: ask_user
2576
2506
  };
@@ -2590,8 +2520,8 @@ var init_tools = __esm({
2590
2520
 
2591
2521
  // src/utils/ai.js
2592
2522
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
2593
- import path16 from "path";
2594
- import fs17 from "fs";
2523
+ import path15 from "path";
2524
+ import fs16 from "fs";
2595
2525
  var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
2596
2526
  var init_ai = __esm({
2597
2527
  "src/utils/ai.js"() {
@@ -2620,14 +2550,13 @@ var init_ai = __esm({
2620
2550
  "search_keyword": "Finding Files",
2621
2551
  "ask": "Asking User",
2622
2552
  "write_pdf": "Creating PDF",
2623
- "write_pptx": "Creating Presentation",
2624
2553
  "write_docx": "Creating Document"
2625
2554
  };
2626
2555
  getToolDetail = (toolName, argsStr) => {
2627
2556
  try {
2628
2557
  const pArgs = parseArgs(argsStr);
2629
2558
  const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
2630
- return filePath ? path16.basename(filePath.replace(/[\\"]/g, "")) : null;
2559
+ return filePath ? path15.basename(filePath.replace(/[\\"]/g, "")) : null;
2631
2560
  } catch (e) {
2632
2561
  return null;
2633
2562
  }
@@ -2708,9 +2637,9 @@ var init_ai = __esm({
2708
2637
  finalSynthesis = fullContent;
2709
2638
  if (lastUsage) await addToUsage("tokens", lastUsage.totalTokenCount || 0);
2710
2639
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
2711
- const janitorLogDir = path16.join(LOGS_DIR, "janitor");
2712
- if (!fs17.existsSync(janitorLogDir)) fs17.mkdirSync(janitorLogDir, { recursive: true });
2713
- fs17.appendFileSync(path16.join(janitorLogDir, "debug.log"), `
2640
+ const janitorLogDir = path15.join(LOGS_DIR, "janitor");
2641
+ if (!fs16.existsSync(janitorLogDir)) fs16.mkdirSync(janitorLogDir, { recursive: true });
2642
+ fs16.appendFileSync(path15.join(janitorLogDir, "debug.log"), `
2714
2643
 
2715
2644
  ---------------------------------------------------
2716
2645
 
@@ -2730,8 +2659,8 @@ DEBUG [${date}]: ${finalSynthesis}
2730
2659
  const toolContext = { chatId, sessionId: chatId, history };
2731
2660
  const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
2732
2661
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
2733
- const janitorLogDir = path16.join(LOGS_DIR, "janitor");
2734
- fs17.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
2662
+ const janitorLogDir = path15.join(LOGS_DIR, "janitor");
2663
+ fs16.appendFileSync(path15.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
2735
2664
  `);
2736
2665
  if (janitorToolCall.toolName === "memory" && !janitorToolCall.args.includes("action='temp'")) {
2737
2666
  if (onMemoryUpdated) onMemoryUpdated();
@@ -2741,9 +2670,9 @@ DEBUG [${date}]: ${finalSynthesis}
2741
2670
  } catch (janitorErr) {
2742
2671
  attempts++;
2743
2672
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
2744
- const janitorErrDir = path16.join(LOGS_DIR, "janitor");
2745
- if (!fs17.existsSync(janitorErrDir)) fs17.mkdirSync(janitorErrDir, { recursive: true });
2746
- fs17.appendFileSync(path16.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
2673
+ const janitorErrDir = path15.join(LOGS_DIR, "janitor");
2674
+ if (!fs16.existsSync(janitorErrDir)) fs16.mkdirSync(janitorErrDir, { recursive: true });
2675
+ fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
2747
2676
 
2748
2677
  `);
2749
2678
  if (attempts > MAX_JANITOR_RETRIES) break;
@@ -2752,8 +2681,8 @@ DEBUG [${date}]: ${finalSynthesis}
2752
2681
  }
2753
2682
  }
2754
2683
  if (attempts) {
2755
- const janitorErrDir = path16.join(LOGS_DIR, "janitor");
2756
- fs17.appendFileSync(path16.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
2684
+ const janitorErrDir = path15.join(LOGS_DIR, "janitor");
2685
+ fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
2757
2686
 
2758
2687
 
2759
2688
  `);
@@ -3144,19 +3073,19 @@ DEBUG [${date}]: ${finalSynthesis}
3144
3073
  const potentialTool = toolContext.toolName;
3145
3074
  const partialArgs = toolContext.args || "";
3146
3075
  let detail = null;
3147
- if (["write_file", "update_file", "view_file", "read_folder", "write_pdf", "write_pptx", "write_docx", "search_keyword"].includes(potentialTool)) {
3076
+ if (["write_file", "update_file", "view_file", "read_folder", "write_pdf", "write_docx", "search_keyword"].includes(potentialTool)) {
3148
3077
  const pArgs = parseArgs(partialArgs);
3149
3078
  const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
3150
3079
  const keyword = pArgs.keyword;
3151
3080
  if (keyword) {
3152
3081
  detail = keyword.replace(/[\\"]/g, "");
3153
3082
  } else if (filePath) {
3154
- detail = path16.basename(filePath.replace(/[\\"]/g, ""));
3083
+ detail = path15.basename(filePath.replace(/[\\"]/g, ""));
3155
3084
  } else {
3156
3085
  const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
3157
3086
  if (m) {
3158
3087
  const val = m[1].replace(/[\\"]/g, "");
3159
- detail = potentialTool === "search_keyword" ? val : path16.basename(val);
3088
+ detail = potentialTool === "search_keyword" ? val : path15.basename(val);
3160
3089
  }
3161
3090
  }
3162
3091
  }
@@ -3243,9 +3172,9 @@ DEBUG [${date}]: ${finalSynthesis}
3243
3172
  let totalLines = "...";
3244
3173
  let actualEndLine = eLine;
3245
3174
  try {
3246
- const absPath = path16.resolve(process.cwd(), targetPath2);
3247
- if (fs17.existsSync(absPath)) {
3248
- const content = fs17.readFileSync(absPath, "utf8");
3175
+ const absPath = path15.resolve(process.cwd(), targetPath2);
3176
+ if (fs16.existsSync(absPath)) {
3177
+ const content = fs16.readFileSync(absPath, "utf8");
3249
3178
  const lines = content.split("\n").length;
3250
3179
  totalLines = lines;
3251
3180
  actualEndLine = Math.min(eLine, lines);
@@ -3272,8 +3201,6 @@ DEBUG [${date}]: ${finalSynthesis}
3272
3201
  label = `\u{1F4D1} PDF CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3273
3202
  } else if (toolCall.toolName === "write_docx") {
3274
3203
  label = `\u{1F4DD} DOCX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3275
- } else if (toolCall.toolName === "write_pptx") {
3276
- label = `\u{1F4CA} PPTX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3277
3204
  } else if (toolCall.toolName === "search_keyword") {
3278
3205
  const { keyword } = parseArgs(toolCall.args);
3279
3206
  label = `\u{1F50E} KEYWORD SEARCHED: "${keyword}"`.toUpperCase();
@@ -3295,7 +3222,7 @@ ${boxBottom}` };
3295
3222
  const { command } = parseArgs(toolCall.args);
3296
3223
  if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
3297
3224
  const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
3298
- const currentDrive = path16.resolve(process.cwd()).substring(0, 3).toLowerCase();
3225
+ const currentDrive = path15.resolve(process.cwd()).substring(0, 3).toLowerCase();
3299
3226
  const isViolating = riskyPatterns.some((pattern) => {
3300
3227
  if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
3301
3228
  const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
@@ -3318,8 +3245,8 @@ ${boxBottom}` };
3318
3245
  const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
3319
3246
  if (targetPath) {
3320
3247
  const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
3321
- const absoluteTarget = path16.resolve(targetPath);
3322
- const absoluteCwd = path16.resolve(process.cwd());
3248
+ const absoluteTarget = path15.resolve(targetPath);
3249
+ const absoluteCwd = path15.resolve(process.cwd());
3323
3250
  if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
3324
3251
  const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace. To enable this, ask the user to turn on "External Workspace Access" in /settings.`;
3325
3252
  toolResults.push({ role: "user", text: `[TOOL_RESULT]: ERROR: ${denyMsg}
@@ -3422,9 +3349,9 @@ ${boxBottom}` };
3422
3349
  const errMsg = err.status || err.error && err.error.message || String(err);
3423
3350
  const errLog = String(err);
3424
3351
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
3425
- const agentErrDir = path16.join(LOGS_DIR, "agent");
3426
- if (!fs17.existsSync(agentErrDir)) fs17.mkdirSync(agentErrDir, { recursive: true });
3427
- fs17.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
3352
+ const agentErrDir = path15.join(LOGS_DIR, "agent");
3353
+ if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
3354
+ fs16.appendFileSync(path15.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
3428
3355
 
3429
3356
  ----------------------------------------------------------------------
3430
3357
 
@@ -3447,7 +3374,7 @@ ${boxBottom}` };
3447
3374
  yield { type: "status", content: `Error Occured. Recovering Stream...` };
3448
3375
  } else {
3449
3376
  throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
3450
- Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
3377
+ Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
3451
3378
  }
3452
3379
  } else {
3453
3380
  if (retryCount <= MAX_RETRIES) {
@@ -3462,7 +3389,7 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
3462
3389
  yield { type: "status", content: `Retrying Connection...` };
3463
3390
  } else {
3464
3391
  throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
3465
- Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
3392
+ Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
3466
3393
  }
3467
3394
  }
3468
3395
  }
@@ -3523,8 +3450,8 @@ ${timestamp}`;
3523
3450
  });
3524
3451
 
3525
3452
  // src/utils/settings.js
3526
- import fs18 from "fs-extra";
3527
- import path17 from "path";
3453
+ import fs17 from "fs-extra";
3454
+ import path16 from "path";
3528
3455
  var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
3529
3456
  var init_settings = __esm({
3530
3457
  "src/utils/settings.js"() {
@@ -3559,8 +3486,8 @@ var init_settings = __esm({
3559
3486
  };
3560
3487
  loadSettings = async () => {
3561
3488
  try {
3562
- if (await fs18.exists(SETTINGS_FILE)) {
3563
- const saved = await fs18.readJson(SETTINGS_FILE);
3489
+ if (await fs17.exists(SETTINGS_FILE)) {
3490
+ const saved = await fs17.readJson(SETTINGS_FILE);
3564
3491
  const merged = {
3565
3492
  ...DEFAULT_SETTINGS,
3566
3493
  ...saved,
@@ -3570,7 +3497,7 @@ var init_settings = __esm({
3570
3497
  };
3571
3498
  if (merged.showFullThinking === false) {
3572
3499
  merged.showFullThinking = true;
3573
- await fs18.writeJson(SETTINGS_FILE, merged, { spaces: 2 });
3500
+ await fs17.writeJson(SETTINGS_FILE, merged, { spaces: 2 });
3574
3501
  }
3575
3502
  return merged;
3576
3503
  }
@@ -3583,12 +3510,12 @@ var init_settings = __esm({
3583
3510
  const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
3584
3511
  const folders = ["logs", "secret"];
3585
3512
  for (const folder of folders) {
3586
- const src = path17.join(FLUXFLOW_DIR2, folder);
3587
- const dest = path17.join(newPath, folder);
3513
+ const src = path16.join(FLUXFLOW_DIR2, folder);
3514
+ const dest = path16.join(newPath, folder);
3588
3515
  try {
3589
- if (await fs18.exists(src)) {
3590
- await fs18.ensureDir(dest);
3591
- await fs18.copy(src, dest, { overwrite: true });
3516
+ if (await fs17.exists(src)) {
3517
+ await fs17.ensureDir(dest);
3518
+ await fs17.copy(src, dest, { overwrite: true });
3592
3519
  }
3593
3520
  } catch (err) {
3594
3521
  console.error(`Migration failed for ${folder}:`, err);
@@ -3602,8 +3529,8 @@ var init_settings = __esm({
3602
3529
  await migrateToExternal(settings.systemSettings.externalDataPath);
3603
3530
  }
3604
3531
  const updated = { ...current, ...settings };
3605
- await fs18.ensureDir(path17.dirname(SETTINGS_FILE));
3606
- await fs18.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
3532
+ await fs17.ensureDir(path16.dirname(SETTINGS_FILE));
3533
+ await fs17.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
3607
3534
  return true;
3608
3535
  } catch (err) {
3609
3536
  console.error("Failed to save settings:", err);
@@ -3816,7 +3743,7 @@ var init_UpdateProcessor = __esm({
3816
3743
  import puppeteer4 from "puppeteer";
3817
3744
  import { exec as exec3 } from "child_process";
3818
3745
  import { promisify } from "util";
3819
- import fs19 from "fs";
3746
+ import fs18 from "fs";
3820
3747
  var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
3821
3748
  var init_setup = __esm({
3822
3749
  "src/utils/setup.js"() {
@@ -3824,7 +3751,7 @@ var init_setup = __esm({
3824
3751
  checkPuppeteerReady = () => {
3825
3752
  try {
3826
3753
  const exePath = puppeteer4.executablePath();
3827
- const exists = exePath && fs19.existsSync(exePath);
3754
+ const exists = exePath && fs18.existsSync(exePath);
3828
3755
  if (exists) return true;
3829
3756
  } catch (e) {
3830
3757
  return false;
@@ -3858,8 +3785,8 @@ import os3 from "os";
3858
3785
  import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
3859
3786
  import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
3860
3787
  import Spinner2 from "ink-spinner";
3861
- import fs20 from "fs-extra";
3862
- import path18 from "path";
3788
+ import fs19 from "fs-extra";
3789
+ import path17 from "path";
3863
3790
  import { exec as exec4 } from "child_process";
3864
3791
  import { MultilineInput } from "ink-multiline-input";
3865
3792
  import TextInput3 from "ink-text-input";
@@ -4581,12 +4508,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
4581
4508
  setCompletedIndex(prev.length + 1);
4582
4509
  return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
4583
4510
  });
4584
- if (fs20.existsSync(LOGS_DIR)) fs20.removeSync(LOGS_DIR);
4585
- if (fs20.existsSync(SECRET_DIR)) fs20.removeSync(SECRET_DIR);
4586
- if (fs20.existsSync(SETTINGS_FILE)) fs20.removeSync(SETTINGS_FILE);
4511
+ if (fs19.existsSync(LOGS_DIR)) fs19.removeSync(LOGS_DIR);
4512
+ if (fs19.existsSync(SECRET_DIR)) fs19.removeSync(SECRET_DIR);
4513
+ if (fs19.existsSync(SETTINGS_FILE)) fs19.removeSync(SETTINGS_FILE);
4587
4514
  try {
4588
- const items = fs20.readdirSync(FLUXFLOW_DIR);
4589
- if (items.length === 0) fs20.removeSync(FLUXFLOW_DIR);
4515
+ const items = fs19.readdirSync(FLUXFLOW_DIR);
4516
+ if (items.length === 0) fs19.removeSync(FLUXFLOW_DIR);
4590
4517
  } catch (e) {
4591
4518
  }
4592
4519
  setTimeout(() => {
@@ -4643,14 +4570,14 @@ ${list || "No saved chats found."}`, isMeta: true }];
4643
4570
  # SKILLS & WORKFLOWS
4644
4571
  - [Define custom step-by-step recipes for this project here]
4645
4572
  `;
4646
- const filePath = path18.join(process.cwd(), "FluxFlow.md");
4647
- if (fs20.pathExistsSync(filePath)) {
4573
+ const filePath = path17.join(process.cwd(), "FluxFlow.md");
4574
+ if (fs19.pathExistsSync(filePath)) {
4648
4575
  setMessages((prev) => {
4649
4576
  setCompletedIndex(prev.length + 1);
4650
4577
  return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
4651
4578
  });
4652
4579
  } else {
4653
- fs20.writeFileSync(filePath, template);
4580
+ fs19.writeFileSync(filePath, template);
4654
4581
  setMessages((prev) => {
4655
4582
  setCompletedIndex(prev.length + 1);
4656
4583
  return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "\u2705 [SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
@@ -5624,8 +5551,8 @@ var init_app = __esm({
5624
5551
  init_text();
5625
5552
  SESSION_START_TIME = Date.now();
5626
5553
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5627
- versionFluxflow = "1.9.18";
5628
- updatedOn = "2026-05-16";
5554
+ versionFluxflow = "1.9.20";
5555
+ updatedOn = "2026-05-17";
5629
5556
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 0 }, /* @__PURE__ */ React10.createElement(
5630
5557
  CommandMenu,
5631
5558
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.9.18",
3
+ "version": "1.9.20",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",
@@ -42,7 +42,6 @@
42
42
  "fs-extra": "^11.3.4",
43
43
  "gradient-string": "^3.0.0",
44
44
  "html-to-docx": "^1.8.0",
45
- "html2pptxgenjs": "^0.0.3",
46
45
  "ink": "^7.0.1",
47
46
  "ink-multiline-input": "^0.1.0",
48
47
  "ink-select-input": "^6.2.0",
@@ -50,7 +49,6 @@
50
49
  "ink-text-input": "^6.0.0",
51
50
  "nanoid": "^5.1.9",
52
51
  "pdf-lib": "^1.17.1",
53
- "pptxgenjs": "^4.0.1",
54
52
  "puppeteer": "24.43.1",
55
53
  "react": "^19.2.5",
56
54
  "zod": "^4.3.6"