fluxflow-cli 1.0.0 โ 1.0.2
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 +2 -2
- package/TOOLS.md +48 -0
- package/UI_FEATURES.md +66 -0
- package/dist/{index.js โ fluxflow.js} +47 -6
- package/package.json +13 -4
- package/fluxflow.png +0 -0
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# ๐ Flux Flow (`fluxflow-cli`)
|
|
2
|
-

|
|
3
3
|
|
|
4
4
|
### *The High-Fidelity Agentic Terminal for the Flux Era.*
|
|
5
5
|
|
|
6
|
-
**Flux Flow** is not just another CLIโit's a high-speed, sassy, and goal-oriented
|
|
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 frontier models. Designed for developers who demand a premium UI/UX while managing complex file-system tasks, web research, and autonomous workflows.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
package/TOOLS.md
ADDED
|
@@ -0,0 +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.
|
|
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
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
- **/help**: List all available commands.
|
|
18
|
+
|
|
19
|
+
### Command Shortcuts
|
|
20
|
+
|
|
21
|
+
For power users, several commands support direct arguments to skip the menus:
|
|
22
|
+
- ` /mode flux ` or ` /mode flow `
|
|
23
|
+
- ` /thinking low ` / ` /thinking medium ` / ` /thinking high ` / ` /thinking max `
|
|
24
|
+
- ` /thinking show ` / ` /thinking hide ` (Toggles thinking process visibility)
|
|
25
|
+
- ` /model gemini-3.1-pro-preview ` (Switches model directly)
|
|
26
|
+
|
|
27
|
+
## ๐ง Thinking Levels & Visualization
|
|
28
|
+
|
|
29
|
+
Flux Flow separates the model's "internal monologue" (reasoning) from its final response using `<think>` tags.
|
|
30
|
+
|
|
31
|
+
- **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.
|
|
32
|
+
- **Show/Hide Thinking**: You can toggle the visibility of the thinking process using `/thinking show/hide`.
|
|
33
|
+
- 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.
|
|
34
|
+
|
|
35
|
+
## ๐ก๏ธ Human-in-the-Loop (HITL) Verification
|
|
36
|
+
|
|
37
|
+
Security and safety are paramount when an AI has access to your file system and terminal. Flux Flow implements several layers of verification:
|
|
38
|
+
|
|
39
|
+
### Tool Approval
|
|
40
|
+
By default, the agent **cannot** execute dangerous actions without your consent.
|
|
41
|
+
- **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.
|
|
42
|
+
- **File Approval**: Similar to terminal commands, writing or updating files requires manual approval unless configured otherwise.
|
|
43
|
+
- **Safe Commands**: Basic read-only commands (like `ls`, `git status`, `pwd`) are automatically allowed to minimize friction.
|
|
44
|
+
|
|
45
|
+
### Auto-Execution (Advanced)
|
|
46
|
+
For power users, **Auto-Exec** can be enabled in `/settings`.
|
|
47
|
+
- **โ ๏ธ Warning**: This allows the agent to run any tool and execute any command autonomously.
|
|
48
|
+
- **External Access**: You can also toggle whether the agent is allowed to access files outside of its current working directory.
|
|
49
|
+
|
|
50
|
+
## ๐ Steering & Resolution
|
|
51
|
+
|
|
52
|
+
### Real-time Steering
|
|
53
|
+
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.
|
|
54
|
+
|
|
55
|
+
### Resolution Modal
|
|
56
|
+
If the agent finishes its task just as you send a steering hint, a **Resolution Modal** appears. It asks if you want to:
|
|
57
|
+
- **Send Anyway**: Start a new loop with your feedback.
|
|
58
|
+
- **Edit Prompt**: Refine your feedback before sending.
|
|
59
|
+
|
|
60
|
+
## ๐ Status Bar & Feedback
|
|
61
|
+
The bottom of the screen features a dynamic status bar showing:
|
|
62
|
+
- **Active Mode** (Flux/Flow)
|
|
63
|
+
- **Thinking Level**
|
|
64
|
+
- **Token Usage**: Real-time tracking of tokens used in the current session.
|
|
65
|
+
- **Agentic Loops**: Counters showing how many times the agent has "looped" to solve the current task.
|
|
66
|
+
- **API Status**: Visual feedback when the model is thinking or executing a tool.
|
|
@@ -7,6 +7,9 @@ import { render } from "ink";
|
|
|
7
7
|
// src/app.jsx
|
|
8
8
|
import React8, { useState as useState4, useEffect as useEffect3, useRef, useMemo } from "react";
|
|
9
9
|
import { Box as Box8, Text as Text8, useInput as useInput3, useStdout, Static } from "ink";
|
|
10
|
+
import fs14 from "fs-extra";
|
|
11
|
+
import path16 from "path";
|
|
12
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
10
13
|
import { MultilineInput } from "ink-multiline-input";
|
|
11
14
|
import TextInput2 from "ink-text-input";
|
|
12
15
|
|
|
@@ -191,7 +194,7 @@ function StatusBar({ mode, thinkingLevel, tokens = "0.0k", chatId = "NEW-SESSION
|
|
|
191
194
|
},
|
|
192
195
|
/* @__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)),
|
|
193
196
|
/* @__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())),
|
|
194
|
-
/* @__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 /
|
|
197
|
+
/* @__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 / 196e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, "ID: ", chatId, " "))
|
|
195
198
|
);
|
|
196
199
|
}
|
|
197
200
|
|
|
@@ -792,7 +795,7 @@ var memory = async (rawArgs, context = {}) => {
|
|
|
792
795
|
if (!content) return "ERROR: Missing 'content' for temp memory.";
|
|
793
796
|
const tempStorage = readEncryptedJson(TEMP_MEM_PATH, {});
|
|
794
797
|
if (!tempStorage[chatId]) tempStorage[chatId] = [];
|
|
795
|
-
const MAX_CHARS =
|
|
798
|
+
const MAX_CHARS = 3e3 * 4;
|
|
796
799
|
let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
|
|
797
800
|
while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
798
801
|
const removed = tempStorage[chatId].shift();
|
|
@@ -806,7 +809,7 @@ var memory = async (rawArgs, context = {}) => {
|
|
|
806
809
|
const memories = readEncryptedJson(MEMORIES_PATH, []);
|
|
807
810
|
if (method === "add") {
|
|
808
811
|
if (!content) return "ERROR: Missing 'content' for memory addition.";
|
|
809
|
-
const MAX_CHARS =
|
|
812
|
+
const MAX_CHARS = 2e3 * 4;
|
|
810
813
|
let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
|
|
811
814
|
while (memories.length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
812
815
|
const removed = memories.shift();
|
|
@@ -1282,7 +1285,7 @@ var getAIStream = async function* (modelName, history, settings, steeringCallbac
|
|
|
1282
1285
|
const needTitle = isFirstPrompt || hasTitleSignal;
|
|
1283
1286
|
const agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
|
|
1284
1287
|
let modifiedHistory = [...history.slice(0, -1)];
|
|
1285
|
-
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) >
|
|
1288
|
+
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 196e3) {
|
|
1286
1289
|
modifiedHistory = getTruncatedHistory(modifiedHistory, 4);
|
|
1287
1290
|
}
|
|
1288
1291
|
const tempStorage = readEncryptedJson(TEMP_MEM_PATH2, {});
|
|
@@ -1391,7 +1394,17 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
1391
1394
|
const url = parseArgs(toolCall.args).url || "...";
|
|
1392
1395
|
label = `\u{1F4D6} READING SITE: ${url}`.toUpperCase();
|
|
1393
1396
|
} else if (toolCall.toolName === "view_file") {
|
|
1394
|
-
|
|
1397
|
+
const { path: targetPath2, start_line = 1, end_line = 500 } = parseArgs(toolCall.args);
|
|
1398
|
+
let totalLines = "...";
|
|
1399
|
+
try {
|
|
1400
|
+
const absPath = path13.resolve(process.cwd(), targetPath2);
|
|
1401
|
+
if (fs12.existsSync(absPath)) {
|
|
1402
|
+
const content = fs12.readFileSync(absPath, "utf8");
|
|
1403
|
+
totalLines = content.split("\n").length;
|
|
1404
|
+
}
|
|
1405
|
+
} catch (e) {
|
|
1406
|
+
}
|
|
1407
|
+
label = `\u{1F4C4} READING FILE: ${targetPath2}. LINES ${start_line} - ${end_line} FROM ${totalLines}`.toUpperCase();
|
|
1395
1408
|
} else if (toolCall.toolName === "list_files" || toolCall.toolName === "read_folder") {
|
|
1396
1409
|
const action = toolCall.toolName === "list_files" ? "LISTING" : "DISCOVERING";
|
|
1397
1410
|
label = `\u{1F4C2} ${action} DIRECTORY: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
|
|
@@ -1910,7 +1923,7 @@ function App() {
|
|
|
1910
1923
|
setTempKey("");
|
|
1911
1924
|
}
|
|
1912
1925
|
};
|
|
1913
|
-
const COMMANDS = ["/mode", "/thinking", "/model", "/resume", "/memory", "/profile", "/settings", "/key", "/stats", "/help", "/clear", "/quit"];
|
|
1926
|
+
const COMMANDS = ["/mode", "/thinking", "/model", "/resume", "/memory", "/profile", "/settings", "/key", "/stats", "/reset", "/help", "/clear", "/quit"];
|
|
1914
1927
|
const handleSubmit = (value) => {
|
|
1915
1928
|
const normalizedValue = value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimEnd();
|
|
1916
1929
|
if (normalizedValue.endsWith("\\")) {
|
|
@@ -2081,6 +2094,34 @@ ${list || "No saved chats found."}` }];
|
|
|
2081
2094
|
setActiveView("memory");
|
|
2082
2095
|
break;
|
|
2083
2096
|
}
|
|
2097
|
+
case "/reset": {
|
|
2098
|
+
const runReset = async () => {
|
|
2099
|
+
const AGENT_ROOT7 = path16.join(path16.dirname(fileURLToPath9(import.meta.url)), "../");
|
|
2100
|
+
const logsDir = path16.join(AGENT_ROOT7, "logs");
|
|
2101
|
+
const secretDir = path16.join(AGENT_ROOT7, "secret");
|
|
2102
|
+
const settingsFile = path16.join(AGENT_ROOT7, "settings.json");
|
|
2103
|
+
try {
|
|
2104
|
+
setMessages((prev) => {
|
|
2105
|
+
setCompletedIndex(prev.length + 1);
|
|
2106
|
+
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset..." }];
|
|
2107
|
+
});
|
|
2108
|
+
if (fs14.existsSync(logsDir)) fs14.removeSync(logsDir);
|
|
2109
|
+
if (fs14.existsSync(secretDir)) fs14.removeSync(secretDir);
|
|
2110
|
+
if (fs14.existsSync(settingsFile)) fs14.removeSync(settingsFile);
|
|
2111
|
+
setTimeout(() => {
|
|
2112
|
+
setActiveView("exit");
|
|
2113
|
+
setTimeout(() => process.exit(0), 500);
|
|
2114
|
+
}, 500);
|
|
2115
|
+
} catch (err) {
|
|
2116
|
+
setMessages((prev) => {
|
|
2117
|
+
setCompletedIndex(prev.length + 1);
|
|
2118
|
+
return [...prev, { id: Date.now(), role: "system", text: `\u274C [RESET ERROR] Failed to purge data: ${err.message}` }];
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
};
|
|
2122
|
+
runReset();
|
|
2123
|
+
break;
|
|
2124
|
+
}
|
|
2084
2125
|
case "/help": {
|
|
2085
2126
|
setMessages((prev) => {
|
|
2086
2127
|
setCompletedIndex(prev.length + 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluxflow-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A high-fidelity agentic terminal assistant for the Flux Era.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -12,20 +12,29 @@
|
|
|
12
12
|
"flux"
|
|
13
13
|
],
|
|
14
14
|
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/KushalRoyChowdhury/fluxflow-cli.git"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
},
|
|
15
22
|
"files": [
|
|
16
23
|
"dist",
|
|
17
24
|
"README.md",
|
|
18
25
|
"package.json",
|
|
19
26
|
"ARCHITECTURE.md",
|
|
20
|
-
"
|
|
27
|
+
"TOOLS.md",
|
|
28
|
+
"UI_FEATURES.md"
|
|
21
29
|
],
|
|
22
30
|
"type": "module",
|
|
23
31
|
"bin": {
|
|
24
|
-
"fluxflow-cli": "dist/
|
|
32
|
+
"fluxflow-cli": "dist/fluxflow.js",
|
|
33
|
+
"fluxflow": "dist/fluxflow.js"
|
|
25
34
|
},
|
|
26
35
|
"scripts": {
|
|
27
36
|
"start": "tsx ./src/cli.jsx",
|
|
28
|
-
"build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/
|
|
37
|
+
"build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:ink-spinner --external:ink-multiline-input --external:@google/genai --external:zod --external:duck-duck-scrape --external:nanoid --external:cuimp"
|
|
29
38
|
},
|
|
30
39
|
"dependencies": {
|
|
31
40
|
"@google/genai": "^1.50.1",
|
package/fluxflow.png
DELETED
|
Binary file
|