fluxflow-cli 1.9.9 β†’ 1.9.10

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 (3) hide show
  1. package/README.md +60 -60
  2. package/dist/fluxflow.js +171 -162
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,14 +1,38 @@
1
- # 🌌 Flux Flow (`fluxflow-cli`)
2
- ![Flux Flow Logo](https://github.com/KushalRoyChowdhury/fluxflow-cli/blob/main/fluxflow.png)
1
+ # 🌊 Flux Flow
2
+ ![Flux Flow Hero](./fluxflow.png)
3
3
 
4
- ### *The High-Fidelity Agentic Terminal for the Flux Era.*
4
+ **A Beautiful, Autonomous Terminal AI Agent**
5
5
 
6
- **Flux Flow** is not just another CLIβ€”it's a high-speed, sassy, and goal-oriented CLI AI Agent powered by the latest Gemini/Gemma frontier models. Designed for developers who demand a premium UI/UX while managing complex file-system tasks, web research, and autonomous workflows.
6
+ Flux Flow is an advanced, fully autonomous AI agent that lives directly in your terminal. Built with Node.js and [Ink](https://github.com/vadimdemedes/ink) (React for interactive command-line apps), it provides a highly responsive, component-based UI powered by a sophisticated dual-model AI architecture.
7
+
8
+ Whether you need a conversational partner or an autonomous developer that can write code, run shell commands, and read your project files, Flux Flow adapts to your needs.
7
9
 
8
10
  ---
9
11
 
10
- ## πŸš€ Instant Ignition (No Setup Required)
11
- You don't even need to install it. Just fire up your terminal and run:
12
+ ## ✨ Features
13
+
14
+ - **Native Multimodality**: Flux Flow can now see! Analyze images (JPG, PNG) and PDF documents natively through the `view_file` tool with high-fidelity context retention.
15
+ - **Document Engineering Suite**: Generate professional, branded PDF, DOCX, and PPTX documents on the fly. Features native HTML-to-Office translation for selectable text, high-performance rendering, and automatic watermarking.
16
+ - **External Data Sanctuary**: Redirect your logs, history, and memories to any external path for maximum portability and privacy.
17
+ - **Responsive Terminal UI**: A gorgeous, reactive interface built with React and Ink, featuring multi-line input, status bars, modals, and diff views.
18
+ - **Dual-Model Architecture**: A primary agent interacts with you and executes tasks, while a silent background "Janitor" model handles chat summarization and long-term memory extraction without blocking the main UI.
19
+ - **Two Operating Modes**:
20
+ - **Flux (Dev Mode)**: Full system access. The agent can read/write files, execute shell commands, and run autonomous agentic loops (up to 45 iterations) to solve complex coding tasks.
21
+ - **Flow (Chat Mode)**: Focused on conversation and web research, with limited agentic loops for faster response times.
22
+ - **Advanced Memory System**: Features both temporary session context and persistent, cross-session user memories encrypted locally on your machine.
23
+ - **Agentic Tooling**: Built-in tools for smart file patching, web scraping, web searching, terminal execution and high-fidelity Office document generation (PDF/DOCX/PPTX).
24
+ - **Autonomous Project Alignment**: Automatically detects and adheres to project-specific instructions in `Agent.md`, `Skills.md`, and `Fluxflow.md` for high-fidelity coding standards and complex workflows.
25
+ - **Customizable "Thinking" Levels**: Adjust the depth of the model's reasoning process (from Minimal to Max).
26
+ - **High-Reliability Fallback**: Automatic failover to a lighter, high-concurrency model (Gemini 3.1 Flash Lite) during peak traffic to ensure 100% session persistence.
27
+
28
+ ## πŸš€ Quick Start
29
+
30
+ ### Prerequisites
31
+ - [Node.js](https://nodejs.org/) (v18 or higher recommended)
32
+ - `npm`, `yarn`, or `pnpm`
33
+
34
+ ### Via NPM (Global & Instant)
35
+ You can run the agent instantly or install it globally for high-speed access:
12
36
 
13
37
  ```bash
14
38
  # Run instantly (Zero Setup)
@@ -16,69 +40,45 @@ npx fluxflow-cli
16
40
 
17
41
  # OR Install Globally
18
42
  npm install -g fluxflow-cli
19
- fluxflow-cli
43
+ fluxflow
20
44
  ```
21
45
 
22
- *The agent will prompt you for your Gemini API Key on the first run and store it securely in an XOR-encrypted vault.* Free API Key recomemded to use Gemma 4 (Default Model).
23
-
24
- ---
25
-
26
- ## ✨ Why Flux Flow?
27
-
28
- ### 🎨 **Premium Visual Sovereignty**
29
- Experience a terminal UI that feels alive. Built with **Ink** and **React**, Flux Flow features:
30
- - **Dynamic Status Bar**: Real-time telemetry showing your "Neural Headroom" (token usage), Thinking Level, and Session ID.
46
+ ### From Source (Local Development)
47
+ 1. Clone the repository and install dependencies:
48
+ ```bash
49
+ git clone <repository-url>
50
+ cd Flux-Flow
51
+ npm install
52
+ ```
31
53
 
32
- ### πŸ‘οΈ **Native Multimodality**
33
- Flux Flow can now see! Use the `view_file` tool to analyze images (JPG, PNG) or deep-dive into PDF technical papers. The agent extracts high-fidelity visual context natively, making it a true multimodal companion.
54
+ 2. Start the agent:
55
+ ```bash
56
+ npm start
57
+ ```
34
58
 
35
- ### πŸ“‘ **Document Engineering Suite**
36
- Need a report or a presentation? Just ask. Flux Flow features a high-fidelity "Printing Press" that generates professional, branded documents natively:
37
- - **PDF**: Branded documents from HTML/CSS with automatic watermarking.
38
- - **DOCX**: Native Word documents with multi-page support and automatic numbering.
39
- - **PPTX**: High-fidelity PowerPoint presentations using native elements (selectable text, shapes) translated directly from HTML.
59
+ ## πŸ“– Documentation
40
60
 
41
- ### πŸš‘ **Self-Healing Infrastructure**
42
- Zero setup means zero setup. On first run, Flux Flow performs an integrity check and autonomously installs its own Chromium engine if needed, ensuring features like PDF generation work 100% of the time without manual intervention.
61
+ To keep this README concise, detailed information about specific components of Flux Flow has been split into separate documents:
43
62
 
44
- - **Archived Terminal Flow**: See execution outputs transform from live elements into permanent conversation records.
45
- - **Rich Aesthetics**: High-contrast, sleek design with smooth transitions and micro-animations.
63
+ - **[Architecture & Design](./ARCHITECTURE.md)**: Deep dive into the React/Ink rendering, the Agentic Loop, and the Janitor background process.
64
+ - **[Agent Tools & Capabilities](./TOOLS.md)**: A comprehensive list of the tools available to the agent (e.g., File I/O, Execution, Web tools).
65
+ - **[UI & Interaction Features](./UI_FEATURES.md)**: Details on commands, thinking levels, and human-in-the-loop verification.
46
66
 
47
- ### 🧠 **The Dual-Intelligence System**
48
- - **Flux Mode (Dev)**: High-speed, agentic problem solving with a 50-turn persistent loop for massive coding tasks.
49
- - **Flow Mode (Chat)**: Optimized for deep research, high-quality conversation, and web-assisted reasoning.
67
+ ## πŸ”’ Security & Privacy
50
68
 
51
- ### πŸ›‘οΈ **Digital Fortress Governance**
52
- Security isn't an afterthought; it's a boundary.
53
- - **External Path Hardlock**: Restricts the agent to your Current Working Directory (CWD) unless you explicitly unlock it.
54
- - **Human-in-the-Loop (HITL)**: Every file write and terminal command requires your high-fidelity approval.
55
- - **XOR Vaulting**: All local session histories, memories, and API keys are obfuscated and encrypted at rest.
56
- - **Adaptive Failover**: Automatic multi-stage retry logic with high-concurrency fallback model switching (Gemini 3.1 Flash Lite) during peak API congestion.
69
+ Flux Flow runs entirely locally on your machine.
70
+ - **Global Storage**: All history, memories, and API keys are stored securely in your home directory at `~/.fluxflow`. Sensitive data is encrypted.
71
+ - **Nuclear Reset**: Use the `/reset` command to instantly purge all logs, secrets, and settings from the global storage directory.
72
+ - **Configurable Boundaries**: In Flux mode, file access can be strictly confined to the Current Working Directory, or expanded globally via settings.
73
+ - **API Keys**: You supply your own Gemini/Google AI Studio API keys.
57
74
 
58
- ### 🧹 **The Background Janitor**
59
- While you move at high speed, the Janitor follows behindβ€”refining session titles, compressing data, and ensuring your context window remains at absolute peak performance.
60
-
61
- ---
62
-
63
- ## πŸ› οΈ Key Capabilities
64
- - **Deep File-System Interaction**: Edit, move, and refactor code across multiple files with atomic precision.
65
- - **Real-Time Web Intelligence**: Autonomous web-searching via DuckDuckGo for live news and technical research.
66
- - **Autonomous Project Alignment**: Automatically detects and adheres to project-specific instructions in `Agent.md`, `Skills.md`, and `Fluxflow.md` for high-fidelity alignment with your coding standards and custom workflows.
67
- - **High-Reliability Fallback**: Automatic failover to a lighter, high-concurrency model during peak traffic to ensure zero session loss.
68
- - **Persistent Memory**: The agent learns from your preferences and project requirements across sessions.
69
-
70
- ---
71
-
72
- ## βš™οΈ Configuration
73
- Type `/settings` in-app to live-configure:
74
- - **Thinking Level**: Low, Medium, or High (Deep-Reasoning).
75
- - **Auto-Execution**: For ultimate high-speed flow (Advanced users only).
76
- - **Security Perimeter**: Toggle External Workspace access.
77
-
78
- ---
75
+ ## πŸ› οΈ Built With
79
76
 
80
- ## 🏁 License
81
- MIT Β© 2026 Flux Flow Team.
77
+ - **[React](https://react.dev/) & [Ink](https://github.com/vadimdemedes/ink)**: For the interactive CLI rendering.
78
+ - **[@google/genai](https://www.npmjs.com/package/@google/genai)**: The core AI SDK powering the agent's intelligence.
79
+ - **[chalk](https://www.npmjs.com/package/chalk) & [gradient-string](https://www.npmjs.com/package/gradient-string)**: For terminal styling and aesthetics.
80
+ - **[fs-extra](https://www.npmjs.com/package/fs-extra)**: For robust file system operations.
81
+ - **[pptxgenjs](https://www.npmjs.com/package/pptxgenjs) & [html-to-docx](https://www.npmjs.com/package/html-to-docx)**: For native Office document generation.
82
82
 
83
83
  ---
84
- *Forged with ⚑ and 🧬. Welcome to the FluxFlow.*
84
+ *Created as a demonstration of highly capable AI tooling.*
package/dist/fluxflow.js CHANGED
@@ -10,6 +10,7 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/utils/text.js
13
+ import os from "os";
13
14
  var wrapText, formatTokens, truncatePath;
14
15
  var init_text = __esm({
15
16
  "src/utils/text.js"() {
@@ -82,13 +83,14 @@ var init_text = __esm({
82
83
  if (!tokens && tokens !== 0) return "0.0k";
83
84
  const num = typeof tokens === "string" ? parseFloat(tokens) : tokens;
84
85
  if (num >= 1e6) {
85
- return `${(num / 1e6).toFixed(2)}m`;
86
+ return `${(num / 1e6).toFixed(1)}m`;
86
87
  } else if (num >= 1e3) {
87
- return `${(num / 1e3).toFixed(2)}k`;
88
+ return `${(num / 1e3).toFixed(1)}k`;
88
89
  }
89
90
  return num.toString();
90
91
  };
91
92
  truncatePath = (p, maxLength = 40) => {
93
+ p = p.replace(os.homedir(), "~");
92
94
  if (!p || p.length <= maxLength) return p;
93
95
  const half = Math.floor((maxLength - 3) / 2);
94
96
  return p.substring(0, half) + "..." + p.substring(p.length - half);
@@ -798,13 +800,13 @@ __export(paths_exports, {
798
800
  TEMP_MEM_FILE: () => TEMP_MEM_FILE,
799
801
  USAGE_FILE: () => USAGE_FILE
800
802
  });
801
- import os from "os";
803
+ import os2 from "os";
802
804
  import path2 from "path";
803
805
  import fs2 from "fs";
804
806
  var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE;
805
807
  var init_paths = __esm({
806
808
  "src/utils/paths.js"() {
807
- FLUXFLOW_DIR = path2.join(os.homedir(), ".fluxflow");
809
+ FLUXFLOW_DIR = path2.join(os2.homedir(), ".fluxflow");
808
810
  SETTINGS_FILE = path2.join(FLUXFLOW_DIR, "settings.json");
809
811
  externalDir = null;
810
812
  try {
@@ -868,7 +870,7 @@ var TOOL_PROTOCOL;
868
870
  var init_main_tools = __esm({
869
871
  "src/data/main_tools.js"() {
870
872
  TOOL_PROTOCOL = (mode) => `
871
- -- START TOOL DEFINITIONS --
873
+ -- TOOL DEFINITIONS --
872
874
  You have access to internal tools. To call a tool, you MUST use the following exact syntax on a new line:
873
875
  [tool:functions.tool_name(arguments)]
874
876
 
@@ -881,7 +883,7 @@ NOTE: Suggest best options; don't ask for preferences. System handles the rest.
881
883
  2. Web Scrape: [tool:functions.web_scrape(url="<url>")]. provides detail from a URL.
882
884
 
883
885
  ${mode === "Flux" ? `
884
- - DEV & FILE TOOLS (path will always be relative to CWD) -
886
+ - DEV TOOLS (path will always be relative to CWD) -
885
887
  1. View File: [tool:functions.view_file(path="...", start_line=N, end_line=N)]. Reads content (800 lines max). Supports images/docs. If user provides an image/doc, view it first.
886
888
  2. Read Folder: [tool:functions.read_folder(path="...")]. Detailed stats of a directory.
887
889
  3. Write File: [tool:functions.write_file(path="...", content="content to write")]. Creates/Overwrites. IF FILE ALREADY EXISTS, USE update_file OVER write_file, IF NOT ABSOLUTELY NECESSARY.
@@ -894,18 +896,17 @@ CSS: background-color,color,font-family,font-size(pt),font-style,font-weight,mar
894
896
  8. Execution: [tool:functions.exec_command(command="command")]. Runs a shell command. Use ask tool to confirm before executing any destructive or irreversible operations.
895
897
  9. Search: [tool:functions.search_keyword(keyword="...")]. Global search. Use to locate definitions/logic without reading every file.
896
898
 
897
- - VERIFY SUCCESS CONTENTS. Fix errors. No success hallucinations.
898
- - No guessing; read files before editing.
899
+ - VERIFY SUCCESS CONTENTS. Fix errors. No hallucinations.
899
900
  - File tools > Chat code blocks.
900
901
 
901
902
  - Escape quotes: Use \\" inside code strings.
902
903
  - Literal escapes: Double-escape sequences (e.g., \\\\n, \\\\t).
903
904
  - File structure: Use real newlines for code formatting.`.trim() : `
904
- - DEV & FILE TOOLS ARE NOT AVAILABLE IN FLOW MODE. If you need to access files, tell the user to switch to FLUX MODE (manually by user).`.trim()}
905
+ - DEV TOOLS ARE NOT AVAILABLE IN FLOW MODE. If you need to access files, tell the user to switch to FLUX.`.trim()}
905
906
 
906
907
  - Results: Passed as [TOOL_RESULT] (SYSTEM), USER_PROMPT (USER).
907
908
  - Tool calls: End with [turn: continue]. Only use [turn: finish] after verifying goals.
908
- - Multi-call: Stack 1-by-1. Internal only; don't discuss tools with user.
909
+ - Multi-call: Stack 1-by-1. Upto 4.
909
910
  -- END TOOL DEFINITIONS --`.trim();
910
911
  }
911
912
  });
@@ -915,12 +916,12 @@ var JANITOR_TOOLS_PROTOCOL;
915
916
  var init_janitor_tools = __esm({
916
917
  "src/data/janitor_tools.js"() {
917
918
  JANITOR_TOOLS_PROTOCOL = (isMemoryEnabled = true, needTitle = true) => `
918
- ${needTitle ? `-- START CHAT MANAGEMENT TOOLS --
919
+ ${needTitle ? `-- CHAT MANAGEMENT TOOLS --
919
920
  1. YOU MUST UPDATE CHAT TITLE (URGENT PRIORITY):
920
921
  [tool:functions.chat(title='<short creative title of FULL conversation in 3-5 words>')]. Consider full chat context to generate title NOT just latest message.
921
922
  -- END CHAT MANAGEMENT TOOLS --
922
923
  `.trimEnd() : ""}
923
- -- START MEMORY TOOLS (YOU SHOULD NOT OUTPUT ANYTHING OTHER THAN THESE SPECIFIC TOOLS) --
924
+ -- MEMORY TOOLS (YOU SHOULD NOT OUTPUT ANYTHING OTHER THAN THESE SPECIFIC TOOLS) --
924
925
  Your tool syntax is: '[tool:functions.function_name(args...)]'
925
926
  You have access to the following memory functions to persist important information:
926
927
 
@@ -945,7 +946,6 @@ var init_thinking_prompts = __esm({
945
946
  "src/data/thinking_prompts.json"() {
946
947
  thinking_prompts_default = {
947
948
  Max: `EFFORT_LEVEL: MAX
948
- **THINKING <think> ... </think> IS MANDATORY**
949
949
  Think in a continuous, fluid analytical monologue within the <think>...</think> block. Do NOT use headings, bullet points, or artificial sections. Engage in a deep "Stream of Consciousness" that follows this cognitive path:
950
950
  Deep Analysis: Deconstruct the request into its core technical and logic requirements.
951
951
  Hypothesis & Test: Propose multiple solutions mentally and critique them for edge cases or security risks.
@@ -956,21 +956,34 @@ RULES:
956
956
  - Be thorough and exhaustive. Explore the 'why' behind every decision, depth and nuances.
957
957
  - Use internal critique: Question your own logic as you go.
958
958
  - MANDATORY THINKING: You MUST engage in full reasoning regardless of perceived simplicity.`,
959
- High: "EFFORT_LEVEL: HIGH\n**THINKING <think> ... </think> IS MANDATORY**\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.",
960
- Medium: "EFFORT_LEVEL: MEDIUM\n**THINKING <think> ... </think> IS MANDATORY**\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.",
961
- Minimal: "EFFORT_LEVEL: LOW\n**THINKING <think> ... </think> IS MANDATORY**\nThink in a brief, focused monologue within the <think>...</think> block. No headings. Just a quick mental check before acting:\nVerify the objective.\nNote the target files/tools.\nRULES:\n- NO HEADINGS. Just a few lines of clear, linear thought.\n- Use minimal thinking for simple or conversational requests."
959
+ 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.",
960
+ 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.",
961
+ Minimal: "EFFORT_LEVEL: LOW\nThink in a brief, focused monologue within the <think>...</think> block. No headings. Just a quick mental check before acting:\nVerify the objective.\nNote the target files/tools.\nRULES:\n- NO HEADINGS. Just a few lines of clear, linear thought.\n- Use minimal thinking for simple or conversational requests."
962
962
  };
963
963
  }
964
964
  });
965
965
 
966
966
  // src/utils/prompts.js
967
- var getSystemInstruction, getJanitorInstruction;
967
+ import fs4 from "fs";
968
+ var getMemoryPrompt, getSystemInstruction, getJanitorInstruction;
968
969
  var init_prompts = __esm({
969
970
  "src/utils/prompts.js"() {
970
971
  init_main_tools();
971
972
  init_janitor_tools();
972
973
  init_thinking_prompts();
973
- getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, tempMemories = "", userMemories = "", isMemoryEnabled = true, isContext32k = false, maxLoops, currentLoop) => {
974
+ getMemoryPrompt = (tempMemories = "", userMemories = "", isMemoryEnabled = true, isContext32k = false) => {
975
+ if (!isMemoryEnabled) return "";
976
+ const tempMemoriesStr = tempMemories?.length > 0 && !isContext32k ? `-- RECENT CONTEXT FROM OTHER CHATS (PRIORITY: LOW) --
977
+ ${tempMemories}
978
+ -- END RECENT CONTEXT --` : "";
979
+ const userMemoriesStr = userMemories?.length > 0 ? `--- SAVED MEMORIES (PRIORITY: MEDIUM, TUNES USER PREFERENCES) ---
980
+ ${userMemories}
981
+ -- END SAVED MEMORIES --` : "";
982
+ const parts = [userMemoriesStr, tempMemoriesStr].filter((p) => p.length > 0);
983
+ return parts.length > 0 ? `${parts.join("\n\n")}
984
+ ` : "";
985
+ };
986
+ getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, isMemoryEnabled = true, maxLoops, currentLoop) => {
974
987
  let levelKey = thinkingLevel;
975
988
  if (thinkingLevel === "Low") levelKey = "Minimal";
976
989
  if (thinkingLevel === "xHigh" || thinkingLevel === "Max") levelKey = "Max";
@@ -982,7 +995,7 @@ var init_prompts = __esm({
982
995
  ` : "";
983
996
  const userInstrStr = profile.instructions && profile.instructions?.length > 0 ? `User Instructions: ${profile.instructions}.
984
997
  ` : "";
985
- const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString();
998
+ const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", hour12: true });
986
999
  const cwdStr = process.cwd();
987
1000
  const isSystemDir = (() => {
988
1001
  const cwd = process.cwd().toLowerCase();
@@ -996,26 +1009,28 @@ var init_prompts = __esm({
996
1009
  return cwd === "/" || sysPaths.some((p) => cwd.startsWith(p));
997
1010
  }
998
1011
  })();
999
- const tempMemoriesStr = tempMemories?.length > 0 && !isContext32k ? `
1000
- -- RECENT CONTEXT FROM OTHER CHATS (PRIORITY: LOW, RECENT > OLD) --
1001
- ${tempMemories}
1002
- -- END RECENT CONTEXT --
1003
- ` : "";
1004
- const userMemoriesStr = userMemories?.length > 0 ? `
1005
- --- SAVED MEMORIES (PRIORITY: MEDIUM, TUNES USER PREFERENCES) ---
1006
- ${userMemories}
1007
- -- END SAVED MEMORIES --
1008
- ` : "";
1009
- return `${isMemoryEnabled ? `${userMemoriesStr}
1010
- ` : ""}${isMemoryEnabled ? `${tempMemoriesStr}
1011
- ` : ""}${nameStr}${nicknameStr}${userInstrStr}
1012
- === START SYSTEM INSTRUCTION (STRICT PRIORITY, OVERRIDES EVERYTHING) ===
1012
+ const projectContextFiles = [
1013
+ { name: "Fluxflow.md", desc: "HIGHEST PRIORITY. Overrides all other files." },
1014
+ { name: "README.md", desc: "Goals" },
1015
+ { name: "Agent.md", desc: "Standards" },
1016
+ { name: "Skills.md", desc: "Workflows" },
1017
+ { name: "design.md", desc: "UI/UX" },
1018
+ { name: "architecture.md", desc: "System Structure" }
1019
+ ];
1020
+ const foundFiles = projectContextFiles.filter((f) => fs4.existsSync(f.name));
1021
+ const projectContextBlock = mode === "Flux" && foundFiles.length > 0 ? `
1022
+ -- PROJECT CONTEXT (Source of Truth) --
1023
+ ${foundFiles.map((f) => `- ${f.name}: ${f.desc}`).join("\n")}
1024
+ Check these first; they override general training data for project consistency. Safety rules still apply.
1025
+ -- END PROJECT CONTEXT --` : "";
1026
+ return `${nameStr}${nicknameStr}${userInstrStr}
1027
+ === SYSTEM INSTRUCTION (STRICT PRIORITY, OVERRIDES EVERYTHING) ===
1013
1028
  Identity: Flux Flow (by Kushal Roy Chowdhury). Sassy, Friendly CLI Agent. No flirting.
1014
- Mode: ${mode} (THINKING MANDATORY). ${mode === "Flux" ? "Goal-oriented. Plan & use tools." : "Conversation & UX focus. Web/Comm tools only."}
1029
+ Mode: ${mode} (THINKING MODE). ${mode === "Flux" ? "Goal-oriented. Plan & use tools." : "Conversation & UX focus. Web/Comm tools only."}
1015
1030
  Context: CWD: ${cwdStr}.${isSystemDir ? " [PROTECTED: ASK BEFORE MODIFYING]." : ""} OS: ${osDetected}.${osDetected === "Windows" ? " (Backslashes only. Prefer PS via CMD)." : ""}
1016
1031
  Protocol: [SYSTEM] and [STEERING HINT] are high-priority.
1017
1032
 
1018
- -- START THINKING INSTRUCTIONS --
1033
+ -- THINKING INSTRUCTIONS --
1019
1034
  ${thinkingConfig}
1020
1035
  ***CRITICAL THINKING POLICY***
1021
1036
  - Always use <think> ... </think> before answering or using any tool.
@@ -1024,25 +1039,19 @@ ${thinkingConfig}
1024
1039
  -- END THINKING INSTRUCTIONS --
1025
1040
 
1026
1041
  ${TOOL_PROTOCOL(mode)}
1027
- ${mode === "Flux" ? `
1028
- -- PROJECT CONTEXT (Source of Truth) --
1029
- - Fluxflow.md: HIGHEST PRIORITY. Overrides all other files.
1030
- - README.md (Goals), Agent.md (Standards), Skills.md (Workflows).
1031
- - design.md (UI/UX), architecture.md (System Structure).
1032
- Check these first; they override general training data for project consistency. Safety rules still apply.
1033
- -- END PROJECT CONTEXT --` : ""}
1042
+ ${projectContextBlock}
1034
1043
 
1035
1044
  -- MEMORY INSTRUCTIONS --
1036
1045
  - Memory: ${isMemoryEnabled ? "Use recent context/logs to personalize. Keep it subtle." : "OFF (tell user to enable in /settings if needed)."}
1037
1046
  - Time: All logs are timestamped. Always use **relative time** (e.g., 'few mins ago', 'few hours ago'...), never absolute.
1038
1047
  -- END MEMORY INSTRUCTIONS --
1039
1048
 
1040
- -- START SECURITY BOUNDARY --
1049
+ -- SECURITY BOUNDARY --
1041
1050
  - EXTERNAL_WORKSPACE_ACCESS: ${systemSettings.allowExternalAccess ? "ENABLED (Global)." : "RESTRICTED (CWD only). Suggest /settings to enable external access if needed."}
1042
- - Safety: Ask permission before reading .env or credential files.
1051
+ - Safety: Ask permission before reading sensitive files.
1043
1052
  -- END SECURITY BOUNDARY --
1044
1053
 
1045
- -- START TEMPORAL AWARENESS --
1054
+ -- TEMPORAL AWARENESS --
1046
1055
  Every ${isMemoryEnabled ? "Prompt, Responses & Memories" : "Prompt & Responses"} are time stamped. You can use those times if temporal context is required. If recalled from ${isMemoryEnabled ? "Memories, Prompts, or Responses" : "Prompts, or Responses"}. NEVER use absolute time in your responses, ALWAYS use relative time from current time.
1047
1056
  -- END TEMPORAL AWARENESS --
1048
1057
 
@@ -1051,13 +1060,13 @@ Every ${isMemoryEnabled ? "Prompt, Responses & Memories" : "Prompt & Responses"}
1051
1060
  - Tables: GFM (Max 4 cols, short rows). Use sparingly.
1052
1061
  - NO LaTeX. Code blocks for literature/poems only. Kaomojis > emojis.
1053
1062
 
1054
- -- START RESPONSE PROTOCOL --
1055
- - Protocol: End with [turn: continue] for more steps or [turn: finish] when 100% done.
1063
+ -- RESPONSE PROTOCOL --
1064
+ - End with [turn: continue] for more steps or [turn: finish] when done.
1056
1065
  - Multi-tool: Stack tools if needed, but always end with [turn: continue] if called any tools.
1057
- TO END THE LOOP YOU **MUST** WRITE [turn: finish] AT VERY END OF YOUR RESPONSE. AVOID PRE-MATURELY FINISHING THE LOOP.
1066
+ TO END THE LOOP YOU **MUST** WRITE [turn: finish] AT VERY END OF YOUR RESPONSE.
1058
1067
  -- END RESPONSE PROTOCOL --
1059
1068
 
1060
- [SYSTEM METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | Version: 1.9.9 | Turn Progress: ${currentLoop}/${maxLoops} steps (Summarize & prompt user if limit is reached).
1069
+ [METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v1.9.10 | Turn Progress: ${currentLoop}/${maxLoops} steps (Summarize & prompt user if limit is reached).
1061
1070
  === END SYSTEM INSTRUCTION ===`.trim();
1062
1071
  };
1063
1072
  getJanitorInstruction = (originalText, agentRaws, userMemories = "", isMemoryEnabled = true, needTitle = true) => {
@@ -1092,14 +1101,14 @@ ${isMemoryEnabled ? `If user tell something that is important (like, hobbies, pr
1092
1101
 
1093
1102
  ${JANITOR_TOOLS_PROTOCOL(isMemoryEnabled, needTitle)}
1094
1103
 
1095
- Current date and Time: ${(/* @__PURE__ */ new Date()).toLocaleString()}
1104
+ Current date and Time: ${(/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", hour12: true })}
1096
1105
  === END SYSTEM INSTRUCTION ===`.trim();
1097
1106
  };
1098
1107
  }
1099
1108
  });
1100
1109
 
1101
1110
  // src/utils/history.js
1102
- import fs4 from "fs-extra";
1111
+ import fs5 from "fs-extra";
1103
1112
  import path4 from "path";
1104
1113
  import { nanoid } from "nanoid";
1105
1114
  var WRITE_LOCK, withLock, loadHistory, saveChat, saveChatTitle, deleteChat, generateChatId, cleanupOldHistory, getTruncatedHistory;
@@ -1122,9 +1131,9 @@ var init_history = __esm({
1122
1131
  return nextLock;
1123
1132
  };
1124
1133
  loadHistory = async () => {
1125
- if (await fs4.pathExists(HISTORY_FILE)) {
1134
+ if (await fs5.pathExists(HISTORY_FILE)) {
1126
1135
  try {
1127
- return await fs4.readJson(HISTORY_FILE);
1136
+ return await fs5.readJson(HISTORY_FILE);
1128
1137
  } catch (e) {
1129
1138
  return {};
1130
1139
  }
@@ -1142,8 +1151,8 @@ var init_history = __esm({
1142
1151
  messages: persistentMessages,
1143
1152
  updatedAt: Date.now()
1144
1153
  };
1145
- await fs4.ensureDir(path4.dirname(HISTORY_FILE));
1146
- await fs4.writeJson(HISTORY_FILE, history, { spaces: 2 });
1154
+ await fs5.ensureDir(path4.dirname(HISTORY_FILE));
1155
+ await fs5.writeJson(HISTORY_FILE, history, { spaces: 2 });
1147
1156
  });
1148
1157
  };
1149
1158
  saveChatTitle = async (id, title) => {
@@ -1155,15 +1164,15 @@ var init_history = __esm({
1155
1164
  } else {
1156
1165
  history[id] = { name: title, messages: [], updatedAt: Date.now() };
1157
1166
  }
1158
- await fs4.ensureDir(path4.dirname(HISTORY_FILE));
1159
- await fs4.writeJson(HISTORY_FILE, history, { spaces: 2 });
1167
+ await fs5.ensureDir(path4.dirname(HISTORY_FILE));
1168
+ await fs5.writeJson(HISTORY_FILE, history, { spaces: 2 });
1160
1169
  });
1161
1170
  };
1162
1171
  deleteChat = async (id) => {
1163
1172
  return withLock(async () => {
1164
1173
  const history = await loadHistory();
1165
1174
  delete history[id];
1166
- await fs4.writeJson(HISTORY_FILE, history, { spaces: 2 });
1175
+ await fs5.writeJson(HISTORY_FILE, history, { spaces: 2 });
1167
1176
  const temp = readEncryptedJson(TEMP_MEM_FILE, {});
1168
1177
  if (temp[id]) {
1169
1178
  delete temp[id];
@@ -1202,7 +1211,7 @@ var init_history = __esm({
1202
1211
  });
1203
1212
 
1204
1213
  // src/utils/usage.js
1205
- import fs5 from "fs-extra";
1214
+ import fs6 from "fs-extra";
1206
1215
  import path5 from "path";
1207
1216
  var cachedUsage, writeTimeout, lastWriteTime, isDirty, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota;
1208
1217
  var init_usage = __esm({
@@ -1215,8 +1224,8 @@ var init_usage = __esm({
1215
1224
  loadUsageFromFile = async () => {
1216
1225
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1217
1226
  try {
1218
- if (await fs5.exists(USAGE_FILE)) {
1219
- const data = await fs5.readJson(USAGE_FILE);
1227
+ if (await fs6.exists(USAGE_FILE)) {
1228
+ const data = await fs6.readJson(USAGE_FILE);
1220
1229
  if (data && data.date === today && data.stats) {
1221
1230
  return {
1222
1231
  ...data,
@@ -1241,11 +1250,11 @@ var init_usage = __esm({
1241
1250
  flushUsage = async () => {
1242
1251
  if (!isDirty || !cachedUsage) return;
1243
1252
  try {
1244
- await fs5.ensureDir(path5.dirname(USAGE_FILE));
1253
+ await fs6.ensureDir(path5.dirname(USAGE_FILE));
1245
1254
  let diskData = null;
1246
1255
  try {
1247
- if (await fs5.exists(USAGE_FILE)) {
1248
- diskData = await fs5.readJson(USAGE_FILE);
1256
+ if (await fs6.exists(USAGE_FILE)) {
1257
+ diskData = await fs6.readJson(USAGE_FILE);
1249
1258
  }
1250
1259
  } catch (e) {
1251
1260
  }
@@ -1257,11 +1266,11 @@ var init_usage = __esm({
1257
1266
  }
1258
1267
  }
1259
1268
  const tempFile = USAGE_FILE + ".tmp";
1260
- await fs5.writeJson(tempFile, cachedUsage, { spaces: 2 });
1261
- const fd = await fs5.open(tempFile, "r+");
1262
- await fs5.fsync(fd);
1263
- await fs5.close(fd);
1264
- await fs5.rename(tempFile, USAGE_FILE);
1269
+ await fs6.writeJson(tempFile, cachedUsage, { spaces: 2 });
1270
+ const fd = await fs6.open(tempFile, "r+");
1271
+ await fs6.fsync(fd);
1272
+ await fs6.close(fd);
1273
+ await fs6.rename(tempFile, USAGE_FILE);
1265
1274
  isDirty = false;
1266
1275
  lastWriteTime = Date.now();
1267
1276
  } catch (e) {
@@ -1459,7 +1468,7 @@ var init_arg_parser = __esm({
1459
1468
 
1460
1469
  // src/tools/web_search.js
1461
1470
  import puppeteer from "puppeteer";
1462
- import fs6 from "fs";
1471
+ import fs7 from "fs";
1463
1472
  import path6 from "path";
1464
1473
  var web_search;
1465
1474
  var init_web_search = __esm({
@@ -1484,7 +1493,7 @@ var init_web_search = __esm({
1484
1493
  ]
1485
1494
  });
1486
1495
  const page = await browser.newPage();
1487
- await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36");
1496
+ await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36");
1488
1497
  await page.setViewport({ width: 1366, height: 768 });
1489
1498
  const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
1490
1499
  await new Promise((r) => setTimeout(r, jitter));
@@ -1515,8 +1524,8 @@ Snippet: ${snippet}`;
1515
1524
  }
1516
1525
  const finalResults = results.join("\n\n");
1517
1526
  const toolLogDir = path6.join(LOGS_DIR, "tools");
1518
- if (!fs6.existsSync(toolLogDir)) fs6.mkdirSync(toolLogDir, { recursive: true });
1519
- fs6.appendFileSync(path6.join(toolLogDir, "search-results.log"), `SEARCH ${(/* @__PURE__ */ new Date()).toLocaleString()} - Query: [${query}]. Count: ${results.length}.
1527
+ if (!fs7.existsSync(toolLogDir)) fs7.mkdirSync(toolLogDir, { recursive: true });
1528
+ fs7.appendFileSync(path6.join(toolLogDir, "search-results.log"), `SEARCH ${(/* @__PURE__ */ new Date()).toLocaleString()} - Query: [${query}]. Count: ${results.length}.
1520
1529
  Content:
1521
1530
  ${finalResults}
1522
1531
 
@@ -1544,7 +1553,7 @@ ${finalResults}`;
1544
1553
 
1545
1554
  // src/tools/web_scrape.js
1546
1555
  import puppeteer2 from "puppeteer";
1547
- import fs7 from "fs";
1556
+ import fs8 from "fs";
1548
1557
  import path7 from "path";
1549
1558
  var web_scrape;
1550
1559
  var init_web_scrape = __esm({
@@ -1568,7 +1577,7 @@ var init_web_scrape = __esm({
1568
1577
  ]
1569
1578
  });
1570
1579
  const page = await browser.newPage();
1571
- await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36");
1580
+ await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36");
1572
1581
  await page.setViewport({ width: 1366, height: 768 });
1573
1582
  const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
1574
1583
  await new Promise((r) => setTimeout(r, jitter));
@@ -1613,8 +1622,8 @@ var init_web_scrape = __esm({
1613
1622
  if (!htmlContent) throw new Error("EMPTY_RENDER_RESULT");
1614
1623
  const cleanedHtml = htmlContent.replace(/\s+/g, " ").replace(/>\s+</g, "><").trim().substring(0, 3e4);
1615
1624
  const toolLogDir = path7.join(LOGS_DIR, "tools");
1616
- if (!fs7.existsSync(toolLogDir)) fs7.mkdirSync(toolLogDir, { recursive: true });
1617
- fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toLocaleString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
1625
+ if (!fs8.existsSync(toolLogDir)) fs8.mkdirSync(toolLogDir, { recursive: true });
1626
+ fs8.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toLocaleString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
1618
1627
  Content:
1619
1628
  ${cleanedHtml}${htmlContent.length > 3e4 ? "\n\n[TRUNCATED AT 30K CHARS]" : ""}
1620
1629
 
@@ -1662,7 +1671,7 @@ var init_memory = __esm({
1662
1671
  if (!content) return "ERROR: Missing 'content' for temp memory.";
1663
1672
  const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
1664
1673
  if (!tempStorage[chatId]) tempStorage[chatId] = [];
1665
- const MAX_CHARS = 3072 * 4;
1674
+ const MAX_CHARS = 1024 * 4;
1666
1675
  let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
1667
1676
  while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
1668
1677
  const removed = tempStorage[chatId].shift();
@@ -1676,7 +1685,7 @@ var init_memory = __esm({
1676
1685
  const memories = readEncryptedJson(MEMORIES_FILE, []);
1677
1686
  if (method === "add") {
1678
1687
  if (!content) return "ERROR: Missing 'content' for memory addition.";
1679
- const MAX_CHARS = 2048 * 4;
1688
+ const MAX_CHARS = 1024 * 4;
1680
1689
  let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
1681
1690
  while (memories.length > 0 && currentTotalLength + content.length > MAX_CHARS) {
1682
1691
  const removed = memories.shift();
@@ -1735,7 +1744,7 @@ var init_chat = __esm({
1735
1744
  });
1736
1745
 
1737
1746
  // src/tools/list_files.js
1738
- import fs8 from "fs";
1747
+ import fs9 from "fs";
1739
1748
  import path8 from "path";
1740
1749
  var list_files;
1741
1750
  var init_list_files = __esm({
@@ -1745,14 +1754,14 @@ var init_list_files = __esm({
1745
1754
  const { path: targetPath = "." } = parseArgs(args);
1746
1755
  const absolutePath = path8.resolve(process.cwd(), targetPath);
1747
1756
  try {
1748
- if (!fs8.existsSync(absolutePath)) {
1757
+ if (!fs9.existsSync(absolutePath)) {
1749
1758
  return `ERROR: Path [${targetPath}] does not exist.`;
1750
1759
  }
1751
- const stats = fs8.statSync(absolutePath);
1760
+ const stats = fs9.statSync(absolutePath);
1752
1761
  if (!stats.isDirectory()) {
1753
1762
  return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
1754
1763
  }
1755
- const files = fs8.readdirSync(absolutePath);
1764
+ const files = fs9.readdirSync(absolutePath);
1756
1765
  if (files.length === 0) {
1757
1766
  return `Directory [${targetPath}] is empty.`;
1758
1767
  }
@@ -1764,7 +1773,7 @@ var init_list_files = __esm({
1764
1773
  let indicator = "\u{1F4C4}";
1765
1774
  let metaPart = "";
1766
1775
  try {
1767
- const fStats = fs8.statSync(fPath);
1776
+ const fStats = fs9.statSync(fPath);
1768
1777
  indicator = fStats.isDirectory() ? "\u{1F4C1}" : "\u{1F4C4}";
1769
1778
  const sizeKB = (fStats.size / 1024).toFixed(1);
1770
1779
  metaPart = fStats.isFile() ? ` - [${sizeKB} KB]` : "";
@@ -1796,7 +1805,7 @@ ${list}${footer}`;
1796
1805
  });
1797
1806
 
1798
1807
  // src/tools/view_file.js
1799
- import fs9 from "fs";
1808
+ import fs10 from "fs";
1800
1809
  import path9 from "path";
1801
1810
  var view_file;
1802
1811
  var init_view_file = __esm({
@@ -1811,10 +1820,10 @@ var init_view_file = __esm({
1811
1820
  if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
1812
1821
  const absolutePath = path9.resolve(process.cwd(), targetPath);
1813
1822
  try {
1814
- if (!fs9.existsSync(absolutePath)) {
1823
+ if (!fs10.existsSync(absolutePath)) {
1815
1824
  return `ERROR: File [${targetPath}] does not exist.`;
1816
1825
  }
1817
- const stats = fs9.statSync(absolutePath);
1826
+ const stats = fs10.statSync(absolutePath);
1818
1827
  if (stats.isDirectory()) {
1819
1828
  return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
1820
1829
  }
@@ -1829,7 +1838,7 @@ var init_view_file = __esm({
1829
1838
  ".doc": "application/msword"
1830
1839
  };
1831
1840
  if (mimeMap[ext]) {
1832
- const buffer = fs9.readFileSync(absolutePath);
1841
+ const buffer = fs10.readFileSync(absolutePath);
1833
1842
  const base64 = buffer.toString("base64");
1834
1843
  const mimeType = mimeMap[ext];
1835
1844
  return {
@@ -1842,7 +1851,7 @@ var init_view_file = __esm({
1842
1851
  }
1843
1852
  };
1844
1853
  }
1845
- let content = fs9.readFileSync(absolutePath, "utf8");
1854
+ let content = fs10.readFileSync(absolutePath, "utf8");
1846
1855
  if (content.startsWith("\uFEFF")) {
1847
1856
  content = content.slice(1);
1848
1857
  }
@@ -1865,7 +1874,7 @@ ${code}`;
1865
1874
  });
1866
1875
 
1867
1876
  // src/tools/write_file.js
1868
- import fs10 from "fs";
1877
+ import fs11 from "fs";
1869
1878
  import path10 from "path";
1870
1879
  var write_file;
1871
1880
  var init_write_file = __esm({
@@ -1880,9 +1889,9 @@ var init_write_file = __esm({
1880
1889
  const parentDir = path10.dirname(absolutePath);
1881
1890
  try {
1882
1891
  let ancestry = "";
1883
- if (fs10.existsSync(absolutePath)) {
1892
+ if (fs11.existsSync(absolutePath)) {
1884
1893
  try {
1885
- const oldData = fs10.readFileSync(absolutePath, "utf8");
1894
+ const oldData = fs11.readFileSync(absolutePath, "utf8");
1886
1895
  const lines = oldData.split(/\r?\n/);
1887
1896
  ancestry = `Old File contents:
1888
1897
  ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
@@ -1894,15 +1903,15 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
1894
1903
  `;
1895
1904
  }
1896
1905
  }
1897
- if (!fs10.existsSync(parentDir)) {
1898
- fs10.mkdirSync(parentDir, { recursive: true });
1906
+ if (!fs11.existsSync(parentDir)) {
1907
+ fs11.mkdirSync(parentDir, { recursive: true });
1899
1908
  }
1900
1909
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
1901
1910
  const processedContent = strip(content);
1902
1911
  const lineCount = processedContent.split(/\r?\n/).length;
1903
1912
  const originalSize = Buffer.byteLength(processedContent, "utf8");
1904
- fs10.writeFileSync(absolutePath, processedContent, "utf8");
1905
- let verifiedContent = fs10.readFileSync(absolutePath, "utf8");
1913
+ fs11.writeFileSync(absolutePath, processedContent, "utf8");
1914
+ let verifiedContent = fs11.readFileSync(absolutePath, "utf8");
1906
1915
  const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
1907
1916
  const verifiedLines = verifiedContent.split(/\r?\n/);
1908
1917
  const verifiedLineCount = verifiedLines.length;
@@ -1938,7 +1947,7 @@ Check if Starting and Ending matches your write.`;
1938
1947
  });
1939
1948
 
1940
1949
  // src/tools/update_file.js
1941
- import fs11 from "fs";
1950
+ import fs12 from "fs";
1942
1951
  import path11 from "path";
1943
1952
  var update_file;
1944
1953
  var init_update_file = __esm({
@@ -1954,16 +1963,16 @@ var init_update_file = __esm({
1954
1963
  content_to_add = strip(content_to_add);
1955
1964
  const absolutePath = path11.resolve(process.cwd(), targetPath);
1956
1965
  try {
1957
- if (!fs11.existsSync(absolutePath)) {
1966
+ if (!fs12.existsSync(absolutePath)) {
1958
1967
  return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
1959
1968
  }
1960
- let diskContent = fs11.readFileSync(absolutePath, "utf8");
1969
+ let diskContent = fs12.readFileSync(absolutePath, "utf8");
1961
1970
  if (diskContent.startsWith("\uFEFF")) {
1962
1971
  diskContent = diskContent.slice(1);
1963
1972
  }
1964
1973
  const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
1965
1974
  if (diskContent !== normalizedDisk) {
1966
- fs11.writeFileSync(absolutePath, normalizedDisk, "utf8");
1975
+ fs12.writeFileSync(absolutePath, normalizedDisk, "utf8");
1967
1976
  diskContent = normalizedDisk;
1968
1977
  }
1969
1978
  const currentContent = diskContent;
@@ -2032,7 +2041,7 @@ var init_update_file = __esm({
2032
2041
  const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
2033
2042
  const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
2034
2043
  const finalContentToReplace = firstMatchContent;
2035
- fs11.writeFileSync(absolutePath, newFileContent, "utf8");
2044
+ fs12.writeFileSync(absolutePath, newFileContent, "utf8");
2036
2045
  const allOriginalLines = currentContent.split(/\r?\n/);
2037
2046
  const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
2038
2047
  const oldLines = content_to_replace.split(/\r?\n/);
@@ -2168,7 +2177,7 @@ ${finalOutput}`);
2168
2177
  });
2169
2178
 
2170
2179
  // src/tools/read_folder.js
2171
- import fs12 from "fs";
2180
+ import fs13 from "fs";
2172
2181
  import path12 from "path";
2173
2182
  var read_folder;
2174
2183
  var init_read_folder = __esm({
@@ -2178,14 +2187,14 @@ var init_read_folder = __esm({
2178
2187
  const { path: targetPath = "." } = parseArgs(args);
2179
2188
  const absolutePath = path12.resolve(process.cwd(), targetPath);
2180
2189
  try {
2181
- if (!fs12.existsSync(absolutePath)) {
2190
+ if (!fs13.existsSync(absolutePath)) {
2182
2191
  return `ERROR: Path [${targetPath}] does not exist.`;
2183
2192
  }
2184
- const stats = fs12.statSync(absolutePath);
2193
+ const stats = fs13.statSync(absolutePath);
2185
2194
  if (!stats.isDirectory()) {
2186
2195
  return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
2187
2196
  }
2188
- const files = fs12.readdirSync(absolutePath);
2197
+ const files = fs13.readdirSync(absolutePath);
2189
2198
  const totalItems = files.length;
2190
2199
  const maxDisplay = 100;
2191
2200
  const displayItems = files.slice(0, maxDisplay);
@@ -2195,7 +2204,7 @@ var init_read_folder = __esm({
2195
2204
  let indicator = "\u{1F4C4}";
2196
2205
  let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
2197
2206
  try {
2198
- const fStats = fs12.statSync(fPath);
2207
+ const fStats = fs13.statSync(fPath);
2199
2208
  info = {
2200
2209
  name: file,
2201
2210
  type: fStats.isDirectory() ? "directory" : "file",
@@ -2279,7 +2288,7 @@ var init_ask_user = __esm({
2279
2288
  // src/tools/write_pdf.js
2280
2289
  import puppeteer3 from "puppeteer";
2281
2290
  import path13 from "path";
2282
- import fs13 from "fs-extra";
2291
+ import fs14 from "fs-extra";
2283
2292
  import { PDFDocument } from "pdf-lib";
2284
2293
  var write_pdf;
2285
2294
  var init_write_pdf = __esm({
@@ -2297,7 +2306,7 @@ var init_write_pdf = __esm({
2297
2306
  const absolutePath = path13.resolve(process.cwd(), targetPath);
2298
2307
  let browser = null;
2299
2308
  try {
2300
- await fs13.ensureDir(path13.dirname(absolutePath));
2309
+ await fs14.ensureDir(path13.dirname(absolutePath));
2301
2310
  browser = await puppeteer3.launch({
2302
2311
  headless: true,
2303
2312
  args: [
@@ -2360,8 +2369,8 @@ var init_write_pdf = __esm({
2360
2369
  pdfDoc.setCreator("FluxFlow PDF Engine");
2361
2370
  pdfDoc.setProducer("FluxFlow (Generative AI)");
2362
2371
  const finalPdfBytes = await pdfDoc.save();
2363
- await fs13.writeFile(absolutePath, finalPdfBytes);
2364
- const stats = await fs13.stat(absolutePath);
2372
+ await fs14.writeFile(absolutePath, finalPdfBytes);
2373
+ const stats = await fs14.stat(absolutePath);
2365
2374
  return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
2366
2375
  } catch (err) {
2367
2376
  return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
@@ -2373,7 +2382,7 @@ var init_write_pdf = __esm({
2373
2382
  });
2374
2383
 
2375
2384
  // src/tools/write_docx.js
2376
- import fs14 from "fs-extra";
2385
+ import fs15 from "fs-extra";
2377
2386
  import path14 from "path";
2378
2387
  import HTMLtoDOCX from "html-to-docx";
2379
2388
  var write_docx;
@@ -2389,7 +2398,7 @@ var init_write_docx = __esm({
2389
2398
  if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
2390
2399
  const absolutePath = path14.resolve(process.cwd(), targetPath);
2391
2400
  try {
2392
- await fs14.ensureDir(path14.dirname(absolutePath));
2401
+ await fs15.ensureDir(path14.dirname(absolutePath));
2393
2402
  const fileName = path14.basename(targetPath);
2394
2403
  const fullHtml = content.includes("<html") ? content : `
2395
2404
  <!DOCTYPE html>
@@ -2411,7 +2420,7 @@ var init_write_docx = __esm({
2411
2420
  footer: true,
2412
2421
  pageNumber: true
2413
2422
  });
2414
- await fs14.writeFile(absolutePath, docxBuffer);
2423
+ await fs15.writeFile(absolutePath, docxBuffer);
2415
2424
  return `SUCCESS: Word document [${targetPath}] generated successfully.
2416
2425
  - Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
2417
2426
  } catch (err) {
@@ -2422,7 +2431,7 @@ var init_write_docx = __esm({
2422
2431
  });
2423
2432
 
2424
2433
  // src/tools/write_pptx.js
2425
- import fs15 from "fs-extra";
2434
+ import fs16 from "fs-extra";
2426
2435
  import path15 from "path";
2427
2436
  import pptxgen from "pptxgenjs";
2428
2437
  import html2pptxgenjs from "html2pptxgenjs";
@@ -2440,7 +2449,7 @@ var init_write_pptx = __esm({
2440
2449
  if (!content) return 'ERROR: No "content" (HTML) provided for write_pptx.';
2441
2450
  const absolutePath = path15.resolve(process.cwd(), targetPath);
2442
2451
  try {
2443
- await fs15.ensureDir(path15.dirname(absolutePath));
2452
+ await fs16.ensureDir(path15.dirname(absolutePath));
2444
2453
  const PptxConstructor = typeof pptxgen === "function" ? pptxgen : pptxgen.default;
2445
2454
  if (!PptxConstructor) throw new Error("Could not find PptxGenJS constructor in module");
2446
2455
  const pres = new PptxConstructor();
@@ -2477,7 +2486,7 @@ var init_write_pptx = __esm({
2477
2486
  }
2478
2487
  }
2479
2488
  const buffer = await pres.write({ outputType: "nodebuffer" });
2480
- await fs15.writeFile(absolutePath, buffer);
2489
+ await fs16.writeFile(absolutePath, buffer);
2481
2490
  return `SUCCESS: Native HTML-to-PPTX [${targetPath}] generated with ${slideBlocks.length} slides.
2482
2491
  - Size: ${(buffer.length / 1024).toFixed(1)} KB`;
2483
2492
  } catch (err) {
@@ -2596,7 +2605,7 @@ var init_tools = __esm({
2596
2605
  // src/utils/ai.js
2597
2606
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
2598
2607
  import path16 from "path";
2599
- import fs16 from "fs";
2608
+ import fs17 from "fs";
2600
2609
  var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
2601
2610
  var init_ai = __esm({
2602
2611
  "src/utils/ai.js"() {
@@ -2714,8 +2723,8 @@ var init_ai = __esm({
2714
2723
  if (lastUsage) await addToUsage("tokens", lastUsage.totalTokenCount || 0);
2715
2724
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
2716
2725
  const janitorLogDir = path16.join(LOGS_DIR, "janitor");
2717
- if (!fs16.existsSync(janitorLogDir)) fs16.mkdirSync(janitorLogDir, { recursive: true });
2718
- fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `
2726
+ if (!fs17.existsSync(janitorLogDir)) fs17.mkdirSync(janitorLogDir, { recursive: true });
2727
+ fs17.appendFileSync(path16.join(janitorLogDir, "debug.log"), `
2719
2728
 
2720
2729
  ---------------------------------------------------
2721
2730
 
@@ -2736,7 +2745,7 @@ DEBUG [${date}]: ${finalSynthesis}
2736
2745
  const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
2737
2746
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
2738
2747
  const janitorLogDir = path16.join(LOGS_DIR, "janitor");
2739
- fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
2748
+ fs17.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
2740
2749
  `);
2741
2750
  if (janitorToolCall.toolName === "memory" && !janitorToolCall.args.includes("action='temp'")) {
2742
2751
  if (onMemoryUpdated) onMemoryUpdated();
@@ -2747,8 +2756,8 @@ DEBUG [${date}]: ${finalSynthesis}
2747
2756
  attempts++;
2748
2757
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
2749
2758
  const janitorErrDir = path16.join(LOGS_DIR, "janitor");
2750
- if (!fs16.existsSync(janitorErrDir)) fs16.mkdirSync(janitorErrDir, { recursive: true });
2751
- fs16.appendFileSync(path16.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
2759
+ if (!fs17.existsSync(janitorErrDir)) fs17.mkdirSync(janitorErrDir, { recursive: true });
2760
+ fs17.appendFileSync(path16.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
2752
2761
 
2753
2762
  `);
2754
2763
  if (attempts > MAX_JANITOR_RETRIES) break;
@@ -2758,7 +2767,7 @@ DEBUG [${date}]: ${finalSynthesis}
2758
2767
  }
2759
2768
  if (attempts) {
2760
2769
  const janitorErrDir = path16.join(LOGS_DIR, "janitor");
2761
- fs16.appendFileSync(path16.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
2770
+ fs17.appendFileSync(path16.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
2762
2771
 
2763
2772
 
2764
2773
  `);
@@ -2982,9 +2991,10 @@ DEBUG [${date}]: ${finalSynthesis}
2982
2991
  const otherMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems).map((mem) => `- ${mem}`).join("\n");
2983
2992
  const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
2984
2993
  const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
2985
- const firstUserMsg = `[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING*.
2986
-
2987
- USER_PROMPT: "${agentText}"`.trim();
2994
+ const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
2995
+ const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
2996
+ const firstUserMsg = `${memoryPrompt}[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.
2997
+ USER_PROMPT: "${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}"`.trim();
2988
2998
  modifiedHistory.push({ role: "user", text: firstUserMsg });
2989
2999
  let lastUsage = null;
2990
3000
  const MAX_LOOPS = mode === "Flux" ? 70 : 7;
@@ -3014,7 +3024,7 @@ USER_PROMPT: "${agentText}"`.trim();
3014
3024
 
3015
3025
  [STEERING HINT]: ${hint}`;
3016
3026
  } else {
3017
- modifiedHistory.push({ role: "user", text: `[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING*.
3027
+ modifiedHistory.push({ role: "user", text: `[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.
3018
3028
 
3019
3029
  [STEERING HINT]: ${hint}` });
3020
3030
  }
@@ -3066,8 +3076,7 @@ USER_PROMPT: "${agentText}"`.trim();
3066
3076
  } else if (retryCount > 0) {
3067
3077
  yield { type: "model_update", content: null };
3068
3078
  }
3069
- const isContext32k = (sessionStats.tokens || 0) >= 32e3;
3070
- const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, otherMemories, mainUserMemories, isMemoryEnabled, isContext32k, MAX_LOOPS, loop + 1);
3079
+ const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
3071
3080
  const jitInstruction = `
3072
3081
 
3073
3082
  [SYSTEM] Tool result received. Analyze output and proceed with your turn. **STRICTLY MAINTAIN THINKING PROTOCOL. NEVER START A RESPONSE WITHOUT THINKING**.`;
@@ -3247,8 +3256,8 @@ USER_PROMPT: "${agentText}"`.trim();
3247
3256
  let actualEndLine = eLine;
3248
3257
  try {
3249
3258
  const absPath = path16.resolve(process.cwd(), targetPath2);
3250
- if (fs16.existsSync(absPath)) {
3251
- const content = fs16.readFileSync(absPath, "utf8");
3259
+ if (fs17.existsSync(absPath)) {
3260
+ const content = fs17.readFileSync(absPath, "utf8");
3252
3261
  const lines = content.split("\n").length;
3253
3262
  totalLines = lines;
3254
3263
  actualEndLine = Math.min(eLine, lines);
@@ -3327,7 +3336,7 @@ ${boxBottom}` };
3327
3336
  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.`;
3328
3337
  toolResults.push({ role: "user", text: `[TOOL_RESULT]: ERROR: ${denyMsg}
3329
3338
 
3330
- [SYSTEM] **MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGHEST PRIORITY**.` });
3339
+ [SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.` });
3331
3340
  yield { type: "tool_result", content: `[TOOL_RESULT]: ERROR: ${denyMsg}` };
3332
3341
  toolCallPointer++;
3333
3342
  continue;
@@ -3342,7 +3351,7 @@ ${boxBottom}` };
3342
3351
  const denyMsg = `Permission Denied: User rejected the ${toolCall.toolName === "exec_command" ? "terminal execution" : "file edit"}.`;
3343
3352
  toolResults.push({ role: "user", text: `[TOOL_RESULT]: DENIED: ${denyMsg}
3344
3353
 
3345
- [SYSTEM] **MUST FOLLOW THINKING${mode === "Flux" ? ", NEWLINE, QUOTE ESCAPE" : ""} POLICY AS HIGHEST PRIORITY**.` });
3354
+ [SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.` });
3346
3355
  yield { type: "tool_result", content: `[TOOL_RESULT]: DENIED: ${denyMsg}` };
3347
3356
  await incrementUsage("toolDenied");
3348
3357
  if (settings.onToolResult) settings.onToolResult("denied");
@@ -3426,8 +3435,8 @@ ${boxBottom}` };
3426
3435
  const errLog = String(err);
3427
3436
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
3428
3437
  const agentErrDir = path16.join(LOGS_DIR, "agent");
3429
- if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
3430
- fs16.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
3438
+ if (!fs17.existsSync(agentErrDir)) fs17.mkdirSync(agentErrDir, { recursive: true });
3439
+ fs17.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
3431
3440
 
3432
3441
  ----------------------------------------------------------------------
3433
3442
 
@@ -3440,7 +3449,7 @@ ${boxBottom}` };
3440
3449
  if (toolResults.length > 0) {
3441
3450
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3442
3451
  }
3443
- modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly after the EXACT word it cut off and DON'T repeat what you already said! PICK UP FROM THE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF. Rules:\n- Do not reuse <think> if the thinking already started just continue from the word and end it properly.\n- If the cutoff was in middle of a tool call, start the tool call from start as the system won't pick half tool formats.\n- Visually the new pickup and continuation should look natual sentence flow.\n- DON'T try to think shorter, keep length standard." });
3452
+ modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly, DON'T repeat what you already said! PICK UP FROM THE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF. Rules:\n- Do not reuse <think> if the thinking already started just continue from the word and end it properly.\n- If the cutoff was in middle of a tool call, start the tool call from start.\n- Visually the new pickup and continuation should look natual sentence flow.\n- DON'T try to think shorter, keep length standard." });
3444
3453
  accumulatedContext += turnText;
3445
3454
  for (let i = waitTime / 1e3; i > 0; i--) {
3446
3455
  yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
@@ -3524,7 +3533,7 @@ ${timestamp}`;
3524
3533
  });
3525
3534
 
3526
3535
  // src/utils/settings.js
3527
- import fs17 from "fs-extra";
3536
+ import fs18 from "fs-extra";
3528
3537
  import path17 from "path";
3529
3538
  var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
3530
3539
  var init_settings = __esm({
@@ -3560,8 +3569,8 @@ var init_settings = __esm({
3560
3569
  };
3561
3570
  loadSettings = async () => {
3562
3571
  try {
3563
- if (await fs17.exists(SETTINGS_FILE)) {
3564
- const saved = await fs17.readJson(SETTINGS_FILE);
3572
+ if (await fs18.exists(SETTINGS_FILE)) {
3573
+ const saved = await fs18.readJson(SETTINGS_FILE);
3565
3574
  const merged = {
3566
3575
  ...DEFAULT_SETTINGS,
3567
3576
  ...saved,
@@ -3571,7 +3580,7 @@ var init_settings = __esm({
3571
3580
  };
3572
3581
  if (merged.showFullThinking === false) {
3573
3582
  merged.showFullThinking = true;
3574
- await fs17.writeJson(SETTINGS_FILE, merged, { spaces: 2 });
3583
+ await fs18.writeJson(SETTINGS_FILE, merged, { spaces: 2 });
3575
3584
  }
3576
3585
  return merged;
3577
3586
  }
@@ -3587,9 +3596,9 @@ var init_settings = __esm({
3587
3596
  const src = path17.join(FLUXFLOW_DIR2, folder);
3588
3597
  const dest = path17.join(newPath, folder);
3589
3598
  try {
3590
- if (await fs17.exists(src)) {
3591
- await fs17.ensureDir(dest);
3592
- await fs17.copy(src, dest, { overwrite: true });
3599
+ if (await fs18.exists(src)) {
3600
+ await fs18.ensureDir(dest);
3601
+ await fs18.copy(src, dest, { overwrite: true });
3593
3602
  }
3594
3603
  } catch (err) {
3595
3604
  console.error(`Migration failed for ${folder}:`, err);
@@ -3603,8 +3612,8 @@ var init_settings = __esm({
3603
3612
  await migrateToExternal(settings.systemSettings.externalDataPath);
3604
3613
  }
3605
3614
  const updated = { ...current, ...settings };
3606
- await fs17.ensureDir(path17.dirname(SETTINGS_FILE));
3607
- await fs17.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
3615
+ await fs18.ensureDir(path17.dirname(SETTINGS_FILE));
3616
+ await fs18.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
3608
3617
  return true;
3609
3618
  } catch (err) {
3610
3619
  console.error("Failed to save settings:", err);
@@ -3817,7 +3826,7 @@ var init_UpdateProcessor = __esm({
3817
3826
  import puppeteer4 from "puppeteer";
3818
3827
  import { exec as exec3 } from "child_process";
3819
3828
  import { promisify } from "util";
3820
- import fs18 from "fs";
3829
+ import fs19 from "fs";
3821
3830
  var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
3822
3831
  var init_setup = __esm({
3823
3832
  "src/utils/setup.js"() {
@@ -3825,7 +3834,7 @@ var init_setup = __esm({
3825
3834
  checkPuppeteerReady = () => {
3826
3835
  try {
3827
3836
  const exePath = puppeteer4.executablePath();
3828
- const exists = exePath && fs18.existsSync(exePath);
3837
+ const exists = exePath && fs19.existsSync(exePath);
3829
3838
  if (exists) return true;
3830
3839
  } catch (e) {
3831
3840
  return false;
@@ -3855,11 +3864,11 @@ var app_exports = {};
3855
3864
  __export(app_exports, {
3856
3865
  default: () => App
3857
3866
  });
3858
- import os2 from "os";
3867
+ import os3 from "os";
3859
3868
  import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
3860
3869
  import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
3861
3870
  import Spinner2 from "ink-spinner";
3862
- import fs19 from "fs-extra";
3871
+ import fs20 from "fs-extra";
3863
3872
  import path18 from "path";
3864
3873
  import { exec as exec4 } from "child_process";
3865
3874
  import { MultilineInput } from "ink-multiline-input";
@@ -4026,7 +4035,7 @@ function App() {
4026
4035
  const [messages, setMessages] = useState7(() => {
4027
4036
  const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
4028
4037
  const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
4029
- const isHomeDir = process.cwd() === os2.homedir();
4038
+ const isHomeDir = process.cwd() === os3.homedir();
4030
4039
  const isSystemDir = (() => {
4031
4040
  const cwd = process.cwd().toLowerCase();
4032
4041
  if (process.platform === "win32") {
@@ -4054,7 +4063,7 @@ function App() {
4054
4063
  id: "home-warning",
4055
4064
  role: "system",
4056
4065
  text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
4057
- subText: `You are currently in ${os2.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
4066
+ subText: `You are currently in ${os3.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
4058
4067
  isHomeWarning: true,
4059
4068
  isMeta: true
4060
4069
  });
@@ -4064,7 +4073,7 @@ function App() {
4064
4073
  const queuedPromptRef = useRef2(null);
4065
4074
  const [completedIndex, setCompletedIndex] = useState7(messages.length);
4066
4075
  const windowedHistory = useMemo(() => {
4067
- const MAX_HISTORY_LINES = 2e3;
4076
+ const MAX_HISTORY_LINES = 1536;
4068
4077
  const width = terminalSize.columns || 80;
4069
4078
  let totalLines = 0;
4070
4079
  let startIdx = 0;
@@ -4582,12 +4591,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
4582
4591
  setCompletedIndex(prev.length + 1);
4583
4592
  return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
4584
4593
  });
4585
- if (fs19.existsSync(LOGS_DIR)) fs19.removeSync(LOGS_DIR);
4586
- if (fs19.existsSync(SECRET_DIR)) fs19.removeSync(SECRET_DIR);
4587
- if (fs19.existsSync(SETTINGS_FILE)) fs19.removeSync(SETTINGS_FILE);
4594
+ if (fs20.existsSync(LOGS_DIR)) fs20.removeSync(LOGS_DIR);
4595
+ if (fs20.existsSync(SECRET_DIR)) fs20.removeSync(SECRET_DIR);
4596
+ if (fs20.existsSync(SETTINGS_FILE)) fs20.removeSync(SETTINGS_FILE);
4588
4597
  try {
4589
- const items = fs19.readdirSync(FLUXFLOW_DIR);
4590
- if (items.length === 0) fs19.removeSync(FLUXFLOW_DIR);
4598
+ const items = fs20.readdirSync(FLUXFLOW_DIR);
4599
+ if (items.length === 0) fs20.removeSync(FLUXFLOW_DIR);
4591
4600
  } catch (e) {
4592
4601
  }
4593
4602
  setTimeout(() => {
@@ -4645,13 +4654,13 @@ ${list || "No saved chats found."}`, isMeta: true }];
4645
4654
  - [Define custom step-by-step recipes for this project here]
4646
4655
  `;
4647
4656
  const filePath = path18.join(process.cwd(), "FluxFlow.md");
4648
- if (fs19.pathExistsSync(filePath)) {
4657
+ if (fs20.pathExistsSync(filePath)) {
4649
4658
  setMessages((prev) => {
4650
4659
  setCompletedIndex(prev.length + 1);
4651
4660
  return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
4652
4661
  });
4653
4662
  } else {
4654
- fs19.writeFileSync(filePath, template);
4663
+ fs20.writeFileSync(filePath, template);
4655
4664
  setMessages((prev) => {
4656
4665
  setCompletedIndex(prev.length + 1);
4657
4666
  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 }];
@@ -5502,7 +5511,7 @@ Selection: ${val}`,
5502
5511
  newline: (key) => key.return && key.shift || key.return && key.ctrl || key.return && key.leftAlt || key.return && key.rightAlt
5503
5512
  }
5504
5513
  }
5505
- )))) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React10.createElement(Text10, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\u{1F9E0} " : "\u{1F4A0} ")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, position: "relative" }, input === "" && /* @__PURE__ */ React10.createElement(Box10, { position: "absolute", paddingLeft: 0 }, activeCommand && !isTerminalFocused ? /* @__PURE__ */ React10.createElement(Text10, { color: "yellow" }, " Press TAB to interact with terminal...") : activeCommand && isTerminalFocused ? /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true }, " [ TERMINAL FOCUSED ] Type to interact, press TAB to exit...") : /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, escPressed ? " Press ESC again to cancel the request." : !isProcessing ? ` Send message or /cmd... (${terminalEnv.shortcut} for newline)` : " Enter a prompt to steer the agent.")), /* @__PURE__ */ React10.createElement(
5514
+ )))) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React10.createElement(Text10, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\u2726 " : "\u{1F4A0} ")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, position: "relative" }, input === "" && /* @__PURE__ */ React10.createElement(Box10, { position: "absolute", paddingLeft: 0 }, activeCommand && !isTerminalFocused ? /* @__PURE__ */ React10.createElement(Text10, { color: "yellow" }, " Press TAB to interact with terminal...") : activeCommand && isTerminalFocused ? /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true }, " [ TERMINAL FOCUSED ] Type to interact, press TAB to exit...") : /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, escPressed ? " Press ESC again to cancel the request." : !isProcessing ? ` Send message or /cmd... (${terminalEnv.shortcut} for newline)` : " Enter a prompt to steer the agent.")), /* @__PURE__ */ React10.createElement(
5506
5515
  MultilineInput,
5507
5516
  {
5508
5517
  focus: !isTerminalFocused,
@@ -5625,8 +5634,8 @@ var init_app = __esm({
5625
5634
  init_text();
5626
5635
  SESSION_START_TIME = Date.now();
5627
5636
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5628
- versionFluxflow = "1.9.9";
5629
- updatedOn = "2026-05-14";
5637
+ versionFluxflow = "1.9.10";
5638
+ updatedOn = "2026-05-15";
5630
5639
  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(
5631
5640
  CommandMenu,
5632
5641
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.9.9",
3
+ "version": "1.9.10",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",