fluxflow-cli 1.1.2 → 1.1.3

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/ARCHITECTURE.md CHANGED
@@ -1,48 +1,48 @@
1
- # 🏛️ Architecture & Design
2
-
3
- Flux Flow is built on a modern, reactive stack that brings web-like development paradigms to the terminal. It utilizes a custom agentic loop for reasoning and a unique dual-model system for background processing.
4
-
5
- ## UI Layer: React & Ink
6
-
7
- The entire terminal interface is built using **React** via the [Ink](https://github.com/vadimdemedes/ink) renderer.
8
- - **Component-Based**: The UI is composed of isolated, reusable React components (`ChatLayout`, `StatusBar`, `CommandMenu`, `TerminalBox`, `ProfileForm`).
9
- - **Reactive State**: The application uses React hooks (`useState`, `useEffect`) to manage user input, application mode, model selection, and the terminal's resizing events.
10
- - **Zero-Render Overheads**: Critical performance trackers, like the session start time, are kept outside the React render cycle to maintain terminal responsiveness during high-speed AI text streaming.
11
-
12
- ## The Agentic Loop
13
-
14
- The core intelligence of Flux Flow resides in `src/utils/ai.js`. It does not rely on opaque third-party agent frameworks; instead, it uses a custom, highly transparent string-based protocol powered by an asynchronous generator (`async function*`). This approach allows for real-time UI updates while managing complex multi-step reasoning.
15
-
16
- The execution flow of a single user prompt follows this loop:
17
-
18
- 1. **Context Assembly**: The user's prompt is combined with the system instructions, temporary session context, persistent user memories, and the current chat history. If the history gets too large (e.g., >128k tokens) and compression is disabled, it is gracefully truncated.
19
- 2. **Stream Processing**: The main loop initiates a streaming request to the Gemini API (`client.models.generateContentStream`). It yields chunks of text and status updates directly back to the React UI as they arrive.
20
- 3. **Detection & Tool Execution**: Once the stream completes for a given turn, the entire response is scanned for tool calls using a custom regex and bracket-balancing parser (looking for `tool:functions.tool_name(args...)`).
21
- - If tools are found, the loop pauses.
22
- - Each tool is dispatched to its respective handler in `src/tools/`.
23
- - Tool outputs are collected and appended to the context as `[TOOL_RESULT]: ...`.
24
- 4. **Security Governance**: During tool execution, the loop enforces security checks (e.g., blocking `exec_command` from accessing system root drives if "External Workspace Access" is off) and pauses for Human-in-the-Loop (HITL) approval if necessary.
25
- 5. **Turn Management & Continuation**: The model is instructed to append `[turn: finish]` if its goal is complete, or `[turn: continue]` if it expects tool results.
26
- - If tools were called or `[turn: continue]` is present, the loop increments and re-prompts the model with the newly gathered `[TOOL_RESULT]` data.
27
- - If `[turn: finish]` is detected and no further tools were called, the main loop terminates, passing the final synthesized context to the background Janitor process.
28
- 6. **Loop Limits & Resilience**: To prevent infinite loops or excessive API usage, **Flux mode** is capped at 50 iterations per user prompt, while **Flow mode** is capped at 5.
29
- - **Multi-Stage Failover**: The loop features a sophisticated 8-attempt retry engine with random backoff (800ms - 2s).
30
- - **Critical Fallback Pivot**: If the primary model fails 5 consecutive times, the agent surgically pivots to a lighter, high-concurrency fallback model (`gemini-3.1-flash-lite-preview`) for the final 3 attempts to ensure session navigation through API congestion.
31
-
32
- ## The Dual-Model System
33
-
34
- To maintain a fast, snappy UI while still performing complex data management, Flux Flow employs two separate AI models for every interaction:
35
-
36
- ### 1. The Main Agent
37
- - **Responsibility**: Direct user interaction, reasoning, and tool execution.
38
- - **Behavior**: Streams text directly to the UI. It focuses entirely on solving the user's immediate problem or answering their question.
39
-
40
- ### 2. The Janitor (Background Process)
41
- - **Responsibility**: System maintenance, long-term memory extraction, and chat summarization.
42
- - **Behavior**: After the Main Agent finishes its loop, the entire context (User Prompt + Agent Raws) is sent to the Janitor model.
43
- - **Headless Operation**: The Janitor is explicitly instructed to be a "silent background system process" with "no mouth." It *only* outputs valid tool calls (e.g., updating the chat title or saving a new user preference to the persistent memory vault).
44
-
45
- ## Data Persistence & Safety
46
-
47
- - **High-Fidelity Lock**: Because both the UI and the Janitor model may attempt to write to the `history.json` file simultaneously, a Promise-based `WRITE_LOCK` (`src/utils/history.js`) is utilized. This prevents race conditions and ensures data integrity.
1
+ # 🏛️ Architecture & Design
2
+
3
+ Flux Flow is built on a modern, reactive stack that brings web-like development paradigms to the terminal. It utilizes a custom agentic loop for reasoning and a unique dual-model system for background processing.
4
+
5
+ ## UI Layer: React & Ink
6
+
7
+ The entire terminal interface is built using **React** via the [Ink](https://github.com/vadimdemedes/ink) renderer.
8
+ - **Component-Based**: The UI is composed of isolated, reusable React components (`ChatLayout`, `StatusBar`, `CommandMenu`, `TerminalBox`, `ProfileForm`).
9
+ - **Reactive State**: The application uses React hooks (`useState`, `useEffect`) to manage user input, application mode, model selection, and the terminal's resizing events.
10
+ - **Zero-Render Overheads**: Critical performance trackers, like the session start time, are kept outside the React render cycle to maintain terminal responsiveness during high-speed AI text streaming.
11
+
12
+ ## The Agentic Loop
13
+
14
+ The core intelligence of Flux Flow resides in `src/utils/ai.js`. It does not rely on opaque third-party agent frameworks; instead, it uses a custom, highly transparent string-based protocol powered by an asynchronous generator (`async function*`). This approach allows for real-time UI updates while managing complex multi-step reasoning.
15
+
16
+ The execution flow of a single user prompt follows this loop:
17
+
18
+ 1. **Context Assembly**: The user's prompt is combined with the system instructions, temporary session context, persistent user memories, and the current chat history. If the history gets too large (e.g., >128k tokens) and compression is disabled, it is gracefully truncated.
19
+ 2. **Stream Processing**: The main loop initiates a streaming request to the Gemini API (`client.models.generateContentStream`). It yields chunks of text and status updates directly back to the React UI as they arrive.
20
+ 3. **Detection & Tool Execution**: Once the stream completes for a given turn, the entire response is scanned for tool calls using a custom regex and bracket-balancing parser (looking for `tool:functions.tool_name(args...)`).
21
+ - If tools are found, the loop pauses.
22
+ - Each tool is dispatched to its respective handler in `src/tools/`.
23
+ - Tool outputs are collected and appended to the context as `[TOOL_RESULT]: ...`.
24
+ 4. **Security Governance**: During tool execution, the loop enforces security checks (e.g., blocking `exec_command` from accessing system root drives if "External Workspace Access" is off) and pauses for Human-in-the-Loop (HITL) approval if necessary.
25
+ 5. **Turn Management & Continuation**: The model is instructed to append `[turn: finish]` if its goal is complete, or `[turn: continue]` if it expects tool results.
26
+ - If tools were called or `[turn: continue]` is present, the loop increments and re-prompts the model with the newly gathered `[TOOL_RESULT]` data.
27
+ - If `[turn: finish]` is detected and no further tools were called, the main loop terminates, passing the final synthesized context to the background Janitor process.
28
+ 6. **Loop Limits & Resilience**: To prevent infinite loops or excessive API usage, **Flux mode** is capped at 50 iterations per user prompt, while **Flow mode** is capped at 5.
29
+ - **Multi-Stage Failover**: The loop features a sophisticated 8-attempt retry engine with random backoff (800ms - 2s).
30
+ - **Critical Fallback Pivot**: If the primary model fails 5 consecutive times, the agent surgically pivots to a lighter, high-concurrency fallback model (`gemini-3.1-flash-lite-preview`) for the final 3 attempts to ensure session navigation through API congestion.
31
+
32
+ ## The Dual-Model System
33
+
34
+ To maintain a fast, snappy UI while still performing complex data management, Flux Flow employs two separate AI models for every interaction:
35
+
36
+ ### 1. The Main Agent
37
+ - **Responsibility**: Direct user interaction, reasoning, and tool execution.
38
+ - **Behavior**: Streams text directly to the UI. It focuses entirely on solving the user's immediate problem or answering their question.
39
+
40
+ ### 2. The Janitor (Background Process)
41
+ - **Responsibility**: System maintenance, long-term memory extraction, and chat summarization.
42
+ - **Behavior**: After the Main Agent finishes its loop, the entire context (User Prompt + Agent Raws) is sent to the Janitor model.
43
+ - **Headless Operation**: The Janitor is explicitly instructed to be a "silent background system process" with "no mouth." It *only* outputs valid tool calls (e.g., updating the chat title or saving a new user preference to the persistent memory vault).
44
+
45
+ ## Data Persistence & Safety
46
+
47
+ - **High-Fidelity Lock**: Because both the UI and the Janitor model may attempt to write to the `history.json` file simultaneously, a Promise-based `WRITE_LOCK` (`src/utils/history.js`) is utilized. This prevents race conditions and ensures data integrity.
48
48
  - **Encryption**: User secrets and persistent memories (`secret/memories.json`) are handled by `src/utils/crypto.js` to ensure local privacy.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Kushal Roy Chowdhury
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kushal Roy Chowdhury
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/TOOLS.md CHANGED
@@ -1,48 +1,48 @@
1
- # 🧰 Agent Tools & Capabilities
2
-
3
- Flux Flow provides a robust set of tools that allow the AI to interact with the file system, execute code, and search the web. The availability of these tools depends on the active operating mode.
4
-
5
- ## Tool Availability by Mode
6
-
7
- | Tool | Flux Mode (Dev) | Flow Mode (Chat) |
8
- | :--- | :---: | :---: |
9
- | **Web Search** | ✅ | ✅ |
10
- | **Web Scrape** | ✅ | ✅ |
11
- | **View/Read Files** | ✅ | ❌ |
12
- | **Write/Update Files** | ✅ | ❌ |
13
- | **Execute Commands** | ✅ | ❌ |
14
-
15
- ---
16
-
17
- ## Core Tools
18
-
19
- ### 🌐 Web & Research
20
- - **`web_search`**: Uses DuckDuckGo to find up-to-date information on the internet. Crucial for answering questions about recent events or unlearned documentation.
21
- - **`web_scrape`**: Extracts the detailed text content from a specific URL, allowing the agent to read documentation or articles.
22
-
23
- ### 📁 File System Operations
24
- - **`list_files`**: Lists the contents of a directory to help the agent understand the project structure.
25
- - **`read_folder`**: Provides detailed statistics and metadata about a directory's contents.
26
- - **`view_file`**: Reads the content of a file. Supports reading specific line ranges (`start_line`, `end_line`) to manage context size efficiently.
27
-
28
- ### ✍️ Code Editing
29
- - **`write_file`**: Creates a new file or completely overwrites an existing one with new content.
30
- - **`update_file` (Smart Patching)**: Surgically replaces a specific block of text within a file.
31
- - *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.
32
-
33
- ### 💻 Terminal Execution
34
- - **`exec_command`**: Runs a shell command directly in the terminal using Node's `child_process.spawn`.
35
- - *Context Aware*: Runs in the current working directory.
36
- - *Cross-Platform*: Uses `shell: true` to handle Windows `.cmd`/`.bat` files natively.
37
-
38
- ---
39
-
40
- ## Memory Management
41
-
42
- The memory tool (`memory.js`) is primarily used by the background **Janitor** model, but can be accessed by the main agent if necessary.
43
-
44
- - **Temporary Context (`action='temp'`)**: Saves a rolling summary of the current session to maintain conversational context without bloating the main prompt history.
45
- - **Persistent User Memory (`action='user'`)**:
46
- - The Janitor analyzes conversations to detect user preferences, hobbies, or instructions.
47
- - It uses `add`, `update`, or `delete` methods to manage facts in the encrypted `memories.json` vault.
1
+ # 🧰 Agent Tools & Capabilities
2
+
3
+ Flux Flow provides a robust set of tools that allow the AI to interact with the file system, execute code, and search the web. The availability of these tools depends on the active operating mode.
4
+
5
+ ## Tool Availability by Mode
6
+
7
+ | Tool | Flux Mode (Dev) | Flow Mode (Chat) |
8
+ | :--- | :---: | :---: |
9
+ | **Web Search** | ✅ | ✅ |
10
+ | **Web Scrape** | ✅ | ✅ |
11
+ | **View/Read Files** | ✅ | ❌ |
12
+ | **Write/Update Files** | ✅ | ❌ |
13
+ | **Execute Commands** | ✅ | ❌ |
14
+
15
+ ---
16
+
17
+ ## Core Tools
18
+
19
+ ### 🌐 Web & Research
20
+ - **`web_search`**: Uses DuckDuckGo to find up-to-date information on the internet. Crucial for answering questions about recent events or unlearned documentation.
21
+ - **`web_scrape`**: Extracts the detailed text content from a specific URL, allowing the agent to read documentation or articles.
22
+
23
+ ### 📁 File System Operations
24
+ - **`list_files`**: Lists the contents of a directory to help the agent understand the project structure.
25
+ - **`read_folder`**: Provides detailed statistics and metadata about a directory's contents.
26
+ - **`view_file`**: Reads the content of a file. Supports reading specific line ranges (`start_line`, `end_line`) to manage context size efficiently.
27
+
28
+ ### ✍️ Code Editing
29
+ - **`write_file`**: Creates a new file or completely overwrites an existing one with new content.
30
+ - **`update_file` (Smart Patching)**: Surgically replaces a specific block of text within a file.
31
+ - *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.
32
+
33
+ ### 💻 Terminal Execution
34
+ - **`exec_command`**: Runs a shell command directly in the terminal using Node's `child_process.spawn`.
35
+ - *Context Aware*: Runs in the current working directory.
36
+ - *Cross-Platform*: Uses `shell: true` to handle Windows `.cmd`/`.bat` files natively.
37
+
38
+ ---
39
+
40
+ ## Memory Management
41
+
42
+ The memory tool (`memory.js`) is primarily used by the background **Janitor** model, but can be accessed by the main agent if necessary.
43
+
44
+ - **Temporary Context (`action='temp'`)**: Saves a rolling summary of the current session to maintain conversational context without bloating the main prompt history.
45
+ - **Persistent User Memory (`action='user'`)**:
46
+ - The Janitor analyzes conversations to detect user preferences, hobbies, or instructions.
47
+ - It uses `add`, `update`, or `delete` methods to manage facts in the encrypted `memories.json` vault.
48
48
  - These memories are injected into the system prompt of *future* sessions, allowing Flux Flow to learn and adapt to the user over time.
package/UI_FEATURES.md CHANGED
@@ -1,67 +1,67 @@
1
- # 🎮 User Interface & Interaction Features
2
-
3
- Flux Flow is designed to be a high-performance terminal application. Beyond basic chat, it includes a variety of advanced UI features and human-in-the-loop controls to keep you in command of the agent.
4
-
5
- ## ⌨️ Command System
6
-
7
- You can control the application using `/` commands directly in the chat input:
8
-
9
- - **/mode [flux|flow]**: Quickly switch between **Flux** (Dev) and **Flow** (Chat) modes. Using it without arguments opens the selection menu.
10
- - **/thinking [low|medium|high|max|show|hide]**: Adjust reasoning depth or toggle visibility of the thinking process. Using it without arguments opens the selection menu.
11
- - **/model [name]**: Choose which AI model to use for the main interaction.
12
- - **/key**: Open the API Key management view to update or remove your credentials.
13
- - **/settings**: Access the system configuration menu.
14
- - **/profile**: Update your name, nickname, and custom instructions.
15
- - **/memory**: View and manage the persistent memories extracted by the Janitor.
16
- - **/resume <chat-id>**: Switch back to a previous conversation.
17
- - **/changelog**: Open the project's changelog in your default browser.
18
- - **/help**: List all available commands.
19
-
20
- ### Command Shortcuts
21
-
22
- For power users, several commands support direct arguments to skip the menus:
23
- - ` /mode flux ` or ` /mode flow `
24
- - ` /thinking low ` / ` /thinking medium ` / ` /thinking high ` / ` /thinking max `
25
- - ` /thinking show ` / ` /thinking hide ` (Toggles thinking process visibility)
26
- - ` /model gemini-3.1-pro-preview ` (Switches model directly)
27
-
28
- ## 🧠 Thinking Levels & Visualization
29
-
30
- Flux Flow separates the model's "internal monologue" (reasoning) from its final response using `<think>` tags.
31
-
32
- - **Thinking Levels**: Depending on the mode, you can choose from **Low**, **Medium**, **High**, or **Max**. Higher levels allow the agent more "space" to reason through complex architecture or debugging problems.
33
- - **Show/Hide Thinking**: You can toggle the visibility of the thinking process using `/thinking show/hide`.
34
- - When **Hidden**, the agent doesn't just disappear; it provides a "minimalist" view showing only the core **Headings** and **Action Steps** (bolded lines) from its reasoning. This keeps you informed of its current "step" without cluttering the screen with detailed internal monologue.
35
-
36
- ## 🛡️ Human-in-the-Loop (HITL) Verification
37
-
38
- Security and safety are paramount when an AI has access to your file system and terminal. Flux Flow implements several layers of verification:
39
-
40
- ### Tool Approval
41
- By default, the agent **cannot** execute dangerous actions without your consent.
42
- - **Terminal Approval**: If the agent attempts to run a shell command (`exec_command`), a dedicated approval screen appears showing the exact command. You can **Allow** or **Deny** the execution.
43
- - **File Approval**: Similar to terminal commands, writing or updating files requires manual approval unless configured otherwise.
44
- - **Safe Commands**: Basic read-only commands (like `ls`, `git status`, `pwd`) are automatically allowed to minimize friction.
45
-
46
- ### Auto-Execution (Advanced)
47
- For power users, **Auto-Exec** can be enabled in `/settings`.
48
- - **⚠️ Warning**: This allows the agent to run any tool and execute any command autonomously.
49
- - **External Access**: You can also toggle whether the agent is allowed to access files outside of its current working directory.
50
-
51
- ## 🔄 Steering & Resolution
52
-
53
- ### Real-time Steering
54
- If you realize the agent is going down the wrong path *while* it is in an agentic loop, you can provide "Steering Hints." The system will inject your feedback into the next loop to course-correct the agent.
55
-
56
- ### Resolution Modal
57
- If the agent finishes its task just as you send a steering hint, a **Resolution Modal** appears. It asks if you want to:
58
- - **Send Anyway**: Start a new loop with your feedback.
59
- - **Edit Prompt**: Refine your feedback before sending.
60
-
61
- ## 📊 Status Bar & Feedback
62
- The bottom of the screen features a dynamic status bar showing:
63
- - **Active Mode** (Flux/Flow)
64
- - **Thinking Level**
65
- - **Token Usage**: Real-time tracking of tokens used in the current session.
66
- - **Agentic Loops**: Counters showing how many times the agent has "looped" to solve the current task.
1
+ # 🎮 User Interface & Interaction Features
2
+
3
+ Flux Flow is designed to be a high-performance terminal application. Beyond basic chat, it includes a variety of advanced UI features and human-in-the-loop controls to keep you in command of the agent.
4
+
5
+ ## ⌨️ Command System
6
+
7
+ You can control the application using `/` commands directly in the chat input:
8
+
9
+ - **/mode [flux|flow]**: Quickly switch between **Flux** (Dev) and **Flow** (Chat) modes. Using it without arguments opens the selection menu.
10
+ - **/thinking [low|medium|high|max|show|hide]**: Adjust reasoning depth or toggle visibility of the thinking process. Using it without arguments opens the selection menu.
11
+ - **/model [name]**: Choose which AI model to use for the main interaction.
12
+ - **/key**: Open the API Key management view to update or remove your credentials.
13
+ - **/settings**: Access the system configuration menu.
14
+ - **/profile**: Update your name, nickname, and custom instructions.
15
+ - **/memory**: View and manage the persistent memories extracted by the Janitor.
16
+ - **/resume <chat-id>**: Switch back to a previous conversation.
17
+ - **/changelog**: Open the project's changelog in your default browser.
18
+ - **/help**: List all available commands.
19
+
20
+ ### Command Shortcuts
21
+
22
+ For power users, several commands support direct arguments to skip the menus:
23
+ - ` /mode flux ` or ` /mode flow `
24
+ - ` /thinking low ` / ` /thinking medium ` / ` /thinking high ` / ` /thinking max `
25
+ - ` /thinking show ` / ` /thinking hide ` (Toggles thinking process visibility)
26
+ - ` /model gemini-3.1-pro-preview ` (Switches model directly)
27
+
28
+ ## 🧠 Thinking Levels & Visualization
29
+
30
+ Flux Flow separates the model's "internal monologue" (reasoning) from its final response using `<think>` tags.
31
+
32
+ - **Thinking Levels**: Depending on the mode, you can choose from **Low**, **Medium**, **High**, or **Max**. Higher levels allow the agent more "space" to reason through complex architecture or debugging problems.
33
+ - **Show/Hide Thinking**: You can toggle the visibility of the thinking process using `/thinking show/hide`.
34
+ - When **Hidden**, the agent doesn't just disappear; it provides a "minimalist" view showing only the core **Headings** and **Action Steps** (bolded lines) from its reasoning. This keeps you informed of its current "step" without cluttering the screen with detailed internal monologue.
35
+
36
+ ## 🛡️ Human-in-the-Loop (HITL) Verification
37
+
38
+ Security and safety are paramount when an AI has access to your file system and terminal. Flux Flow implements several layers of verification:
39
+
40
+ ### Tool Approval
41
+ By default, the agent **cannot** execute dangerous actions without your consent.
42
+ - **Terminal Approval**: If the agent attempts to run a shell command (`exec_command`), a dedicated approval screen appears showing the exact command. You can **Allow** or **Deny** the execution.
43
+ - **File Approval**: Similar to terminal commands, writing or updating files requires manual approval unless configured otherwise.
44
+ - **Safe Commands**: Basic read-only commands (like `ls`, `git status`, `pwd`) are automatically allowed to minimize friction.
45
+
46
+ ### Auto-Execution (Advanced)
47
+ For power users, **Auto-Exec** can be enabled in `/settings`.
48
+ - **⚠️ Warning**: This allows the agent to run any tool and execute any command autonomously.
49
+ - **External Access**: You can also toggle whether the agent is allowed to access files outside of its current working directory.
50
+
51
+ ## 🔄 Steering & Resolution
52
+
53
+ ### Real-time Steering
54
+ If you realize the agent is going down the wrong path *while* it is in an agentic loop, you can provide "Steering Hints." The system will inject your feedback into the next loop to course-correct the agent.
55
+
56
+ ### Resolution Modal
57
+ If the agent finishes its task just as you send a steering hint, a **Resolution Modal** appears. It asks if you want to:
58
+ - **Send Anyway**: Start a new loop with your feedback.
59
+ - **Edit Prompt**: Refine your feedback before sending.
60
+
61
+ ## 📊 Status Bar & Feedback
62
+ The bottom of the screen features a dynamic status bar showing:
63
+ - **Active Mode** (Flux/Flow)
64
+ - **Thinking Level**
65
+ - **Token Usage**: Real-time tracking of tokens used in the current session.
66
+ - **Agentic Loops**: Counters showing how many times the agent has "looped" to solve the current task.
67
67
  - **API Status**: Visual feedback when the model is thinking or executing a tool.
package/dist/fluxflow.js CHANGED
@@ -199,7 +199,7 @@ var ChatLayout_default = ChatLayout;
199
199
  // src/components/StatusBar.jsx
200
200
  import React3 from "react";
201
201
  import { Box as Box3, Text as Text3 } from "ink";
202
- var StatusBar = React3.memo(({ mode, thinkingLevel, tokens = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true }) => {
202
+ var StatusBar = React3.memo(({ mode, thinkingLevel, tokens = "0.0k", tokensTotal = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true }) => {
203
203
  const modeColor = mode === "Flux" ? "yellow" : "cyan";
204
204
  const modeIcon = mode === "Flux" ? "\u26A1" : "\u{1F30A}";
205
205
  const memStatus = isMemoryEnabled ? "ON" : "OFF";
@@ -215,7 +215,7 @@ var StatusBar = React3.memo(({ mode, thinkingLevel, tokens = "0.0k", chatId = "N
215
215
  },
216
216
  /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: modeColor, bold: true }, modeIcon, " ", mode.toUpperCase()), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "magenta" }, "\u{1F9E0} ", thinkingLevel)),
217
217
  /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1, justifyContent: "center", paddingX: 2 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, "\u{1F4C1} "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue", dimColor: true, italic: true }, process.cwd())),
218
- /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, "MEM: "), /* @__PURE__ */ React3.createElement(Text3, { color: memStatus === "ON" ? "green" : "red" }, memStatus), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, " Tokens ", tokens > 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : tokens, " (", Math.round(tokens / 254e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, "ID: ", chatId, " "))
218
+ /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, "MEM: "), /* @__PURE__ */ React3.createElement(Text3, { color: memStatus === "ON" ? "green" : "red" }, memStatus), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, " Tokens ", tokensTotal > 1e3 ? `${(tokensTotal / 1e3).toFixed(1)}k` : tokensTotal, " (", Math.round(tokens / 254e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, "ID: ", chatId, " "))
219
219
  );
