fluxflow-cli 2.7.0 → 2.7.1

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/TOOLS.md +78 -50
  2. package/dist/fluxflow.js +362 -130
  3. package/package.json +2 -2
package/TOOLS.md CHANGED
@@ -4,64 +4,92 @@ Flux Flow provides a robust set of tools that allow the AI to interact with the
4
4
 
5
5
  ## Tool Availability by Mode
6
6
 
7
- | Tool | Flux Mode (Dev) | Flow Mode (Chat) |
7
+ | Tool Category | Flux Mode (Dev) | Flow Mode (Chat) |
8
8
  | :--- | :---: | :---: |
9
- | **Web Search** | ✅ | ✅ |
10
- | **Web Scrape** | ✅ | ✅ |
11
- | **Write PDF** | ✅ | ❌ |
12
- | **Write DOCX** | ✅ | ❌ |
13
- | **View/Read Files** | ✅ | ❌ |
14
- | **Write/Update Files** | ✅ | ❌ |
15
- | **Execute Commands** | ✅ | ❌ |
9
+ | **Communication (Ask)** | ✅ | ✅ |
10
+ | **Web Search & Scrape** | ✅ | ✅ |
11
+ | **File System (Read/Write)** | ✅ | ❌ |
12
+ | **Terminal Execution** | ✅ | ❌ |
16
13
  | **Search Keyword** | ✅ | ❌ |
17
14
  | **File Map** | ✅ | ❌ |
15
+ | **Todo (Planning)** | ✅ | ❌ |
16
+ | **Creative (PDF/DOCX/Image)** | ❌ | ✅ |
18
17
 
19
18
  ---
20
19
 
21
- ## Core Tools
22
-
23
- ### 🌐 Web & Research
24
- - **`WebSearch`**: Uses DuckDuckGo to find up-to-date information on the internet. Crucial for answering questions about recent events or unlearned documentation.
25
- - **`WebScrape`**: Extracts the detailed text content from a specific URL, allowing the agent to read documentation or articles.
26
-
27
- ### 📄 Document Engineering (The Office Suite)
28
- - **`WritePDF`**: Generates high-fidelity, branded PDF documents from HTML/CSS. Features automatic watermarking and page-aware layout management.
29
- - **`WriteDOCX`**: Generates professional Word documents (.docx) from HTML. Supports multi-page layouts, automatic page numbering, and native styling.
30
-
31
- ### 🎨 Creative & Visual
32
- - **`GenerateImage`**: Generates high-fidelity images using Pollinations AI.
33
- - **Customization**: Supports customizable models (Flux, ZImage, Qwen, Nanobanana-Pro, etc.), aspect ratios, custom prompt generation, and random seeds.
34
- - **Telemetry**: Tracks hourly credit usage (Low, Medium, Ultra, Premium tiers) with built-in daily limit checks and interactive dashboard displays.
35
-
36
- ### 📁 File System Operations
37
- - **`ListFiles`**: Lists the contents of a directory to help the agent understand the project structure.
38
- - **`ReadFolder`**: Provides detailed statistics and metadata about a directory's contents.
39
- - **`ViewFile`**: Reads the content of a file.
40
- - **Native Multimodality**: Supports analyzing images (JPG, PNG, WEBP) and PDF documents. The tool automatically detects binary formats and encodes them for AI analysis.
41
- - **Text Reading**: Supports specific line ranges (`start_line`, `end_line`) to manage context size efficiently.
42
- - **`FileMap`**: Generates a high-level structural map of a code file using Tree-Sitter.
43
- - **Structural Insight**: Identifies classes, functions, methods, and control flow blocks without reading the entire file content.
44
- - **Multi-Language**: Supports JS, TS, TSX, Python, C, C++, Java, and HTML.
45
- - **`SearchKeyword`**: Performs a global project search for a specific string or keyword. Returns file paths and line numbers where matches are found, making it essential for navigation and impact analysis.
46
-
47
- ### ✍️ Code Editing
48
- - **`WriteFile`**: Creates a new file or completely overwrites an existing one with new content.
49
- - **`UpdateFile` (Smart Patching)**: Surgically replaces a specific block of text within a file.
50
- - *Diff Generation*: It returns a high-fidelity visual diff (Red/Green changes with context lines) to the UI, allowing the user to see exactly what the agent modified.
51
-
52
- ### 💻 Terminal Execution
53
- - **`Run`**: Runs a shell command directly in the terminal using Node's `child_process.spawn` or `node-pty` when available.
54
- - *Context Aware*: Runs in the current working directory.
55
- - *Cross-Platform*: Uses `shell: true` to handle Windows `.cmd`/`.bat` files natively.
20
+ ## Tool Protocol
21
+
22
+ FluxFlow uses a transparent, string-based protocol for tool dispatching:
23
+ `[[tool:functions.ToolName(arg1="value", arg2=123)]]`
56
24
 
57
25
  ---
58
26
 
59
- ## Memory Management
27
+ ## Communication Tools
28
+
29
+ ### `Ask`
30
+ - **Purpose**: Ambiguity Resolution.
31
+ - **Triggers**: Mandatory for Path Divergence, Security concerns, or Risk Mitigation.
32
+ - **Usage**: Suggests up to 4 best options; does not ask for open-ended preferences.
33
+
34
+ ---
35
+
36
+ ## Web Tools
37
+
38
+ ### `WebSearch`
39
+ - **Purpose**: Proactive search for unknown topics.
40
+ - **Limit**: 3-10 results.
41
+
42
+ ### `WebScrape`
43
+ - **Purpose**: Deep-dive research into specific webpages, documentation, or APIs.
44
+
45
+ ---
46
+
47
+ ## Workspace Tools (Flux Mode Only)
48
+
49
+ ### `ReadFile`
50
+ - **Purpose**: Reads file content with support for line ranges.
51
+ - **Multimodal**: Supports images and documents.
52
+
53
+ ### `FileMap`
54
+ - **Purpose**: Shows file structure, dependencies, functions, and variable maps. More token-efficient than ReadFile.
55
+
56
+ ### `ReadFolder`
57
+ - **Purpose**: Provides detailed directory statistics.
60
58
 
61
- The memory tool (`memory.js`) is primarily used by the background **Janitor** model, but can be accessed by the main agent if necessary.
59
+ ### `PatchFile` (UpdateFile)
60
+ - **Purpose**: Surgical patching of code.
61
+ - **Usage**: Supports multiple patches in a single call to prevent spam. MUST VERIFY DIFF.
62
+
63
+ ### `WriteFile`
64
+ - **Purpose**: Creates or overwrites files.
65
+ - **Safety**: Prefers PatchFile if the file already exists.
66
+
67
+ ### `SearchKeyword`
68
+ - **Purpose**: Global project search for definitions or logic.
69
+
70
+ ### `Run` (exec_command)
71
+ - **Purpose**: Runs shell commands (PowerShell/CMD on Windows, Bash on Unix).
72
+ - **Safety**: Restricted to workspace directory unless explicitly allowed. Irreversible operations require user approval.
73
+
74
+ ### `Todo`
75
+ - **Purpose**: Manages an internal task list (`todo.md`) to keep goals consistent during long tasks.
76
+ - **Methods**: `create`, `append`, `check`.
77
+
78
+ ---
79
+
80
+ ## Creative Tools (Flow Mode Only)
81
+
82
+ ### `WritePDF`
83
+ - **Purpose**: Generates high-fidelity, branded PDF documents from HTML/CSS.
84
+
85
+ ### `WriteDoc`
86
+ - **Purpose**: Creates professional Word documents (.docx).
87
+
88
+ ### `GenerateImage`
89
+ - **Purpose**: Creates high-fidelity images via AI.
90
+
91
+ ---
92
+
93
+ ## Memory Management
62
94
 
