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.
- package/TOOLS.md +78 -50
- package/dist/fluxflow.js +362 -130
- 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
|
-
| **
|
|
10
|
-
| **Web Scrape** | ✅ | ✅ |
|
|
11
|
-
| **Write
|
|
12
|
-
| **
|
|
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
|
-
##
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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)]]
|
|
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)]]
|
|
2162
|
-
2. [[tool:functions.WebScrape(url="...")]]
|
|
2163
|
-
|
|
2164
|
-
${mode === "Flux" ? `-
|
|
2165
|
-
1. [[tool:functions.ReadFile(path="...", startLine=number, endLine=number)]]
|
|
2166
|
-
2. [[tool:functions.FileMap(path="path/file")]]
|
|
2167
|
-
3. [[tool:functions.ReadFolder(path="...")]]
|
|
2168
|
-
4. [[tool:functions.PatchFile(path="...", replaceContent1="exact string", newContent1="...", ...MAX 10)]]
|
|
2169
|
-
5. [[tool:functions.WriteFile(path="...", content="...")]]
|
|
2170
|
-
6. [[tool:functions.SearchKeyword(keyword="...", file="optional")]]
|
|
2171
|
-
7. [[tool:functions.Run(command="...")]]
|
|
2172
|
-
8. [[tool:functions.
|
|
2173
|
-
|
|
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:
|
|
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).
|
|
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 (
|
|
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
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
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
|
|
6029
|
-
import
|
|
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 ?
|
|
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 =
|
|
6795
|
-
if (!
|
|
6796
|
-
|
|
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 =
|
|
6806
|
-
|
|
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 =
|
|
7156
|
-
if (!
|
|
7157
|
-
|
|
7158
|
-
|
|
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 =
|
|
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 =
|
|
7240
|
-
if (
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
7632
|
+
const sep = path19.sep;
|
|
7501
7633
|
if (entries.length > 100) {
|
|
7502
|
-
return `${prefix}\u2514\u2500\u2500 ${
|
|
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 =
|
|
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 =
|
|
7737
|
+
const relFocused = path19.relative(process.cwd(), ideCtx.file_focused);
|
|
7606
7738
|
const relOpened = (ideCtx.opened_editors || []).map((p) => {
|
|
7607
|
-
const rel =
|
|
7608
|
-
return rel.startsWith("..") ? `[External] ${
|
|
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 =
|
|
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 :
|
|
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 =
|
|
8325
|
-
if (
|
|
8326
|
-
const content =
|
|
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
|
|
8347
|
-
label = `\u{1F4C2} ${action}: ${
|
|
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 =
|
|
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 =
|
|
8401
|
-
const absoluteCwd =
|
|
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
|
-
|
|
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 =
|
|
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 (
|
|
8502
|
-
originalContent =
|
|
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 [${
|
|
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: ${
|
|
8532
|
-
|
|
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: ${
|
|
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 (!
|
|
8695
|
+
if (!fs20.existsSync(absPath)) {
|
|
8554
8696
|
isNewFileCreated = true;
|
|
8555
|
-
|
|
8556
|
-
|
|
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: ${
|
|
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 =
|
|
8736
|
+
const absPath = path19.resolve(process.cwd(), filePath);
|
|
8595
8737
|
closeDiffInIDE(absPath, approval);
|
|
8596
|
-
if (approval === "deny" && isNewFileCreated &&
|
|
8738
|
+
if (approval === "deny" && isNewFileCreated && fs20.existsSync(absPath)) {
|
|
8597
8739
|
try {
|
|
8598
|
-
|
|
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 =
|
|
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 (
|
|
8616
|
-
finalContent =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
8960
|
-
if (!
|
|
8961
|
-
|
|
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 ${
|
|
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 ${
|
|
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 =
|
|
9110
|
-
if (!
|
|
9111
|
-
|
|
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
|
|
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 &&
|
|
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
|
|
9954
|
-
import
|
|
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(
|
|
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 === "
|
|
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 =
|
|
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
|
-
|
|
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 (
|
|
11570
|
-
if (
|
|
11571
|
-
if (
|
|
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 =
|
|
11574
|
-
if (items.length === 0)
|
|
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 =
|
|
11632
|
-
if (
|
|
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
|
-
|
|
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: "
|
|
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
|
|
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 =
|
|
13114
|
-
packageJson = JSON.parse(
|
|
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 =
|
|
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 =
|
|
13216
|
-
const stat =
|
|
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:
|
|
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
|
|
13258
|
-
const
|
|
13488
|
+
const fs23 = await import("fs");
|
|
13489
|
+
const path21 = await import("path");
|
|
13259
13490
|
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
13260
|
-
const packageJsonPath2 =
|
|
13261
|
-
const packageJson2 = JSON.parse(
|
|
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, {
|
|
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 (
|
|
13659
|
+
if (true) {
|
|
13428
13660
|
const result = await promptPackageManager();
|
|
13429
13661
|
manager = result.manager;
|
|
13430
13662
|
customCommand = result.customCommand;
|