fluxflow-cli 1.11.3 → 1.12.0
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 +19 -0
- package/dist/fluxflow.js +361 -220
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -83,6 +83,25 @@ While you move at high speed, the Janitor follows behind—refining session titl
|
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
|
|
86
|
+
## 💻 CLI Startup Arguments
|
|
87
|
+
Customize your session parameters directly from your console launch command:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
fluxflow [options]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Supported Flags:
|
|
94
|
+
- `--model <model-name>`: Temporary override for the active AI model (e.g., `gemini-2.5-pro`). Keeps settings file untouched.
|
|
95
|
+
- `--memory <on|off>`: Toggle persistent long-term agent memory for the session.
|
|
96
|
+
- `--resume <session-id>`: Resume a previous chat session programmatically.
|
|
97
|
+
- `--update <check|latest>`: Manually run an update check (`check`) or execute latest update setup (`latest`).
|
|
98
|
+
- `--package <npm|pnpm|yarn|bun>`: Override default package manager to run core application updates.
|
|
99
|
+
- `--auto-del <1d|7d|30d>`: Set automated chat log deletion schedule.
|
|
100
|
+
- `--auto-exec <on|off>`: Toggle autonomous command execution permission.
|
|
101
|
+
- `--external-access <on|off>`: Toggle permission to let agent read files outside CWD.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
86
105
|
## ⚙️ Configuration
|
|
87
106
|
Type `/settings` in-app to live-configure:
|
|
88
107
|
- **Thinking Level**: Fast (No Reasoning), Low, Medium, High, xHigh (Extended Reasoning).
|
package/dist/fluxflow.js
CHANGED
|
@@ -609,18 +609,26 @@ var init_CommandMenu = __esm({
|
|
|
609
609
|
});
|
|
610
610
|
|
|
611
611
|
// src/components/ProfileForm.jsx
|
|
612
|
-
import React5, { useState as useState2 } from "react";
|
|
612
|
+
import React5, { useState as useState2, useEffect as useEffect2 } from "react";
|
|
613
613
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
614
614
|
import TextInput from "ink-text-input";
|
|
615
|
-
function ProfileForm({ onSave, onCancel }) {
|
|
615
|
+
function ProfileForm({ initialData, onSave, onCancel }) {
|
|
616
616
|
const [step, setStep] = useState2(0);
|
|
617
617
|
const [currentInput, setCurrentInput] = useState2("");
|
|
618
|
-
const [profile, setProfile] = useState2(
|
|
618
|
+
const [profile, setProfile] = useState2(() => ({
|
|
619
|
+
name: initialData?.name || "",
|
|
620
|
+
nickname: initialData?.nickname || "",
|
|
621
|
+
instructions: initialData?.instructions || ""
|
|
622
|
+
}));
|
|
619
623
|
const steps = [
|
|
620
624
|
{ key: "name", label: "Enter your Name: " },
|
|
621
625
|
{ key: "nickname", label: "Enter a Nickname (Agent will use this): " },
|
|
622
626
|
{ key: "instructions", label: "System Instructions (Persona overrides): " }
|
|
623
627
|
];
|
|
628
|
+
useEffect2(() => {
|
|
629
|
+
const currentKey = steps[step].key;
|
|
630
|
+
setCurrentInput(profile[currentKey] || "");
|
|
631
|
+
}, [step, profile]);
|
|
624
632
|
const handleSubmit = (val) => {
|
|
625
633
|
if (val.trim().toLowerCase() === "/cancel") {
|
|
626
634
|
onCancel();
|
|
@@ -714,7 +722,8 @@ var init_AskUserModal = __esm({
|
|
|
714
722
|
flexDirection: "column",
|
|
715
723
|
width: "100%",
|
|
716
724
|
backgroundColor: isSelected ? "#2a2a2a" : void 0,
|
|
717
|
-
paddingX: 1
|
|
725
|
+
paddingX: 1,
|
|
726
|
+
marginBottom: idx === allOptions.length - 1 ? 0 : 1
|
|
718
727
|
},
|
|
719
728
|
/* @__PURE__ */ React6.createElement(Text6, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", opt.label),
|
|
720
729
|
opt.description && /* @__PURE__ */ React6.createElement(Box6, { marginLeft: 4 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", italic: true, dimColor: true }, opt.description))
|
|
@@ -952,11 +961,11 @@ ${mode === "Flux" ? `- FILE TOOLS (path = relative to CWD) -
|
|
|
952
961
|
2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
|
|
953
962
|
3. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? -> update_file > write_file
|
|
954
963
|
4. [tool:functions.PatchFile(path="...", content_to_replace="exact old content", content_to_add="new content")]. Surgical patching. Unsure content_to_replace? -> view_file >> guessing.
|
|
955
|
-
5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. A4 PDF.
|
|
964
|
+
5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. A4 PDF. HTML/CSS for premium layout (100vh/vw). Handle page breaks; no manual footers
|
|
956
965
|
6. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word doc. Proper margins and page breaks
|
|
957
966
|
7. [tool:functions.Run(command="...")]. Runs a shell command. Destructive/Irreversible ops -> ask user
|
|
958
967
|
8. [tool:functions.SearchKeyword(keyword="...")]. Global search. Finds definitions/logic without reading every file
|
|
959
|
-
9. [tool:functions.GenerateImage(path="... png", prompt="
|
|
968
|
+
9. [tool:functions.GenerateImage(path="... png", prompt="detailed", ratio="16:9, 9:16, 1:1, 4:3, 3:4")]. AI images. Usage: Mockups, PDF thumbnails, any visual content
|
|
960
969
|
|
|
961
970
|
- VERIFY RESULT CONTENTS. Fix errors. No hallucinations
|
|
962
971
|
- File tools > code chat
|
|
@@ -1404,18 +1413,49 @@ var init_usage = __esm({
|
|
|
1404
1413
|
};
|
|
1405
1414
|
loadUsageFromFile = async () => {
|
|
1406
1415
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1416
|
+
const tempFile = USAGE_FILE + ".tmp";
|
|
1407
1417
|
let primaryData = null;
|
|
1408
1418
|
let backupData = null;
|
|
1409
1419
|
try {
|
|
1410
|
-
if (await fs6.exists(
|
|
1411
|
-
const rawContent = (await fs6.readFile(
|
|
1420
|
+
if (await fs6.exists(tempFile)) {
|
|
1421
|
+
const rawContent = (await fs6.readFile(tempFile, "utf8")).trim();
|
|
1422
|
+
let parsed = null;
|
|
1412
1423
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1413
|
-
|
|
1424
|
+
parsed = JSON.parse(rawContent);
|
|
1425
|
+
} else {
|
|
1426
|
+
parsed = JSON.parse(decryptAes(rawContent));
|
|
1427
|
+
}
|
|
1428
|
+
if (parsed && parsed.date && parsed.stats) {
|
|
1429
|
+
primaryData = parsed;
|
|
1430
|
+
try {
|
|
1431
|
+
await fs6.rename(tempFile, USAGE_FILE);
|
|
1432
|
+
} catch (e) {
|
|
1433
|
+
}
|
|
1414
1434
|
} else {
|
|
1415
|
-
|
|
1435
|
+
try {
|
|
1436
|
+
await fs6.remove(tempFile);
|
|
1437
|
+
} catch (e) {
|
|
1438
|
+
}
|
|
1416
1439
|
}
|
|
1417
1440
|
}
|
|
1418
1441
|
} catch (err) {
|
|
1442
|
+
try {
|
|
1443
|
+
await fs6.remove(tempFile);
|
|
1444
|
+
} catch (e) {
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
if (!primaryData) {
|
|
1448
|
+
try {
|
|
1449
|
+
if (await fs6.exists(USAGE_FILE)) {
|
|
1450
|
+
const rawContent = (await fs6.readFile(USAGE_FILE, "utf8")).trim();
|
|
1451
|
+
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1452
|
+
primaryData = JSON.parse(rawContent);
|
|
1453
|
+
} else {
|
|
1454
|
+
primaryData = JSON.parse(decryptAes(rawContent));
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
} catch (err) {
|
|
1458
|
+
}
|
|
1419
1459
|
}
|
|
1420
1460
|
try {
|
|
1421
1461
|
if (await fs6.exists(BACKUP_FILE)) {
|
|
@@ -2148,70 +2188,9 @@ var init_chat = __esm({
|
|
|
2148
2188
|
}
|
|
2149
2189
|
});
|
|
2150
2190
|
|
|
2151
|
-
// src/tools/
|
|
2191
|
+
// src/tools/view_file.js
|
|
2152
2192
|
import fs7 from "fs";
|
|
2153
2193
|
import path6 from "path";
|
|
2154
|
-
var list_files;
|
|
2155
|
-
var init_list_files = __esm({
|
|
2156
|
-
"src/tools/list_files.js"() {
|
|
2157
|
-
init_arg_parser();
|
|
2158
|
-
list_files = async (args) => {
|
|
2159
|
-
const { path: targetPath = "." } = parseArgs(args);
|
|
2160
|
-
const absolutePath = path6.resolve(process.cwd(), targetPath);
|
|
2161
|
-
try {
|
|
2162
|
-
if (!fs7.existsSync(absolutePath)) {
|
|
2163
|
-
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2164
|
-
}
|
|
2165
|
-
const stats = fs7.statSync(absolutePath);
|
|
2166
|
-
if (!stats.isDirectory()) {
|
|
2167
|
-
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2168
|
-
}
|
|
2169
|
-
const files = fs7.readdirSync(absolutePath);
|
|
2170
|
-
if (files.length === 0) {
|
|
2171
|
-
return `Directory [${targetPath}] is empty.`;
|
|
2172
|
-
}
|
|
2173
|
-
const totalFiles = files.length;
|
|
2174
|
-
const maxDisplay = 100;
|
|
2175
|
-
const displayFiles = files.slice(0, maxDisplay);
|
|
2176
|
-
const list = displayFiles.map((file) => {
|
|
2177
|
-
const fPath = path6.join(absolutePath, file);
|
|
2178
|
-
let indicator = "\u{1F4C4}";
|
|
2179
|
-
let metaPart = "";
|
|
2180
|
-
try {
|
|
2181
|
-
const fStats = fs7.statSync(fPath);
|
|
2182
|
-
indicator = fStats.isDirectory() ? "\u{1F4C1}" : "\u{1F4C4}";
|
|
2183
|
-
const sizeKB = (fStats.size / 1024).toFixed(1);
|
|
2184
|
-
metaPart = fStats.isFile() ? ` - [${sizeKB} KB]` : "";
|
|
2185
|
-
} catch (e) {
|
|
2186
|
-
indicator = "\u2753";
|
|
2187
|
-
metaPart = " - [Access Denied]";
|
|
2188
|
-
}
|
|
2189
|
-
return `${indicator} ${file}${metaPart}`;
|
|
2190
|
-
}).join("\n");
|
|
2191
|
-
let footer = `
|
|
2192
|
-
|
|
2193
|
-
(Total items: ${totalFiles})`;
|
|
2194
|
-
if (totalFiles > maxDisplay) {
|
|
2195
|
-
footer = `
|
|
2196
|
-
|
|
2197
|
-
\u26A0\uFE0F TRUNCATED: Showing first ${maxDisplay} of ${totalFiles} items. Use more specific paths to see others.`;
|
|
2198
|
-
}
|
|
2199
|
-
const result = `Contents of [${targetPath}]:
|
|
2200
|
-
|
|
2201
|
-
${list}${footer}`;
|
|
2202
|
-
files.length = 0;
|
|
2203
|
-
displayFiles.length = 0;
|
|
2204
|
-
return result;
|
|
2205
|
-
} catch (err) {
|
|
2206
|
-
return `ERROR: Failed to list files in [${targetPath}]: ${err.message}`;
|
|
2207
|
-
}
|
|
2208
|
-
};
|
|
2209
|
-
}
|
|
2210
|
-
});
|
|
2211
|
-
|
|
2212
|
-
// src/tools/view_file.js
|
|
2213
|
-
import fs8 from "fs";
|
|
2214
|
-
import path7 from "path";
|
|
2215
2194
|
var view_file;
|
|
2216
2195
|
var init_view_file = __esm({
|
|
2217
2196
|
"src/tools/view_file.js"() {
|
|
@@ -2223,16 +2202,21 @@ var init_view_file = __esm({
|
|
|
2223
2202
|
const finalStart = sLine || 1;
|
|
2224
2203
|
const finalEnd = eLine || (sLine ? sLine + 800 : 800);
|
|
2225
2204
|
if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
|
|
2226
|
-
const absolutePath =
|
|
2205
|
+
const absolutePath = path6.resolve(process.cwd(), targetPath);
|
|
2227
2206
|
try {
|
|
2228
|
-
if (!
|
|
2207
|
+
if (!fs7.existsSync(absolutePath)) {
|
|
2229
2208
|
return `ERROR: File [${targetPath}] does not exist.`;
|
|
2230
2209
|
}
|
|
2231
|
-
const stats =
|
|
2210
|
+
const stats = fs7.statSync(absolutePath);
|
|
2232
2211
|
if (stats.isDirectory()) {
|
|
2233
2212
|
return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
|
|
2234
2213
|
}
|
|
2235
|
-
const ext =
|
|
2214
|
+
const ext = path6.extname(targetPath).toLowerCase();
|
|
2215
|
+
const videoExtensions = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".mpeg", ".mpg"];
|
|
2216
|
+
if (videoExtensions.includes(ext)) {
|
|
2217
|
+
const format = ext.slice(1).toUpperCase();
|
|
2218
|
+
return `ERROR: Unable to read. Type ${format} not supported`;
|
|
2219
|
+
}
|
|
2236
2220
|
const mimeMap = {
|
|
2237
2221
|
".pdf": "application/pdf",
|
|
2238
2222
|
".jpg": "image/jpeg",
|
|
@@ -2243,7 +2227,7 @@ var init_view_file = __esm({
|
|
|
2243
2227
|
".doc": "application/msword"
|
|
2244
2228
|
};
|
|
2245
2229
|
if (mimeMap[ext]) {
|
|
2246
|
-
const buffer =
|
|
2230
|
+
const buffer = fs7.readFileSync(absolutePath);
|
|
2247
2231
|
const base64 = buffer.toString("base64");
|
|
2248
2232
|
const mimeType = mimeMap[ext];
|
|
2249
2233
|
return {
|
|
@@ -2256,7 +2240,7 @@ var init_view_file = __esm({
|
|
|
2256
2240
|
}
|
|
2257
2241
|
};
|
|
2258
2242
|
}
|
|
2259
|
-
let content =
|
|
2243
|
+
let content = fs7.readFileSync(absolutePath, "utf8");
|
|
2260
2244
|
if (content.startsWith("\uFEFF")) {
|
|
2261
2245
|
content = content.slice(1);
|
|
2262
2246
|
}
|
|
@@ -2279,8 +2263,8 @@ ${code}`;
|
|
|
2279
2263
|
});
|
|
2280
2264
|
|
|
2281
2265
|
// src/tools/write_file.js
|
|
2282
|
-
import
|
|
2283
|
-
import
|
|
2266
|
+
import fs8 from "fs";
|
|
2267
|
+
import path7 from "path";
|
|
2284
2268
|
var write_file;
|
|
2285
2269
|
var init_write_file = __esm({
|
|
2286
2270
|
"src/tools/write_file.js"() {
|
|
@@ -2290,13 +2274,13 @@ var init_write_file = __esm({
|
|
|
2290
2274
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_file.';
|
|
2291
2275
|
if (content === void 0) return 'ERROR: Missing "content" argument for write_file.';
|
|
2292
2276
|
content = content.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2293
|
-
const absolutePath =
|
|
2294
|
-
const parentDir =
|
|
2277
|
+
const absolutePath = path7.resolve(process.cwd(), targetPath);
|
|
2278
|
+
const parentDir = path7.dirname(absolutePath);
|
|
2295
2279
|
try {
|
|
2296
2280
|
let ancestry = "";
|
|
2297
|
-
if (
|
|
2281
|
+
if (fs8.existsSync(absolutePath)) {
|
|
2298
2282
|
try {
|
|
2299
|
-
const oldData =
|
|
2283
|
+
const oldData = fs8.readFileSync(absolutePath, "utf8");
|
|
2300
2284
|
const lines = oldData.split(/\r?\n/);
|
|
2301
2285
|
ancestry = `Old File contents:
|
|
2302
2286
|
${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
@@ -2308,15 +2292,15 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
2308
2292
|
`;
|
|
2309
2293
|
}
|
|
2310
2294
|
}
|
|
2311
|
-
if (!
|
|
2312
|
-
|
|
2295
|
+
if (!fs8.existsSync(parentDir)) {
|
|
2296
|
+
fs8.mkdirSync(parentDir, { recursive: true });
|
|
2313
2297
|
}
|
|
2314
2298
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2315
2299
|
const processedContent = strip(content);
|
|
2316
2300
|
const lineCount = processedContent.split(/\r?\n/).length;
|
|
2317
2301
|
const originalSize = Buffer.byteLength(processedContent, "utf8");
|
|
2318
|
-
|
|
2319
|
-
let verifiedContent =
|
|
2302
|
+
fs8.writeFileSync(absolutePath, processedContent, "utf8");
|
|
2303
|
+
let verifiedContent = fs8.readFileSync(absolutePath, "utf8");
|
|
2320
2304
|
const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
|
|
2321
2305
|
const verifiedLines = verifiedContent.split(/\r?\n/);
|
|
2322
2306
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -2352,8 +2336,8 @@ Check if Starting and Ending matches your write.`;
|
|
|
2352
2336
|
});
|
|
2353
2337
|
|
|
2354
2338
|
// src/tools/update_file.js
|
|
2355
|
-
import
|
|
2356
|
-
import
|
|
2339
|
+
import fs9 from "fs";
|
|
2340
|
+
import path8 from "path";
|
|
2357
2341
|
var update_file;
|
|
2358
2342
|
var init_update_file = __esm({
|
|
2359
2343
|
"src/tools/update_file.js"() {
|
|
@@ -2366,18 +2350,18 @@ var init_update_file = __esm({
|
|
|
2366
2350
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2367
2351
|
content_to_replace = strip(content_to_replace);
|
|
2368
2352
|
content_to_add = strip(content_to_add);
|
|
2369
|
-
const absolutePath =
|
|
2353
|
+
const absolutePath = path8.resolve(process.cwd(), targetPath);
|
|
2370
2354
|
try {
|
|
2371
|
-
if (!
|
|
2355
|
+
if (!fs9.existsSync(absolutePath)) {
|
|
2372
2356
|
return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
|
|
2373
2357
|
}
|
|
2374
|
-
let diskContent =
|
|
2358
|
+
let diskContent = fs9.readFileSync(absolutePath, "utf8");
|
|
2375
2359
|
if (diskContent.startsWith("\uFEFF")) {
|
|
2376
2360
|
diskContent = diskContent.slice(1);
|
|
2377
2361
|
}
|
|
2378
2362
|
const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2379
2363
|
if (diskContent !== normalizedDisk) {
|
|
2380
|
-
|
|
2364
|
+
fs9.writeFileSync(absolutePath, normalizedDisk, "utf8");
|
|
2381
2365
|
diskContent = normalizedDisk;
|
|
2382
2366
|
}
|
|
2383
2367
|
const currentContent = diskContent;
|
|
@@ -2446,7 +2430,7 @@ var init_update_file = __esm({
|
|
|
2446
2430
|
const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
|
|
2447
2431
|
const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
|
|
2448
2432
|
const finalContentToReplace = firstMatchContent;
|
|
2449
|
-
|
|
2433
|
+
fs9.writeFileSync(absolutePath, newFileContent, "utf8");
|
|
2450
2434
|
const allOriginalLines = currentContent.split(/\r?\n/);
|
|
2451
2435
|
const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
|
|
2452
2436
|
const oldLines = content_to_replace.split(/\r?\n/);
|
|
@@ -2709,34 +2693,34 @@ ${finalOutput}`);
|
|
|
2709
2693
|
});
|
|
2710
2694
|
|
|
2711
2695
|
// src/tools/read_folder.js
|
|
2712
|
-
import
|
|
2713
|
-
import
|
|
2696
|
+
import fs10 from "fs";
|
|
2697
|
+
import path9 from "path";
|
|
2714
2698
|
var read_folder;
|
|
2715
2699
|
var init_read_folder = __esm({
|
|
2716
2700
|
"src/tools/read_folder.js"() {
|
|
2717
2701
|
init_arg_parser();
|
|
2718
2702
|
read_folder = async (args) => {
|
|
2719
2703
|
const { path: targetPath = "." } = parseArgs(args);
|
|
2720
|
-
const absolutePath =
|
|
2704
|
+
const absolutePath = path9.resolve(process.cwd(), targetPath);
|
|
2721
2705
|
try {
|
|
2722
|
-
if (!
|
|
2706
|
+
if (!fs10.existsSync(absolutePath)) {
|
|
2723
2707
|
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2724
2708
|
}
|
|
2725
|
-
const stats =
|
|
2709
|
+
const stats = fs10.statSync(absolutePath);
|
|
2726
2710
|
if (!stats.isDirectory()) {
|
|
2727
2711
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2728
2712
|
}
|
|
2729
|
-
const files =
|
|
2713
|
+
const files = fs10.readdirSync(absolutePath);
|
|
2730
2714
|
const totalItems = files.length;
|
|
2731
2715
|
const maxDisplay = 100;
|
|
2732
2716
|
const displayItems = files.slice(0, maxDisplay);
|
|
2733
2717
|
const folderData = [];
|
|
2734
2718
|
for (const file of displayItems) {
|
|
2735
|
-
const fPath =
|
|
2719
|
+
const fPath = path9.join(absolutePath, file);
|
|
2736
2720
|
let indicator = "\u{1F4C4}";
|
|
2737
2721
|
let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
|
|
2738
2722
|
try {
|
|
2739
|
-
const fStats =
|
|
2723
|
+
const fStats = fs10.statSync(fPath);
|
|
2740
2724
|
info = {
|
|
2741
2725
|
name: file,
|
|
2742
2726
|
type: fStats.isDirectory() ? "directory" : "file",
|
|
@@ -2819,8 +2803,8 @@ var init_ask_user = __esm({
|
|
|
2819
2803
|
|
|
2820
2804
|
// src/tools/write_pdf.js
|
|
2821
2805
|
import puppeteer3 from "puppeteer";
|
|
2822
|
-
import
|
|
2823
|
-
import
|
|
2806
|
+
import path10 from "path";
|
|
2807
|
+
import fs11 from "fs-extra";
|
|
2824
2808
|
import { PDFDocument } from "pdf-lib";
|
|
2825
2809
|
var write_pdf;
|
|
2826
2810
|
var init_write_pdf = __esm({
|
|
@@ -2835,10 +2819,10 @@ var init_write_pdf = __esm({
|
|
|
2835
2819
|
} = parseArgs(args);
|
|
2836
2820
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
|
|
2837
2821
|
if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
|
|
2838
|
-
const absolutePath =
|
|
2822
|
+
const absolutePath = path10.resolve(process.cwd(), targetPath);
|
|
2839
2823
|
let browser = null;
|
|
2840
2824
|
try {
|
|
2841
|
-
await
|
|
2825
|
+
await fs11.ensureDir(path10.dirname(absolutePath));
|
|
2842
2826
|
browser = await puppeteer3.launch({
|
|
2843
2827
|
headless: true,
|
|
2844
2828
|
args: [
|
|
@@ -2858,11 +2842,11 @@ var init_write_pdf = __esm({
|
|
|
2858
2842
|
continue;
|
|
2859
2843
|
}
|
|
2860
2844
|
try {
|
|
2861
|
-
const imgPath =
|
|
2862
|
-
if (await
|
|
2863
|
-
const ext =
|
|
2845
|
+
const imgPath = path10.resolve(process.cwd(), originalSrc);
|
|
2846
|
+
if (await fs11.pathExists(imgPath)) {
|
|
2847
|
+
const ext = path10.extname(imgPath).toLowerCase().replace(".", "") || "png";
|
|
2864
2848
|
const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
|
|
2865
|
-
const base64 = await
|
|
2849
|
+
const base64 = await fs11.readFile(imgPath, "base64");
|
|
2866
2850
|
const dataUri = `data:image/${mime};base64,${base64}`;
|
|
2867
2851
|
resolvedContent = resolvedContent.split(originalSrc).join(dataUri);
|
|
2868
2852
|
}
|
|
@@ -2913,7 +2897,7 @@ var init_write_pdf = __esm({
|
|
|
2913
2897
|
printBackground: true
|
|
2914
2898
|
});
|
|
2915
2899
|
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
2916
|
-
const fileName =
|
|
2900
|
+
const fileName = path10.basename(targetPath);
|
|
2917
2901
|
pdfDoc.setTitle(`FluxFlow_${fileName}`);
|
|
2918
2902
|
pdfDoc.setAuthor("FluxFlow CLI");
|
|
2919
2903
|
pdfDoc.setSubject("Generated with Agentic AI System");
|
|
@@ -2921,8 +2905,8 @@ var init_write_pdf = __esm({
|
|
|
2921
2905
|
pdfDoc.setCreator("FluxFlow PDF Engine");
|
|
2922
2906
|
pdfDoc.setProducer("FluxFlow (Generative AI)");
|
|
2923
2907
|
const finalPdfBytes = await pdfDoc.save();
|
|
2924
|
-
await
|
|
2925
|
-
const stats = await
|
|
2908
|
+
await fs11.writeFile(absolutePath, finalPdfBytes);
|
|
2909
|
+
const stats = await fs11.stat(absolutePath);
|
|
2926
2910
|
return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
|
|
2927
2911
|
} catch (err) {
|
|
2928
2912
|
return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
|
|
@@ -2934,8 +2918,8 @@ var init_write_pdf = __esm({
|
|
|
2934
2918
|
});
|
|
2935
2919
|
|
|
2936
2920
|
// src/tools/write_docx.js
|
|
2937
|
-
import
|
|
2938
|
-
import
|
|
2921
|
+
import fs12 from "fs-extra";
|
|
2922
|
+
import path11 from "path";
|
|
2939
2923
|
import HTMLtoDOCX from "html-to-docx";
|
|
2940
2924
|
var write_docx;
|
|
2941
2925
|
var init_write_docx = __esm({
|
|
@@ -2948,10 +2932,10 @@ var init_write_docx = __esm({
|
|
|
2948
2932
|
} = parseArgs(args);
|
|
2949
2933
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
|
|
2950
2934
|
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
2951
|
-
const absolutePath =
|
|
2935
|
+
const absolutePath = path11.resolve(process.cwd(), targetPath);
|
|
2952
2936
|
try {
|
|
2953
|
-
await
|
|
2954
|
-
const fileName =
|
|
2937
|
+
await fs12.ensureDir(path11.dirname(absolutePath));
|
|
2938
|
+
const fileName = path11.basename(targetPath);
|
|
2955
2939
|
const fullHtml = content.includes("<html") ? content : `
|
|
2956
2940
|
<!DOCTYPE html>
|
|
2957
2941
|
<html lang="en">
|
|
@@ -2972,7 +2956,7 @@ var init_write_docx = __esm({
|
|
|
2972
2956
|
footer: true,
|
|
2973
2957
|
pageNumber: true
|
|
2974
2958
|
});
|
|
2975
|
-
await
|
|
2959
|
+
await fs12.writeFile(absolutePath, docxBuffer);
|
|
2976
2960
|
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
2977
2961
|
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
2978
2962
|
} catch (err) {
|
|
@@ -3029,7 +3013,7 @@ var init_search_keyword = __esm({
|
|
|
3029
3013
|
`;
|
|
3030
3014
|
output += matches.join("\n");
|
|
3031
3015
|
if (filteredLines.length > 100) {
|
|
3032
|
-
output += "\n\n... (Truncated to first 100 matches
|
|
3016
|
+
output += "\n\n... (Truncated to first 100 matches)";
|
|
3033
3017
|
}
|
|
3034
3018
|
resolve(output);
|
|
3035
3019
|
});
|
|
@@ -3039,8 +3023,8 @@ var init_search_keyword = __esm({
|
|
|
3039
3023
|
});
|
|
3040
3024
|
|
|
3041
3025
|
// src/utils/settings.js
|
|
3042
|
-
import
|
|
3043
|
-
import
|
|
3026
|
+
import fs13 from "fs-extra";
|
|
3027
|
+
import path12 from "path";
|
|
3044
3028
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
3045
3029
|
var init_settings = __esm({
|
|
3046
3030
|
"src/utils/settings.js"() {
|
|
@@ -3082,7 +3066,7 @@ var init_settings = __esm({
|
|
|
3082
3066
|
loadSettings = async () => {
|
|
3083
3067
|
let settingsObj = { ...DEFAULT_SETTINGS };
|
|
3084
3068
|
try {
|
|
3085
|
-
if (await
|
|
3069
|
+
if (await fs13.exists(SETTINGS_FILE)) {
|
|
3086
3070
|
const saved = readAesEncryptedJson(SETTINGS_FILE);
|
|
3087
3071
|
if (saved.imageSettings && saved.imageSettings.apiKey) {
|
|
3088
3072
|
try {
|
|
@@ -3127,12 +3111,12 @@ var init_settings = __esm({
|
|
|
3127
3111
|
const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
3128
3112
|
const folders = ["logs", "secret"];
|
|
3129
3113
|
for (const folder of folders) {
|
|
3130
|
-
const src =
|
|
3131
|
-
const dest =
|
|
3114
|
+
const src = path12.join(FLUXFLOW_DIR2, folder);
|
|
3115
|
+
const dest = path12.join(newPath, folder);
|
|
3132
3116
|
try {
|
|
3133
|
-
if (await
|
|
3134
|
-
await
|
|
3135
|
-
await
|
|
3117
|
+
if (await fs13.exists(src)) {
|
|
3118
|
+
await fs13.ensureDir(dest);
|
|
3119
|
+
await fs13.copy(src, dest, { overwrite: true });
|
|
3136
3120
|
}
|
|
3137
3121
|
} catch (err) {
|
|
3138
3122
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -3158,7 +3142,7 @@ var init_settings = __esm({
|
|
|
3158
3142
|
if (updated.imageSettings) {
|
|
3159
3143
|
updated.imageSettings = { ...updated.imageSettings, apiKey: "" };
|
|
3160
3144
|
}
|
|
3161
|
-
await
|
|
3145
|
+
await fs13.ensureDir(path12.dirname(SETTINGS_FILE));
|
|
3162
3146
|
writeAesEncryptedJson(SETTINGS_FILE, updated);
|
|
3163
3147
|
return true;
|
|
3164
3148
|
} catch (err) {
|
|
@@ -3178,8 +3162,8 @@ var init_fallback_key = __esm({
|
|
|
3178
3162
|
});
|
|
3179
3163
|
|
|
3180
3164
|
// src/tools/generate_image.js
|
|
3181
|
-
import
|
|
3182
|
-
import
|
|
3165
|
+
import fs14 from "fs-extra";
|
|
3166
|
+
import path13 from "path";
|
|
3183
3167
|
var injectPngMetadata, generate_image;
|
|
3184
3168
|
var init_generate_image = __esm({
|
|
3185
3169
|
"src/tools/generate_image.js"() {
|
|
@@ -3251,6 +3235,30 @@ var init_generate_image = __esm({
|
|
|
3251
3235
|
if (!prompt) {
|
|
3252
3236
|
return 'ERROR: Missing "prompt" argument for generate_image.';
|
|
3253
3237
|
}
|
|
3238
|
+
const BLOCKED_KEYWORDS = [
|
|
3239
|
+
"nsfw",
|
|
3240
|
+
"naked",
|
|
3241
|
+
"nudity",
|
|
3242
|
+
"nude",
|
|
3243
|
+
"porn",
|
|
3244
|
+
"sex",
|
|
3245
|
+
"xxx",
|
|
3246
|
+
"erotic",
|
|
3247
|
+
"gore",
|
|
3248
|
+
"bloody",
|
|
3249
|
+
"violence",
|
|
3250
|
+
"abuse",
|
|
3251
|
+
"suicide",
|
|
3252
|
+
"murder",
|
|
3253
|
+
"hentai",
|
|
3254
|
+
"pedophile",
|
|
3255
|
+
"rape"
|
|
3256
|
+
];
|
|
3257
|
+
const promptLower = prompt.toLowerCase();
|
|
3258
|
+
const isBlocked = BLOCKED_KEYWORDS.some((kw) => promptLower.includes(kw));
|
|
3259
|
+
if (isBlocked) {
|
|
3260
|
+
return "ERROR: Prompt blocked by system safety filter (inappropriate or unsafe content detected).";
|
|
3261
|
+
}
|
|
3254
3262
|
try {
|
|
3255
3263
|
const settings = await loadSettings();
|
|
3256
3264
|
const hasQuota = await checkImageQuota(settings);
|
|
@@ -3292,7 +3300,8 @@ var init_generate_image = __esm({
|
|
|
3292
3300
|
}
|
|
3293
3301
|
}
|
|
3294
3302
|
const seed = Math.floor(Math.random() * 1e7);
|
|
3295
|
-
const
|
|
3303
|
+
const negativePrompt = "deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, disconnected limbs, mutation, mutated hands and fingers, blurry, low quality, low resolution, extra fingers, censored, watermarks, signatures";
|
|
3304
|
+
const url = `https://gen.pollinations.ai/image/${encodeURIComponent(prompt)}?model=${selectedModel}&width=${width}&height=${height}&seed=${seed}&enhance=true&reasoning=high&quality=high&negative=${encodeURIComponent(negativePrompt)}`;
|
|
3296
3305
|
const response = await fetch(url, {
|
|
3297
3306
|
method: "GET",
|
|
3298
3307
|
headers: {
|
|
@@ -3333,9 +3342,9 @@ var init_generate_image = __esm({
|
|
|
3333
3342
|
"Seed": String(seed)
|
|
3334
3343
|
};
|
|
3335
3344
|
finalBuffer = injectPngMetadata(finalBuffer, metadata);
|
|
3336
|
-
const absolutePath =
|
|
3337
|
-
await
|
|
3338
|
-
await
|
|
3345
|
+
const absolutePath = path13.resolve(process.cwd(), outputPath);
|
|
3346
|
+
await fs14.ensureDir(path13.dirname(absolutePath));
|
|
3347
|
+
await fs14.writeFile(absolutePath, finalBuffer);
|
|
3339
3348
|
await recordImageGeneration(settings);
|
|
3340
3349
|
return `SUCCESS: Image successfully generated from prompt [${prompt}] and saved to [${outputPath}].`;
|
|
3341
3350
|
} catch (err) {
|
|
@@ -3353,7 +3362,6 @@ var init_tools = __esm({
|
|
|
3353
3362
|
init_web_scrape();
|
|
3354
3363
|
init_memory();
|
|
3355
3364
|
init_chat();
|
|
3356
|
-
init_list_files();
|
|
3357
3365
|
init_view_file();
|
|
3358
3366
|
init_write_file();
|
|
3359
3367
|
init_update_file();
|
|
@@ -3369,7 +3377,6 @@ var init_tools = __esm({
|
|
|
3369
3377
|
web_scrape,
|
|
3370
3378
|
memory,
|
|
3371
3379
|
chat,
|
|
3372
|
-
list_files,
|
|
3373
3380
|
view_file,
|
|
3374
3381
|
write_file,
|
|
3375
3382
|
update_file,
|
|
@@ -3412,8 +3419,8 @@ var init_tools = __esm({
|
|
|
3412
3419
|
|
|
3413
3420
|
// src/utils/ai.js
|
|
3414
3421
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
3415
|
-
import
|
|
3416
|
-
import
|
|
3422
|
+
import path14 from "path";
|
|
3423
|
+
import fs15 from "fs";
|
|
3417
3424
|
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
|
|
3418
3425
|
var init_ai = __esm({
|
|
3419
3426
|
"src/utils/ai.js"() {
|
|
@@ -3449,7 +3456,7 @@ var init_ai = __esm({
|
|
|
3449
3456
|
try {
|
|
3450
3457
|
const pArgs = parseArgs(argsStr);
|
|
3451
3458
|
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
3452
|
-
return filePath ?
|
|
3459
|
+
return filePath ? path14.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
|
|
3453
3460
|
} catch (e) {
|
|
3454
3461
|
return null;
|
|
3455
3462
|
}
|
|
@@ -3562,8 +3569,8 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
|
|
|
3562
3569
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
3563
3570
|
const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
|
|
3564
3571
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
3565
|
-
const janitorLogDir =
|
|
3566
|
-
|
|
3572
|
+
const janitorLogDir = path14.join(LOGS_DIR, "janitor");
|
|
3573
|
+
fs15.appendFileSync(path14.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
|
|
3567
3574
|
`);
|
|
3568
3575
|
if (janitorToolCall.toolName.toLowerCase() === "memory" && !janitorToolCall.args.includes("action='temp'")) {
|
|
3569
3576
|
if (onMemoryUpdated) onMemoryUpdated();
|
|
@@ -3581,9 +3588,9 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
|
|
|
3581
3588
|
process.stdout.write(`\x1B]0;Memory Error\x07`);
|
|
3582
3589
|
}
|
|
3583
3590
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3584
|
-
const janitorErrDir =
|
|
3585
|
-
if (!
|
|
3586
|
-
|
|
3591
|
+
const janitorErrDir = path14.join(LOGS_DIR, "janitor");
|
|
3592
|
+
if (!fs15.existsSync(janitorErrDir)) fs15.mkdirSync(janitorErrDir, { recursive: true });
|
|
3593
|
+
fs15.appendFileSync(path14.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
|
|
3587
3594
|
|
|
3588
3595
|
`);
|
|
3589
3596
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -3592,8 +3599,8 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
|
|
|
3592
3599
|
}
|
|
3593
3600
|
}
|
|
3594
3601
|
if (attempts) {
|
|
3595
|
-
const janitorErrDir =
|
|
3596
|
-
|
|
3602
|
+
const janitorErrDir = path14.join(LOGS_DIR, "janitor");
|
|
3603
|
+
fs15.appendFileSync(path14.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
3597
3604
|
|
|
3598
3605
|
|
|
3599
3606
|
`);
|
|
@@ -4036,12 +4043,12 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
4036
4043
|
if (keyword) {
|
|
4037
4044
|
detail = keyword.replace(/["']/g, "");
|
|
4038
4045
|
} else if (filePath) {
|
|
4039
|
-
detail =
|
|
4046
|
+
detail = path14.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
|
|
4040
4047
|
} else {
|
|
4041
4048
|
const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
|
|
4042
4049
|
if (m) {
|
|
4043
4050
|
const val = m[1].replace(/["']/g, "");
|
|
4044
|
-
detail = potentialTool === "search_keyword" ? val :
|
|
4051
|
+
detail = potentialTool === "search_keyword" ? val : path14.basename(val.replace(/\\/g, "/"));
|
|
4045
4052
|
}
|
|
4046
4053
|
}
|
|
4047
4054
|
}
|
|
@@ -4201,9 +4208,9 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
4201
4208
|
let totalLines = "...";
|
|
4202
4209
|
let actualEndLine = eLine;
|
|
4203
4210
|
try {
|
|
4204
|
-
const absPath =
|
|
4205
|
-
if (
|
|
4206
|
-
const content =
|
|
4211
|
+
const absPath = path14.resolve(process.cwd(), targetPath2);
|
|
4212
|
+
if (fs15.existsSync(absPath)) {
|
|
4213
|
+
const content = fs15.readFileSync(absPath, "utf8");
|
|
4207
4214
|
const lines = content.split("\n").length;
|
|
4208
4215
|
totalLines = lines;
|
|
4209
4216
|
actualEndLine = Math.min(eLine, lines);
|
|
@@ -4254,7 +4261,7 @@ ${boxBottom}` };
|
|
|
4254
4261
|
const { command } = parseArgs(toolCall.args);
|
|
4255
4262
|
if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
|
|
4256
4263
|
const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
|
|
4257
|
-
const currentDrive =
|
|
4264
|
+
const currentDrive = path14.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
4258
4265
|
const isViolating = riskyPatterns.some((pattern) => {
|
|
4259
4266
|
if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
|
|
4260
4267
|
const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
|
|
@@ -4277,8 +4284,8 @@ ${boxBottom}` };
|
|
|
4277
4284
|
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
4278
4285
|
if (targetPath) {
|
|
4279
4286
|
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
4280
|
-
const absoluteTarget =
|
|
4281
|
-
const absoluteCwd =
|
|
4287
|
+
const absoluteTarget = path14.resolve(targetPath);
|
|
4288
|
+
const absoluteCwd = path14.resolve(process.cwd());
|
|
4282
4289
|
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
4283
4290
|
const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace. To enable this, ask the user to turn on "External Workspace Access" in /settings.`;
|
|
4284
4291
|
toolResults.push({ role: "user", text: `[TOOL RESULT]: ERROR: ${denyMsg}${thinkingLevel != "Fast" ? "\n\n[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRICT PRIORITY. DO NOT START A RESPONSE WITHOUT THINKING**" : ""}` });
|
|
@@ -4393,6 +4400,11 @@ ${boxBottom}` };
|
|
|
4393
4400
|
success = true;
|
|
4394
4401
|
await incrementUsage("agent");
|
|
4395
4402
|
} catch (err) {
|
|
4403
|
+
if (String(err).includes("Incomplete JSON segment at the end")) {
|
|
4404
|
+
success = true;
|
|
4405
|
+
await incrementUsage("agent");
|
|
4406
|
+
break;
|
|
4407
|
+
}
|
|
4396
4408
|
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4397
4409
|
let overlapLen = 0;
|
|
4398
4410
|
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
@@ -4415,9 +4427,9 @@ ${boxBottom}` };
|
|
|
4415
4427
|
const errMsg = err.status || err.error && err.error.message || String(err);
|
|
4416
4428
|
const errLog = String(err);
|
|
4417
4429
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
4418
|
-
const agentErrDir =
|
|
4419
|
-
if (!
|
|
4420
|
-
|
|
4430
|
+
const agentErrDir = path14.join(LOGS_DIR, "agent");
|
|
4431
|
+
if (!fs15.existsSync(agentErrDir)) fs15.mkdirSync(agentErrDir, { recursive: true });
|
|
4432
|
+
fs15.appendFileSync(path14.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
4421
4433
|
DEBUG STATE: turnText='${turnText}', length=${turnText.trim().length}, inStreamRetryCount=${inStreamRetryCount}, retryCount=${retryCount}, isDedupeActive=${isDedupeActive}, dedupeBuffer='${dedupeBuffer}'
|
|
4422
4434
|
|
|
4423
4435
|
----------------------------------------------------------------------
|
|
@@ -4462,7 +4474,7 @@ ${recoveryText}`
|
|
|
4462
4474
|
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
4463
4475
|
} else {
|
|
4464
4476
|
throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
|
|
4465
|
-
Error Log can be found in ${
|
|
4477
|
+
Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4466
4478
|
}
|
|
4467
4479
|
} else {
|
|
4468
4480
|
if (retryCount <= MAX_RETRIES) {
|
|
@@ -4479,7 +4491,7 @@ Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
4479
4491
|
yield { type: "status", content: `Retrying Connection...` };
|
|
4480
4492
|
} else {
|
|
4481
4493
|
throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
4482
|
-
Error Log can be found in ${
|
|
4494
|
+
Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4483
4495
|
}
|
|
4484
4496
|
}
|
|
4485
4497
|
}
|
|
@@ -4540,13 +4552,13 @@ ${timestamp}`;
|
|
|
4540
4552
|
});
|
|
4541
4553
|
|
|
4542
4554
|
// src/components/ResumeModal.jsx
|
|
4543
|
-
import React7, { useState as useState4, useEffect as
|
|
4555
|
+
import React7, { useState as useState4, useEffect as useEffect3 } from "react";
|
|
4544
4556
|
import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
|
|
4545
4557
|
function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
4546
4558
|
const [history, setHistory] = useState4({});
|
|
4547
4559
|
const [keys, setKeys] = useState4([]);
|
|
4548
4560
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
4549
|
-
|
|
4561
|
+
useEffect3(() => {
|
|
4550
4562
|
const fetchHistory = async () => {
|
|
4551
4563
|
const h = await loadHistory();
|
|
4552
4564
|
setHistory(h);
|
|
@@ -4571,9 +4583,23 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
|
4571
4583
|
}
|
|
4572
4584
|
});
|
|
4573
4585
|
const s = emojiSpace(2);
|
|
4574
|
-
|
|
4586
|
+
const MAX_VISIBLE = 15;
|
|
4587
|
+
let startIndex = 0;
|
|
4588
|
+
if (keys.length > MAX_VISIBLE) {
|
|
4589
|
+
const half = Math.floor(MAX_VISIBLE / 2);
|
|
4590
|
+
startIndex = selectedIndex - half;
|
|
4591
|
+
if (startIndex < 0) {
|
|
4592
|
+
startIndex = 0;
|
|
4593
|
+
} else if (startIndex + MAX_VISIBLE > keys.length) {
|
|
4594
|
+
startIndex = keys.length - MAX_VISIBLE;
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
const visibleKeys = keys.slice(startIndex, startIndex + MAX_VISIBLE);
|
|
4598
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 95 }, /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan", bold: true }, "\u{1F4A0} CHAT HISTORY: RESUME CONVERSATION")), keys.length === 0 ? /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React7.createElement(Text7, { italic: true, color: "gray" }, "No saved chats found.")) : /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", width: "100%" }, startIndex > 0 && /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: true }, "\u25B2 (+", startIndex, " more chats above)")), visibleKeys.map((id, index) => {
|
|
4575
4599
|
const chat2 = history[id];
|
|
4576
|
-
const
|
|
4600
|
+
const actualIndex = startIndex + index;
|
|
4601
|
+
const isSelected = actualIndex === selectedIndex;
|
|
4602
|
+
const dateStr = formatDate(chat2?.updatedAt);
|
|
4577
4603
|
return /* @__PURE__ */ React7.createElement(
|
|
4578
4604
|
Box7,
|
|
4579
4605
|
{
|
|
@@ -4582,10 +4608,10 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
|
4582
4608
|
backgroundColor: isSelected ? "#2a2a2a" : void 0,
|
|
4583
4609
|
width: "100%"
|
|
4584
4610
|
},
|
|
4585
|
-
/* @__PURE__ */ React7.createElement(Box7, { flexGrow: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", chat2
|
|
4611
|
+
/* @__PURE__ */ React7.createElement(Box7, { flexGrow: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", chat2?.name || id, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: !isSelected }, " [", dateStr, " \u2022 ", id.slice(5), "]"))),
|
|
4586
4612
|
isSelected && /* @__PURE__ */ React7.createElement(Box7, { flexShrink: 0 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, "[X] DELETE "))
|
|
4587
4613
|
);
|
|
4588
|
-
})), /* @__PURE__ */ React7.createElement(
|
|
4614
|
+
}), startIndex + MAX_VISIBLE < keys.length && /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: true }, "\u25BC (+", keys.length - (startIndex + MAX_VISIBLE), " more chats below)"))), /* @__PURE__ */ React7.createElement(
|
|
4589
4615
|
Box7,
|
|
4590
4616
|
{
|
|
4591
4617
|
marginTop: 1,
|
|
@@ -4599,6 +4625,17 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
|
4599
4625
|
/* @__PURE__ */ React7.createElement(Text7, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close")
|
|
4600
4626
|
));
|
|
4601
4627
|
}
|
|
4628
|
+
function formatDate(timestamp) {
|
|
4629
|
+
if (!timestamp) return "N/A";
|
|
4630
|
+
const d = new Date(timestamp);
|
|
4631
|
+
if (isNaN(d.getTime())) return "N/A";
|
|
4632
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
4633
|
+
const mm = pad(d.getMonth() + 1);
|
|
4634
|
+
const dd = pad(d.getDate());
|
|
4635
|
+
const hh = pad(d.getHours());
|
|
4636
|
+
const min = pad(d.getMinutes());
|
|
4637
|
+
return `${mm}-${dd} ${hh}:${min}`;
|
|
4638
|
+
}
|
|
4602
4639
|
var init_ResumeModal = __esm({
|
|
4603
4640
|
"src/components/ResumeModal.jsx"() {
|
|
4604
4641
|
init_history();
|
|
@@ -4607,16 +4644,24 @@ var init_ResumeModal = __esm({
|
|
|
4607
4644
|
});
|
|
4608
4645
|
|
|
4609
4646
|
// src/components/MemoryModal.jsx
|
|
4610
|
-
import React8, { useState as useState5, useEffect as
|
|
4647
|
+
import React8, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
4611
4648
|
import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
|
|
4612
4649
|
function MemoryModal({ onClose }) {
|
|
4613
4650
|
const [memories, setMemories] = useState5([]);
|
|
4614
4651
|
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
4652
|
+
const [isMemoryOn, setIsMemoryOn] = useState5(true);
|
|
4615
4653
|
const loadMemories = () => {
|
|
4616
4654
|
const data = readEncryptedJson(MEMORIES_FILE, []);
|
|
4617
4655
|
setMemories(data);
|
|
4656
|
+
try {
|
|
4657
|
+
const settings = readAesEncryptedJson(SETTINGS_FILE, {});
|
|
4658
|
+
const memoryOn = settings.systemSettings?.memory !== false;
|
|
4659
|
+
setIsMemoryOn(memoryOn);
|
|
4660
|
+
} catch (e) {
|
|
4661
|
+
setIsMemoryOn(true);
|
|
4662
|
+
}
|
|
4618
4663
|
};
|
|
4619
|
-
|
|
4664
|
+
useEffect4(() => {
|
|
4620
4665
|
loadMemories();
|
|
4621
4666
|
}, []);
|
|
4622
4667
|
useInput3((input, key) => {
|
|
@@ -4637,7 +4682,7 @@ function MemoryModal({ onClose }) {
|
|
|
4637
4682
|
return text.replace(/\[Saved on: .*?\]/g, "").trim();
|
|
4638
4683
|
};
|
|
4639
4684
|
const s = emojiSpace(2);
|
|
4640
|
-
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F9E0} AGENT MEMORY: LONG-TERM KNOWLEDGE")), memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "
|
|
4685
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F9E0} AGENT MEMORY: LONG-TERM KNOWLEDGE")), !isMemoryOn && memories.length > 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "Memory is currently Off...")) : memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, isMemoryOn ? "Learning..." : "Memory not available...")) : /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, memories.map((mem, idx) => {
|
|
4641
4686
|
const isSelected = idx === selectedIndex;
|
|
4642
4687
|
return /* @__PURE__ */ React8.createElement(
|
|
4643
4688
|
Box8,
|
|
@@ -4673,7 +4718,7 @@ var init_MemoryModal = __esm({
|
|
|
4673
4718
|
});
|
|
4674
4719
|
|
|
4675
4720
|
// src/components/UpdateProcessor.jsx
|
|
4676
|
-
import React9, { useState as useState6, useEffect as
|
|
4721
|
+
import React9, { useState as useState6, useEffect as useEffect5 } from "react";
|
|
4677
4722
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
4678
4723
|
import Spinner from "ink-spinner";
|
|
4679
4724
|
import { exec as exec2 } from "child_process";
|
|
@@ -4684,7 +4729,7 @@ var init_UpdateProcessor = __esm({
|
|
|
4684
4729
|
const [status, setStatus] = useState6("initializing");
|
|
4685
4730
|
const [log, setLog] = useState6("");
|
|
4686
4731
|
const [error, setError] = useState6(null);
|
|
4687
|
-
|
|
4732
|
+
useEffect5(() => {
|
|
4688
4733
|
let child;
|
|
4689
4734
|
const runUpdate = async () => {
|
|
4690
4735
|
const manager = settings.updateManager || "npm";
|
|
@@ -4727,7 +4772,7 @@ var init_UpdateProcessor = __esm({
|
|
|
4727
4772
|
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, /* @__PURE__ */ React9.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React9.createElement(Text9, { marginLeft: 1, bold: true }, " Updating Flux Flow to v", latest, "...")), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "#333" }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true, italic: true }, log || "Preparing environment...")), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, dimColor: true }, "(Please do not close the terminal)"));
|
|
4728
4773
|
}
|
|
4729
4774
|
if (status === "success") {
|
|
4730
|
-
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "green", bold: true }, "\u2705 UPDATE SUCCESSFUL!"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Flux Flow has been
|
|
4775
|
+
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "green", bold: true }, "\u2705 UPDATE SUCCESSFUL!"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Flux Flow has been updated to ", /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "v", latest), "."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "yellow", bold: true }, "CRITICAL: Please restart your terminal session to apply changes."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "(Press ESC to return to chat)")));
|
|
4731
4776
|
}
|
|
4732
4777
|
if (status === "error") {
|
|
4733
4778
|
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true }, "\u274C UPDATE FAILED"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "red" }, /* @__PURE__ */ React9.createElement(Text9, { color: "red" }, error)), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Possible causes:"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Missing permissions (Try running as Administrator/Sudo)"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Package manager (", settings.updateManager, ") not found"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Network failure"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "(Press ESC to return to chat)")));
|
|
@@ -4742,7 +4787,7 @@ var init_UpdateProcessor = __esm({
|
|
|
4742
4787
|
import puppeteer4 from "puppeteer";
|
|
4743
4788
|
import { exec as exec3 } from "child_process";
|
|
4744
4789
|
import { promisify } from "util";
|
|
4745
|
-
import
|
|
4790
|
+
import fs16 from "fs";
|
|
4746
4791
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
4747
4792
|
var init_setup = __esm({
|
|
4748
4793
|
"src/utils/setup.js"() {
|
|
@@ -4750,7 +4795,7 @@ var init_setup = __esm({
|
|
|
4750
4795
|
checkPuppeteerReady = () => {
|
|
4751
4796
|
try {
|
|
4752
4797
|
const exePath = puppeteer4.executablePath();
|
|
4753
|
-
const exists = exePath &&
|
|
4798
|
+
const exists = exePath && fs16.existsSync(exePath);
|
|
4754
4799
|
if (exists) return true;
|
|
4755
4800
|
} catch (e) {
|
|
4756
4801
|
return false;
|
|
@@ -4781,17 +4826,17 @@ __export(app_exports, {
|
|
|
4781
4826
|
default: () => App
|
|
4782
4827
|
});
|
|
4783
4828
|
import os4 from "os";
|
|
4784
|
-
import React10, { useState as useState7, useEffect as
|
|
4829
|
+
import React10, { useState as useState7, useEffect as useEffect6, useRef as useRef2, useMemo } from "react";
|
|
4785
4830
|
import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
|
|
4786
4831
|
import Spinner2 from "ink-spinner";
|
|
4787
|
-
import
|
|
4788
|
-
import
|
|
4832
|
+
import fs17 from "fs-extra";
|
|
4833
|
+
import path15 from "path";
|
|
4789
4834
|
import { exec as exec4 } from "child_process";
|
|
4790
4835
|
import { fileURLToPath } from "url";
|
|
4791
4836
|
import { MultilineInput } from "ink-multiline-input";
|
|
4792
4837
|
import TextInput3 from "ink-text-input";
|
|
4793
4838
|
import gradient from "gradient-string";
|
|
4794
|
-
function App() {
|
|
4839
|
+
function App({ args = [] }) {
|
|
4795
4840
|
const [confirmExit, setConfirmExit] = useState7(false);
|
|
4796
4841
|
const [exitCountdown, setExitCountdown] = useState7(10);
|
|
4797
4842
|
const { stdout } = useStdout();
|
|
@@ -4803,6 +4848,45 @@ function App() {
|
|
|
4803
4848
|
rows: stdout?.rows || 24
|
|
4804
4849
|
});
|
|
4805
4850
|
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
4851
|
+
const persistedModelRef = useRef2(null);
|
|
4852
|
+
const parsedArgs = useMemo(() => {
|
|
4853
|
+
const parsed = {};
|
|
4854
|
+
for (let i = 0; i < args.length; i++) {
|
|
4855
|
+
const arg = args[i];
|
|
4856
|
+
if (arg === "--model" && args[i + 1]) {
|
|
4857
|
+
parsed.model = args[i + 1];
|
|
4858
|
+
i++;
|
|
4859
|
+
} else if (arg === "--memory" && args[i + 1]) {
|
|
4860
|
+
parsed.memory = args[i + 1].toLowerCase();
|
|
4861
|
+
i++;
|
|
4862
|
+
} else if (arg === "--resume" && args[i + 1]) {
|
|
4863
|
+
parsed.resume = args[i + 1];
|
|
4864
|
+
i++;
|
|
4865
|
+
} else if (arg === "--update" && args[i + 1]) {
|
|
4866
|
+
parsed.update = args[i + 1].toLowerCase();
|
|
4867
|
+
i++;
|
|
4868
|
+
} else if (arg === "--package" && args[i + 1]) {
|
|
4869
|
+
const pkg = args[i + 1].toLowerCase();
|
|
4870
|
+
if (["npm", "pnpm", "yarn", "bun"].includes(pkg)) {
|
|
4871
|
+
parsed.package = pkg;
|
|
4872
|
+
}
|
|
4873
|
+
i++;
|
|
4874
|
+
} else if (arg === "--auto-del" && args[i + 1]) {
|
|
4875
|
+
const del = args[i + 1].toLowerCase();
|
|
4876
|
+
if (["1d", "7d", "30d"].includes(del)) {
|
|
4877
|
+
parsed.autoDel = del;
|
|
4878
|
+
}
|
|
4879
|
+
i++;
|
|
4880
|
+
} else if (arg === "--auto-exec" && args[i + 1]) {
|
|
4881
|
+
parsed.autoExec = args[i + 1].toLowerCase();
|
|
4882
|
+
i++;
|
|
4883
|
+
} else if (arg === "--external-access" && args[i + 1]) {
|
|
4884
|
+
parsed.externalAccess = args[i + 1].toLowerCase();
|
|
4885
|
+
i++;
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
return parsed;
|
|
4889
|
+
}, [args]);
|
|
4806
4890
|
const performVersionCheck = async (manual = false, settingsOverride = null) => {
|
|
4807
4891
|
const settingsToUse = settingsOverride || systemSettings;
|
|
4808
4892
|
if (manual) {
|
|
@@ -4854,7 +4938,7 @@ function App() {
|
|
|
4854
4938
|
}
|
|
4855
4939
|
}
|
|
4856
4940
|
};
|
|
4857
|
-
|
|
4941
|
+
useEffect6(() => {
|
|
4858
4942
|
const handleResize = () => {
|
|
4859
4943
|
stdout.write("\x1Bc");
|
|
4860
4944
|
setTerminalSize({
|
|
@@ -4898,7 +4982,7 @@ function App() {
|
|
|
4898
4982
|
const [activeCommand, setActiveCommand] = useState7(null);
|
|
4899
4983
|
const [execOutput, setExecOutput] = useState7("");
|
|
4900
4984
|
const [isTerminalFocused, setIsTerminalFocused] = useState7(false);
|
|
4901
|
-
|
|
4985
|
+
useEffect6(() => {
|
|
4902
4986
|
if (apiTier !== "Free" && activeModel === "gemma-4-31b-it") {
|
|
4903
4987
|
setActiveModel("gemini-3-flash-preview");
|
|
4904
4988
|
setMessages((prev) => {
|
|
@@ -4921,10 +5005,10 @@ function App() {
|
|
|
4921
5005
|
}, []);
|
|
4922
5006
|
const activeCommandRef = useRef2(null);
|
|
4923
5007
|
const execOutputRef = useRef2("");
|
|
4924
|
-
|
|
5008
|
+
useEffect6(() => {
|
|
4925
5009
|
activeCommandRef.current = activeCommand;
|
|
4926
5010
|
}, [activeCommand]);
|
|
4927
|
-
|
|
5011
|
+
useEffect6(() => {
|
|
4928
5012
|
execOutputRef.current = execOutput;
|
|
4929
5013
|
}, [execOutput]);
|
|
4930
5014
|
const [autoAcceptWrites, setAutoAcceptWrites] = useState7(false);
|
|
@@ -5107,7 +5191,7 @@ function App() {
|
|
|
5107
5191
|
setInput((prev) => prev.replace(/\\\r?$/, "").replace(/\r?$/, "") + "\n");
|
|
5108
5192
|
}
|
|
5109
5193
|
});
|
|
5110
|
-
|
|
5194
|
+
useEffect6(() => {
|
|
5111
5195
|
async function init() {
|
|
5112
5196
|
if (process.stdout.isTTY) {
|
|
5113
5197
|
process.stdout.write(`\x1B]0;FluxFlow | Ready\x07`);
|
|
@@ -5126,7 +5210,12 @@ function App() {
|
|
|
5126
5210
|
const saved = await loadSettings();
|
|
5127
5211
|
setMode(saved.mode);
|
|
5128
5212
|
setThinkingLevel(saved.thinkingLevel);
|
|
5129
|
-
|
|
5213
|
+
persistedModelRef.current = saved.activeModel;
|
|
5214
|
+
if (parsedArgs.model) {
|
|
5215
|
+
setActiveModel(parsedArgs.model);
|
|
5216
|
+
} else {
|
|
5217
|
+
setActiveModel(saved.activeModel);
|
|
5218
|
+
}
|
|
5130
5219
|
setShowFullThinking(saved.showFullThinking);
|
|
5131
5220
|
setApiTier(saved.apiTier || "Free");
|
|
5132
5221
|
setQuotas(saved.quotas || { agentLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
|
|
@@ -5140,6 +5229,27 @@ function App() {
|
|
|
5140
5229
|
customUpdateCommand: "",
|
|
5141
5230
|
...saved.systemSettings || {}
|
|
5142
5231
|
};
|
|
5232
|
+
if (parsedArgs.memory === "on") {
|
|
5233
|
+
freshSettings.memory = true;
|
|
5234
|
+
} else if (parsedArgs.memory === "off") {
|
|
5235
|
+
freshSettings.memory = false;
|
|
5236
|
+
}
|
|
5237
|
+
if (parsedArgs.package) {
|
|
5238
|
+
freshSettings.updateManager = parsedArgs.package;
|
|
5239
|
+
}
|
|
5240
|
+
if (parsedArgs.autoDel) {
|
|
5241
|
+
freshSettings.autoDeleteHistory = parsedArgs.autoDel;
|
|
5242
|
+
}
|
|
5243
|
+
if (parsedArgs.autoExec === "on") {
|
|
5244
|
+
freshSettings.autoExec = true;
|
|
5245
|
+
} else if (parsedArgs.autoExec === "off") {
|
|
5246
|
+
freshSettings.autoExec = false;
|
|
5247
|
+
}
|
|
5248
|
+
if (parsedArgs.externalAccess === "on") {
|
|
5249
|
+
freshSettings.allowExternalAccess = true;
|
|
5250
|
+
} else if (parsedArgs.externalAccess === "off") {
|
|
5251
|
+
freshSettings.allowExternalAccess = false;
|
|
5252
|
+
}
|
|
5143
5253
|
setSystemSettings(freshSettings);
|
|
5144
5254
|
setProfileData(saved.profileData);
|
|
5145
5255
|
setImageSettings(saved.imageSettings || { keyType: "Default", quality: "Low-High", apiKey: "" });
|
|
@@ -5152,13 +5262,41 @@ function App() {
|
|
|
5152
5262
|
cleanupOldHistory(saved.systemSettings.autoDeleteHistory);
|
|
5153
5263
|
}
|
|
5154
5264
|
cleanupOldLogs(LOGS_DIR);
|
|
5155
|
-
|
|
5265
|
+
if (parsedArgs.update === "check") {
|
|
5266
|
+
performVersionCheck(true, freshSettings);
|
|
5267
|
+
} else if (parsedArgs.update === "latest") {
|
|
5268
|
+
setActiveView("update");
|
|
5269
|
+
performVersionCheck(true, freshSettings);
|
|
5270
|
+
} else {
|
|
5271
|
+
performVersionCheck(false, freshSettings);
|
|
5272
|
+
}
|
|
5156
5273
|
await initUsage();
|
|
5274
|
+
if (parsedArgs.resume) {
|
|
5275
|
+
const h = await loadHistory();
|
|
5276
|
+
const id = parsedArgs.resume;
|
|
5277
|
+
if (h[id]) {
|
|
5278
|
+
setChatId(id);
|
|
5279
|
+
const resumedMsgs = [...h[id].messages];
|
|
5280
|
+
const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
|
|
5281
|
+
if (!hasLogo) {
|
|
5282
|
+
resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...", isMeta: true });
|
|
5283
|
+
}
|
|
5284
|
+
setMessages(resumedMsgs);
|
|
5285
|
+
setActiveView("chat");
|
|
5286
|
+
setMessages((prev) => {
|
|
5287
|
+
const newMsgs = [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED VIA CLI: [${id}]`, isMeta: true }];
|
|
5288
|
+
setCompletedIndex(newMsgs.length);
|
|
5289
|
+
return newMsgs;
|
|
5290
|
+
});
|
|
5291
|
+
} else {
|
|
5292
|
+
setMessages((prev) => [...prev, { id: "sys-err-" + Date.now(), role: "system", text: `\u274C ERROR: Chat session [${id}] not found. Started new session.`, isMeta: true }]);
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5157
5295
|
setIsInitializing(false);
|
|
5158
5296
|
}
|
|
5159
5297
|
init();
|
|
5160
5298
|
}, []);
|
|
5161
|
-
|
|
5299
|
+
useEffect6(() => {
|
|
5162
5300
|
let timer;
|
|
5163
5301
|
if (confirmExit) {
|
|
5164
5302
|
setExitCountdown(10);
|
|
@@ -5176,19 +5314,20 @@ function App() {
|
|
|
5176
5314
|
if (timer) clearInterval(timer);
|
|
5177
5315
|
};
|
|
5178
5316
|
}, [confirmExit]);
|
|
5179
|
-
|
|
5317
|
+
useEffect6(() => {
|
|
5180
5318
|
if (!isInitializing) {
|
|
5319
|
+
const modelToSave = parsedArgs.model && activeModel === parsedArgs.model ? persistedModelRef.current : activeModel;
|
|
5181
5320
|
saveSettings({
|
|
5182
5321
|
mode,
|
|
5183
5322
|
thinkingLevel,
|
|
5184
|
-
activeModel,
|
|
5323
|
+
activeModel: modelToSave || activeModel,
|
|
5185
5324
|
showFullThinking,
|
|
5186
5325
|
systemSettings,
|
|
5187
5326
|
profileData,
|
|
5188
5327
|
imageSettings
|
|
5189
5328
|
});
|
|
5190
5329
|
}
|
|
5191
|
-
}, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing]);
|
|
5330
|
+
}, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs]);
|
|
5192
5331
|
const handleSetup = async (val) => {
|
|
5193
5332
|
const key = val.trim();
|
|
5194
5333
|
if (key.length >= 30) {
|
|
@@ -5202,7 +5341,7 @@ function App() {
|
|
|
5202
5341
|
}
|
|
5203
5342
|
};
|
|
5204
5343
|
const lastSavedTimeRef = useRef2(SESSION_START_TIME);
|
|
5205
|
-
|
|
5344
|
+
useEffect6(() => {
|
|
5206
5345
|
if (activeView === "exit") {
|
|
5207
5346
|
const flush = async () => {
|
|
5208
5347
|
const now = Date.now();
|
|
@@ -5220,7 +5359,7 @@ function App() {
|
|
|
5220
5359
|
return () => clearTimeout(timer);
|
|
5221
5360
|
}
|
|
5222
5361
|
}, [activeView]);
|
|
5223
|
-
|
|
5362
|
+
useEffect6(() => {
|
|
5224
5363
|
const interval = setInterval(async () => {
|
|
5225
5364
|
if (!isInitializing) {
|
|
5226
5365
|
const now = Date.now();
|
|
@@ -5297,10 +5436,11 @@ function App() {
|
|
|
5297
5436
|
cmd: "/model",
|
|
5298
5437
|
desc: "Switch AI model",
|
|
5299
5438
|
subs: [
|
|
5300
|
-
{ cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default
|
|
5301
|
-
{ cmd: "gemini-3.1-pro-preview", desc: "Most Capable
|
|
5439
|
+
{ cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default (Free, Recommended)" : "Standard Default (Free, Recommended) - Use Free API Key to use this model " },
|
|
5440
|
+
{ cmd: "gemini-3.1-pro-preview", desc: "Most Capable (Paid)" },
|
|
5302
5441
|
{ cmd: "gemini-3-flash-preview", desc: "Fast & Lightweight (Paid, Limited Free quota)" },
|
|
5303
|
-
{ cmd: "gemini-3.
|
|
5442
|
+
{ cmd: "gemini-3.5-flash", desc: "New (Paid, Limited Free quota)" },
|
|
5443
|
+
{ cmd: "gemini-3.1-flash-lite", desc: "Ultra Fast (Paid, Decent Free quota)" }
|
|
5304
5444
|
]
|
|
5305
5445
|
},
|
|
5306
5446
|
{ cmd: "/settings", desc: "Configure system prefs" },
|
|
@@ -5327,8 +5467,8 @@ function App() {
|
|
|
5327
5467
|
]
|
|
5328
5468
|
}
|
|
5329
5469
|
];
|
|
5330
|
-
const handleSubmit = async (value) => {
|
|
5331
|
-
if (suggestions.length > 0) {
|
|
5470
|
+
const handleSubmit = async (value, isProgrammatic = false) => {
|
|
5471
|
+
if (!isProgrammatic && suggestions.length > 0) {
|
|
5332
5472
|
const nextMatch = suggestions[selectedIndex] || suggestions[0];
|
|
5333
5473
|
const parts = value.split(" ");
|
|
5334
5474
|
if (parts.length === 1) {
|
|
@@ -5676,12 +5816,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
5676
5816
|
setCompletedIndex(prev.length + 1);
|
|
5677
5817
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
5678
5818
|
});
|
|
5679
|
-
if (
|
|
5680
|
-
if (
|
|
5681
|
-
if (
|
|
5819
|
+
if (fs17.existsSync(LOGS_DIR)) fs17.removeSync(LOGS_DIR);
|
|
5820
|
+
if (fs17.existsSync(SECRET_DIR)) fs17.removeSync(SECRET_DIR);
|
|
5821
|
+
if (fs17.existsSync(SETTINGS_FILE)) fs17.removeSync(SETTINGS_FILE);
|
|
5682
5822
|
try {
|
|
5683
|
-
const items =
|
|
5684
|
-
if (items.length === 0)
|
|
5823
|
+
const items = fs17.readdirSync(FLUXFLOW_DIR);
|
|
5824
|
+
if (items.length === 0) fs17.removeSync(FLUXFLOW_DIR);
|
|
5685
5825
|
} catch (e) {
|
|
5686
5826
|
}
|
|
5687
5827
|
setTimeout(() => {
|
|
@@ -5720,8 +5860,8 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
5720
5860
|
break;
|
|
5721
5861
|
}
|
|
5722
5862
|
case "/fluxflow": {
|
|
5723
|
-
const
|
|
5724
|
-
if (
|
|
5863
|
+
const args2 = parts.slice(1);
|
|
5864
|
+
if (args2[0] === "init") {
|
|
5725
5865
|
const template = `# FluxFlow Configuration
|
|
5726
5866
|
# This file defines project-specific instructions for the Flux Flow Agent.
|
|
5727
5867
|
|
|
@@ -5738,14 +5878,14 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
5738
5878
|
# SKILLS & WORKFLOWS
|
|
5739
5879
|
- [Define custom step-by-step recipes for this project here]
|
|
5740
5880
|
`;
|
|
5741
|
-
const filePath =
|
|
5742
|
-
if (
|
|
5881
|
+
const filePath = path15.join(process.cwd(), "FluxFlow.md");
|
|
5882
|
+
if (fs17.pathExistsSync(filePath)) {
|
|
5743
5883
|
setMessages((prev) => {
|
|
5744
5884
|
setCompletedIndex(prev.length + 1);
|
|
5745
5885
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
5746
5886
|
});
|
|
5747
5887
|
} else {
|
|
5748
|
-
|
|
5888
|
+
fs17.writeFileSync(filePath, template);
|
|
5749
5889
|
setMessages((prev) => {
|
|
5750
5890
|
setCompletedIndex(prev.length + 1);
|
|
5751
5891
|
return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "\u2705 [SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
|
|
@@ -5856,20 +5996,20 @@ OUTPUT: ${execOutputRef.current}`;
|
|
|
5856
5996
|
setSessionToolFailure((prev) => prev + 1);
|
|
5857
5997
|
}
|
|
5858
5998
|
},
|
|
5859
|
-
onToolApproval: async (tool,
|
|
5999
|
+
onToolApproval: async (tool, args2) => {
|
|
5860
6000
|
const isAuto = autoAcceptWrites || systemSettings.autoExec;
|
|
5861
6001
|
if (tool === "exec_command") {
|
|
5862
|
-
const { command } = parseArgs(
|
|
6002
|
+
const { command } = parseArgs(args2 || "{}");
|
|
5863
6003
|
const safeRegex = /^(echo|ls|dir|pwd|cd|git status|git log|git diff|type|cat|help)\b/i;
|
|
5864
6004
|
if (isAuto || command && safeRegex.test(command.trim())) return "allow";
|
|
5865
6005
|
return new Promise((resolve) => {
|
|
5866
|
-
setPendingApproval({ tool, args, resolve });
|
|
6006
|
+
setPendingApproval({ tool, args: args2, resolve });
|
|
5867
6007
|
setActiveView("terminalApproval");
|
|
5868
6008
|
});
|
|
5869
6009
|
}
|
|
5870
6010
|
if (isAuto) return "allow";
|
|
5871
6011
|
return new Promise((resolve) => {
|
|
5872
|
-
setPendingApproval({ tool, args, resolve });
|
|
6012
|
+
setPendingApproval({ tool, args: args2, resolve });
|
|
5873
6013
|
setActiveView("approval");
|
|
5874
6014
|
});
|
|
5875
6015
|
},
|
|
@@ -6168,7 +6308,7 @@ Selection: ${val}`,
|
|
|
6168
6308
|
}
|
|
6169
6309
|
return currentList.filter((s) => s.cmd.toLowerCase().includes(query));
|
|
6170
6310
|
}, [input]);
|
|
6171
|
-
|
|
6311
|
+
useEffect6(() => {
|
|
6172
6312
|
setSelectedIndex(0);
|
|
6173
6313
|
}, [suggestions]);
|
|
6174
6314
|
const renderActiveView = () => {
|
|
@@ -6484,6 +6624,7 @@ Selection: ${val}`,
|
|
|
6484
6624
|
return /* @__PURE__ */ React10.createElement(
|
|
6485
6625
|
ProfileForm,
|
|
6486
6626
|
{
|
|
6627
|
+
initialData: profileData,
|
|
6487
6628
|
onSave: (profile) => {
|
|
6488
6629
|
setProfileData(profile);
|
|
6489
6630
|
setMessages((prev) => [...prev, { id: Date.now(), role: "system", text: `\u2705 Profile updated: ${profile.name} (${profile.nickname})` }]);
|
|
@@ -6501,7 +6642,7 @@ Selection: ${val}`,
|
|
|
6501
6642
|
setResolutionData(null);
|
|
6502
6643
|
setActiveView("chat");
|
|
6503
6644
|
setTimeout(() => {
|
|
6504
|
-
handleSubmit(val);
|
|
6645
|
+
handleSubmit(val, true);
|
|
6505
6646
|
}, 500);
|
|
6506
6647
|
},
|
|
6507
6648
|
onEdit: (val) => {
|
|
@@ -6513,9 +6654,9 @@ Selection: ${val}`,
|
|
|
6513
6654
|
));
|
|
6514
6655
|
case "approval":
|
|
6515
6656
|
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true, underline: true }, "\u{1F510} SECURITY GATE: FILE WRITE PERMISSION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent is attempting to modify: ", /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, parseArgs(pendingApproval?.args || "{}").path || "Unknown File")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, borderStyle: "single", borderColor: "#333", paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, "--- PROPOSED CONTENT / DIFF ---"), (() => {
|
|
6516
|
-
const
|
|
6517
|
-
const oldVal =
|
|
6518
|
-
const newVal =
|
|
6657
|
+
const args2 = parseArgs(pendingApproval?.args || "{}");
|
|
6658
|
+
const oldVal = args2.TargetContent || args2.content_to_replace || null;
|
|
6659
|
+
const newVal = args2.content || args2.ReplacementContent || args2.content_to_add || args2.replacementContent || null;
|
|
6519
6660
|
if (oldVal && newVal) {
|
|
6520
6661
|
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal.replace(/\[\/n\]?/g, "\\n"))));
|
|
6521
6662
|
}
|
|
@@ -6767,10 +6908,10 @@ var init_app = __esm({
|
|
|
6767
6908
|
init_text();
|
|
6768
6909
|
SESSION_START_TIME = Date.now();
|
|
6769
6910
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
6770
|
-
packageJsonPath =
|
|
6771
|
-
packageJson = JSON.parse(
|
|
6911
|
+
packageJsonPath = path15.join(path15.dirname(fileURLToPath(import.meta.url)), "../package.json");
|
|
6912
|
+
packageJson = JSON.parse(fs17.readFileSync(packageJsonPath, "utf8"));
|
|
6772
6913
|
versionFluxflow = packageJson.version;
|
|
6773
|
-
updatedOn = "2026-05-20";
|
|
6914
|
+
updatedOn = packageJson.date || "2026-05-20";
|
|
6774
6915
|
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 0 }, /* @__PURE__ */ React10.createElement(
|
|
6775
6916
|
CommandMenu,
|
|
6776
6917
|
{
|
|
@@ -6832,5 +6973,5 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
6832
6973
|
console.warn = (...args) => !isNoise(args) && originalWarn(...args);
|
|
6833
6974
|
console.error = (...args) => !isNoise(args) && originalError(...args);
|
|
6834
6975
|
process.stdout.write("\x1Bc");
|
|
6835
|
-
render(/* @__PURE__ */ React11.createElement(App2,
|
|
6976
|
+
render(/* @__PURE__ */ React11.createElement(App2, { args: process.argv.slice(2) }), { exitOnCtrlC: false });
|
|
6836
6977
|
}
|