63
- - **Temporary Context (`action='temp'`)**: Saves a rolling summary of the current session to maintain conversational context without bloating the main prompt history.
64
- - **Persistent User Memory (`action='user'`)**:
65
- - The Janitor analyzes conversations to detect user preferences, hobbies, or instructions.
66
- - It uses `add`, `update`, or `delete` methods to manage facts in the encrypted `memories.json` vault.
67
- - These memories are injected into the system prompt of *future* sessions, allowing Flux Flow to learn and adapt to the user over time.
95
+ Managed primarily by the background **Janitor** model to maintain persistent user context and session summaries without bloating the reasoning loop.
package/dist/fluxflow.js CHANGED
@@ -1847,6 +1847,7 @@ var init_ChatLayout = __esm({
1847
1847
  { cmd: "/reset", desc: "Wipe all project data" },
1848
1848
  { cmd: "/about", desc: "Project info & credits" },
1849
1849
  { cmd: "/changelog", desc: "View latest updates" },
1850
+ { cmd: "/docs", desc: "View documentation" },
1850
1851
  { cmd: "/fluxflow", desc: "Project management" },
1851
1852
  { cmd: "/update", desc: "Check/Install updates" }
1852
1853
  ];
@@ -2155,28 +2156,29 @@ Access to internal tools. MUST use the exact syntax on a new line: [[tool:functi
2155
2156
  ${mode === "Flux" ? "- USE multiple search & replace on patch tool if editing same file/path with many changes \u2190 **HIGHLY PREFERRED**\n- Tool execution denied? MUST use 'Ask' tool immediately to ask for reason/changes. NEVER END RESPONSE OR PROCEED BLINDLY \u2190 **MANDATORY**\n- FileMap >> ReadFile for understandling files efficiently\n- Want a spefific word/varible to find across project? SearchKeyword >> Guessing/ReadFile" : ""}- No brute force, no spamming of tools
2156
2157
  ${mode === "Flux" ? "- **File Tools >> Code in chat**\n" : ""}
2157
2158
  - COMMUNICATION TOOLS -
2158
- 1. [[tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish. Suggest best options; don't ask for preferences
2159
+ 1. [[tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]] Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish. Suggest best options; don't ask for preferences
2159
2160
 
2160
2161
  - WEB TOOLS -
2161
- 1. [[tool:functions.WebSearch(query="...", limit=number)]]. Limit 3-10. Proactive use for unknown topics
2162
- 2. [[tool:functions.WebScrape(url="...")]]. Proactive use for specific webpage/docs/api
2163
-
2164
- ${mode === "Flux" ? `- PROJECT TOOLS (path = relative to CWD, path separator: '/') -
2165
- 1. [[tool:functions.ReadFile(path="...", startLine=number, endLine=number)]]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs. User gives image/doc: VIEW FIRST` : `No Multimodal support`}` : `Supports images/docs. User gives image/doc: VIEW FIRST`}
2166
- 2. [[tool:functions.FileMap(path="path/file")]]. Shows file structure, dependency, functions, variable maps. Token Efficient than ReadFile
2167
- 3. [[tool:functions.ReadFolder(path="...")]]. Detailed DIR stats
2168
- 4. [[tool:functions.PatchFile(path="...", replaceContent1="exact string", newContent1="...", ...MAX 10)]]. Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile >> guessing. **MUST VERIFY DIFF**
2169
- 5. [[tool:functions.WriteFile(path="...", content="...")]]. Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
2170
- 6. [[tool:functions.SearchKeyword(keyword="...", file="optional")]]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
2171
- 7. [[tool:functions.Run(command="...")]]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `${isPtyAvailable ? "Interactive " : ""}WINDOWS POWERSHELL ONLY` : `${isPtyAvailable ? "Interactive " : ""}WINDOWS CMD ONLY` : `${isPtyAvailable ? "Interactive " : ""}BASH`} command. Destructive/Irreversible ops -> Ask user. **TOOL DENY RULE APPLIES**. **1 CALL LIMIT OR 3 CONSECUTIVE RUN TOOL ONLY**
2172
- 8. [[tool:functions.WritePDF(path="...", content="...", orientation="...")]]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
2173
- 9. [[tool:functions.WriteDoc(path="...", content="...")]]. A4 Word document
2162
+ 1. [[tool:functions.WebSearch(query="...", limit=number)]] Limit 3-10. Proactive use for unknown topics
2163
+ 2. [[tool:functions.WebScrape(url="...")]] Proactive use for specific webpage/docs/api
2164
+
2165
+ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD, path separator: '/') -
2166
+ 1. [[tool:functions.ReadFile(path="...", startLine=number, endLine=number)]] ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs. User gives image/doc: VIEW FIRST` : `No Multimodal support`}` : `Supports images/docs. User gives image/doc: VIEW FIRST`}
2167
+ 2. [[tool:functions.FileMap(path="path/file")]] Shows file structure, dependency, functions, variable maps. Token Efficient than ReadFile
2168
+ 3. [[tool:functions.ReadFolder(path="...")]] Detailed DIR stats
2169
+ 4. [[tool:functions.PatchFile(path="...", replaceContent1="exact string", newContent1="...", ...MAX 10)]] Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile >> guessing. **MUST VERIFY DIFF**
2170
+ 5. [[tool:functions.WriteFile(path="...", content="...")]] Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
2171
+ 6. [[tool:functions.SearchKeyword(keyword="...", file="optional")]] Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
2172
+ 7. [[tool:functions.Run(command="...")]] Runs ${osDetected === "Windows" ? isPsAvailable() ? `${isPtyAvailable ? "Interactive " : ""}WINDOWS POWERSHELL ONLY` : `${isPtyAvailable ? "Interactive " : ""}WINDOWS CMD ONLY` : `${isPtyAvailable ? "Interactive " : ""}BASH`} command. Destructive/Irreversible ops -> Ask user. **TOOL DENY RULE APPLIES**. **1 CALL LIMIT FOR RUN**
2173
+ 8. [[tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS, NO MD CHECKBOXES], markDone=[ARRAY OF TASK STRINGS, NO MD CHECKBOXES])]] Internal TODO List. Usage: LONG MULTISTEP TASKS TO KEEP GOAL CONSISTENT. 'tasks' & 'markDone' are OPTIONAL WITH method 'get'. TO MARK DONE USE 'get' method WITH 'markDone'. MUST UPDATE TASKS AS SOON AS COMPLETION`.trim() : `- CREATIVE TOOLS (path = relative to CWD, path separator: '/') -
2174
+ 1. [[tool:functions.WritePDF(path="...", content="...", orientation="...")]] PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
2175
+ 2. [[tool:functions.WriteDoc(path="...", content="...")]] A4 Word document
2176
+ - WORKSPACE TOOLS ARE NOT AVAILABLE IN FLOW`.trim()}
2174
2177
 
2175
2178
  - VERIFY TOOL RESULT CONTENTS. Fix errors. No hallucinations
2176
2179
  - Escape quotes: \\" for code strings
2177
2180
  - Literal escapes: Double-escape sequences (e.g., \\\\n, \\\\t)
2178
- - File structure: Real newlines for code formatting`.trim() : `
2179
- - FILE TOOLS ARE NOT AVAILABLE IN FLOW (Tell user to,\` /mode flux\` if needed)`.trim()}`.trim();
2181
+ - File structure: Real newlines for code formatting`.trim();
2180
2182
  }
2181
2183
  });
2182
2184
 
@@ -3286,7 +3288,7 @@ var thinking_prompts_default;
3286
3288
  var init_thinking_prompts = __esm({
3287
3289
  "src/data/thinking_prompts.json"() {
3288
3290
  thinking_prompts_default = {
3289
- xHigh: "EFFORT LEVEL: MAX\nThink in a continuous, relentless analytical monologue within <think>...</think>. Engage in adversarial self interrogation that treats every assumption as hostile until proven:\nDeconstruct requirements into atomic invariants. Trace every implicit dependency, side effect, and state mutation. Map the entire dependency graph and identify circular dependencies or tight coupling before they manifest\nEvaluate algorithmic complexity (time/space) for every operation. Consider memory models, cache locality, and allocation patterns. For concurrent systems, reason through race conditions, deadlocks, and memory ordering\nFormulate solutions by comparing multiple architectural approaches. Explicitly evaluate trade offs, monolithic vs modular, eager vs lazy, mutable vs immutable, sync vs async. Choose based on measured criteria, not intuition\nMentally execute the solution at multiple scales. What breaks at 10x load? 100x? What happens under resource exhaustion? Trace error propagation paths through every layer\nActively attempt to falsify your own logic. Steel man the opposite approach. Search for, off by one errors, integer overflow, null/undefined propagation, unhandled promises, resource leaks, SQL injection vectors, XSS vulnerabilities, CSRF holes, timing attacks, and privilege escalation paths\nReason about observability, what metrics matter? Where are the logging gaps? How will this be debugged in production at 3am?\nConsider future evolution, what changes will this architecture resist vs accommodate? Where are the extension points? What will break when requirements inevitably change?\nMap out implementation with surgical precision, exact file structure, module boundaries, interface contracts, error types, and test strategies before writing a single line\nRULES:\n- NO HEADINGS/MARKERS/LISTS\n- Dense, unbroken stream of consciousness that reads like an internal monologue\n- Ruthlessly question every architectural choice. Default to skepticism\n- Think in terms of invariants, contracts, and failure modes, not just happy paths\n- Verify ALL imports and system stability, AVOID ANY Syntax errors, re-read TOOL RESULTS/files to verify\n- MANDATORY THINKING: Full reasoning required for ALL requests/greetings (verify context, check for hidden complexity)",
3291
+ xHigh: "EFFORT LEVEL: HIGH\nThink in a continuous, relentless analytical monologue within <think>...</think>. Engage in adversarial self interrogation that treats every assumption as hostile until proven:\nDeconstruct requirements into atomic invariants. Trace every implicit dependency, side effect, and state mutation. Map the entire dependency graph and identify circular dependencies or tight coupling before they manifest\nEvaluate algorithmic complexity (time/space) for every operation. Consider memory models, cache locality, and allocation patterns. For concurrent systems, reason through race conditions, deadlocks, and memory ordering\nFormulate solutions by comparing multiple architectural approaches. Explicitly evaluate trade offs, monolithic vs modular, eager vs lazy, mutable vs immutable, sync vs async. Choose based on measured criteria, not intuition\nMentally execute the solution at multiple scales. What breaks at 10x load? 100x? What happens under resource exhaustion? Trace error propagation paths through every layer\nActively attempt to falsify your own logic. Steel man the opposite approach. Search for, off by one errors, integer overflow, null/undefined propagation, unhandled promises, resource leaks, SQL injection vectors, XSS vulnerabilities, CSRF holes, timing attacks, and privilege escalation paths\nReason about observability, what metrics matter? Where are the logging gaps? How will this be debugged in production at 3am?\nConsider future evolution, what changes will this architecture resist vs accommodate? Where are the extension points? What will break when requirements inevitably change?\nMap out implementation with surgical precision, exact file structure, module boundaries, interface contracts, error types, and test strategies before writing a single line\nRULES:\n- NO HEADINGS/MARKERS/LISTS\n- Dense, unbroken stream of consciousness that reads like an internal monologue\n- Ruthlessly question every architectural choice. Default to skepticism\n- Think in terms of invariants, contracts, and failure modes, not just happy paths\n- Verify ALL imports and system stability, AVOID ANY Syntax errors, re-read TOOL RESULTS/files to verify\n- MANDATORY THINKING: Full reasoning required for ALL requests/greetings (verify context, check for hidden complexity)",
3290
3292
  High: "EFFORT LEVEL: HIGH\nThink in a rigorous, technically grounded monologue within <think>...</think>. Treat this as a design review where every decision must be justified:\nBreak the objective into verifiable steps with clear success criteria. Identify the critical path and potential bottlenecks\nMentally compile and execute your approach. Check for: missing imports, undefined behavior, type mismatches, unhandled errors, and resource cleanup. Trace data flow from input to output, noting transformations\nRecognize design patterns and anti patterns. If you see God objects, tight coupling, or premature optimization, call it out and refactor mentally before committing\nEvaluate performance characteristics. Will this scale? Are there O(n\xB2) operations hiding in innocent looking code? Where are the allocation hotspots?\nConsider the error surface, what can fail and how? Design error handling that preserves invariants and provides actionable feedback\nReview your architecture for, separation of concerns, single responsibility, dependency inversion, and interface segregation. Ensure clean abstractions with minimal coupling\nRULES:\n- NO HEADINGS/MARKERS/LISTS\n- Continuous analytical flow\n- Verify correctness through first principles reasoning, not pattern matching\n- Actively search for ways your solution could fail or degrade\n- Verify ALL imports and system stability, AVOID ANY Syntax errors, re-read TOOL RESULTS/files to verify\n- MANDATORY THINKING: Full technical verification for all tasks/greetings",
3291
3293
  Medium: "EFFORT LEVEL: MEDIUM\nThink in a focused, technically-aware monologue within <think>...</think>\nIdentify the most direct path that satisfies requirements without over-engineering\nQuickly scan for obvious issues, missing error handling, incorrect input assumptions, forgotten edge cases, or missing dependencies\nVerify the solution is appropriately modular with cohesive changes\nOutline the concrete changes, which files, which functions, what the key logic looks like\nRULES:\n- NO HEADINGS/MARKERS/LISTS\n- Clean logical stream\n- Efficient but deliberate. Focus energy on actionable implementation details\n- Verify ALL imports and system stability, AVOID ANY Syntax errors, re-read TOOL RESULTS/files to verify\n- MANDATORY THINKING: Brief verification for technical tasks/greetings",
3292
3294
  Minimal: "EFFORT LEVEL: LOW\nThink in a quick, focused monologue within <think>...</think>. Just verify the basics:\nConfirm what the user wants and whether it's straightforward or has hidden complexity\nIdentify the specific tool, file, or action needed\nCheck for any obvious correctness issues before acting\nRULES:\n- NO HEADINGS/MARKERS/LISTS\n- Few lines of clear thought\n- Just enough thinking to avoid obvious mistakes\n- Verify ALL imports and system stability, AVOID ANY Syntax errors, re-read TOOL RESULTS/files to verify\n- Suitable for simple requests/greetings",
@@ -3364,12 +3366,12 @@ Check these first; These Files > Training Data. Safety rules apply
3364
3366
  }
3365
3367
  const projectContextBlock = cachedProjectContextBlock;
3366
3368
  return `${nameStr}${nicknameStr}${userInstrStr}[[SYSTEM]]
3367
- Identity: Flux Flow (by Kushal Roy Chowdhury). Conversational, Sassy${mode === "Flux" ? ", Respectful" : ", Friendly, Humorous, Sarcastic"}, CLI Agent
3369
+ Identity: Flux Flow (by Kushal Roy Chowdhury). ${mode === "Flux" ? "Conversational" : "Conversational, Sassy, Friendly, Humorous, Sarcastic"}, CLI Agent
3368
3370
  Mode: ${mode}${thinkingLevel !== "Fast" ? " (Thinking)" : ""}. ${mode === "Flux" ? "Logical, Highly Detailed, Task-Driven. Prioritizes scalable file/folder structures, modular architecture, clean code abstractions, step-by-step execution. Industry standard latest coding practices/libraries, clean code, Double Check Imports, Client-Server Sync" : "Concise"}
3369
3371
 
3370
- -- AGENT RULES (PRIORITY: HIGH) --
3372
+ -- AGENT RULES (IMPORTANT) --
3371
3373
  - **MANDATORY: MUST END EVERY RESPONSE WITH [[END]]**
3372
- - NO CHAT OUTPUT AFTER TOOL CALL IN SAME TURN
3374
+ - **NO CHAT OUTPUT AFTER TOOL CALL IN SAME TURN**
3373
3375
 
3374
3376
  -- MARKERS --
3375
3377
  - TOOL SYSTEM: [[TOOL RESULT]] (system priority)
@@ -3381,7 +3383,7 @@ ${thinkingLevel !== "Fast" ? `
3381
3383
  CRITICAL THINKING POLICY
3382
3384
  - ALWAYS use <think> ... </think> before responding, even with simple queries/greetings
3383
3385
  - ${thinkingLevel === "Low" || thinkingLevel === "Medium" || thinkingLevel === "Fast" ? "C" : "Interrogate approaches adversarially, but c"}ommit once best solution is determined through analysis. Avoid spiraling after reaching decision point
3384
- ` : ""}` : ""}` : ``}
3386
+ - Thinking should scale with task complexity` : ""}` : ""}` : ``}
3385
3387
  ${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider)}
