fluxflow-cli 1.8.19 → 1.8.21

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,65 +1,65 @@
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
- ## Multimodal Pipeline
33
-
34
- Flux Flow implements a native multimodal processing engine in `src/tools/view_file.js`. This allows the agent to move beyond text-based reasoning and analyze visual assets directly.
35
-
36
- - **Binary Detection**: The pipeline uses `is-binary-path` to distinguish between text and binary files.
37
- - **Visual Encoding**: If an image or PDF is detected, the engine reads the raw bytes and converts them into base64-encoded `InlineData` objects.
38
- - **PDF Extraction**: For PDF documents, the engine extracts visual representation of pages to provide the model with high-fidelity spatial and textual context simultaneously.
39
- - **Context Injection**: These multimodal assets are injected directly into the Gemini model's multimodal part array, allowing the model to "see" the file as if it were looking at a screenshot.
40
-
41
- ## The Dual-Model System
42
-
43
- To maintain a fast, snappy UI while still performing complex data management, Flux Flow employs two separate AI models for every interaction:
44
-
45
- ### 1. The Main Agent
46
- - **Responsibility**: Direct user interaction, reasoning, and tool execution.
47
- - **Behavior**: Streams text directly to the UI. It focuses entirely on solving the user's immediate problem or answering their question.
48
-
49
- ### 2. The Janitor (Background Process)
50
- - **Responsibility**: System maintenance, long-term memory extraction, and chat summarization.
51
- - **Behavior**: After the Main Agent finishes its loop, the entire context (User Prompt + Agent Raws) is sent to the Janitor model.
52
- - **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).
53
-
54
- ## Data Persistence & Safety
55
-
56
- - **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.
57
- - **Encryption**: User secrets and persistent memories (`secret/memories.json`) are handled by `src/utils/crypto.js` to ensure local privacy.
58
-
59
- ## Redirection & The Anchor Strategy
60
-
61
- To support data portability (e.g., storing all app data on an external encrypted drive), Flux Flow utilizes a synchronous "Anchor" strategy in `src/utils/paths.js`.
62
-
63
- - **Synchronous Pivot**: Because many core modules (History, Secrets, Usage) initialize their file paths as constants during module loading, the application must determine the "Actual" data root before anything else.
64
- - **Boot-Sequence Priority**: On every launch, `paths.js` performs a synchronous file system check for `~/.fluxflow/settings.json`. If a redirection path is found (`useExternalData: true`), it immediately overrides the global `DATA_DIR` constant for the entire process.
65
- - **Sub-Coordinate Resolution**: All secondary directories (`LOGS_DIR`, `SECRET_DIR`) are derived dynamically from the redirected `DATA_DIR`, ensuring that all session data flows to the external sanctuary without requiring individual configuration updates across the codebase.
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
+ ## Multimodal Pipeline
33
+
34
+ Flux Flow implements a native multimodal processing engine in `src/tools/view_file.js`. This allows the agent to move beyond text-based reasoning and analyze visual assets directly.
35
+
36
+ - **Binary Detection**: The pipeline uses `is-binary-path` to distinguish between text and binary files.
37
+ - **Visual Encoding**: If an image or PDF is detected, the engine reads the raw bytes and converts them into base64-encoded `InlineData` objects.
38
+ - **PDF Extraction**: For PDF documents, the engine extracts visual representation of pages to provide the model with high-fidelity spatial and textual context simultaneously.
39
+ - **Context Injection**: These multimodal assets are injected directly into the Gemini model's multimodal part array, allowing the model to "see" the file as if it were looking at a screenshot.
40
+
41
+ ## The Dual-Model System
42
+
43
+ To maintain a fast, snappy UI while still performing complex data management, Flux Flow employs two separate AI models for every interaction:
44
+
45
+ ### 1. The Main Agent
46
+ - **Responsibility**: Direct user interaction, reasoning, and tool execution.
47
+ - **Behavior**: Streams text directly to the UI. It focuses entirely on solving the user's immediate problem or answering their question.
48
+
49
+ ### 2. The Janitor (Background Process)
50
+ - **Responsibility**: System maintenance, long-term memory extraction, and chat summarization.
51
+ - **Behavior**: After the Main Agent finishes its loop, the entire context (User Prompt + Agent Raws) is sent to the Janitor model.
52
+ - **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).
53
+
54
+ ## Data Persistence & Safety
55
+
56
+ - **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.
57
+ - **Encryption**: User secrets and persistent memories (`secret/memories.json`) are handled by `src/utils/crypto.js` to ensure local privacy.
58
+
59
+ ## Redirection & The Anchor Strategy
60
+
61
+ To support data portability (e.g., storing all app data on an external encrypted drive), Flux Flow utilizes a synchronous "Anchor" strategy in `src/utils/paths.js`.
62
+
63
+ - **Synchronous Pivot**: Because many core modules (History, Secrets, Usage) initialize their file paths as constants during module loading, the application must determine the "Actual" data root before anything else.
64
+ - **Boot-Sequence Priority**: On every launch, `paths.js` performs a synchronous file system check for `~/.fluxflow/settings.json`. If a redirection path is found (`useExternalData: true`), it immediately overrides the global `DATA_DIR` constant for the entire process.
65
+ - **Sub-Coordinate Resolution**: All secondary directories (`LOGS_DIR`, `SECRET_DIR`) are derived dynamically from the redirected `DATA_DIR`, ensuring that all session data flows to the external sanctuary without requiring individual configuration updates across the codebase.
package/dist/fluxflow.js CHANGED
@@ -833,7 +833,7 @@ If you see a [STEERING HINT] from user, give that prompt priority for the task a
833
833
  -- START THINKING INSTRUCTIONS --
