fluxflow-cli 1.3.2 โ 1.3.4
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/README.md +47 -56
- package/dist/fluxflow.js +74 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,35 +1,14 @@
|
|
|
1
|
-
#
|
|
2
|
-

|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
### *The High-Fidelity Agentic Terminal for the Flux Era.*
|
|
5
5
|
|
|
6
|
-
Flux Flow is
|
|
7
|
-
|
|
8
|
-
Whether you need a conversational partner or an autonomous developer that can write code, run shell commands, and read your project files, Flux Flow adapts to your needs.
|
|
6
|
+
**Flux Flow** is not just another CLIโit's a high-speed, sassy, and goal-oriented CLI AI Agent powered by the latest Gemini/Gemma frontier models. Designed for developers who demand a premium UI/UX while managing complex file-system tasks, web research, and autonomous workflows.
|
|
9
7
|
|
|
10
8
|
---
|
|
11
9
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
- **Responsive Terminal UI**: A gorgeous, reactive interface built with React and Ink, featuring multi-line input, status bars, modals, and diff views.
|
|
15
|
-
- **Dual-Model Architecture**: A primary agent interacts with you and executes tasks, while a silent background "Janitor" model handles chat summarization and long-term memory extraction without blocking the main UI.
|
|
16
|
-
- **Two Operating Modes**:
|
|
17
|
-
- **Flux (Dev Mode)**: Full system access. The agent can read/write files, execute shell commands, and run autonomous agentic loops (up to 45 iterations) to solve complex coding tasks.
|
|
18
|
-
- **Flow (Chat Mode)**: Focused on conversation and web research, with limited agentic loops for faster response times.
|
|
19
|
-
- **Advanced Memory System**: Features both temporary session context and persistent, cross-session user memories encrypted locally on your machine.
|
|
20
|
-
- **Agentic Tooling**: Built-in tools for smart file patching, web scraping, web searching, and terminal execution.
|
|
21
|
-
- **Autonomous Project Alignment**: Automatically detects and adheres to project-specific instructions in `Agent.md`, `Skills.md`, and `Fluxflow.md` for high-fidelity coding standards and complex workflows.
|
|
22
|
-
- **Customizable "Thinking" Levels**: Adjust the depth of the model's reasoning process (from Minimal to Max).
|
|
23
|
-
- **High-Reliability Fallback**: Automatic failover to a lighter, high-concurrency model (Gemini 3.1 Flash Lite) during peak traffic to ensure 100% session persistence.
|
|
24
|
-
|
|
25
|
-
## ๐ Quick Start
|
|
26
|
-
|
|
27
|
-
### Prerequisites
|
|
28
|
-
- [Node.js](https://nodejs.org/) (v18 or higher recommended)
|
|
29
|
-
- `npm`, `yarn`, or `pnpm`
|
|
30
|
-
|
|
31
|
-
### Via NPM (Global & Instant)
|
|
32
|
-
You can run the agent instantly or install it globally for high-speed access:
|
|
10
|
+
## ๐ Instant Ignition (No Setup Required)
|
|
11
|
+
You don't even need to install it. Just fire up your terminal and run:
|
|
33
12
|
|
|
34
13
|
```bash
|
|
35
14
|
# Run instantly (Zero Setup)
|
|
@@ -37,44 +16,56 @@ npx fluxflow-cli
|
|
|
37
16
|
|
|
38
17
|
# OR Install Globally
|
|
39
18
|
npm install -g fluxflow-cli
|
|
40
|
-
fluxflow
|
|
19
|
+
fluxflow-cli
|
|
41
20
|
```
|
|
42
21
|
|
|
43
|
-
|
|
44
|
-
1. Clone the repository and install dependencies:
|
|
45
|
-
```bash
|
|
46
|
-
git clone <repository-url>
|
|
47
|
-
cd Flux-Flow
|
|
48
|
-
npm install
|
|
49
|
-
```
|
|
22
|
+
*The agent will prompt you for your Gemini API Key on the first run and store it securely in an XOR-encrypted vault.* Free API Key recomemded to use Gemma 4 (Default Model).
|
|
50
23
|
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npm start
|
|
54
|
-
```
|
|
24
|
+
---
|
|
55
25
|
|
|
56
|
-
##
|
|
26
|
+
## โจ Why Flux Flow?
|
|
57
27
|
|
|
58
|
-
|
|
28
|
+
### ๐จ **Premium Visual Sovereignty**
|
|
29
|
+
Experience a terminal UI that feels alive. Built with **Ink** and **React**, Flux Flow features:
|
|
30
|
+
- **Dynamic Status Bar**: Real-time telemetry showing your "Neural Headroom" (token usage), Thinking Level, and Session ID.
|
|
31
|
+
- **Archived Terminal Flow**: See execution outputs transform from live elements into permanent conversation records.
|
|
32
|
+
- **Rich Aesthetics**: High-contrast, sleek design with smooth transitions and micro-animations.
|
|
59
33
|
|
|
60
|
-
|
|
61
|
-
- **
|
|
62
|
-
- **
|
|
34
|
+
### ๐ง **The Dual-Intelligence System**
|
|
35
|
+
- **Flux Mode (Dev)**: High-speed, agentic problem solving with a 50-turn persistent loop for massive coding tasks.
|
|
36
|
+
- **Flow Mode (Chat)**: Optimized for deep research, high-quality conversation, and web-assisted reasoning.
|
|
63
37
|
|
|
64
|
-
|
|
38
|
+
### ๐ก๏ธ **Digital Fortress Governance**
|
|
39
|
+
Security isn't an afterthought; it's a boundary.
|
|
40
|
+
- **External Path Hardlock**: Restricts the agent to your Current Working Directory (CWD) unless you explicitly unlock it.
|
|
41
|
+
- **Human-in-the-Loop (HITL)**: Every file write and terminal command requires your high-fidelity approval.
|
|
42
|
+
- **XOR Vaulting**: All local session histories, memories, and API keys are obfuscated and encrypted at rest.
|
|
43
|
+
- **Adaptive Failover**: Automatic multi-stage retry logic with high-concurrency fallback model switching (Gemini 3.1 Flash Lite) during peak API congestion.
|
|
65
44
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- **Nuclear Reset**: Use the `/reset` command to instantly purge all logs, secrets, and settings from the global storage directory.
|
|
69
|
-
- **Configurable Boundaries**: In Flux mode, file access can be strictly confined to the Current Working Directory, or expanded globally via settings.
|
|
70
|
-
- **API Keys**: You supply your own Gemini/Google AI Studio API keys.
|
|
45
|
+
### ๐งน **The Background Janitor**
|
|
46
|
+
While you move at high speed, the Janitor follows behindโrefining session titles, compressing data, and ensuring your context window remains at absolute peak performance.
|
|
71
47
|
|
|
72
|
-
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## ๐ ๏ธ Key Capabilities
|
|
51
|
+
- **Deep File-System Interaction**: Edit, move, and refactor code across multiple files with atomic precision.
|
|
52
|
+
- **Real-Time Web Intelligence**: Autonomous web-searching via DuckDuckGo for live news and technical research.
|
|
53
|
+
- **Autonomous Project Alignment**: Automatically detects and adheres to project-specific instructions in `Agent.md`, `Skills.md`, and `Fluxflow.md` for high-fidelity alignment with your coding standards and custom workflows.
|
|
54
|
+
- **High-Reliability Fallback**: Automatic failover to a lighter, high-concurrency model during peak traffic to ensure zero session loss.
|
|
55
|
+
- **Persistent Memory**: The agent learns from your preferences and project requirements across sessions.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## โ๏ธ Configuration
|
|
60
|
+
Type `/settings` in-app to live-configure:
|
|
61
|
+
- **Thinking Level**: Low, Medium, or High (Deep-Reasoning).
|
|
62
|
+
- **Auto-Execution**: For ultimate high-speed flow (Advanced users only).
|
|
63
|
+
- **Security Perimeter**: Toggle External Workspace access.
|
|
64
|
+
|
|
65
|
+
---
|
|
73
66
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- **[chalk](https://www.npmjs.com/package/chalk) & [gradient-string](https://www.npmjs.com/package/gradient-string)**: For terminal styling and aesthetics.
|
|
77
|
-
- **[fs-extra](https://www.npmjs.com/package/fs-extra)**: For robust file system operations.
|
|
67
|
+
## ๐ License
|
|
68
|
+
MIT ยฉ 2026 Flux Flow Team.
|
|
78
69
|
|
|
79
70
|
---
|
|
80
|
-
*
|
|
71
|
+
*Forged with โก and ๐งฌ. Welcome to the FluxFlow.*
|
package/dist/fluxflow.js
CHANGED
|
@@ -71,13 +71,14 @@ var init_ChatLayout = __esm({
|
|
|
71
71
|
};
|
|
72
72
|
InlineMarkdown = React2.memo(({ text, color }) => {
|
|
73
73
|
if (!text) return null;
|
|
74
|
-
const parts = text.split(/(\*\*.*?\*\*|\*.*?\*|`.*?`|\$\\viewtext\{.*?\}\$|\[.*?\]\(.*?\))/g);
|
|
74
|
+
const parts = text.split(/(\*\*.*?\*\*|\*.*?\*|`.*?`|\$\\viewtext\{.*?\}\$|\[.*?\]\s*\(.*?\)|\[.*?\]\s*\[.*?\]|https?:\/\/[^\s]+)/g);
|
|
75
75
|
return /* @__PURE__ */ React2.createElement(Text2, { color, wrap: "anywhere" }, parts.map((part, j) => {
|
|
76
|
+
if (!part) return null;
|
|
76
77
|
if (part.startsWith("**") && part.endsWith("**")) {
|
|
77
|
-
return /* @__PURE__ */ React2.createElement(Text2, { key: j, bold: true, color: "white" }, part.slice(2, -2));
|
|
78
|
+
return /* @__PURE__ */ React2.createElement(Text2, { key: j, bold: true, color: "white" }, /* @__PURE__ */ React2.createElement(InlineMarkdown, { text: part.slice(2, -2), color: "white" }));
|
|
78
79
|
}
|
|
79
80
|
if (part.startsWith("*") && part.endsWith("*")) {
|
|
80
|
-
return /* @__PURE__ */ React2.createElement(Text2, { key: j, italic: true, color: "gray" }, part.slice(1, -1));
|
|
81
|
+
return /* @__PURE__ */ React2.createElement(Text2, { key: j, italic: true, color: "gray" }, /* @__PURE__ */ React2.createElement(InlineMarkdown, { text: part.slice(1, -1), color: "gray" }));
|
|
81
82
|
}
|
|
82
83
|
if (part.startsWith("`") && part.endsWith("`")) {
|
|
83
84
|
return /* @__PURE__ */ React2.createElement(Text2, { key: j, color: "cyan", backgroundColor: "#003333" }, " ", part.slice(1, -1), " ");
|
|
@@ -86,11 +87,16 @@ var init_ChatLayout = __esm({
|
|
|
86
87
|
const content = part.slice(11, -2);
|
|
87
88
|
return /* @__PURE__ */ React2.createElement(Text2, { key: j, color: "white", backgroundColor: "#4c0099", bold: true, italic: true }, " ", content, " ");
|
|
88
89
|
}
|
|
89
|
-
if (part.startsWith("[") && part.includes("](")) {
|
|
90
|
-
const match = part.match(/\[(.*?)\]\((.*?)\)/);
|
|
91
|
-
if (match) {
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
if (part.startsWith("[") && (part.includes("](") || part.includes("] ("))) {
|
|
91
|
+
const match = part.match(/\[(.*?)\]\s*\((.*?)\)/);
|
|
92
|
+
if (match) return /* @__PURE__ */ React2.createElement(Text2, { key: j }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", underline: true, bold: true }, match[1]), /* @__PURE__ */ React2.createElement(Text2, { color: "gray", dimColor: true, italic: true }, " (", match[2], ")"));
|
|
93
|
+
}
|
|
94
|
+
if (part.startsWith("[") && (part.includes("][") || part.includes("] ["))) {
|
|
95
|
+
const match = part.match(/\[(.*?)\]\s*\[(.*?)\]/);
|
|
96
|
+
if (match) return /* @__PURE__ */ React2.createElement(Text2, { key: j }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", underline: true, bold: true }, match[1]), /* @__PURE__ */ React2.createElement(Text2, { color: "gray", dimColor: true, italic: true }, " [", match[2], "]"));
|
|
97
|
+
}
|
|
98
|
+
if (part.startsWith("http")) {
|
|
99
|
+
return /* @__PURE__ */ React2.createElement(Text2, { key: j, color: "cyan", underline: true, italic: true }, part);
|
|
94
100
|
}
|
|
95
101
|
return part;
|
|
96
102
|
}));
|
|
@@ -102,15 +108,8 @@ var init_ChatLayout = __esm({
|
|
|
102
108
|
);
|
|
103
109
|
const header = rows[0];
|
|
104
110
|
const data = rows.slice(2);
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
data.forEach((row) => {
|
|
108
|
-
const cleanCell = (row[i] || "").replace(/\*|`/g, "");
|
|
109
|
-
if (cleanCell.length > max) max = cleanCell.length;
|
|
110
|
-
});
|
|
111
|
-
return max;
|
|
112
|
-
});
|
|
113
|
-
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "single", borderColor: "#333", paddingX: 1, marginY: 1, alignSelf: "flex-start" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "row", marginBottom: 1 }, header.map((cell, i) => /* @__PURE__ */ React2.createElement(Box2, { key: i, width: colWidths[i] + 4, paddingRight: 4 }, /* @__PURE__ */ React2.createElement(InlineMarkdown, { text: cell, color: "cyan" })))), /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: "#444", width: "100%", marginBottom: 1 }), data.map((row, ri) => /* @__PURE__ */ React2.createElement(Box2, { key: ri, flexDirection: "row", marginBottom: ri === data.length - 1 ? 0 : 1 }, row.map((cell, ci) => /* @__PURE__ */ React2.createElement(Box2, { key: ci, width: colWidths[ci] + 4, paddingRight: 4, flexDirection: "column" }, /* @__PURE__ */ React2.createElement(InlineMarkdown, { text: cell, color: "white" }))))));
|
|
111
|
+
const colPercentage = Math.floor(100 / header.length);
|
|
112
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "single", borderColor: "#333", paddingX: 1, marginY: 1, width: "100%", flexGrow: 1 }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "row", borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, borderColor: "#444", marginBottom: 1, paddingBottom: 1, width: "100%" }, header.map((cell, i) => /* @__PURE__ */ React2.createElement(Box2, { key: i, flexBasis: `${colPercentage}%`, flexGrow: 1, flexShrink: 0, paddingRight: 2 }, /* @__PURE__ */ React2.createElement(InlineMarkdown, { text: cell, color: "cyan" })))), data.map((row, ri) => /* @__PURE__ */ React2.createElement(Box2, { key: ri, flexDirection: "row", marginBottom: ri === data.length - 1 ? 0 : 1, width: "100%" }, row.map((cell, ci) => /* @__PURE__ */ React2.createElement(Box2, { key: ci, flexBasis: `${colPercentage}%`, flexGrow: 1, flexShrink: 0, paddingRight: 2, flexDirection: "column" }, /* @__PURE__ */ React2.createElement(InlineMarkdown, { text: cell, color: "white" }))))));
|
|
114
113
|
});
|
|
115
114
|
MarkdownText = React2.memo(({ text, color = "white", columns = 80 }) => {
|
|
116
115
|
if (!text) return null;
|
|
@@ -171,7 +170,7 @@ var init_ChatLayout = __esm({
|
|
|
171
170
|
}
|
|
172
171
|
});
|
|
173
172
|
flushBuffers("final");
|
|
174
|
-
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width:
|
|
173
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: columns - 2 }, result);
|
|
175
174
|
});
|
|
176
175
|
DiffLine = React2.memo(({ line }) => {
|
|
177
176
|
const isContext = line.includes("[UI_CONTEXT]");
|
|
@@ -262,7 +261,7 @@ var init_ChatLayout = __esm({
|
|
|
262
261
|
}
|
|
263
262
|
return content;
|
|
264
263
|
}, [content, msg.role, showFullThinking]);
|
|
265
|
-
return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, flexDirection: "column", flexShrink: 0, width: "100%" }, msg.role === "user" ? /* @__PURE__ */ React2.createElement(
|
|
264
|
+
return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, flexDirection: "column", flexShrink: 0, width: "100%", flexGrow: 1 }, msg.role === "user" ? /* @__PURE__ */ React2.createElement(
|
|
266
265
|
Box2,
|
|
267
266
|
{
|
|
268
267
|
backgroundColor: "#262626",
|
|
@@ -577,7 +576,8 @@ ${isMemoryEnabled ? `2. User-specific long-term memory (USE BASED ON CONVERSATIO
|
|
|
577
576
|
- Update: tool:functions.memory(action='user', method='update', content-new='string to update', content-old='exact memory id')
|
|
578
577
|
|
|
579
578
|
Usage Rules:
|
|
580
|
-
- Frequency for 'user' action: Only when explicit context from chat is found or explicitly requested by the user
|
|
579
|
+
- Frequency for 'user' action: Only when explicit context from chat is found or explicitly requested by the user.
|
|
580
|
+
- IF YOU WANT TO SAVE SOMETHING, BUT SIMILAR MEMORY ALREADY EXISTS, USE THE UPDATE METHOD NOT THE ADD METHOD` : ""}
|
|
581
581
|
-- END MEMORY TOOLS --`.trim();
|
|
582
582
|
}
|
|
583
583
|
});
|
|
@@ -2487,11 +2487,30 @@ Check what's new using \`/changelog\` command.`,
|
|
|
2487
2487
|
setTempKey("");
|
|
2488
2488
|
}
|
|
2489
2489
|
};
|
|
2490
|
-
const COMMANDS = [
|
|
2490
|
+
const COMMANDS = [
|
|
2491
|
+
{ cmd: "/quit", desc: "Exit and shutdown Flux" },
|
|
2492
|
+
{ cmd: "/help", desc: "Show all available commands" },
|
|
2493
|
+
{ cmd: "/clear", desc: "Clear terminal screen" },
|
|
2494
|
+
{ cmd: "/resume", desc: "Load previous session" },
|
|
2495
|
+
{ cmd: "/save", desc: "Force save current chat" },
|
|
2496
|
+
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
2497
|
+
{ cmd: "/mode", desc: "Toggle Flux/Flow modes" },
|
|
2498
|
+
{ cmd: "/thinking", desc: "Set AI reasoning depth" },
|
|
2499
|
+
{ cmd: "/model", desc: "Switch AI brain model" },
|
|
2500
|
+
{ cmd: "/settings", desc: "Configure system prefs" },
|
|
2501
|
+
{ cmd: "/key", desc: "Manage API keys" },
|
|
2502
|
+
{ cmd: "/profile", desc: "Edit developer persona" },
|
|
2503
|
+
{ cmd: "/memory", desc: "Manage agent memory" },
|
|
2504
|
+
{ cmd: "/stats", desc: "Show session usage" },
|
|
2505
|
+
{ cmd: "/reset", desc: "Wipe all project data" },
|
|
2506
|
+
{ cmd: "/about", desc: "Project info & credits" },
|
|
2507
|
+
{ cmd: "/changelog", desc: "View latest updates" },
|
|
2508
|
+
{ cmd: "/update", desc: "Check/Install updates" }
|
|
2509
|
+
];
|
|
2491
2510
|
const handleSubmit = (value) => {
|
|
2492
2511
|
if (suggestions.length > 0) {
|
|
2493
|
-
const
|
|
2494
|
-
setInput(
|
|
2512
|
+
const nextMatch = suggestions[selectedIndex] || suggestions[0];
|
|
2513
|
+
setInput(nextMatch.cmd + " ");
|
|
2495
2514
|
setSelectedIndex(0);
|
|
2496
2515
|
return;
|
|
2497
2516
|
}
|
|
@@ -3005,7 +3024,7 @@ Selection: ${val}`,
|
|
|
3005
3024
|
};
|
|
3006
3025
|
const suggestions = useMemo(() => {
|
|
3007
3026
|
if (!input.startsWith("/") || input.includes(" ")) return [];
|
|
3008
|
-
return COMMANDS.filter((c) => c.startsWith(input.toLowerCase()));
|
|
3027
|
+
return COMMANDS.filter((c) => c.cmd.startsWith(input.toLowerCase()));
|
|
3009
3028
|
}, [input]);
|
|
3010
3029
|
useEffect4(() => {
|
|
3011
3030
|
setSelectedIndex(0);
|
|
@@ -3059,7 +3078,7 @@ Selection: ${val}`,
|
|
|
3059
3078
|
CommandMenu,
|
|
3060
3079
|
{
|
|
3061
3080
|
title: "\u{1F916} Select AI Model",
|
|
3062
|
-
items: [{ label: "Gemma 4 31B
|
|
3081
|
+
items: [{ label: "Gemma 4 31B (Recomended - Default, Use Free Tier Key)", value: "gemma-4-31b-it" }, { label: "Gemini 3.1 Pro (Recomended - Req. paid API Key)", value: "gemini-3.1-pro-preview" }, { label: "Gemini 3 Flash (Paid API Key Recomended)", value: "gemini-3-flash-preview" }, { label: "Gemini 3.1 Flash Lite (Fastest - For Quick Tasks ONLY)", value: "gemini-3.1-flash-lite-preview" }, { label: "Cancel", value: "Cancel" }],
|
|
3063
3082
|
onSelect: (item) => {
|
|
3064
3083
|
if (item.value !== "Cancel") setActiveModel(item.value);
|
|
3065
3084
|
setActiveView("chat");
|
|
@@ -3546,7 +3565,7 @@ Selection: ${val}`,
|
|
|
3546
3565
|
)))))));
|
|
3547
3566
|
}
|
|
3548
3567
|
};
|
|
3549
|
-
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, windowedHistory.isTruncated && /* @__PURE__ */ React10.createElement(Box10, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1, width: "100%", justifyContent: "center" }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true, italic: true }, "[ \u2191 History truncated for performance (showing last ~1000 lines) ]")), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, windowedHistory.items.map((msg, idx) => /* @__PURE__ */ React10.createElement(MessageItem, { key: msg.id || idx, msg, showFullThinking }))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1, width: "100%" }, (activeView === "chat" || ["ask", "approval", "terminalApproval"].includes(activeView)) && /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React10.createElement(
|
|
3568
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, windowedHistory.isTruncated && /* @__PURE__ */ React10.createElement(Box10, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1, width: "100%", justifyContent: "center" }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true, italic: true }, "[ \u2191 History truncated for performance (showing last ~1000 lines) ]")), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%", flexGrow: 1 }, windowedHistory.items.map((msg, idx) => /* @__PURE__ */ React10.createElement(MessageItem, { key: msg.id || idx, msg, showFullThinking, columns: stdout?.columns || 80 }))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1, width: "100%" }, (activeView === "chat" || ["ask", "approval", "terminalApproval"].includes(activeView)) && /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React10.createElement(
|
|
3550
3569
|
ChatLayout_default,
|
|
3551
3570
|
{
|
|
3552
3571
|
messages: messages.slice(completedIndex),
|
|
@@ -3571,7 +3590,33 @@ Selection: ${val}`,
|
|
|
3571
3590
|
chatId,
|
|
3572
3591
|
isMemoryEnabled: systemSettings.memory
|
|
3573
3592
|
}
|
|
3574
|
-
))
|
|
3593
|
+
)), suggestions.length > 0 && (() => {
|
|
3594
|
+
const windowSize = 5;
|
|
3595
|
+
const startIdx = Math.max(0, Math.min(selectedIndex - 2, suggestions.length - windowSize));
|
|
3596
|
+
const visible = suggestions.slice(startIdx, startIdx + windowSize);
|
|
3597
|
+
const remaining = suggestions.length - (startIdx + visible.length);
|
|
3598
|
+
return /* @__PURE__ */ React10.createElement(
|
|
3599
|
+
Box10,
|
|
3600
|
+
{
|
|
3601
|
+
flexDirection: "column",
|
|
3602
|
+
backgroundColor: "#222",
|
|
3603
|
+
borderStyle: "round",
|
|
3604
|
+
borderColor: "yellow",
|
|
3605
|
+
paddingX: 1,
|
|
3606
|
+
paddingY: 0,
|
|
3607
|
+
marginTop: 0,
|
|
3608
|
+
width: "100%",
|
|
3609
|
+
minHeight: suggestions.length >= 5 ? 7 : 0
|
|
3610
|
+
},
|
|
3611
|
+
visible.map((s, i) => {
|
|
3612
|
+
const actualIdx = startIdx + i;
|
|
3613
|
+
const isActive = actualIdx === selectedIndex;
|
|
3614
|
+
const cmdText = s.cmd.padEnd(12);
|
|
3615
|
+
return /* @__PURE__ */ React10.createElement(Box10, { key: s.cmd, flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Text10, { color: isActive ? "cyan" : "gray" }, isActive ? "\u276F " : " "), /* @__PURE__ */ React10.createElement(Text10, { color: isActive ? "yellow" : "gray", bold: isActive }, cmdText), /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true, italic: true }, s.desc));
|
|
3616
|
+
}),
|
|
3617
|
+
suggestions.length > 5 && /* @__PURE__ */ React10.createElement(Box10, { height: 1 }, remaining > 0 && /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true }, " ... (", remaining, " more)"))
|
|
3618
|
+
);
|
|
3619
|
+
})()));
|
|
3575
3620
|
}
|
|
3576
3621
|
var SESSION_START_TIME, CHANGELOG_URL, versionFluxflow, updatedOn, ResolutionModal, FLUX_LOGO;
|
|
3577
3622
|
var init_app = __esm({
|
|
@@ -3595,8 +3640,8 @@ var init_app = __esm({
|
|
|
3595
3640
|
init_terminal();
|
|
3596
3641
|
SESSION_START_TIME = Date.now();
|
|
3597
3642
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
3598
|
-
versionFluxflow = "1.3.
|
|
3599
|
-
updatedOn = "2026-04-
|
|
3643
|
+
versionFluxflow = "1.3.4";
|
|
3644
|
+
updatedOn = "2026-04-29";
|
|
3600
3645
|
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 (turn: finish) 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(
|
|
3601
3646
|
CommandMenu,
|
|
3602
3647
|
{
|