3386
3388
  ${projectContextBlock}
3387
3389
  -- MEMORY RULES --
@@ -5836,6 +5838,120 @@ Stack: ${err.stack}` : "";
5836
5838
  }
5837
5839
  });
5838
5840
 
5841
+ // src/tools/todo.js
5842
+ import fs19 from "fs";
5843
+ import path18 from "path";
5844
+ var todo;
5845
+ var init_todo = __esm({
5846
+ "src/tools/todo.js"() {
5847
+ init_arg_parser();
5848
+ init_paths();
5849
+ todo = async (args, context = {}) => {
5850
+ const { method, tasks, markDone } = parseArgs(args);
5851
+ const chatId = context.chatId || "default";
5852
+ if (!method) return 'ERROR: Missing "method" argument for todo tool (create/append/get).';
5853
+ const todoDir = path18.join(DATA_DIR, "plan", chatId);
5854
+ const todoFile = path18.join(todoDir, "todo.md");
5855
+ const parseMessyArray = (input) => {
5856
+ if (!input || Array.isArray(input)) return input;
5857
+ const trimmed = String(input).trim();
5858
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
5859
+ const matches = trimmed.match(/"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'/g);
5860
+ if (matches) {
5861
+ return matches.map((m) => m.slice(1, -1).replace(/\\(.)/g, "$1"));
5862
+ }
5863
+ return trimmed.slice(1, -1).split(",").map((s) => s.trim()).filter(Boolean);
5864
+ }
5865
+ return input;
5866
+ };
5867
+ const getTasksString = (input) => {
5868
+ const rawItems = parseMessyArray(input);
5869
+ if (!rawItems) return "";
5870
+ const items = Array.isArray(rawItems) ? rawItems : String(rawItems).split("\n");
5871
+ return items.map((item) => {
5872
+ const trimmed = String(item).trim();
5873
+ if (!trimmed) return null;
5874
+ if (trimmed.startsWith("- [ ]") || trimmed.startsWith("- [x]") || trimmed.startsWith("- [X]")) return trimmed;
5875
+ return `- [ ] ${trimmed}`;
5876
+ }).filter(Boolean).join("\n") + "\n";
5877
+ };
5878
+ try {
5879
+ if (!fs19.existsSync(todoDir)) {
5880
+ fs19.mkdirSync(todoDir, { recursive: true });
5881
+ }
5882
+ if (method === "create") {
5883
+ if (!tasks) return 'ERROR: Missing "tasks" for create method.';
5884
+ const content = getTasksString(tasks);
5885
+ fs19.writeFileSync(todoFile, content, "utf8");
5886
+ const total = (content.match(/^- \[ [xX ]\]/gm) || []).length;
5887
+ return `SUCCESS: TASK LIST CREATED (${total} total)
5888
+ ${content}`;
5889
+ }
5890
+ if (method === "append") {
5891
+ if (!tasks) return 'ERROR: Missing "tasks" for append method.';
5892
+ const appendContent = getTasksString(tasks);
5893
+ fs19.appendFileSync(todoFile, appendContent, "utf8");
5894
+ const fullContent = fs19.readFileSync(todoFile, "utf8");
5895
+ const total = (fullContent.match(/^- \[ [xX ]\]/gm) || []).length;
5896
+ const completed = (fullContent.match(/^- \[x\]/gim) || []).length;
5897
+ const added = (appendContent.match(/^- \[ [xX ]\]/gm) || []).length;
5898
+ return `SUCCESS: TASK APPENDED (${completed} completed, ${total - completed} left, ${added} added)
5899
+ ${fullContent}`;
5900
+ }
5901
+ if (method === "get") {
5902
+ if (!fs19.existsSync(todoFile)) {
5903
+ return "TODO GET: No task list found for this session.";
5904
+ }
5905
+ let content = fs19.readFileSync(todoFile, "utf8");
5906
+ let markedCount = 0;
5907
+ if (markDone) {
5908
+ const rawTargets = parseMessyArray(markDone);
5909
+ const targets = (Array.isArray(rawTargets) ? rawTargets : [rawTargets]).map((t) => String(t).replace(/^- \[[xX ]\]\s*/i, "").trim()).filter(Boolean);
5910
+ const lines = content.split("\n");
5911
+ let fileUpdated = false;
5912
+ for (const searchStr of targets) {
5913
+ let updatedThisTarget = false;
5914
+ for (let i = 0; i < lines.length; i++) {
5915
+ if (lines[i].includes(searchStr) && /^- \[\s\]/.test(lines[i].trim())) {
5916
+ lines[i] = lines[i].replace("- [ ]", "- [x]");
5917
+ updatedThisTarget = true;
5918
+ fileUpdated = true;
5919
+ markedCount++;
5920
+ break;
5921
+ }
5922
+ }
5923
+ if (!updatedThisTarget) {
5924
+ for (let i = 0; i < lines.length; i++) {
5925
+ if (lines[i].toLowerCase().includes(searchStr.toLowerCase()) && /^- \[\s\]/.test(lines[i].trim())) {
5926
+ lines[i] = lines[i].replace("- [ ]", "- [x]");
5927
+ updatedThisTarget = true;
5928
+ fileUpdated = true;
5929
+ markedCount++;
5930
+ break;
5931
+ }
5932
+ }
5933
+ }
5934
+ }
5935
+ if (fileUpdated) {
5936
+ content = lines.join("\n");
5937
+ fs19.writeFileSync(todoFile, content, "utf8");
5938
+ }
5939
+ }
5940
+ const total = (content.match(/^- \[ [xX ]\]/gm) || []).length;
5941
+ const completed = (content.match(/^- \[x\]/gim) || []).length;
5942
+ const prefix = markedCount > 0 ? `SUCCESS: ${markedCount} TASK(S) MARKED DONE` : `TODO GET`;
5943
+ return `${prefix}: ${completed} Completed, ${total - completed} left
5944
+ ${content}`;
5945
+ }
5946
+ return `ERROR: Unknown method "${method}". Use create, append, or get.`;
5947
+ } catch (err) {
5948
+ const errorMsg = err instanceof Error ? err.message : String(err);
5949
+ return `ERROR: Todo tool failure: ${errorMsg}`;
5950
+ }
5951
+ };
5952
+ }
5953
+ });
5954
+
5839
5955
  // src/utils/tools.js
5840
5956
  var TOOL_MAP, dispatchTool;
5841
5957
  var init_tools = __esm({
@@ -5857,6 +5973,7 @@ var init_tools = __esm({
5857
5973
  init_saveSummary();
5858
5974
  init_addMemScore();
5859
5975
  init_file_map();
5976
+ init_todo();
5860
5977
  TOOL_MAP = {
5861
5978
  web_search,
5862
5979
  web_scrape,
@@ -5874,6 +5991,7 @@ var init_tools = __esm({
5874
5991
  saveSummary,
5875
5992
  addMemScore,
5876
5993
  file_map,
5994
+ todo,
5877
5995
  ask: ask_user,
5878
5996
  // PascalCase Normalizations for Token Efficiency
5879
5997
  Ask: ask_user,
@@ -5897,14 +6015,26 @@ var init_tools = __esm({
5897
6015
  AddMemScore: addMemScore,
5898
6016
  addMemoryScore: addMemScore,
5899
6017
  AddMemoryScore: addMemScore,
5900
- FileMap: file_map
6018
+ FileMap: file_map,
6019
+ Todo: todo,
6020
+ TODO: todo
5901
6021
  };
5902
6022
  dispatchTool = async (toolName, args, context = {}) => {
5903
- if (context.mode && context.mode.toLowerCase() === "flow") {
5904
- const normalized = toolName.toLowerCase();
5905
- const isWebOrAsk = normalized.startsWith("web") || normalized.startsWith("ask");
5906
- if (!isWebOrAsk) {
5907
- return `ERROR: Tool [${toolName}] is restricted in Flow mode.`;
6023
+ const mode = context.mode ? context.mode.toLowerCase() : "flux";
6024
+ const normalized = toolName.toLowerCase();
6025
+ const systemTools = ["memory", "chat", "savesummary", "addmemscore", "add_mem_score", "ask", "web_search", "web_scrape"];
6026
+ const isSystem = systemTools.some((t) => normalized.includes(t)) || normalized === "ask";
6027
+ if (!isSystem) {
6028
+ if (mode === "flow") {
6029
+ const isCreative = normalized.includes("write_pdf") || normalized.includes("write_docx") || normalized.includes("generate_image");
6030
+ if (!isCreative) {
6031
+ return `ERROR: Tool [${toolName}] is a Workspace Tool and NOT available in Flow mode. Tell user to switch (\`/mode flux\`) to use this tool.`;
6032
+ }
6033
+ } else {
6034
+ const isCreative = normalized.includes("write_pdf") || normalized.includes("write_docx") || normalized.includes("generate_image");
6035
+ if (isCreative) {
6036
+ return `ERROR: Tool [${toolName}] is not available in Flux mode. Tell user to switch (\`/mode flow\`) for document generation.`;
6037
+ }
5908
6038
  }