834
834
  ${thinkingConfig}
835
835
 
836
- BEFORE USING ANY TOOL THINKING IS **MANDATORY** WITH TOOL RULES. ALWAYS PRIORITIZE THINKING FIRST BEFORE RESPONDING. YOU ARE **FORBIDDEN** TO JUMP TO RESPONSES FIRST.
836
+ BEFORE USING ANY TOOL THINKING IS **MANDATORY** WITH TOOL RULES. ALWAYS PRIORITIZE THINKING FIRST BEFORE RESPONDING. YOU ARE **FORBIDDEN** TO JUMP TO RESPONSES FIRST. THINKING IS REQUIRED EVEN WITH CONVERSATIONAL RESPONSES.
837
837
  -- END THINKING INSTRUCTIONS --
838
838
 
839
839
  ${TOOL_PROTOCOL(mode)}
@@ -1890,13 +1890,18 @@ var init_update_file = __esm({
1890
1890
  diffText += `-${startLine + i}|${line}
1891
1891
  `;
1892
1892
  });
1893
- fullNewLines.forEach((line, i) => {
1894
- diffText += `+${startLine + i}|${line}
1893
+ let currentNewLine = startLine;
1894
+ fullNewLines.forEach((line) => {
1895
+ diffText += `+${currentNewLine}|${line}
1895
1896
  `;
1897
+ currentNewLine++;
1896
1898
  });
1897
- for (let i = endLine; i < Math.min(allOriginalLines.length, endLine + 15); i++) {
1898
- diffText += `[UI_CONTEXT] ${i + 1}|${allOriginalLines[i]}
1899
+ const linesAffected = fullOldLines.length;
1900
+ const originalContextIdx = startLine + linesAffected - 1;
1901
+ for (let i = originalContextIdx; i < Math.min(allOriginalLines.length, originalContextIdx + 15); i++) {
1902
+ diffText += `[UI_CONTEXT] ${currentNewLine}|${allOriginalLines[i]}
1899
1903
  `;
1904
+ currentNewLine++;
1900
1905
  }
1901
1906
  diffText += `[DIFF_END]`;
1902
1907
  return diffText;
@@ -3064,27 +3069,29 @@ ${boxBottom}
3064
3069
  if (turnText.trim().length > 0) {
3065
3070
  if (inStreamRetryCount <= MAX_RETRIES) {
3066
3071
  inStreamRetryCount++;
3067
- const waitTime = Math.floor(Math.random() * (3e3 - 1e3 + 1)) + 1e3;
3072
+ const waitTime = Math.min(1e3 * Math.pow(2, inStreamRetryCount - 1), 12e3);
3068
3073
  modifiedHistory.push({ role: "agent", text: turnText });
3069
3074
  if (toolResults.length > 0) {
3070
3075
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3071
3076
  }
3072
3077
  modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly and DON'T repeat what you already said!" });
3073
3078
  accumulatedContext += turnText;
3074
- yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES})...` };
3079
+ yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${(waitTime / 1e3).toFixed(0)}s]...` };
3075
3080
  await new Promise((resolve) => setTimeout(resolve, waitTime));
3076
3081
  } else {
3082
+ yield { type: "status", content: `Error Occured. Recovering Stream...` };
3077
3083
  throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
3078
3084
  Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
3079
3085
  }
3080
3086
  } else {
3081
3087
  if (retryCount <= MAX_RETRIES) {
3082
3088
  retryCount++;
3083
- const waitTime = Math.floor(Math.random() * (3e3 - 1e3 + 1)) + 1e3;
3089
+ const waitTime = Math.min(1e3 * Math.pow(2, retryCount - 1), 12e3);
3084
3090
  isInitialAttempt = true;
3085
- yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES})...` };
3091
+ yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${(waitTime / 1e3).toFixed(0)}s]...` };
3086
3092
  await new Promise((resolve) => setTimeout(resolve, waitTime));
3087
3093
  } else {
3094
+ yield { type: "status", content: `Retrying Connection...` };
3088
3095
  throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
3089
3096
  Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
3090
3097
  }
@@ -5202,7 +5209,7 @@ var init_app = __esm({
5202
5209
  init_text();
5203
5210
  SESSION_START_TIME = Date.now();
5204
5211
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5205
- versionFluxflow = "1.8.19";
5212
+ versionFluxflow = "1.8.21";
5206
5213
  updatedOn = "2026-05-10";
5207
5214
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent already finished the task before your hint was consumed."), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
5208
5215
  CommandMenu,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.8.19",
3
+ "version": "1.8.21",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",