220
220
  });
221
221
  var StatusBar_default = StatusBar;
@@ -410,7 +410,7 @@ tool:functions.tool_name(arguments)
410
410
  - WEB TOOLS (Available in Flux & Flow) -
411
411
  1. Web Search: tool:functions.web_search(query="<query>", limit=number). Find info. limit is optional (3-10, default 10). If user asks about something that is not in your training data, proactively use this tool to find the information.Winder search recomemded (limit = 10) when exploring a topic.
412
412
  2. Web Scrape: tool:functions.web_scrape(url="<url>"). provides detail from a URL.
413
- 3. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). You can use this tool if you hit a roadblock and need user direction on which path to continue. This allows you to pause for guidance without ending your task loop. Format options as 'Short Label::Detailed Description'. You can provide 2 - 4 options (optionA, optionB, optionC, optionD). Tool can also return result as none of the 4 if user write custom one. Example cases to use this tool: ask or user permission (Yes/No). Ask user to choose between two or more options. Ask user for any clarification needed to proceed with the task.
413
+ 3. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). Mandatory triggers include: 1) **Path Divergence**: When multiple architectural or technical solutions exist, present options via 'ask' instead of choosing arbitrarily. 2) **Security Boundaries**: Explicitly request permission via 'ask' before accessing sensitive files (e.g., .env, config keys, credentials). 3) **Ambiguity Resolution**: Use 'ask' to clarify vague prompts before executing terminal commands or writing code. 4) **Risk Mitigation**: Require a 'Yes/No' confirmation for any destructive or irreversible operations. Options must always follow the 'Short Label::Detailed Description' format. This tool is a non-terminating suspension so you can get guidance without losing context.
414
414
  ${mode === "Flux" ? `
415
415
  - DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
416
416
  1. View File: tool:functions.view_file(path="relative/path", start_line=number, end_line=number). Reads file content. Auto-truncates at 500 lines unless start_line and end_line are provided.
@@ -422,7 +422,7 @@ ${mode === "Flux" ? `
422
422
  - DEV & FILE TOOLS are not available in FLOW MODE. If you need to access files, tell the user to switch to FLUX MODE (manually by user).`.trim()}
423
423
  -----------------
424
424
  Results will be provided in the next loop as: [TOOL_RESULT]: [content]
425
- WHEN CALLING TOOLS, YOU **MUST** END YOUR RESPONSE WITH '[turn: continue]' AFTER CALLING FUNCTIONS.
425
+ WHEN CALLING TOOLS, YOU **MUST** end your response with '[turn: continue]'. NEVER use '[turn: finish]' in the same turn as a tool call. After receiving the [TOOL_RESULT], acknowledge the output and verify if the goal is met; only then may you use '[turn: finish]', otherwise use '[turn: continue]'.
426
426
  Do NOT over-use tools. Use them only when strictly necessary for the user's objective. You can stack multiple tool calls 1-by-1.
427
427
  Distinguish clearly between tool discussion and execution. Use the 'tool:' prefix ONLY when calling a function. When discussing tools with the user, refer to them by name as nouns (e.g., 'write_file', 'list_files') to avoid accidental triggers and context bloat. Even in your <think> ... </think> tags, do not use the 'tool:' prefix when planning to select a tool.
428
428
  -- END FUNCTION CALLING PROTOCOL --`.trim();
@@ -465,6 +465,7 @@ var getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, tempMe
465
465
  if (thinkingLevel === "Low") levelKey = "Minimal";
466
466
  if (thinkingLevel === "xHigh" || thinkingLevel === "Max") levelKey = "Max";
467
467
  const thinkingConfig = thinking_prompts_default[levelKey] || thinking_prompts_default["Medium"];
468
+ const osDetected = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
468
469
  const nameStr = profile.name && profile.name?.length > 0 ? `User Name: ${profile.name}` : "";
469
470
  const nicknameStr = profile.nickname && profile.nickname?.length > 0 ? `. User Nickname: ${profile.nickname}.` : "";
470
471
  const userInstrStr = profile.instructions && profile.instructions?.length > 0 ? `. User Instructions: ${profile.instructions}.` : "";
@@ -485,8 +486,9 @@ ${userMemories}
485
486
  ` : ""}${isMemoryEnabled ? `${tempMemoriesStr}
486
487
 
487
488
  ` : ""}--- START SYSTEM INSTRUCTION ---
488
- You are Flux Flow. A CLI Agent. Your tone will be friendly, warm, sassy, approchable, respectable, NO ROMANTIC OR FLIRTY WORDS. Dont mention modes unless explicitly asked. ${mode === "Flux" ? "You are currently operating in FLUX (dev) mode. Keep your agentic approach goal oriented. Use provided tools when needed. And try to minimize number of agentic loops (Agent Loop is limited to 50 per turn, finish your goal by then). Analyze user prompt and project requirements, then plan your approach." : "You are currently operating in Flow (chat) mode. Focus more on conversation quality and user experience. Keep Agentic Loops to minimum (Agent Loop is limited to 7 per turn, finish your goal by then). You will get access to Web Tools only in this mode."}
489
+ You are Flux Flow. A CLI Agent. Your tone will be friendly, warm, sassy, approchable, funny, NO ROMANTIC OR FLIRTY WORDS. Dont mention modes unless explicitly asked. ${mode === "Flux" ? "You are currently operating in FLUX (dev) mode. Keep your agentic approach goal oriented. Use provided tools when needed. And try to minimize number of agentic loops (Agent Loop is limited to 50 per turn, finish your goal by then). Analyze user prompt and project requirements, then plan your approach." : "You are currently operating in Flow (chat) mode. Focus more on conversation quality and user experience. Keep Agentic Loops to minimum (Agent Loop is limited to 7 per turn, finish your goal by then). You will get access to Web Tools only in this mode."}
489
490
  CURRENT_WORKING_DIRECTORY: ${cwdStr}.
491
+ OS: ${osDetected}. ${osDetected && mode == "Flux" ? "Your terminal commands will run on CMD. Prefer PS scripts via CMD instead of raw CMD commands." : ""}
490
492
  ${nameStr}${nicknameStr}${userInstrStr}
491
493
 
492
494
  ${thinkingConfig}
@@ -1614,7 +1616,7 @@ ${boxBottom}
1614
1616
  yield { type: "status", content: "Working..." };
1615
1617
  }
1616
1618
  const cleanedTurnText = turnText.replace(/<think>[\s\S]*?<\/think>/g, "").replace(/\[?\s*(turn\s*:)?\s*(continue|finish)\s*\]?/gi, "").trim();
1617
- const isActuallyFinished = hasFinish || !shouldContinue && toolResults.length === 0 && turnText.length < 5;
1619
+ const isActuallyFinished = hasFinish;
1618
1620
  if (isActuallyFinished) {
1619
1621
  const lateHint = await steeringCallback();
1620
1622
  if (lateHint) {
@@ -1703,10 +1705,8 @@ ${timestamp}`;
1703
1705
  if (isActuallyFinished) break;
1704
1706
  const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
1705
1707
  modifiedHistory.push({ role: "agent", text: nextAgentMsg });
1706
- const nextUserMsg = toolResults.length > 0 ? `${toolResults.join("\n")}` : "";
1707
- if (nextUserMsg) {
1708
- modifiedHistory.push({ role: "user", text: nextUserMsg });
1709
- }
1708
+ const nextUserMsg = toolResults.length > 0 ? toolResults.join("\n") : "[turn: continue]";
1709
+ modifiedHistory.push({ role: "user", text: nextUserMsg });
1710
1710
  }