5909
6039
  }
5910
6040
  const tool = TOOL_MAP[toolName];
@@ -6025,8 +6155,8 @@ var init_editor = __esm({
6025
6155
 
6026
6156
  // src/utils/ai.js
6027
6157
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
6028
- import path18 from "path";
6029
- import fs19 from "fs";
6158
+ import path19 from "path";
6159
+ import fs20 from "fs";
6030
6160
  var client, globalSettings, TERMINATION_SIGNAL, MULTIMODAL_MODELS, isModelMultimodal, getCleanGroupedLength, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getNVIDIAStream, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, compressHistory, deleteChatSummary, getAIStream;
6031
6161
  var init_ai = __esm({
6032
6162
  async "src/utils/ai.js"() {
@@ -6570,13 +6700,15 @@ var init_ai = __esm({
6570
6700
  "ask": "User Input",
6571
6701
  "write_pdf": "Creating",
6572
6702
  "write_docx": "Creating",
6573
- "generate_image": "Generating"
6703
+ "generate_image": "Generating",
6704
+ "todo": "Planning",
6705
+ "Todo": "Planning"
6574
6706
  };
6575
6707
  getToolDetail = (toolName, argsStr) => {
6576
6708
  try {
6577
6709
  const pArgs = parseArgs(argsStr);
6578
6710
  const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
6579
- return filePath ? path18.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
6711
+ return filePath ? path19.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
6580
6712
  } catch (e) {
6581
6713
  return null;
6582
6714
  }
@@ -6791,9 +6923,9 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
6791
6923
  process.stdout.write(`\x1B]0;Finalizing Error\x07`);
6792
6924
  }
6793
6925
  await new Promise((resolve) => setTimeout(resolve, 1e3));
6794
- const janitorErrDir = path18.join(LOGS_DIR, "janitor");
6795
- if (!fs19.existsSync(janitorErrDir)) fs19.mkdirSync(janitorErrDir, { recursive: true });
6796
- fs19.appendFileSync(path18.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
6926
+ const janitorErrDir = path19.join(LOGS_DIR, "janitor");
6927
+ if (!fs20.existsSync(janitorErrDir)) fs20.mkdirSync(janitorErrDir, { recursive: true });
6928
+ fs20.appendFileSync(path19.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
6797
6929
 
6798
6930
  `);
6799
6931
  if (attempts > MAX_JANITOR_RETRIES) break;
@@ -6802,8 +6934,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
6802
6934
  }
6803
6935
  }
6804
6936
  if (attempts) {
6805
- const janitorErrDir = path18.join(LOGS_DIR, "janitor");
6806
- fs19.appendFileSync(path18.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
6937
+ const janitorErrDir = path19.join(LOGS_DIR, "janitor");
6938
+ fs20.appendFileSync(path19.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
6807
6939
 
6808
6940
 
6809
6941
  `);
@@ -7152,10 +7284,10 @@ ${newMemoryListStr}
7152
7284
  }
7153
7285
  }
7154
7286
  } catch (err) {
7155
- const janitorLogDir = path18.join(LOGS_DIR, "janitor");
7156
- if (!fs19.existsSync(janitorLogDir)) fs19.mkdirSync(janitorLogDir, { recursive: true });
7157
- fs19.appendFileSync(
7158
- path18.join(janitorLogDir, "error.log"),
7287
+ const janitorLogDir = path19.join(LOGS_DIR, "janitor");
7288
+ if (!fs20.existsSync(janitorLogDir)) fs20.mkdirSync(janitorLogDir, { recursive: true });
7289
+ fs20.appendFileSync(
7290
+ path19.join(janitorLogDir, "error.log"),
7159
7291
  `[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${err.message}
7160
7292
  `
7161
7293
  );
@@ -7163,7 +7295,7 @@ ${newMemoryListStr}
7163
7295
  };
7164
7296
  compressHistory = async (settings, history, isAuto = false) => {
7165
7297
  const { chatId, aiProvider = "Google" } = settings;
7166
- const summariesFile = path18.join(SECRET_DIR, "chat-summaries.json");
7298
+ const summariesFile = path19.join(SECRET_DIR, "chat-summaries.json");
7167
7299
  const flattenContext = (hist) => {
7168
7300
  return hist.filter(
7169
7301
  (m) => (m.role === "user" || m.role === "agent" || m.role === "system") && m.role !== "think" && !m.isVisualFeedback && !m.isMeta && !String(m.id).startsWith("welcome")
@@ -7236,8 +7368,8 @@ Provide a consolidated summary of the entire session.`;
7236
7368
  };
7237
7369
  deleteChatSummary = (chatId) => {
7238
7370
  try {
7239
- const summariesFile = path18.join(SECRET_DIR, "chat-summaries.json");
7240
- if (fs19.existsSync(summariesFile)) {
7371
+ const summariesFile = path19.join(SECRET_DIR, "chat-summaries.json");
7372
+ if (fs20.existsSync(summariesFile)) {
7241
7373
  const summaries = readEncryptedJson(summariesFile, {});
7242
7374
  if (summaries[chatId]) {
7243
7375
  delete summaries[chatId];
@@ -7253,7 +7385,7 @@ Provide a consolidated summary of the entire session.`;
7253
7385
  if (!client && aiProvider === "Google") throw new Error("AI not initialized");
7254
7386
  const isMemoryEnabled = systemSettings?.memory !== false;
7255
7387
  const originalText = history[history.length - 1].text;
7256
- const summariesFile = path18.join(SECRET_DIR, "chat-summaries.json");
7388
+ const summariesFile = path19.join(SECRET_DIR, "chat-summaries.json");
7257
7389
  let wasCompressedInStream = false;
7258
7390
  const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
7259
7391
  const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
@@ -7477,7 +7609,7 @@ Provide a consolidated summary of the entire session.`;
7477
7609
  ];
7478
7610
  const safeReaddirWithTypes = (dir) => {
7479
7611
  try {
7480
- return fs19.readdirSync(dir, { withFileTypes: true });
7612
+ return fs20.readdirSync(dir, { withFileTypes: true });
7481
7613
  } catch (e) {
7482
7614
  return [];
7483
7615
  }
@@ -7490,16 +7622,16 @@ Provide a consolidated summary of the entire session.`;
7490
7622
  if (COLLAPSED_DIRS_GLOBAL.includes(entry.name)) continue;
7491
7623
  if (entry.isDirectory()) {
7492
7624
  currentCount.value++;
7493
- countFolders(path18.join(dir, entry.name), currentCount, depth + 1);
7625
+ countFolders(path19.join(dir, entry.name), currentCount, depth + 1);
7494
7626
  }
7495
7627
  }
7496
7628
  return currentCount.value;
7497
7629
  };
7498
7630
  const getDirTree = (dir, maxDepth, prefix = "", depth = 1) => {
7499
7631
  const entries = safeReaddirWithTypes(dir);
7500
- const sep = path18.sep;
7632
+ const sep = path19.sep;
7501
7633
  if (entries.length > 100) {
7502
- return `${prefix}\u2514\u2500\u2500 ${path18.basename(dir)}${sep} ...100+ files...
7634
+ return `${prefix}\u2514\u2500\u2500 ${path19.basename(dir)}${sep} ...100+ files...
7503
7635
  `;
7504
7636
  }
7505
7637
  let result = "";
@@ -7517,7 +7649,7 @@ Provide a consolidated summary of the entire session.`;
7517
7649
  ];
7518
7650
  finalItems.forEach((item, index) => {
7519
7651
  const isLast = index === finalItems.length - 1;
7520
- const filePath = path18.join(dir, item.name);
7652
+ const filePath = path19.join(dir, item.name);
7521
7653
  const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
7522
7654
  const childPrefix = prefix + (isLast ? " " : "\u2502 ");
7523
7655
  if (item.isCollapsed) {
@@ -7602,10 +7734,10 @@ ${currentSummary}
7602
7734
  if (isBridgeConnected()) {
7603
7735
  ideBlock = "[IDE CONTEXT]\n";
7604
7736
  if (ideCtx.file_focused !== "none") {
7605
- const relFocused = path18.relative(process.cwd(), ideCtx.file_focused);
7737
+ const relFocused = path19.relative(process.cwd(), ideCtx.file_focused);
7606
7738
  const relOpened = (ideCtx.opened_editors || []).map((p) => {
7607
- const rel = path18.relative(process.cwd(), p);
7608
- return rel.startsWith("..") ? `[External] ${path18.basename(p)}` : rel;
7739
+ const rel = path19.relative(process.cwd(), p);
7740
+ return rel.startsWith("..") ? `[External] ${path19.basename(p)}` : rel;
7609
7741
  });
7610
7742
  ideBlock += `Focused File: ${relFocused}
7611
7743
  Cursor Line: ${ideCtx.cursor_line}
@@ -8149,12 +8281,12 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8149
8281
  if (keyword) {
8150
8282
  detail = keyword.replace(/["']/g, "");
8151
8283
  } else if (filePath) {
8152
- detail = path18.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
8284
+ detail = path19.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
8153
8285
  } else {
8154
8286
  const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
8155
8287
  if (m) {
8156
8288
  const val = m[1].replace(/["']/g, "");
8157
- detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val : path18.basename(val.replace(/\\/g, "/"));
8289
+ detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val : path19.basename(val.replace(/\\/g, "/"));
8158
8290
  }
8159
8291
  }
8160
8292
  }
@@ -8299,7 +8431,9 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8299
8431
  "Chat": "chat",
8300
8432
  "chat": "chat",
8301
8433
  "GenerateImage": "generate_image",
8302
- "generate_image": "generate_image"
8434
+ "generate_image": "generate_image",
8435
+ "todo": "todo",
8436
+ "Todo": "todo"
8303
8437
  };
8304
8438
  const normToolName = NORMALIZE_MAP[toolCall.toolName] || toolCall.toolName;
8305
8439
  const displayLabel = TOOL_LABELS2[normToolName] || toolCall.toolName;
@@ -8321,9 +8455,9 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8321
8455
  let totalLines = "...";
8322
8456
  let actualEndLine = eLine;
8323
8457
  try {
8324
- const absPath = path18.resolve(process.cwd(), targetPath2);
8325
- if (fs19.existsSync(absPath)) {
8326
- const content = fs19.readFileSync(absPath, "utf8");
8458
+ const absPath = path19.resolve(process.cwd(), targetPath2);
8459
+ if (fs20.existsSync(absPath)) {
8460
+ const content = fs20.readFileSync(absPath, "utf8");
8327
8461
  const lines = content.split("\n").length;
8328
8462
  totalLines = lines;
8329
8463
  actualEndLine = Math.min(eLine, lines);
@@ -8343,8 +8477,8 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8343
8477
  }
8344
8478
  } else if (normToolName === "list_files" || normToolName === "read_folder") {
8345
8479
  const action = normToolName === "list_files" ? "List" : "Viewed";
8346
- const path20 = parseArgs(toolCall.args).path;
8347
- label = `\u{1F4C2} ${action}: ${path20 === "." ? "./" : path20}`;
8480
+ const path21 = parseArgs(toolCall.args).path;
8481
+ label = `\u{1F4C2} ${action}: ${path21 === "." ? "./" : path21}`;
8348
8482
  } else if (normToolName === "write_file" || normToolName === "update_file") {
8349
8483
  const action = normToolName === "write_file" ? "Created" : "Edited";
8350
8484
  label = `\u{1F4BE} ${action}: ${parseArgs(toolCall.args).path || "..."}`;
@@ -8354,12 +8488,12 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8354
8488
  label = `\u{1F4DD} Created: ${parseArgs(toolCall.args).path || "..."}`;
8355
8489
  } else if (normToolName === "file_map") {
8356
8490
  label = `\u{1F4CB} Get Map: ${parseArgs(toolCall.args).path || "..."}`;
8357
- } else if (normToolName === "search_keyword") {
8491
+ } else if (normToolName.toLowerCase() === "search_keyword" || normToolName.toLowerCase() === "todo") {
8358
8492
  label = "";
8359
- } else if (normToolName === "generate_image") {
8493
+ } else if (normToolName.toLowerCase() === "generate_image") {
8360
8494
  const { path: argPath, outputPath, output } = parseArgs(toolCall.args);
8361
8495
  label = `\u{1F3A8} Generated: ${argPath || outputPath || output || "generated_image.png"}`;
8362
- } else if (normToolName === "exec_command" || normToolName === "ask") {
8496
+ } else if (normToolName.toLowerCase() === "exec_command" || normToolName.toLowerCase() === "ask") {
8363
8497
  label = "";
8364
8498
  } else {
8365
8499
  label = `Executed: ${toolCall.toolName}`;
@@ -8368,7 +8502,7 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8368
8502
  const { command } = parseArgs(toolCall.args);
8369
8503
  if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
8370
8504
  const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
8371
- const currentDrive = path18.resolve(process.cwd()).substring(0, 3).toLowerCase();
8505
+ const currentDrive = path19.resolve(process.cwd()).substring(0, 3).toLowerCase();
8372
8506
  const isViolating = riskyPatterns.some((pattern) => {
8373
8507
  if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
8374
8508
  const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
@@ -8397,14 +8531,18 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
8397
8531
  const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
8398
8532
  if (targetPath) {
8399
8533
  const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
8400
- const absoluteTarget = path18.resolve(targetPath);
8401
- const absoluteCwd = path18.resolve(process.cwd());
8534
+ const absoluteTarget = path19.resolve(targetPath);
8535
+ const absoluteCwd = path19.resolve(process.cwd());
8402
8536
  if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
8403
8537
  const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace.`;
8404
8538
  if (normToolName === "write_file" || normToolName === "update_file") {
8405
8539
  const action = normToolName === "write_file" ? "Write Canceled" : "Edit Canceled";
8406
8540
  const deniedLabel = `\u{1F4BE} ${action}: ${parsedArgs.path || "..."}`;
8407
- const boxWidth = Math.min(deniedLabel.length + 4, 115);
8541
+ let terminalWidth = 115;
8542
+ if (process.stdout.isTTY) {
8543
+ terminalWidth = process.stdout.columns || 120;
8544
+ }
8545
+ const boxWidth = Math.min(deniedLabel.length + 4, terminalWidth);
8408
8546
  const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8409
8547
  const boxMid = `\u2502 ${deniedLabel.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
8410
8548
  const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
@@ -8488,7 +8626,7 @@ ${boxBottom}` };
8488
8626
  const toolArgs = parseArgs(toolCall.args);
8489
8627
  const { path: filePath } = toolArgs;
8490
8628
  if (filePath) {
8491
- const absPath = path18.resolve(process.cwd(), filePath);
8629
+ const absPath = path19.resolve(process.cwd(), filePath);
8492
8630
  const normalize = (p) => p ? p.toLowerCase().replace(/\\/g, "/").replace(/^[a-z]:/, (m) => m.toUpperCase()) : "";
8493
8631
  const normAbsPath = normalize(absPath);
8494
8632
  let originalContent = "";
@@ -8498,8 +8636,8 @@ ${boxBottom}` };
8498
8636
  if (currentIDE && normFocused === normAbsPath && currentIDE.full_content) {
8499
8637
  originalContent = currentIDE.full_content;
8500
8638
  hasOriginal = true;
8501
- } else if (fs19.existsSync(absPath)) {
8502
- originalContent = fs19.readFileSync(absPath, "utf8");
8639
+ } else if (fs20.existsSync(absPath)) {
8640
+ originalContent = fs20.readFileSync(absPath, "utf8");
8503
8641
  hasOriginal = true;
8504
8642
  }
8505
8643
  originalContentForReporting = originalContent;
@@ -8526,10 +8664,14 @@ ${boxBottom}` };
8526
8664
  const successes = patchResults.filter((r) => r.success);
8527
8665
  const failures = patchResults.filter((r) => !r.success);
8528
8666
  if (successes.length === 0) {
8529
- const errorMsg = `[[TOOL RESULT]]: ERROR: Failed to apply patches to [${path18.basename(absPath)}].
8667
+ const errorMsg = `[[TOOL RESULT]]: ERROR: Failed to apply patches to [${path19.basename(absPath)}].
8530
8668
  ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
8531
- const errorLabel = `\u{1F4BE} Edited: ${path18.basename(absPath)}`.toUpperCase();
8532
- const boxWidth = Math.min(errorLabel.length + 4, 115);
8669
+ const errorLabel = `\u{1F4BE} Edited: ${path19.basename(absPath)}`.toUpperCase();
8670
+ let terminalWidth = 115;
8671
+ if (process.stdout.isTTY) {
8672
+ terminalWidth = process.stdout.columns || 120;
8673
+ }
8674
+ const boxWidth = Math.min(errorLabel.length + 4, terminalWidth);
8533
8675
  const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8534
8676
  const boxMid = `\u2502 ${errorLabel.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
8535
8677
  const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
@@ -8544,18 +8686,18 @@ ${boxBottom}` };
8544
8686
  continue;
8545
8687
  }
8546
8688
  }
8547
- yield { type: "status", content: `Opening Diff in IDE: ${path18.basename(absPath)}...` };
8689
+ yield { type: "status", content: `Opening Diff in IDE: ${path19.basename(absPath)}...` };
8548
8690
  showDiffInIDE(absPath, originalContent, modifiedContent);
8549
8691
  diffOpened = true;
8550
8692
  await new Promise((r) => setTimeout(r, 50));
8551
8693
  } else if (normToolName === "write_file") {
8552
8694
  const modifiedContent = toolArgs.content || toolArgs.newContent || "";
8553
- if (!fs19.existsSync(absPath)) {
8695
+ if (!fs20.existsSync(absPath)) {
8554
8696
  isNewFileCreated = true;
8555
- fs19.mkdirSync(path18.dirname(absPath), { recursive: true });
8556
- fs19.writeFileSync(absPath, "", "utf8");
8697
+ fs20.mkdirSync(path19.dirname(absPath), { recursive: true });
8698
+ fs20.writeFileSync(absPath, "", "utf8");
8557
8699
  }
8558
- yield { type: "status", content: `Opening New File Diff in IDE: ${path18.basename(absPath)}...` };
8700
+ yield { type: "status", content: `Opening New File Diff in IDE: ${path19.basename(absPath)}...` };
8559
8701
  showDiffInIDE(absPath, "", modifiedContent);
8560
8702
  diffOpened = true;
8561
8703
  await new Promise((r) => setTimeout(r, 50));
@@ -8591,11 +8733,11 @@ ${boxBottom}` };
8591
8733
  if (normToolName === "write_file" || normToolName === "update_file") {
8592
8734
  const { path: filePath } = parseArgs(toolCall.args);
8593
8735
  if (filePath) {
8594
- const absPath = path18.resolve(process.cwd(), filePath);
8736
+ const absPath = path19.resolve(process.cwd(), filePath);
8595
8737
  closeDiffInIDE(absPath, approval);
8596
- if (approval === "deny" && isNewFileCreated && fs19.existsSync(absPath)) {
8738
+ if (approval === "deny" && isNewFileCreated && fs20.existsSync(absPath)) {
8597
8739
  try {
8598
- fs19.unlinkSync(absPath);
8740
+ fs20.unlinkSync(absPath);
8599
8741
  } catch (e) {
8600
8742
  }
8601
8743
  }
@@ -8607,13 +8749,13 @@ ${boxBottom}` };
8607
8749
  }
8608
8750
  if (approval === "allow" && diffOpened && isBridgeConnected()) {
8609
8751
  const { path: filePath } = parseArgs(toolCall.args);
8610
- const absPath = path18.resolve(process.cwd(), filePath);
8752
+ const absPath = path19.resolve(process.cwd(), filePath);
8611
8753
  const finalIDE = await getIDEContext();
8612
8754
  let finalContent = "";
8613
8755
  if (finalIDE && finalIDE.file_focused === absPath && finalIDE.full_content) {
8614
8756
  finalContent = finalIDE.full_content;
8615
- } else if (fs19.existsSync(absPath)) {
8616
- finalContent = fs19.readFileSync(absPath, "utf8");
8757
+ } else if (fs20.existsSync(absPath)) {
8758
+ finalContent = fs20.readFileSync(absPath, "utf8");
8617
8759
  }
8618
8760
  const verifiedLines = finalContent.split(/\r?\n/);
8619
8761
  const verifiedLineCount = verifiedLines.length;
@@ -8678,7 +8820,11 @@ ${snippet2}
8678
8820
  }
8679
8821
  const action = normToolName === "write_file" ? "Written" : "Edited";
8680
8822
  const feedbackLabel = `\u{1F4BE} ${action}: ${filePath || "..."}`;
8681
- const boxWidth = Math.min(feedbackLabel.length + 4, 115);
8823
+ let terminalWidth = 115;
8824
+ if (process.stdout.isTTY) {
8825
+ terminalWidth = process.stdout.columns || 120;
8826
+ }
8827
+ const boxWidth = Math.min(feedbackLabel.length + 4, terminalWidth);
8682
8828
  const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8683
8829
  const boxMid = `\u2502 ${feedbackLabel.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
8684
8830
  const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
@@ -8711,7 +8857,11 @@ ${boxBottom}` };
8711
8857
  if (normToolName === "write_file" || normToolName === "update_file") {
8712
8858
  const action = normToolName === "write_file" ? "WRITE DENIED" : "UPDATE DENIED";
8713
8859
  const deniedLabel = `\u{1F4BE} ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
8714
- const boxWidth = Math.min(deniedLabel.length + 4, 115);
8860
+ let terminalWidth = 115;
8861
+ if (process.stdout.isTTY) {
8862
+ terminalWidth = process.stdout.columns || 120;
8863
+ }
8864
+ const boxWidth = Math.min(deniedLabel.length + 4, terminalWidth);
8715
8865
  const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8716
8866
  const boxMid = `\u2502 ${deniedLabel.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
8717
8867
  const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
@@ -8735,7 +8885,11 @@ ${boxBottom}` };
8735
8885
  }
8736
8886
  }
8737
8887
  if (label) {
8738
- const boxWidth = Math.min(label.length + 4, 115);
8888
+ let terminalWidth = 115;
8889
+ if (process.stdout.isTTY) {
8890
+ terminalWidth = process.stdout.columns || 120;
8891
+ }
8892
+ const boxWidth = Math.min(label.length + 4, terminalWidth);
8739
8893
  const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8740
8894
  const boxMid = `\u2502 ${label.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
8741
8895
  const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
@@ -8763,7 +8917,7 @@ ${boxBottom}` };
8763
8917
  try {
8764
8918
  const { path: filePath } = parseArgs(toolCall.args);
8765
8919
  if (filePath) {
8766
- const absPath = path18.resolve(process.cwd(), filePath);
8920
+ const absPath = path19.resolve(process.cwd(), filePath);
8767
8921
  const currentIDE = await getIDEContext();
8768
8922
  if (currentIDE && currentIDE.file_focused === absPath && currentIDE.full_content) {
8769
8923
  execToolContext.forcedContent = currentIDE.full_content;
@@ -8777,7 +8931,7 @@ ${boxBottom}` };
8777
8931
  if (normToolName === "write_file" && result.startsWith("SUCCESS")) {
8778
8932
  const { path: filePath } = parseArgs(toolCall.args);
8779
8933
  if (filePath) {
8780
- const absPath = path18.resolve(process.cwd(), filePath);
8934
+ const absPath = path19.resolve(process.cwd(), filePath);
8781
8935
  openFileInEditor(absPath);
8782
8936
  }
8783
8937
  }
@@ -8803,7 +8957,11 @@ ${boxBottom}` };
8803
8957
  }
8804
8958
  }
8805
8959
  const postLabel = `\u{1F50E} Searched: "${keyword}" in ${file ? `"${file}"` : "./"} \u2192 ${matchCount} Match${matchCount === 1 ? "" : "es"}`;
8806
- const boxWidth = Math.min(postLabel.length + 4, 115);
8960
+ let terminalWidth = 115;
8961
+ if (process.stdout.isTTY) {
8962
+ terminalWidth = process.stdout.columns || 120;
8963
+ }
8964
+ const boxWidth = Math.min(postLabel.length + 4, terminalWidth);
8807
8965
  const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8808
8966
  const boxMid = `\u2502 ${postLabel.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
8809
8967
  const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
@@ -8811,6 +8969,61 @@ ${boxBottom}` };
8811
8969
  ${boxMid}
8812
8970
  ${boxBottom}` };
8813
8971
  }
8972
+ if (normToolName === "todo") {
8973
+ const { method, tasks, markDone } = parseArgs(toolCall.args);
8974
+ let uiTitle = "";
8975
+ let listItems = [];
8976
+ const normalizeList = (input) => {
8977
+ if (!input) return [];
8978
+ let items = Array.isArray(input) ? input : [];
8979
+ if (items.length === 0 && typeof input === "string") {
8980
+ const trimmed = input.trim();
8981
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
8982
+ const matches = trimmed.match(/"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'/g);
8983
+ if (matches) {
8984
+ items = matches.map((m) => m.slice(1, -1).replace(/\\(.)/g, "$1"));
8985
+ } else {
8986
+ items = trimmed.slice(1, -1).split(",").map((s) => s.trim()).filter(Boolean);
8987
+ }
8988
+ } else {
8989
+ items = input.split("\n");
8990
+ }
8991
+ }
8992
+ return items.filter((l) => String(l).trim()).map((l) => {
8993
+ const t = String(l).trim();
8994
+ return t.startsWith("- [") ? t.substring(6).trim() : t;
8995
+ });
8996
+ };
8997
+ if (method === "create") {
8998
+ uiTitle = "\u{1F4C5} Created Plan";
8999
+ listItems = normalizeList(tasks).map((item) => `\u25CB ${item}`);
9000
+ } else if (method === "append") {
9001
+ uiTitle = "\u{1F4E5} Added Plan";
9002
+ listItems = normalizeList(tasks).map((item) => `\u25CB ${item}`);
9003
+ } else if (method === "get") {
9004
+ uiTitle = markDone ? "\u{1F4CC} Updated Plan" : "\u{1F4DD} Reviewed Plan";
9005
+ const content = (result || "").split("\n").slice(1).join("\n");
9006
+ listItems = content.split("\n").filter((line) => line.trim().startsWith("- [")).map((line) => {
9007
+ const trimmed = line.trim();
9008
+ const isDone = trimmed.startsWith("- [x]");
9009
+ return `${isDone ? "\x1B[32m\u25CF\x1B[0m" : "\u25CB"} ${trimmed.substring(6).trim()}`;
9010
+ });
9011
+ }
9012
+ if (uiTitle && listItems.length > 0) {
9013
+ const maxLen = Math.max(uiTitle.length, ...listItems.map((i) => i.length)) + 4;
9014
+ let terminalWidth = 100;
9015
+ if (process.stdout.isTTY) {
9016
+ terminalWidth = process.stdout.columns || 120;
9017
+ }
9018
+ const boxWidth = Math.min(maxLen, terminalWidth);
9019
+ const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
9020
+ const boxTitle = `\u2502 ${uiTitle.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
9021
+ const boxSep = `\u251C${"\u2500".repeat(boxWidth)}\u2524`;
9022
+ const boxItems = listItems.map((item) => `\u2502 ${item.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`);
9023
+ const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
9024
+ yield { type: "visual_feedback", content: [boxTop, boxTitle, boxSep, ...boxItems, boxBottom].join("\n") };
9025
+ }
9026
+ }
8814
9027
  if (normToolName === "exec_command" && settings.onExecEnd) {
8815
9028
  await new Promise((resolve) => setTimeout(resolve, 800));
8816
9029
  settings.onExecEnd();
@@ -8901,7 +9114,6 @@ ${boxBottom}` };
8901
9114
  const endsWithFormatting = superSneakyRegex.test(pureOutputText.trim());
8902
9115
  const endsNormally = /[.!?}"'`’“”]$|```$/s.test(pureOutputText) || endsWithFormatting || endsWithEmoji;
8903
9116
  if (!hasFinish2 && !hasContinue2 && !didCallTool && signalSafeText2.length > 0 && !endsNormally && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop) {
8904
- throw new Error("Silent stream cutoff (500): Model stream closed cleanly but cut off mid-sentence without signals.");
8905
9117
  }
8906
9118
  success = true;
8907
9119
  await incrementUsage("agent");
@@ -8956,9 +9168,9 @@ ${boxBottom}` };
8956
9168
  const errMsg = err.status || err.error && err.error.message || String(err);
8957
9169
  const errLog = String(err);
8958
9170
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
8959
- const agentErrDir = path18.join(LOGS_DIR, "agent");
8960
- if (!fs19.existsSync(agentErrDir)) fs19.mkdirSync(agentErrDir, { recursive: true });
8961
- fs19.appendFileSync(path18.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
9171
+ const agentErrDir = path19.join(LOGS_DIR, "agent");
9172
+ if (!fs20.existsSync(agentErrDir)) fs20.mkdirSync(agentErrDir, { recursive: true });
9173
+ fs20.appendFileSync(path19.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
8962
9174
 
8963
9175
  ----------------------------------------------------------------------
8964
9176
 
@@ -9003,7 +9215,7 @@ ${recoveryText}`
9003
9215
  yield { type: "status", content: `Error Occured. Recovering Stream...` };
9004
9216
  } else {
9005
9217
  throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
9006
- Error Log can be found in ${path18.join(LOGS_DIR, "agent", "error.log")}`);
9218
+ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9007
9219
  }
9008
9220
  } else {
9009
9221
  if (retryCount <= MAX_RETRIES) {
@@ -9021,7 +9233,7 @@ Error Log can be found in ${path18.join(LOGS_DIR, "agent", "error.log")}`);
9021
9233
  yield { type: "status", content: `Trying to reach ${modelName}...` };
9022
9234
  } else {
9023
9235
  throw new Error(`Model ${modelName} cannot be reached. (Failed ${MAX_RETRIES} times)
9024
- Error Log can be found in ${path18.join(LOGS_DIR, "agent", "error.log")}`);
9236
+ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9025
9237
  }
9026
9238
  }
9027
9239
  }
@@ -9106,9 +9318,9 @@ Error Log can be found in ${path18.join(LOGS_DIR, "agent", "error.log")}`);
9106
9318
  } catch (err) {
9107
9319
  const errorMsg = err instanceof Error ? err.message : String(err);
9108
9320
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
9109
- const agentErrDir = path18.join(LOGS_DIR, "agent");
9110
- if (!fs19.existsSync(agentErrDir)) fs19.mkdirSync(agentErrDir, { recursive: true });
9111
- fs19.appendFileSync(path18.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${err instanceof Error ? err.stack : err}
9321
+ const agentErrDir = path19.join(LOGS_DIR, "agent");
9322
+ if (!fs20.existsSync(agentErrDir)) fs20.mkdirSync(agentErrDir, { recursive: true });
9323
+ fs20.appendFileSync(path19.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${err instanceof Error ? err.stack : err}
9112
9324
 
9113
9325
  ----------------------------------------------------------------------
9114
9326
 
@@ -9909,7 +10121,7 @@ var init_RevertModal = __esm({
9909
10121
  import puppeteer4 from "puppeteer";
9910
10122
  import { exec } from "child_process";
9911
10123
  import { promisify } from "util";
9912
- import fs20 from "fs";
10124
+ import fs21 from "fs";
9913
10125
  var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
9914
10126
  var init_setup = __esm({
9915
10127
  "src/utils/setup.js"() {
@@ -9917,7 +10129,7 @@ var init_setup = __esm({
9917
10129
  checkPuppeteerReady = () => {
9918
10130
  try {
9919
10131
  const exePath = puppeteer4.executablePath();
9920
- const exists = exePath && fs20.existsSync(exePath);
10132
+ const exists = exePath && fs21.existsSync(exePath);
9921
10133
  if (exists) return true;
9922
10134
  } catch (e) {
9923
10135
  return false;
@@ -9950,8 +10162,8 @@ __export(app_exports, {
9950
10162
  import os4 from "os";
9951
10163
  import React14, { useState as useState11, useEffect as useEffect8, useRef as useRef3, useMemo as useMemo2 } from "react";
9952
10164
  import { Box as Box14, Text as Text14, useInput as useInput8, useStdout } from "ink";
9953
- import fs21 from "fs-extra";
9954
- import path19 from "path";
10165
+ import fs22 from "fs-extra";
10166
+ import path20 from "path";
9955
10167
  import { exec as exec2 } from "child_process";
9956
10168
  import { fileURLToPath } from "url";
9957
10169
  import TextInput4 from "ink-text-input";
@@ -10601,7 +10813,7 @@ function App({ args = [] }) {
10601
10813
  useEffect8(() => {
10602
10814
  async function init() {
10603
10815
  try {
10604
- const pkg = JSON.parse(fs21.readFileSync(path19.join(process.cwd(), "package.json"), "utf8"));
10816
+ const pkg = JSON.parse(fs22.readFileSync(path20.join(process.cwd(), "package.json"), "utf8"));
10605
10817
  initBridge(versionFluxflow || pkg.version || "2.0.0");
10606
10818
  } catch (e) {
10607
10819
  initBridge("2.0.0");
@@ -11104,6 +11316,7 @@ function App({ args = [] }) {
11104
11316
  { cmd: "/reset", desc: "Wipe all project data" },
11105
11317
  { cmd: "/about", desc: "Project info & credits" },
11106
11318
  { cmd: "/changelog", desc: "View latest updates" },
11319
+ { cmd: "/docs", desc: "View Documentation" },
11107
11320
  {
11108
11321
  cmd: "/fluxflow",
11109
11322
  desc: "Project management",
@@ -11390,7 +11603,7 @@ ${hintText}`, color: "magenta" }];
11390
11603
  if (val === "xhigh") {
11391
11604
  formattedLevel = "xHigh";
11392
11605
  }
11393
- if (!isBypass && mode === "Flow" && (formattedLevel === "Medium" || formattedLevel === "High" || formattedLevel === "xHigh")) {
11606
+ if (!isBypass && mode === "Flow" && (formattedLevel === "High" || formattedLevel === "xHigh")) {
11394
11607
  setMessages((prev) => {
11395
11608
  setCompletedIndex(prev.length + 1);
11396
11609
  return [...prev, { id: Date.now(), role: "system", text: `[RESTRICTED] "${formattedLevel}" is restricted in Flow mode. Switch to Flux to enable Higher Thinking Levels.`, isMeta: true }];
@@ -11467,7 +11680,7 @@ ${hintText}`, color: "magenta" }];
11467
11680
  }
11468
11681
  case "/export": {
11469
11682
  const exportFile = `export-fluxflow-${chatId}.txt`;
11470
- const exportPath = path19.join(process.cwd(), exportFile);
11683
+ const exportPath = path20.join(process.cwd(), exportFile);
11471
11684
  const exportLines = [];
11472
11685
  let insideAgentBlock = false;
11473
11686
  for (let i = 0; i < messages.length; i++) {
@@ -11519,7 +11732,7 @@ ${hintText}`, color: "magenta" }];
11519
11732
  }
11520
11733
  const fileContent = exportLines.join("\n");
11521
11734
  try {
11522
- fs21.writeFileSync(exportPath, fileContent, "utf8");
11735
+ fs22.writeFileSync(exportPath, fileContent, "utf8");
11523
11736
  setMessages((prev) => {
11524
11737
  setCompletedIndex(prev.length + 1);
11525
11738
  return [...prev, {
@@ -11566,12 +11779,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
11566
11779
  setCompletedIndex(prev.length + 1);
11567
11780
  return [...prev, { id: Date.now(), role: "system", text: "[NUCLEAR] Initiating reset...", isMeta: true }];
11568
11781
  });
11569
- if (fs21.existsSync(LOGS_DIR)) fs21.removeSync(LOGS_DIR);
11570
- if (fs21.existsSync(SECRET_DIR)) fs21.removeSync(SECRET_DIR);
11571
- if (fs21.existsSync(SETTINGS_FILE)) fs21.removeSync(SETTINGS_FILE);
11782
+ if (fs22.existsSync(LOGS_DIR)) fs22.removeSync(LOGS_DIR);
11783
+ if (fs22.existsSync(SECRET_DIR)) fs22.removeSync(SECRET_DIR);
11784
+ if (fs22.existsSync(SETTINGS_FILE)) fs22.removeSync(SETTINGS_FILE);
11572
11785
  try {
11573
- const items = fs21.readdirSync(FLUXFLOW_DIR);
11574
- if (items.length === 0) fs21.removeSync(FLUXFLOW_DIR);
11786
+ const items = fs22.readdirSync(FLUXFLOW_DIR);
11787
+ if (items.length === 0) fs22.removeSync(FLUXFLOW_DIR);
11575
11788
  } catch (e) {
11576
11789
  }
11577
11790
  setTimeout(() => {
@@ -11609,6 +11822,23 @@ ${list || "No saved chats found."}`, isMeta: true }];
11609
11822
  });
11610
11823
  break;
11611
11824
  }
11825
+ case "/docs": {
11826
+ if (!DOCS_URL) {
11827
+ setMessages((prev) => {
11828
+ setCompletedIndex(prev.length + 1);
11829
+ return [...prev, { id: Date.now(), role: "system", text: `[BROWSER] Documentation URL is not configured.`, isMeta: true }];
11830
+ });
11831
+ break;
11832
+ }
11833
+ const platform = process.platform;
11834
+ const command = platform === "win32" ? "start" : platform === "darwin" ? "open" : "xdg-open";
11835
+ exec2(`${command} ${DOCS_URL}`);
11836
+ setMessages((prev) => {
11837
+ setCompletedIndex(prev.length + 1);
11838
+ return [...prev, { id: Date.now(), role: "system", text: `[BROWSER] Opening documentation: ${DOCS_URL}`, isMeta: true }];
11839
+ });
11840
+ break;
11841
+ }
11612
11842
  case "/fluxflow": {
11613
11843
  const args2 = parts.slice(1);
11614
11844
  if (args2[0] === "init") {
@@ -11628,15 +11858,15 @@ ${list || "No saved chats found."}`, isMeta: true }];
11628
11858
  # SKILLS & WORKFLOWS
11629
11859
  - [Define custom step-by-step recipes for this project here]
11630
11860
  `;
11631
- const filePath = path19.join(process.cwd(), "FluxFlow.md");
11632
- if (fs21.pathExistsSync(filePath)) {
11861
+ const filePath = path20.join(process.cwd(), "FluxFlow.md");
11862
+ if (fs22.pathExistsSync(filePath)) {
11633
11863
  setMessages((prev) => {
11634
11864
  setCompletedIndex(prev.length + 1);
11635
11865
  return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
11636
11866
  });
11637
11867
  } else {
11638
11868
  try {
11639
- fs21.writeFileSync(filePath, template);
11869
+ fs22.writeFileSync(filePath, template);
11640
11870
  setMessages((prev) => {
11641
11871
  setCompletedIndex(prev.length + 1);
11642
11872
  return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "[SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
@@ -13026,7 +13256,7 @@ Selection: ${val}`,
13026
13256
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "grey", width: Math.min(100, (stdout?.columns || 100) - 2), marginTop: 0, marginBottom: 0 }, /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { bold: true }, gradient2(["blue", "purple"])("Agent powering down. Goodbye!"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, chatId)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( ", /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "\u2713 ", sessionToolSuccess), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "yellow" }, "\u2298 ", sessionToolDenied), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "\u2715 ", sessionToolFailure), " )")), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, successRate, "%")), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Code Changes:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "+", linesAdded), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "-", linesRemoved))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 16 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionImageCount)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits")))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB API Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Tool Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
13027
13257
  })())));
13028
13258
  }
13029
- var getIDEName, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles;
13259
+ var getIDEName, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles;
13030
13260
  var init_app = __esm({
13031
13261
  async "src/app.jsx"() {
13032
13262
  init_MultilineInput();
@@ -13103,15 +13333,16 @@ var init_app = __esm({
13103
13333
  height
13104
13334
  },
13105
13335
  /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1, width: Math.min(80, width - 4), justifyContent: "flex-start" }, /* @__PURE__ */ React14.createElement(Text14, null, getFluxLogo(versionFluxflow))),
13106
- /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", paddingX: 3, paddingY: 1, width: Math.min(80, width - 4) }, /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "cyan", textAlign: "center" }, "\u{1F680} UPGRADE YOUR WORKFLOW"), /* @__PURE__ */ React14.createElement(Box14, { marginY: 1, flexDirection: "column", alignItems: "left" }, /* @__PURE__ */ React14.createElement(Text14, null, "You're in ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "cyan" }, ideName), ", but the ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "magenta" }, "FluxFlow-CLI Companion"), " is not installed."), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Real-time file & cursor tracking"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Auto-open files created by agent"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native DIFF viewer for AI edits"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Direct IDE context sharing"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Surgical Diagnostic Sync"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native Right-Click \u276F Chat integration"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Live Status in IDE"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Clickable terminal-to-code links"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, options.map((opt, i) => /* @__PURE__ */ React14.createElement(Box14, { key: i }, /* @__PURE__ */ React14.createElement(Text14, { color: selectedIndex === i ? "yellow" : "white", bold: selectedIndex === i }, selectedIndex === i ? " \u276F " : " ", opt.label)))), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React14.createElement(Text14, { dimColor: true, italic: true }, "(Use arrows to navigate, Enter to select)")))
13336
+ /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "double", borderColor: "grey", paddingX: 3, paddingY: 1, width: Math.min(80, width - 4) }, /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white", textAlign: "center" }, "\u{1F680} UPGRADE YOUR WORKFLOW"), /* @__PURE__ */ React14.createElement(Box14, { marginY: 1, flexDirection: "column", alignItems: "left" }, /* @__PURE__ */ React14.createElement(Text14, null, "You're in ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "cyan" }, ideName), ", but the ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white" }, "FluxFlow-CLI Companion"), " is not installed."), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Real-time file & cursor tracking"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Auto-open files created by agent"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native DIFF viewer for AI edits"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Direct IDE context sharing"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Surgical Diagnostic Sync"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Native Right-Click \u276F Chat integration"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Live Status in IDE"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " \u2705 Clickable terminal-to-code links"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, options.map((opt, i) => /* @__PURE__ */ React14.createElement(Box14, { key: i }, /* @__PURE__ */ React14.createElement(Text14, { color: selectedIndex === i ? "yellow" : "white", bold: selectedIndex === i }, selectedIndex === i ? " \u276F " : " ", opt.label)))), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React14.createElement(Text14, { dimColor: true, italic: true }, "(Use arrows to navigate, Enter to select)")))
13107
13337
  );