1711
1711
  yield { type: "status", content: null };
1712
1712
  };
@@ -1841,11 +1841,28 @@ function MemoryModal({ onClose }) {
1841
1841
  return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "double", borderColor: "yellow", padding: 1, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "yellow" }, "\u{1F9E0} LONG-TERM MEMORY VAULT")), memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "center", paddingY: 2 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "The vault is currently empty...")) : memories.map((mem, idx) => /* @__PURE__ */ React8.createElement(Box8, { key: mem.id, paddingX: 1, backgroundColor: idx === selectedIndex ? "#333" : void 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: idx === selectedIndex ? "yellow" : "white" }, idx === selectedIndex ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory)))), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "\u2191/\u2193 Navigate \u2022 ", /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, "x"), " Delete Memory \u2022 ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, "Esc"), " Back to Chat")));
1842
1842
  }
1843
1843
 
1844
+ // src/utils/terminal.js
1845
+ var getTerminalEnv = () => {
1846
+ if (process.env.TERM_PROGRAM === "vscode") return "vscode";
1847
+ if (process.env.WT_SESSION) return "wt";
1848
+ return "default";
1849
+ };
1850
+ var emojiSpace = (baseSpaces = 2) => {
1851
+ const env = getTerminalEnv();
1852
+ if (env === "wt") {
1853
+ return " ".repeat(Math.max(1, baseSpaces - 1));
1854
+ }
1855
+ if (env === "vscode") {
1856
+ return " ".repeat(baseSpaces);
1857
+ }
1858
+ return " ".repeat(baseSpaces);
1859
+ };
1860
+
1844
1861
  // src/app.jsx