13108
13338
  };
13109
13339
  SESSION_START_TIME = Date.now();
13110
- CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
13340
+ CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog";
13341
+ DOCS_URL = "https://fluxflow-cli.onrender.com/";
13111
13342
  linesAdded = 0;
13112
13343
  linesRemoved = 0;
13113
- packageJsonPath = path19.join(path19.dirname(fileURLToPath(import.meta.url)), "../package.json");
13114
- packageJson = JSON.parse(fs21.readFileSync(packageJsonPath, "utf8"));
13344
+ packageJsonPath = path20.join(path20.dirname(fileURLToPath(import.meta.url)), "../package.json");
13345
+ packageJson = JSON.parse(fs22.readFileSync(packageJsonPath, "utf8"));
13115
13346
  versionFluxflow = packageJson.version;
13116
13347
  updatedOn = packageJson.date || "2026-05-20";
13117
13348
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 0 }, /* @__PURE__ */ React14.createElement(
@@ -13207,19 +13438,19 @@ var init_app = __esm({
13207
13438
  const fileList = [];
13208
13439
  const scan = (currentDir) => {
13209
13440
  try {
13210
- const files = fs21.readdirSync(currentDir);
13441
+ const files = fs22.readdirSync(currentDir);
13211
13442
  for (const file of files) {
13212
13443
  if (["node_modules", ".git", ".gemini", "dist", "build", ".next", ".cache", "out"].includes(file)) {
13213
13444
  continue;
13214
13445
  }
13215
- const filePath = path19.join(currentDir, file);
13216
- const stat = fs21.statSync(filePath);
13446
+ const filePath = path20.join(currentDir, file);
13447
+ const stat = fs22.statSync(filePath);
13217
13448
  if (stat.isDirectory()) {
13218
13449
  scan(filePath);
13219
13450
  } else {
13220
13451
  fileList.push({
13221
13452
  name: file,
13222
- relativePath: path19.relative(process.cwd(), filePath)
13453
+ relativePath: path20.relative(process.cwd(), filePath)
13223
13454
  });
13224
13455
  }
13225
13456
  }
@@ -13254,11 +13485,11 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
13254
13485
  const isVersion = args.includes("--version") || args.includes("-v");
13255
13486
  const isUpdate = args[0] === "--update";
13256
13487
  if (isVersion || isHelp || isHelpCommands || isUpdate) {
13257
- const fs22 = await import("fs");
13258
- const path20 = await import("path");
13488
+ const fs23 = await import("fs");
13489
+ const path21 = await import("path");
13259
13490
  const { fileURLToPath: fileURLToPath3 } = await import("url");
13260
- const packageJsonPath2 = path20.join(path20.dirname(fileURLToPath3(import.meta.url)), "../package.json");
13261
- const packageJson2 = JSON.parse(fs22.readFileSync(packageJsonPath2, "utf8"));
13491
+ const packageJsonPath2 = path21.join(path21.dirname(fileURLToPath3(import.meta.url)), "../package.json");
13492
+ const packageJson2 = JSON.parse(fs23.readFileSync(packageJsonPath2, "utf8"));
13262
13493
  const versionFluxflow2 = packageJson2.version;
13263
13494
  if (isVersion) {
13264
13495
  console.log(`v${versionFluxflow2}`);
@@ -13311,6 +13542,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
13311
13542
  /reset Wipe all project data
13312
13543
  /about Project info & credits
13313
13544
  /changelog View latest updates
13545
+ /docs View documentation
13314
13546
  /fluxflow init Create FluxFlow.md template
13315
13547
  /update check Check for new version
13316
13548
  /update latest Install latest release`);
@@ -13371,7 +13603,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
13371
13603
  { label: "Custom Command", value: "custom" }
13372
13604
  ];
13373
13605
  const CustomItem2 = ({ label, isSelected }) => {
13374
- return /* @__PURE__ */ React16.createElement(Box15, { width: "100%" }, /* @__PURE__ */ React16.createElement(Text15, { color: isSelected ? "cyan" : "gray", bold: isSelected }, "\u2514\u2500 ", isSelected ? "\u25C9" : "\u25CB", " ", label));
13606
+ return /* @__PURE__ */ React16.createElement(Box15, { width: "100%" }, /* @__PURE__ */ React16.createElement(Text15, { bold: isSelected }, "\u2514\u2500 ", isSelected ? "\x1B[32m\u25CF\x1B[0m" : "\u25CB", " ", label));
13375
13607
  };
13376
13608
  let unmountFn;
13377
13609
  const PromptComponent = () => {
@@ -13424,7 +13656,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
13424
13656
  manager = settings?.systemSettings?.updateManager || settings?.updateManager;
13425
13657
  } catch (e) {
13426
13658
  }
13427
- if (!manager) {
13659
+ if (true) {
13428
13660
  const result = await promptPackageManager();
13429
13661
  manager = result.manager;
13430
13662
  customCommand = result.customCommand;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.7.0",
4
- "date": "2026-06-15",
3
+ "version": "2.7.1",
4
+ "date": "2026-06-16",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",