1845
1862
  var SESSION_START_TIME = Date.now();
1846
1863
  var CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
1847
- var versionFluxflow = "1.1.2";
1848
- var updatedOn = "2026-04-26";
1864
+ var versionFluxflow = "1.1.3";
1865
+ var updatedOn = "2026-04-27";
1849
1866
  var ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "The agent already finished the task (turn: finish) before your hint was consumed."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
1850
1867
  CommandMenu,
1851
1868
  {
@@ -1871,6 +1888,7 @@ var FLUX_LOGO = gradient(["#00ffff", "#0077ff", "#ff00ff"]).multiline(
1871
1888
  function App() {
1872
1889
  const { stdout } = useStdout();
1873
1890
  const [input, setInput] = useState5("");
1891
+ const [isExpanded, setIsExpanded] = useState5(false);
1874
1892
  const [mode, setMode] = useState5("Flux");
1875
1893
  const [terminalSize, setTerminalSize] = useState5({
1876
1894
  columns: stdout?.columns || 80,
@@ -1978,8 +1996,8 @@ Check what's new using \`/changelog\` command.`,
1978
1996
  for (let i = completedIndex - 1; i >= 0; i--) {
1979
1997
  const msg = messages[i];
1980
1998
  if (!msg) continue;
1981
- let lines = (msg.text || "").split("\n").length;
1982
- msg.text.split("\n").forEach((l) => {
1999
+ let lines = (msg.text || "").split(/\r?\n/).length;
2000
+ msg.text.split(/\r?\n/).forEach((l) => {
1983
2001
  lines += Math.floor(l.length / width);
1984
2002
  });
1985
2003
  lines += msg.role === "think" ? 3 : 2;
@@ -1994,7 +2012,23 @@ Check what's new using \`/changelog\` command.`,
1994
2012
  isTruncated: startIdx > 0
1995
2013
  };
1996
2014
  }, [messages, completedIndex, stdout?.columns]);
2015
+ const terminalWidth = stdout?.columns || 80;
2016
+ const wrapWidth = Math.max(20, terminalWidth - 10);
2017
+ const wrappedLinesCount = input.split(/\r?\n/).reduce((acc, line) => {
2018
+ return acc + Math.max(1, Math.ceil(line.length / wrapWidth));
2019
+ }, 0);
2020
+ const maxLines = Math.max(1, wrappedLinesCount);
1997
2021
  useInput4((inputText, key) => {
2022
+ if (maxLines > 2 && !isExpanded && activeView === "chat") {
2023
+ if (key.backspace || key.delete) {
2024
+ setInput("");
2025
+ return;
2026
+ }
2027
+ if (key.return) {
2028
+ setIsExpanded(true);
2029
+ return;
2030
+ }
2031
+ }
1998
2032
  if (key.escape) {
1999
2033
  if (isProcessing) {
2000
2034
  if (!escPressed) {
@@ -2075,7 +2109,7 @@ Check what's new using \`/changelog\` command.`,
2075
2109
  setInput(normalizedValue.slice(0, -1) + "\n");
2076
2110
  return;
2077
2111
  }
2078
- const absoluteClean = normalizedValue.replace(/\\\s*\n/g, "\n").split("\n").map((l) => l.replace(/\\$/, "")).join("\n");
2112
+ const absoluteClean = normalizedValue.replace(/\\\s*\n/g, "\n").split(/\r?\n/).map((l) => l.replace(/\\$/, "")).join("\n");
2079
2113
  if (!absoluteClean.trim()) return;
2080
2114
  if (isProcessing) {
2081
2115
  const hintText = absoluteClean.trim();
@@ -2135,6 +2169,7 @@ ${hintText}`, color: "magenta" }];
2135
2169
  setCompletedIndex(0);
2136
2170
  setChatId(generateChatId());
2137
2171
  setSessionStats({ tokens: 0 });
2172
+ setIsExpanded(false);
2138
2173
  break;
2139
2174
  }
2140
2175
  case "/mode": {
@@ -2276,7 +2311,8 @@ ${list || "No saved chats found."}`, isMeta: true }];
2276
2311
  }
2277
2312
  case "/about": {
2278
2313
  const updateStatus = latestVer ? latestVer !== versionFluxflow ? `Update Available [v${latestVer}]` : "No Update Available" : "Checking for updates...";
2279
- const aboutText = `\u2139\uFE0F **FluxFlow Version:** v${versionFluxflow}
2314
+ const s = emojiSpace(2);
2315
+ const aboutText = `\u2139\uFE0F${s}**FluxFlow Version:** v${versionFluxflow}
2280
2316
  \u{1F504} **Status:** ${updateStatus}
2281
2317
  \u{1F4C5} **Updated on:** ${updatedOn}`;
2282
2318
  setMessages((prev) => {
@@ -2319,6 +2355,7 @@ ${timestamp}` };
2319
2355
  });
2320
2356
  const streamChat = async () => {
2321
2357
  setIsProcessing(true);
2358
+ setIsExpanded(false);
2322
2359
  try {
2323
2360
  const cleanHistoryForAI = [...messages, userMessage].filter(
2324
2361
  (m) => m.role !== "think" && !String(m.id).startsWith("welcome")
@@ -2541,6 +2578,7 @@ Selection: ${val}`,
2541
2578
  streamChat();
2542
2579
  }
2543
2580
  setInput("");
2581
+ setIsExpanded(false);
2544
2582
  };
2545
2583
  const getSuggestions = () => {
2546
2584
  if (!input.startsWith("/") || input.includes(" ")) return [];
@@ -2609,11 +2647,12 @@ Selection: ${val}`,
2609
2647
  {
2610
2648
  title: "System Settings",
2611
2649
  items: [
2612
- { label: `Toggle Memory [ ${systemSettings.memory ? "ON" : "OFF"} ]`, value: "memory" },
2613
- { label: `Toggle Auto-Exec [ ${systemSettings.autoExec ? "ON" : "OFF"} ]`, value: "autoExec" },
2614
- { label: `External Workspace Access [ ${systemSettings.allowExternalAccess ? "ON" : "OFF"} ]`, value: "externalAccess" },
2615
- { label: `API Tier [ ${apiTier} ]`, value: "apiTier" },
2616
- { label: `Auto-Delete History [ ${systemSettings.autoDeleteHistory} ]`, value: "autoDelete" },
2650
+ { label: `Toggle Memory [ ${systemSettings.memory ? "ON" : "OFF"} ]`, value: "memory" },
2651
+ { label: `Toggle Auto-Exec [ ${systemSettings.autoExec ? "ON" : "OFF"} ]`, value: "autoExec" },
2652
+ { label: `Alternate Screen Buffer (Experimental) [ ${systemSettings.useAlternateBuffer ? "ON" : "OFF"} ]`, value: "altBuffer" },
2653
+ { label: `External Workspace Access [ ${systemSettings.allowExternalAccess ? "ON" : "OFF"} ]`, value: "externalAccess" },
2654
+ { label: `API Tier [ ${apiTier} ]`, value: "apiTier" },
2655
+ { label: `Auto-Delete History [ ${systemSettings.autoDeleteHistory} ]`, value: "autoDelete" },
2617
2656
  { label: "Exit Settings", value: "Cancel" }
2618
2657
  ],
2619
2658
  onSelect: (item) => {
@@ -2977,45 +3016,29 @@ Selection: ${val}`,
2977
3016
  }
2978
3017
  )));
2979
3018
  default:
2980
- const terminalWidth = stdout.columns || 80;
2981
- const wrapWidth = Math.max(20, terminalWidth - 10);
2982
- const wrappedLines = input.split("\n").reduce((acc, line) => {
2983
- return acc + Math.max(1, Math.ceil(line.length / wrapWidth));
2984
- }, 0);
2985
- const maxLines = Math.max(1, wrappedLines);
2986
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, null, statusText && /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", italic: true }, "\u23F3 ", statusText)), /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "(", tempModelOverride || activeModel, ")")), suggestions.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, "\u{1F4A1} Suggestions: "), suggestions.map((s, i) => /* @__PURE__ */ React9.createElement(Text9, { key: s, color: "yellow", bold: i === 0 }, " ", s, " "))), /* @__PURE__ */ React9.createElement(Box9, { backgroundColor: "#333333", paddingX: 1, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%" }, maxLines > 3 ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%", paddingY: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "[\u{1F4E6} ", maxLines, " lines of text in buffer - Full content will be sent]"), /* @__PURE__ */ React9.createElement(
2987
- Box9,
3019
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, null, statusText && /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", italic: true }, "\u23F3 ", statusText)), /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "(", tempModelOverride || activeModel, ")")), suggestions.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, "\u{1F4A1} Suggestions: "), suggestions.map((s, i) => /* @__PURE__ */ React9.createElement(Text9, { key: s, color: "yellow", bold: i === 0 }, " ", s, " "))), /* @__PURE__ */ React9.createElement(Box9, { backgroundColor: "#333333", paddingX: 1, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%" }, maxLines > 2 && !isExpanded ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "row", width: "100%", paddingY: 0, height: 1, overflow: "hidden" }, /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, flexDirection: "row" }, /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", bold: true }, "[Pasted ", maxLines, " Lines]")), /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React9.createElement(
3020
+ MultilineInput,
2988
3021
  {
2989
- flexDirection: "row",
2990
- width: "100%",
2991
- height: 1,
2992
- overflow: "hidden",
2993
- alignItems: "flex-end"
2994
- },
2995
- /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")),
2996
- /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1 }, /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, position: "relative" }, input.split("\n").pop() === "" && !isProcessing && /* @__PURE__ */ React9.createElement(Box9, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "Type your message...")), /* @__PURE__ */ React9.createElement(
2997
- MultilineInput,
2998
- {
2999
- value: input.split("\n").pop() || "",
3000
- onChange: (val) => {
3001
- const cleanVal = val.replace(/\\$/, "");
3002
- const lines = input.split("\n");
3003
- lines[lines.length - 1] = cleanVal;
3004
- setInput(lines.join("\n"));
3005
- },
3006
- onSubmit: handleSubmit,
3007
- keyBindings: {
3008
- submit: (key) => key.return && !key.shift && !key.ctrl,
3009
- newline: (key) => key.return && key.shift || key.return && key.ctrl
3022
+ value: "",
3023
+ placeholder: " (Backspace to delete / Enter to expand)",
3024
+ onChange: (val) => {
3025
+ if (val.length > 0) {
3026
+ setIsExpanded(true);
3027
+ setInput(input + val);
3010
3028
  }
3029
+ },
3030
+ onSubmit: () => setIsExpanded(true),
3031
+ keyBindings: {
3032
+ submit: (key) => key.return && !key.shift && !key.ctrl,
3033
+ newline: (key) => key.return && key.shift || key.return && key.ctrl
3011
3034
  }
3012
- )))
3013
- )) : /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1 }, /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, position: "relative" }, input === "" && !isProcessing && /* @__PURE__ */ React9.createElement(Box9, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, escPressed ? " Press ESC again to cancel the request." : " Type your message or /command...")), /* @__PURE__ */ React9.createElement(
3035
+ }
3036
+ )))) : /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1 }, /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, position: "relative" }, input === "" && !isProcessing && /* @__PURE__ */ React9.createElement(Box9, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, escPressed ? " Press ESC again to cancel the request." : " Type your message or /command...")), /* @__PURE__ */ React9.createElement(
3014
3037
  MultilineInput,
3015
3038
  {
3016
3039
  value: input,
3017
3040
  onChange: (val) => {
3018
- const cleanVal = val.replace(/\\\s*\n/g, "\n");
3041
+ const cleanVal = val.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\\\s*\n/g, "\n");
3019
3042
  setInput(cleanVal);
3020
3043
  },
3021
3044
  onSubmit: handleSubmit,
@@ -3042,6 +3065,7 @@ Selection: ${val}`,
3042
3065
  mode,
3043
3066
  thinkingLevel,
3044
3067
  tokens: sessionStats.tokens,
3068
+ tokensTotal: sessionTotalTokens,
3045
3069
  chatId,
3046
3070
  isMemoryEnabled: systemSettings.memory
3047
3071
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",