fluxflow-cli 1.11.2 → 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 +470 -237
- package/package.json +2 -1
package/dist/fluxflow.js
CHANGED
|
@@ -173,7 +173,7 @@ var init_ChatLayout = __esm({
|
|
|
173
173
|
};
|
|
174
174
|
cleanSignals = (text) => {
|
|
175
175
|
if (!text) return text;
|
|
176
|
-
let result = text;
|
|
176
|
+
let result = text.replace(/<\/think>(\r?\n){2}/gi, "</think>").replace(/(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi, "");
|
|
177
177
|
const trigger = "tool:functions.";
|
|
178
178
|
while (true) {
|
|
179
179
|
const lowerResult = result.toLowerCase();
|
|
@@ -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
|
|
@@ -1368,11 +1377,25 @@ var init_history = __esm({
|
|
|
1368
1377
|
// src/utils/usage.js
|
|
1369
1378
|
import fs6 from "fs-extra";
|
|
1370
1379
|
import path5 from "path";
|
|
1371
|
-
|
|
1380
|
+
import os3 from "os";
|
|
1381
|
+
var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
|
|
1372
1382
|
var init_usage = __esm({
|
|
1373
1383
|
"src/utils/usage.js"() {
|
|
1374
1384
|
init_paths();
|
|
1375
1385
|
init_crypto();
|
|
1386
|
+
getLocalBackupPath = () => {
|
|
1387
|
+
if (process.platform === "win32") {
|
|
1388
|
+
const localAppData = process.env.LOCALAPPDATA || path5.join(os3.homedir(), "AppData", "Local");
|
|
1389
|
+
return path5.join(localAppData, "FxFl", "backups", "backup.json");
|
|
1390
|
+
}
|
|
1391
|
+
if (process.platform === "darwin") {
|
|
1392
|
+
return path5.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
|
|
1393
|
+
}
|
|
1394
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || path5.join(os3.homedir(), ".local", "share");
|
|
1395
|
+
return path5.join(xdgDataHome, "fxfl", "backups", "backup.json");
|
|
1396
|
+
};
|
|
1397
|
+
BACKUP_FILE = getLocalBackupPath();
|
|
1398
|
+
generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
1376
1399
|
cachedUsage = null;
|
|
1377
1400
|
writeTimeout = null;
|
|
1378
1401
|
lastWriteTime = 0;
|
|
@@ -1390,28 +1413,98 @@ var init_usage = __esm({
|
|
|
1390
1413
|
};
|
|
1391
1414
|
loadUsageFromFile = async () => {
|
|
1392
1415
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1416
|
+
const tempFile = USAGE_FILE + ".tmp";
|
|
1417
|
+
let primaryData = null;
|
|
1418
|
+
let backupData = null;
|
|
1393
1419
|
try {
|
|
1394
|
-
if (await fs6.exists(
|
|
1395
|
-
const rawContent = (await fs6.readFile(
|
|
1396
|
-
let
|
|
1420
|
+
if (await fs6.exists(tempFile)) {
|
|
1421
|
+
const rawContent = (await fs6.readFile(tempFile, "utf8")).trim();
|
|
1422
|
+
let parsed = null;
|
|
1397
1423
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1398
|
-
|
|
1424
|
+
parsed = JSON.parse(rawContent);
|
|
1399
1425
|
} else {
|
|
1400
|
-
|
|
1426
|
+
parsed = JSON.parse(decryptAes(rawContent));
|
|
1401
1427
|
}
|
|
1402
|
-
if (
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1428
|
+
if (parsed && parsed.date && parsed.stats) {
|
|
1429
|
+
primaryData = parsed;
|
|
1430
|
+
try {
|
|
1431
|
+
await fs6.rename(tempFile, USAGE_FILE);
|
|
1432
|
+
} catch (e) {
|
|
1433
|
+
}
|
|
1434
|
+
} else {
|
|
1435
|
+
try {
|
|
1436
|
+
await fs6.remove(tempFile);
|
|
1437
|
+
} catch (e) {
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
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));
|
|
1406
1455
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1456
|
+
}
|
|
1457
|
+
} catch (err) {
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
try {
|
|
1461
|
+
if (await fs6.exists(BACKUP_FILE)) {
|
|
1462
|
+
const rawContent = (await fs6.readFile(BACKUP_FILE, "utf8")).trim();
|
|
1463
|
+
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1464
|
+
backupData = JSON.parse(rawContent);
|
|
1465
|
+
} else {
|
|
1466
|
+
backupData = JSON.parse(decryptAes(rawContent));
|
|
1411
1467
|
}
|
|
1412
1468
|
}
|
|
1413
1469
|
} catch (err) {
|
|
1414
1470
|
}
|
|
1471
|
+
let resolvedData = null;
|
|
1472
|
+
if (primaryData && backupData) {
|
|
1473
|
+
if (primaryData.saveId !== backupData.saveId) {
|
|
1474
|
+
resolvedData = primaryData;
|
|
1475
|
+
try {
|
|
1476
|
+
await fs6.ensureDir(path5.dirname(BACKUP_FILE));
|
|
1477
|
+
await fs6.copy(USAGE_FILE, BACKUP_FILE);
|
|
1478
|
+
} catch (e) {
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
resolvedData = primaryData;
|
|
1482
|
+
}
|
|
1483
|
+
} else if (primaryData && !backupData) {
|
|
1484
|
+
resolvedData = primaryData;
|
|
1485
|
+
try {
|
|
1486
|
+
await fs6.ensureDir(path5.dirname(BACKUP_FILE));
|
|
1487
|
+
await fs6.copy(USAGE_FILE, BACKUP_FILE);
|
|
1488
|
+
} catch (e) {
|
|
1489
|
+
}
|
|
1490
|
+
} else if (!primaryData && backupData) {
|
|
1491
|
+
resolvedData = backupData;
|
|
1492
|
+
try {
|
|
1493
|
+
await fs6.ensureDir(path5.dirname(USAGE_FILE));
|
|
1494
|
+
await fs6.copy(BACKUP_FILE, USAGE_FILE);
|
|
1495
|
+
} catch (e) {
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
if (resolvedData && resolvedData.date === today && resolvedData.stats) {
|
|
1499
|
+
const mergedStats = { ...defaultStats, ...resolvedData.stats };
|
|
1500
|
+
if (!Array.isArray(mergedStats.imageCalls)) {
|
|
1501
|
+
mergedStats.imageCalls = [];
|
|
1502
|
+
}
|
|
1503
|
+
return {
|
|
1504
|
+
...resolvedData,
|
|
1505
|
+
stats: mergedStats
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1415
1508
|
return { date: today, stats: { ...defaultStats } };
|
|
1416
1509
|
};
|
|
1417
1510
|
flushUsage = async () => {
|
|
@@ -1449,6 +1542,7 @@ var init_usage = __esm({
|
|
|
1449
1542
|
}
|
|
1450
1543
|
}
|
|
1451
1544
|
}
|
|
1545
|
+
cachedUsage.saveId = generateSaveId();
|
|
1452
1546
|
const tempFile = USAGE_FILE + ".tmp";
|
|
1453
1547
|
const encryptedStr = encryptAes(JSON.stringify(cachedUsage, null, 2));
|
|
1454
1548
|
await fs6.writeFile(tempFile, encryptedStr, "utf8");
|
|
@@ -1456,6 +1550,11 @@ var init_usage = __esm({
|
|
|
1456
1550
|
await fs6.fsync(fd);
|
|
1457
1551
|
await fs6.close(fd);
|
|
1458
1552
|
await fs6.rename(tempFile, USAGE_FILE);
|
|
1553
|
+
try {
|
|
1554
|
+
await fs6.ensureDir(path5.dirname(BACKUP_FILE));
|
|
1555
|
+
await fs6.copy(USAGE_FILE, BACKUP_FILE);
|
|
1556
|
+
} catch (backupErr) {
|
|
1557
|
+
}
|
|
1459
1558
|
isDirty = false;
|
|
1460
1559
|
lastWriteTime = Date.now();
|
|
1461
1560
|
} catch (e) {
|
|
@@ -2089,70 +2188,9 @@ var init_chat = __esm({
|
|
|
2089
2188
|
}
|
|
2090
2189
|
});
|
|
2091
2190
|
|
|
2092
|
-
// src/tools/
|
|
2191
|
+
// src/tools/view_file.js
|
|
2093
2192
|
import fs7 from "fs";
|
|
2094
2193
|
import path6 from "path";
|
|
2095
|
-
var list_files;
|
|
2096
|
-
var init_list_files = __esm({
|
|
2097
|
-
"src/tools/list_files.js"() {
|
|
2098
|
-
init_arg_parser();
|
|
2099
|
-
list_files = async (args) => {
|
|
2100
|
-
const { path: targetPath = "." } = parseArgs(args);
|
|
2101
|
-
const absolutePath = path6.resolve(process.cwd(), targetPath);
|
|
2102
|
-
try {
|
|
2103
|
-
if (!fs7.existsSync(absolutePath)) {
|
|
2104
|
-
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2105
|
-
}
|
|
2106
|
-
const stats = fs7.statSync(absolutePath);
|
|
2107
|
-
if (!stats.isDirectory()) {
|
|
2108
|
-
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2109
|
-
}
|
|
2110
|
-
const files = fs7.readdirSync(absolutePath);
|
|
2111
|
-
if (files.length === 0) {
|
|
2112
|
-
return `Directory [${targetPath}] is empty.`;
|
|
2113
|
-
}
|
|
2114
|
-
const totalFiles = files.length;
|
|
2115
|
-
const maxDisplay = 100;
|
|
2116
|
-
const displayFiles = files.slice(0, maxDisplay);
|
|
2117
|
-
const list = displayFiles.map((file) => {
|
|
2118
|
-
const fPath = path6.join(absolutePath, file);
|
|
2119
|
-
let indicator = "\u{1F4C4}";
|
|
2120
|
-
let metaPart = "";
|
|
2121
|
-
try {
|
|
2122
|
-
const fStats = fs7.statSync(fPath);
|
|
2123
|
-
indicator = fStats.isDirectory() ? "\u{1F4C1}" : "\u{1F4C4}";
|
|
2124
|
-
const sizeKB = (fStats.size / 1024).toFixed(1);
|
|
2125
|
-
metaPart = fStats.isFile() ? ` - [${sizeKB} KB]` : "";
|
|
2126
|
-
} catch (e) {
|
|
2127
|
-
indicator = "\u2753";
|
|
2128
|
-
metaPart = " - [Access Denied]";
|
|
2129
|
-
}
|
|
2130
|
-
return `${indicator} ${file}${metaPart}`;
|
|
2131
|
-
}).join("\n");
|
|
2132
|
-
let footer = `
|
|
2133
|
-
|
|
2134
|
-
(Total items: ${totalFiles})`;
|
|
2135
|
-
if (totalFiles > maxDisplay) {
|
|
2136
|
-
footer = `
|
|
2137
|
-
|
|
2138
|
-
\u26A0\uFE0F TRUNCATED: Showing first ${maxDisplay} of ${totalFiles} items. Use more specific paths to see others.`;
|
|
2139
|
-
}
|
|
2140
|
-
const result = `Contents of [${targetPath}]:
|
|
2141
|
-
|
|
2142
|
-
${list}${footer}`;
|
|
2143
|
-
files.length = 0;
|
|
2144
|
-
displayFiles.length = 0;
|
|
2145
|
-
return result;
|
|
2146
|
-
} catch (err) {
|
|
2147
|
-
return `ERROR: Failed to list files in [${targetPath}]: ${err.message}`;
|
|
2148
|
-
}
|
|
2149
|
-
};
|
|
2150
|
-
}
|
|
2151
|
-
});
|
|
2152
|
-
|
|
2153
|
-
// src/tools/view_file.js
|
|
2154
|
-
import fs8 from "fs";
|
|
2155
|
-
import path7 from "path";
|
|
2156
2194
|
var view_file;
|
|
2157
2195
|
var init_view_file = __esm({
|
|
2158
2196
|
"src/tools/view_file.js"() {
|
|
@@ -2164,16 +2202,21 @@ var init_view_file = __esm({
|
|
|
2164
2202
|
const finalStart = sLine || 1;
|
|
2165
2203
|
const finalEnd = eLine || (sLine ? sLine + 800 : 800);
|
|
2166
2204
|
if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
|
|
2167
|
-
const absolutePath =
|
|
2205
|
+
const absolutePath = path6.resolve(process.cwd(), targetPath);
|
|
2168
2206
|
try {
|
|
2169
|
-
if (!
|
|
2207
|
+
if (!fs7.existsSync(absolutePath)) {
|
|
2170
2208
|
return `ERROR: File [${targetPath}] does not exist.`;
|
|
2171
2209
|
}
|
|
2172
|
-
const stats =
|
|
2210
|
+
const stats = fs7.statSync(absolutePath);
|
|
2173
2211
|
if (stats.isDirectory()) {
|
|
2174
2212
|
return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
|
|
2175
2213
|
}
|
|
2176
|
-
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
|
+
}
|
|
2177
2220
|
const mimeMap = {
|
|
2178
2221
|
".pdf": "application/pdf",
|
|
2179
2222
|
".jpg": "image/jpeg",
|
|
@@ -2184,7 +2227,7 @@ var init_view_file = __esm({
|
|
|
2184
2227
|
".doc": "application/msword"
|
|
2185
2228
|
};
|
|
2186
2229
|
if (mimeMap[ext]) {
|
|
2187
|
-
const buffer =
|
|
2230
|
+
const buffer = fs7.readFileSync(absolutePath);
|
|
2188
2231
|
const base64 = buffer.toString("base64");
|
|
2189
2232
|
const mimeType = mimeMap[ext];
|
|
2190
2233
|
return {
|
|
@@ -2197,7 +2240,7 @@ var init_view_file = __esm({
|
|
|
2197
2240
|
}
|
|
2198
2241
|
};
|
|
2199
2242
|
}
|
|
2200
|
-
let content =
|
|
2243
|
+
let content = fs7.readFileSync(absolutePath, "utf8");
|
|
2201
2244
|
if (content.startsWith("\uFEFF")) {
|
|
2202
2245
|
content = content.slice(1);
|
|
2203
2246
|
}
|
|
@@ -2220,8 +2263,8 @@ ${code}`;
|
|
|
2220
2263
|
});
|
|
2221
2264
|
|
|
2222
2265
|
// src/tools/write_file.js
|
|
2223
|
-
import
|
|
2224
|
-
import
|
|
2266
|
+
import fs8 from "fs";
|
|
2267
|
+
import path7 from "path";
|
|
2225
2268
|
var write_file;
|
|
2226
2269
|
var init_write_file = __esm({
|
|
2227
2270
|
"src/tools/write_file.js"() {
|
|
@@ -2231,13 +2274,13 @@ var init_write_file = __esm({
|
|
|
2231
2274
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_file.';
|
|
2232
2275
|
if (content === void 0) return 'ERROR: Missing "content" argument for write_file.';
|
|
2233
2276
|
content = content.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2234
|
-
const absolutePath =
|
|
2235
|
-
const parentDir =
|
|
2277
|
+
const absolutePath = path7.resolve(process.cwd(), targetPath);
|
|
2278
|
+
const parentDir = path7.dirname(absolutePath);
|
|
2236
2279
|
try {
|
|
2237
2280
|
let ancestry = "";
|
|
2238
|
-
if (
|
|
2281
|
+
if (fs8.existsSync(absolutePath)) {
|
|
2239
2282
|
try {
|
|
2240
|
-
const oldData =
|
|
2283
|
+
const oldData = fs8.readFileSync(absolutePath, "utf8");
|
|
2241
2284
|
const lines = oldData.split(/\r?\n/);
|
|
2242
2285
|
ancestry = `Old File contents:
|
|
2243
2286
|
${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
@@ -2249,15 +2292,15 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
2249
2292
|
`;
|
|
2250
2293
|
}
|
|
2251
2294
|
}
|
|
2252
|
-
if (!
|
|
2253
|
-
|
|
2295
|
+
if (!fs8.existsSync(parentDir)) {
|
|
2296
|
+
fs8.mkdirSync(parentDir, { recursive: true });
|
|
2254
2297
|
}
|
|
2255
2298
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2256
2299
|
const processedContent = strip(content);
|
|
2257
2300
|
const lineCount = processedContent.split(/\r?\n/).length;
|
|
2258
2301
|
const originalSize = Buffer.byteLength(processedContent, "utf8");
|
|
2259
|
-
|
|
2260
|
-
let verifiedContent =
|
|
2302
|
+
fs8.writeFileSync(absolutePath, processedContent, "utf8");
|
|
2303
|
+
let verifiedContent = fs8.readFileSync(absolutePath, "utf8");
|
|
2261
2304
|
const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
|
|
2262
2305
|
const verifiedLines = verifiedContent.split(/\r?\n/);
|
|
2263
2306
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -2293,8 +2336,8 @@ Check if Starting and Ending matches your write.`;
|
|
|
2293
2336
|
});
|
|
2294
2337
|
|
|
2295
2338
|
// src/tools/update_file.js
|
|
2296
|
-
import
|
|
2297
|
-
import
|
|
2339
|
+
import fs9 from "fs";
|
|
2340
|
+
import path8 from "path";
|
|
2298
2341
|
var update_file;
|
|
2299
2342
|
var init_update_file = __esm({
|
|
2300
2343
|
"src/tools/update_file.js"() {
|
|
@@ -2307,18 +2350,18 @@ var init_update_file = __esm({
|
|
|
2307
2350
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2308
2351
|
content_to_replace = strip(content_to_replace);
|
|
2309
2352
|
content_to_add = strip(content_to_add);
|
|
2310
|
-
const absolutePath =
|
|
2353
|
+
const absolutePath = path8.resolve(process.cwd(), targetPath);
|
|
2311
2354
|
try {
|
|
2312
|
-
if (!
|
|
2355
|
+
if (!fs9.existsSync(absolutePath)) {
|
|
2313
2356
|
return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
|
|
2314
2357
|
}
|
|
2315
|
-
let diskContent =
|
|
2358
|
+
let diskContent = fs9.readFileSync(absolutePath, "utf8");
|
|
2316
2359
|
if (diskContent.startsWith("\uFEFF")) {
|
|
2317
2360
|
diskContent = diskContent.slice(1);
|
|
2318
2361
|
}
|
|
2319
2362
|
const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2320
2363
|
if (diskContent !== normalizedDisk) {
|
|
2321
|
-
|
|
2364
|
+
fs9.writeFileSync(absolutePath, normalizedDisk, "utf8");
|
|
2322
2365
|
diskContent = normalizedDisk;
|
|
2323
2366
|
}
|
|
2324
2367
|
const currentContent = diskContent;
|
|
@@ -2387,7 +2430,7 @@ var init_update_file = __esm({
|
|
|
2387
2430
|
const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
|
|
2388
2431
|
const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
|
|
2389
2432
|
const finalContentToReplace = firstMatchContent;
|
|
2390
|
-
|
|
2433
|
+
fs9.writeFileSync(absolutePath, newFileContent, "utf8");
|
|
2391
2434
|
const allOriginalLines = currentContent.split(/\r?\n/);
|
|
2392
2435
|
const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
|
|
2393
2436
|
const oldLines = content_to_replace.split(/\r?\n/);
|
|
@@ -2650,34 +2693,34 @@ ${finalOutput}`);
|
|
|
2650
2693
|
});
|
|
2651
2694
|
|
|
2652
2695
|
// src/tools/read_folder.js
|
|
2653
|
-
import
|
|
2654
|
-
import
|
|
2696
|
+
import fs10 from "fs";
|
|
2697
|
+
import path9 from "path";
|
|
2655
2698
|
var read_folder;
|
|
2656
2699
|
var init_read_folder = __esm({
|
|
2657
2700
|
"src/tools/read_folder.js"() {
|
|
2658
2701
|
init_arg_parser();
|
|
2659
2702
|
read_folder = async (args) => {
|
|
2660
2703
|
const { path: targetPath = "." } = parseArgs(args);
|
|
2661
|
-
const absolutePath =
|
|
2704
|
+
const absolutePath = path9.resolve(process.cwd(), targetPath);
|
|
2662
2705
|
try {
|
|
2663
|
-
if (!
|
|
2706
|
+
if (!fs10.existsSync(absolutePath)) {
|
|
2664
2707
|
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2665
2708
|
}
|
|
2666
|
-
const stats =
|
|
2709
|
+
const stats = fs10.statSync(absolutePath);
|
|
2667
2710
|
if (!stats.isDirectory()) {
|
|
2668
2711
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2669
2712
|
}
|
|
2670
|
-
const files =
|
|
2713
|
+
const files = fs10.readdirSync(absolutePath);
|
|
2671
2714
|
const totalItems = files.length;
|
|
2672
2715
|
const maxDisplay = 100;
|
|
2673
2716
|
const displayItems = files.slice(0, maxDisplay);
|
|
2674
2717
|
const folderData = [];
|
|
2675
2718
|
for (const file of displayItems) {
|
|
2676
|
-
const fPath =
|
|
2719
|
+
const fPath = path9.join(absolutePath, file);
|
|
2677
2720
|
let indicator = "\u{1F4C4}";
|
|
2678
2721
|
let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
|
|
2679
2722
|
try {
|
|
2680
|
-
const fStats =
|
|
2723
|
+
const fStats = fs10.statSync(fPath);
|
|
2681
2724
|
info = {
|
|
2682
2725
|
name: file,
|
|
2683
2726
|
type: fStats.isDirectory() ? "directory" : "file",
|
|
@@ -2760,8 +2803,8 @@ var init_ask_user = __esm({
|
|
|
2760
2803
|
|
|
2761
2804
|
// src/tools/write_pdf.js
|
|
2762
2805
|
import puppeteer3 from "puppeteer";
|
|
2763
|
-
import
|
|
2764
|
-
import
|
|
2806
|
+
import path10 from "path";
|
|
2807
|
+
import fs11 from "fs-extra";
|
|
2765
2808
|
import { PDFDocument } from "pdf-lib";
|
|
2766
2809
|
var write_pdf;
|
|
2767
2810
|
var init_write_pdf = __esm({
|
|
@@ -2776,10 +2819,10 @@ var init_write_pdf = __esm({
|
|
|
2776
2819
|
} = parseArgs(args);
|
|
2777
2820
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
|
|
2778
2821
|
if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
|
|
2779
|
-
const absolutePath =
|
|
2822
|
+
const absolutePath = path10.resolve(process.cwd(), targetPath);
|
|
2780
2823
|
let browser = null;
|
|
2781
2824
|
try {
|
|
2782
|
-
await
|
|
2825
|
+
await fs11.ensureDir(path10.dirname(absolutePath));
|
|
2783
2826
|
browser = await puppeteer3.launch({
|
|
2784
2827
|
headless: true,
|
|
2785
2828
|
args: [
|
|
@@ -2790,6 +2833,26 @@ var init_write_pdf = __esm({
|
|
|
2790
2833
|
]
|
|
2791
2834
|
});
|
|
2792
2835
|
const page = await browser.newPage();
|
|
2836
|
+
let resolvedContent = content;
|
|
2837
|
+
const imgRegex = /<img[^>]+src=["']([^"']+)["']/gi;
|
|
2838
|
+
let match;
|
|
2839
|
+
while ((match = imgRegex.exec(content)) !== null) {
|
|
2840
|
+
const originalSrc = match[1];
|
|
2841
|
+
if (!originalSrc || originalSrc.startsWith("http://") || originalSrc.startsWith("https://") || originalSrc.startsWith("data:")) {
|
|
2842
|
+
continue;
|
|
2843
|
+
}
|
|
2844
|
+
try {
|
|
2845
|
+
const imgPath = path10.resolve(process.cwd(), originalSrc);
|
|
2846
|
+
if (await fs11.pathExists(imgPath)) {
|
|
2847
|
+
const ext = path10.extname(imgPath).toLowerCase().replace(".", "") || "png";
|
|
2848
|
+
const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
|
|
2849
|
+
const base64 = await fs11.readFile(imgPath, "base64");
|
|
2850
|
+
const dataUri = `data:image/${mime};base64,${base64}`;
|
|
2851
|
+
resolvedContent = resolvedContent.split(originalSrc).join(dataUri);
|
|
2852
|
+
}
|
|
2853
|
+
} catch (e) {
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2793
2856
|
const styledContent = `
|
|
2794
2857
|
<style>
|
|
2795
2858
|
@page {
|
|
@@ -2819,7 +2882,7 @@ var init_write_pdf = __esm({
|
|
|
2819
2882
|
}
|
|
2820
2883
|
</style>
|
|
2821
2884
|
<div class="watermark">Generated by FluxFlow CLI (AI)</div>
|
|
2822
|
-
${
|
|
2885
|
+
${resolvedContent}
|
|
2823
2886
|
`;
|
|
2824
2887
|
await page.setContent(styledContent, { waitUntil: "networkidle0", timeout: 18e4 });
|
|
2825
2888
|
const pdfBytes = await page.pdf({
|
|
@@ -2834,7 +2897,7 @@ var init_write_pdf = __esm({
|
|
|
2834
2897
|
printBackground: true
|
|
2835
2898
|
});
|
|
2836
2899
|
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
2837
|
-
const fileName =
|
|
2900
|
+
const fileName = path10.basename(targetPath);
|
|
2838
2901
|
pdfDoc.setTitle(`FluxFlow_${fileName}`);
|
|
2839
2902
|
pdfDoc.setAuthor("FluxFlow CLI");
|
|
2840
2903
|
pdfDoc.setSubject("Generated with Agentic AI System");
|
|
@@ -2842,8 +2905,8 @@ var init_write_pdf = __esm({
|
|
|
2842
2905
|
pdfDoc.setCreator("FluxFlow PDF Engine");
|
|
2843
2906
|
pdfDoc.setProducer("FluxFlow (Generative AI)");
|
|
2844
2907
|
const finalPdfBytes = await pdfDoc.save();
|
|
2845
|
-
await
|
|
2846
|
-
const stats = await
|
|
2908
|
+
await fs11.writeFile(absolutePath, finalPdfBytes);
|
|
2909
|
+
const stats = await fs11.stat(absolutePath);
|
|
2847
2910
|
return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
|
|
2848
2911
|
} catch (err) {
|
|
2849
2912
|
return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
|
|
@@ -2855,8 +2918,8 @@ var init_write_pdf = __esm({
|
|
|
2855
2918
|
});
|
|
2856
2919
|
|
|
2857
2920
|
// src/tools/write_docx.js
|
|
2858
|
-
import
|
|
2859
|
-
import
|
|
2921
|
+
import fs12 from "fs-extra";
|
|
2922
|
+
import path11 from "path";
|
|
2860
2923
|
import HTMLtoDOCX from "html-to-docx";
|
|
2861
2924
|
var write_docx;
|
|
2862
2925
|
var init_write_docx = __esm({
|
|
@@ -2869,10 +2932,10 @@ var init_write_docx = __esm({
|
|
|
2869
2932
|
} = parseArgs(args);
|
|
2870
2933
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
|
|
2871
2934
|
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
2872
|
-
const absolutePath =
|
|
2935
|
+
const absolutePath = path11.resolve(process.cwd(), targetPath);
|
|
2873
2936
|
try {
|
|
2874
|
-
await
|
|
2875
|
-
const fileName =
|
|
2937
|
+
await fs12.ensureDir(path11.dirname(absolutePath));
|
|
2938
|
+
const fileName = path11.basename(targetPath);
|
|
2876
2939
|
const fullHtml = content.includes("<html") ? content : `
|
|
2877
2940
|
<!DOCTYPE html>
|
|
2878
2941
|
<html lang="en">
|
|
@@ -2893,7 +2956,7 @@ var init_write_docx = __esm({
|
|
|
2893
2956
|
footer: true,
|
|
2894
2957
|
pageNumber: true
|
|
2895
2958
|
});
|
|
2896
|
-
await
|
|
2959
|
+
await fs12.writeFile(absolutePath, docxBuffer);
|
|
2897
2960
|
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
2898
2961
|
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
2899
2962
|
} catch (err) {
|
|
@@ -2950,7 +3013,7 @@ var init_search_keyword = __esm({
|
|
|
2950
3013
|
`;
|
|
2951
3014
|
output += matches.join("\n");
|
|
2952
3015
|
if (filteredLines.length > 100) {
|
|
2953
|
-
output += "\n\n... (Truncated to first 100 matches
|
|
3016
|
+
output += "\n\n... (Truncated to first 100 matches)";
|
|
2954
3017
|
}
|
|
2955
3018
|
resolve(output);
|
|
2956
3019
|
});
|
|
@@ -2960,8 +3023,8 @@ var init_search_keyword = __esm({
|
|
|
2960
3023
|
});
|
|
2961
3024
|
|
|
2962
3025
|
// src/utils/settings.js
|
|
2963
|
-
import
|
|
2964
|
-
import
|
|
3026
|
+
import fs13 from "fs-extra";
|
|
3027
|
+
import path12 from "path";
|
|
2965
3028
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
2966
3029
|
var init_settings = __esm({
|
|
2967
3030
|
"src/utils/settings.js"() {
|
|
@@ -3003,7 +3066,7 @@ var init_settings = __esm({
|
|
|
3003
3066
|
loadSettings = async () => {
|
|
3004
3067
|
let settingsObj = { ...DEFAULT_SETTINGS };
|
|
3005
3068
|
try {
|
|
3006
|
-
if (await
|
|
3069
|
+
if (await fs13.exists(SETTINGS_FILE)) {
|
|
3007
3070
|
const saved = readAesEncryptedJson(SETTINGS_FILE);
|
|
3008
3071
|
if (saved.imageSettings && saved.imageSettings.apiKey) {
|
|
3009
3072
|
try {
|
|
@@ -3048,12 +3111,12 @@ var init_settings = __esm({
|
|
|
3048
3111
|
const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
3049
3112
|
const folders = ["logs", "secret"];
|
|
3050
3113
|
for (const folder of folders) {
|
|
3051
|
-
const src =
|
|
3052
|
-
const dest =
|
|
3114
|
+
const src = path12.join(FLUXFLOW_DIR2, folder);
|
|
3115
|
+
const dest = path12.join(newPath, folder);
|
|
3053
3116
|
try {
|
|
3054
|
-
if (await
|
|
3055
|
-
await
|
|
3056
|
-
await
|
|
3117
|
+
if (await fs13.exists(src)) {
|
|
3118
|
+
await fs13.ensureDir(dest);
|
|
3119
|
+
await fs13.copy(src, dest, { overwrite: true });
|
|
3057
3120
|
}
|
|
3058
3121
|
} catch (err) {
|
|
3059
3122
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -3079,7 +3142,7 @@ var init_settings = __esm({
|
|
|
3079
3142
|
if (updated.imageSettings) {
|
|
3080
3143
|
updated.imageSettings = { ...updated.imageSettings, apiKey: "" };
|
|
3081
3144
|
}
|
|
3082
|
-
await
|
|
3145
|
+
await fs13.ensureDir(path12.dirname(SETTINGS_FILE));
|
|
3083
3146
|
writeAesEncryptedJson(SETTINGS_FILE, updated);
|
|
3084
3147
|
return true;
|
|
3085
3148
|
} catch (err) {
|
|
@@ -3099,8 +3162,8 @@ var init_fallback_key = __esm({
|
|
|
3099
3162
|
});
|
|
3100
3163
|
|
|
3101
3164
|
// src/tools/generate_image.js
|
|
3102
|
-
import
|
|
3103
|
-
import
|
|
3165
|
+
import fs14 from "fs-extra";
|
|
3166
|
+
import path13 from "path";
|
|
3104
3167
|
var injectPngMetadata, generate_image;
|
|
3105
3168
|
var init_generate_image = __esm({
|
|
3106
3169
|
"src/tools/generate_image.js"() {
|
|
@@ -3172,6 +3235,30 @@ var init_generate_image = __esm({
|
|
|
3172
3235
|
if (!prompt) {
|
|
3173
3236
|
return 'ERROR: Missing "prompt" argument for generate_image.';
|
|
3174
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
|
+
}
|
|
3175
3262
|
try {
|
|
3176
3263
|
const settings = await loadSettings();
|
|
3177
3264
|
const hasQuota = await checkImageQuota(settings);
|
|
@@ -3213,7 +3300,8 @@ var init_generate_image = __esm({
|
|
|
3213
3300
|
}
|
|
3214
3301
|
}
|
|
3215
3302
|
const seed = Math.floor(Math.random() * 1e7);
|
|
3216
|
-
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)}`;
|
|
3217
3305
|
const response = await fetch(url, {
|
|
3218
3306
|
method: "GET",
|
|
3219
3307
|
headers: {
|
|
@@ -3254,9 +3342,9 @@ var init_generate_image = __esm({
|
|
|
3254
3342
|
"Seed": String(seed)
|
|
3255
3343
|
};
|
|
3256
3344
|
finalBuffer = injectPngMetadata(finalBuffer, metadata);
|
|
3257
|
-
const absolutePath =
|
|
3258
|
-
await
|
|
3259
|
-
await
|
|
3345
|
+
const absolutePath = path13.resolve(process.cwd(), outputPath);
|
|
3346
|
+
await fs14.ensureDir(path13.dirname(absolutePath));
|
|
3347
|
+
await fs14.writeFile(absolutePath, finalBuffer);
|
|
3260
3348
|
await recordImageGeneration(settings);
|
|
3261
3349
|
return `SUCCESS: Image successfully generated from prompt [${prompt}] and saved to [${outputPath}].`;
|
|
3262
3350
|
} catch (err) {
|
|
@@ -3274,7 +3362,6 @@ var init_tools = __esm({
|
|
|
3274
3362
|
init_web_scrape();
|
|
3275
3363
|
init_memory();
|
|
3276
3364
|
init_chat();
|
|
3277
|
-
init_list_files();
|
|
3278
3365
|
init_view_file();
|
|
3279
3366
|
init_write_file();
|
|
3280
3367
|
init_update_file();
|
|
@@ -3290,7 +3377,6 @@ var init_tools = __esm({
|
|
|
3290
3377
|
web_scrape,
|
|
3291
3378
|
memory,
|
|
3292
3379
|
chat,
|
|
3293
|
-
list_files,
|
|
3294
3380
|
view_file,
|
|
3295
3381
|
write_file,
|
|
3296
3382
|
update_file,
|
|
@@ -3333,8 +3419,8 @@ var init_tools = __esm({
|
|
|
3333
3419
|
|
|
3334
3420
|
// src/utils/ai.js
|
|
3335
3421
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
3336
|
-
import
|
|
3337
|
-
import
|
|
3422
|
+
import path14 from "path";
|
|
3423
|
+
import fs15 from "fs";
|
|
3338
3424
|
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
|
|
3339
3425
|
var init_ai = __esm({
|
|
3340
3426
|
"src/utils/ai.js"() {
|
|
@@ -3370,7 +3456,7 @@ var init_ai = __esm({
|
|
|
3370
3456
|
try {
|
|
3371
3457
|
const pArgs = parseArgs(argsStr);
|
|
3372
3458
|
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
3373
|
-
return filePath ?
|
|
3459
|
+
return filePath ? path14.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
|
|
3374
3460
|
} catch (e) {
|
|
3375
3461
|
return null;
|
|
3376
3462
|
}
|
|
@@ -3483,8 +3569,8 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
|
|
|
3483
3569
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
3484
3570
|
const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
|
|
3485
3571
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
3486
|
-
const janitorLogDir =
|
|
3487
|
-
|
|
3572
|
+
const janitorLogDir = path14.join(LOGS_DIR, "janitor");
|
|
3573
|
+
fs15.appendFileSync(path14.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
|
|
3488
3574
|
`);
|
|
3489
3575
|
if (janitorToolCall.toolName.toLowerCase() === "memory" && !janitorToolCall.args.includes("action='temp'")) {
|
|
3490
3576
|
if (onMemoryUpdated) onMemoryUpdated();
|
|
@@ -3502,9 +3588,9 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
|
|
|
3502
3588
|
process.stdout.write(`\x1B]0;Memory Error\x07`);
|
|
3503
3589
|
}
|
|
3504
3590
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3505
|
-
const janitorErrDir =
|
|
3506
|
-
if (!
|
|
3507
|
-
|
|
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)}
|
|
3508
3594
|
|
|
3509
3595
|
`);
|
|
3510
3596
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -3513,8 +3599,8 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
|
|
|
3513
3599
|
}
|
|
3514
3600
|
}
|
|
3515
3601
|
if (attempts) {
|
|
3516
|
-
const janitorErrDir =
|
|
3517
|
-
|
|
3602
|
+
const janitorErrDir = path14.join(LOGS_DIR, "janitor");
|
|
3603
|
+
fs15.appendFileSync(path14.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
3518
3604
|
|
|
3519
3605
|
|
|
3520
3606
|
`);
|
|
@@ -3795,6 +3881,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
3795
3881
|
let lastToolSniffed = null;
|
|
3796
3882
|
let lastToolDetail = null;
|
|
3797
3883
|
let lastToolEventTime = null;
|
|
3884
|
+
let lastToolFinishedAt = 0;
|
|
3798
3885
|
let toolResults = [];
|
|
3799
3886
|
let toolCallPointer = 0;
|
|
3800
3887
|
let isThinkingLoop = false;
|
|
@@ -3956,12 +4043,12 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
3956
4043
|
if (keyword) {
|
|
3957
4044
|
detail = keyword.replace(/["']/g, "");
|
|
3958
4045
|
} else if (filePath) {
|
|
3959
|
-
detail =
|
|
4046
|
+
detail = path14.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
|
|
3960
4047
|
} else {
|
|
3961
4048
|
const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
|
|
3962
4049
|
if (m) {
|
|
3963
4050
|
const val = m[1].replace(/["']/g, "");
|
|
3964
|
-
detail = potentialTool === "search_keyword" ? val :
|
|
4051
|
+
detail = potentialTool === "search_keyword" ? val : path14.basename(val.replace(/\\/g, "/"));
|
|
3965
4052
|
}
|
|
3966
4053
|
}
|
|
3967
4054
|
}
|
|
@@ -4121,9 +4208,9 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
4121
4208
|
let totalLines = "...";
|
|
4122
4209
|
let actualEndLine = eLine;
|
|
4123
4210
|
try {
|
|
4124
|
-
const absPath =
|
|
4125
|
-
if (
|
|
4126
|
-
const content =
|
|
4211
|
+
const absPath = path14.resolve(process.cwd(), targetPath2);
|
|
4212
|
+
if (fs15.existsSync(absPath)) {
|
|
4213
|
+
const content = fs15.readFileSync(absPath, "utf8");
|
|
4127
4214
|
const lines = content.split("\n").length;
|
|
4128
4215
|
totalLines = lines;
|
|
4129
4216
|
actualEndLine = Math.min(eLine, lines);
|
|
@@ -4174,7 +4261,7 @@ ${boxBottom}` };
|
|
|
4174
4261
|
const { command } = parseArgs(toolCall.args);
|
|
4175
4262
|
if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
|
|
4176
4263
|
const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
|
|
4177
|
-
const currentDrive =
|
|
4264
|
+
const currentDrive = path14.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
4178
4265
|
const isViolating = riskyPatterns.some((pattern) => {
|
|
4179
4266
|
if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
|
|
4180
4267
|
const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
|
|
@@ -4197,8 +4284,8 @@ ${boxBottom}` };
|
|
|
4197
4284
|
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
4198
4285
|
if (targetPath) {
|
|
4199
4286
|
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
4200
|
-
const absoluteTarget =
|
|
4201
|
-
const absoluteCwd =
|
|
4287
|
+
const absoluteTarget = path14.resolve(targetPath);
|
|
4288
|
+
const absoluteCwd = path14.resolve(process.cwd());
|
|
4202
4289
|
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
4203
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.`;
|
|
4204
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**" : ""}` });
|
|
@@ -4223,6 +4310,12 @@ ${boxBottom}` };
|
|
|
4223
4310
|
}
|
|
4224
4311
|
}
|
|
4225
4312
|
}
|
|
4313
|
+
if (lastToolFinishedAt > 0) {
|
|
4314
|
+
const timeSinceLastTool = Date.now() - lastToolFinishedAt;
|
|
4315
|
+
if (timeSinceLastTool < 1e3) {
|
|
4316
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 - timeSinceLastTool));
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4226
4319
|
const effectiveStart = lastToolEventTime || Date.now();
|
|
4227
4320
|
yield { type: "spinner", content: false };
|
|
4228
4321
|
let result = await dispatchTool(normToolName, toolCall.args, {
|
|
@@ -4236,6 +4329,7 @@ ${boxBottom}` };
|
|
|
4236
4329
|
process.stdout.write(`\x1B]0;Working...\x07`);
|
|
4237
4330
|
}
|
|
4238
4331
|
const toolEnd = Date.now();
|
|
4332
|
+
lastToolFinishedAt = toolEnd;
|
|
4239
4333
|
yield { type: "tool_time", content: toolEnd - effectiveStart };
|
|
4240
4334
|
lastToolEventTime = toolEnd;
|
|
4241
4335
|
let binaryPart = null;
|
|
@@ -4306,6 +4400,11 @@ ${boxBottom}` };
|
|
|
4306
4400
|
success = true;
|
|
4307
4401
|
await incrementUsage("agent");
|
|
4308
4402
|
} catch (err) {
|
|
4403
|
+
if (String(err).includes("Incomplete JSON segment at the end")) {
|
|
4404
|
+
success = true;
|
|
4405
|
+
await incrementUsage("agent");
|
|
4406
|
+
break;
|
|
4407
|
+
}
|
|
4309
4408
|
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4310
4409
|
let overlapLen = 0;
|
|
4311
4410
|
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
@@ -4328,9 +4427,9 @@ ${boxBottom}` };
|
|
|
4328
4427
|
const errMsg = err.status || err.error && err.error.message || String(err);
|
|
4329
4428
|
const errLog = String(err);
|
|
4330
4429
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
4331
|
-
const agentErrDir =
|
|
4332
|
-
if (!
|
|
4333
|
-
|
|
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}
|
|
4334
4433
|
DEBUG STATE: turnText='${turnText}', length=${turnText.trim().length}, inStreamRetryCount=${inStreamRetryCount}, retryCount=${retryCount}, isDedupeActive=${isDedupeActive}, dedupeBuffer='${dedupeBuffer}'
|
|
4335
4434
|
|
|
4336
4435
|
----------------------------------------------------------------------
|
|
@@ -4375,7 +4474,7 @@ ${recoveryText}`
|
|
|
4375
4474
|
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
4376
4475
|
} else {
|
|
4377
4476
|
throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
|
|
4378
|
-
Error Log can be found in ${
|
|
4477
|
+
Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4379
4478
|
}
|
|
4380
4479
|
} else {
|
|
4381
4480
|
if (retryCount <= MAX_RETRIES) {
|
|
@@ -4392,7 +4491,7 @@ Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
4392
4491
|
yield { type: "status", content: `Retrying Connection...` };
|
|
4393
4492
|
} else {
|
|
4394
4493
|
throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
4395
|
-
Error Log can be found in ${
|
|
4494
|
+
Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4396
4495
|
}
|
|
4397
4496
|
}
|
|
4398
4497
|
}
|
|
@@ -4453,13 +4552,13 @@ ${timestamp}`;
|
|
|
4453
4552
|
});
|
|
4454
4553
|
|
|
4455
4554
|
// src/components/ResumeModal.jsx
|
|
4456
|
-
import React7, { useState as useState4, useEffect as
|
|
4555
|
+
import React7, { useState as useState4, useEffect as useEffect3 } from "react";
|
|
4457
4556
|
import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
|
|
4458
4557
|
function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
4459
4558
|
const [history, setHistory] = useState4({});
|
|
4460
4559
|
const [keys, setKeys] = useState4([]);
|
|
4461
4560
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
4462
|
-
|
|
4561
|
+
useEffect3(() => {
|
|
4463
4562
|
const fetchHistory = async () => {
|
|
4464
4563
|
const h = await loadHistory();
|
|
4465
4564
|
setHistory(h);
|
|
@@ -4484,9 +4583,23 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
|
4484
4583
|
}
|
|
4485
4584
|
});
|
|
4486
4585
|
const s = emojiSpace(2);
|
|
4487
|
-
|
|
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) => {
|
|
4488
4599
|
const chat2 = history[id];
|
|
4489
|
-
const
|
|
4600
|
+
const actualIndex = startIndex + index;
|
|
4601
|
+
const isSelected = actualIndex === selectedIndex;
|
|
4602
|
+
const dateStr = formatDate(chat2?.updatedAt);
|
|
4490
4603
|
return /* @__PURE__ */ React7.createElement(
|
|
4491
4604
|
Box7,
|
|
4492
4605
|
{
|
|
@@ -4495,10 +4608,10 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
|
4495
4608
|
backgroundColor: isSelected ? "#2a2a2a" : void 0,
|
|
4496
4609
|
width: "100%"
|
|
4497
4610
|
},
|
|
4498
|
-
/* @__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), "]"))),
|
|
4499
4612
|
isSelected && /* @__PURE__ */ React7.createElement(Box7, { flexShrink: 0 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, "[X] DELETE "))
|
|
4500
4613
|
);
|
|
4501
|
-
})), /* @__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(
|
|
4502
4615
|
Box7,
|
|
4503
4616
|
{
|
|
4504
4617
|
marginTop: 1,
|
|
@@ -4512,6 +4625,17 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
|
4512
4625
|
/* @__PURE__ */ React7.createElement(Text7, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close")
|
|
4513
4626
|
));
|
|
4514
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
|
+
}
|
|
4515
4639
|
var init_ResumeModal = __esm({
|
|
4516
4640
|
"src/components/ResumeModal.jsx"() {
|
|
4517
4641
|
init_history();
|
|
@@ -4520,16 +4644,24 @@ var init_ResumeModal = __esm({
|
|
|
4520
4644
|
});
|
|
4521
4645
|
|
|
4522
4646
|
// src/components/MemoryModal.jsx
|
|
4523
|
-
import React8, { useState as useState5, useEffect as
|
|
4647
|
+
import React8, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
4524
4648
|
import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
|
|
4525
4649
|
function MemoryModal({ onClose }) {
|
|
4526
4650
|
const [memories, setMemories] = useState5([]);
|
|
4527
4651
|
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
4652
|
+
const [isMemoryOn, setIsMemoryOn] = useState5(true);
|
|
4528
4653
|
const loadMemories = () => {
|
|
4529
4654
|
const data = readEncryptedJson(MEMORIES_FILE, []);
|
|
4530
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
|
+
}
|
|
4531
4663
|
};
|
|
4532
|
-
|
|
4664
|
+
useEffect4(() => {
|
|
4533
4665
|
loadMemories();
|
|
4534
4666
|
}, []);
|
|
4535
4667
|
useInput3((input, key) => {
|
|
@@ -4550,7 +4682,7 @@ function MemoryModal({ onClose }) {
|
|
|
4550
4682
|
return text.replace(/\[Saved on: .*?\]/g, "").trim();
|
|
4551
4683
|
};
|
|
4552
4684
|
const s = emojiSpace(2);
|
|
4553
|
-
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) => {
|
|
4554
4686
|
const isSelected = idx === selectedIndex;
|
|
4555
4687
|
return /* @__PURE__ */ React8.createElement(
|
|
4556
4688
|
Box8,
|
|
@@ -4586,7 +4718,7 @@ var init_MemoryModal = __esm({
|
|
|
4586
4718
|
});
|
|
4587
4719
|
|
|
4588
4720
|
// src/components/UpdateProcessor.jsx
|
|
4589
|
-
import React9, { useState as useState6, useEffect as
|
|
4721
|
+
import React9, { useState as useState6, useEffect as useEffect5 } from "react";
|
|
4590
4722
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
4591
4723
|
import Spinner from "ink-spinner";
|
|
4592
4724
|
import { exec as exec2 } from "child_process";
|
|
@@ -4597,7 +4729,7 @@ var init_UpdateProcessor = __esm({
|
|
|
4597
4729
|
const [status, setStatus] = useState6("initializing");
|
|
4598
4730
|
const [log, setLog] = useState6("");
|
|
4599
4731
|
const [error, setError] = useState6(null);
|
|
4600
|
-
|
|
4732
|
+
useEffect5(() => {
|
|
4601
4733
|
let child;
|
|
4602
4734
|
const runUpdate = async () => {
|
|
4603
4735
|
const manager = settings.updateManager || "npm";
|
|
@@ -4640,7 +4772,7 @@ var init_UpdateProcessor = __esm({
|
|
|
4640
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)"));
|
|
4641
4773
|
}
|
|
4642
4774
|
if (status === "success") {
|
|
4643
|
-
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)")));
|
|
4644
4776
|
}
|
|
4645
4777
|
if (status === "error") {
|
|
4646
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)")));
|
|
@@ -4655,7 +4787,7 @@ var init_UpdateProcessor = __esm({
|
|
|
4655
4787
|
import puppeteer4 from "puppeteer";
|
|
4656
4788
|
import { exec as exec3 } from "child_process";
|
|
4657
4789
|
import { promisify } from "util";
|
|
4658
|
-
import
|
|
4790
|
+
import fs16 from "fs";
|
|
4659
4791
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
4660
4792
|
var init_setup = __esm({
|
|
4661
4793
|
"src/utils/setup.js"() {
|
|
@@ -4663,7 +4795,7 @@ var init_setup = __esm({
|
|
|
4663
4795
|
checkPuppeteerReady = () => {
|
|
4664
4796
|
try {
|
|
4665
4797
|
const exePath = puppeteer4.executablePath();
|
|
4666
|
-
const exists = exePath &&
|
|
4798
|
+
const exists = exePath && fs16.existsSync(exePath);
|
|
4667
4799
|
if (exists) return true;
|
|
4668
4800
|
} catch (e) {
|
|
4669
4801
|
return false;
|
|
@@ -4693,18 +4825,18 @@ var app_exports = {};
|
|
|
4693
4825
|
__export(app_exports, {
|
|
4694
4826
|
default: () => App
|
|
4695
4827
|
});
|
|
4696
|
-
import
|
|
4697
|
-
import React10, { useState as useState7, useEffect as
|
|
4828
|
+
import os4 from "os";
|
|
4829
|
+
import React10, { useState as useState7, useEffect as useEffect6, useRef as useRef2, useMemo } from "react";
|
|
4698
4830
|
import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
|
|
4699
4831
|
import Spinner2 from "ink-spinner";
|
|
4700
|
-
import
|
|
4701
|
-
import
|
|
4832
|
+
import fs17 from "fs-extra";
|
|
4833
|
+
import path15 from "path";
|
|
4702
4834
|
import { exec as exec4 } from "child_process";
|
|
4703
4835
|
import { fileURLToPath } from "url";
|
|
4704
4836
|
import { MultilineInput } from "ink-multiline-input";
|
|
4705
4837
|
import TextInput3 from "ink-text-input";
|
|
4706
4838
|
import gradient from "gradient-string";
|
|
4707
|
-
function App() {
|
|
4839
|
+
function App({ args = [] }) {
|
|
4708
4840
|
const [confirmExit, setConfirmExit] = useState7(false);
|
|
4709
4841
|
const [exitCountdown, setExitCountdown] = useState7(10);
|
|
4710
4842
|
const { stdout } = useStdout();
|
|
@@ -4716,6 +4848,45 @@ function App() {
|
|
|
4716
4848
|
rows: stdout?.rows || 24
|
|
4717
4849
|
});
|
|
4718
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]);
|
|
4719
4890
|
const performVersionCheck = async (manual = false, settingsOverride = null) => {
|
|
4720
4891
|
const settingsToUse = settingsOverride || systemSettings;
|
|
4721
4892
|
if (manual) {
|
|
@@ -4767,7 +4938,7 @@ function App() {
|
|
|
4767
4938
|
}
|
|
4768
4939
|
}
|
|
4769
4940
|
};
|
|
4770
|
-
|
|
4941
|
+
useEffect6(() => {
|
|
4771
4942
|
const handleResize = () => {
|
|
4772
4943
|
stdout.write("\x1Bc");
|
|
4773
4944
|
setTerminalSize({
|
|
@@ -4811,7 +4982,7 @@ function App() {
|
|
|
4811
4982
|
const [activeCommand, setActiveCommand] = useState7(null);
|
|
4812
4983
|
const [execOutput, setExecOutput] = useState7("");
|
|
4813
4984
|
const [isTerminalFocused, setIsTerminalFocused] = useState7(false);
|
|
4814
|
-
|
|
4985
|
+
useEffect6(() => {
|
|
4815
4986
|
if (apiTier !== "Free" && activeModel === "gemma-4-31b-it") {
|
|
4816
4987
|
setActiveModel("gemini-3-flash-preview");
|
|
4817
4988
|
setMessages((prev) => {
|
|
@@ -4834,10 +5005,10 @@ function App() {
|
|
|
4834
5005
|
}, []);
|
|
4835
5006
|
const activeCommandRef = useRef2(null);
|
|
4836
5007
|
const execOutputRef = useRef2("");
|
|
4837
|
-
|
|
5008
|
+
useEffect6(() => {
|
|
4838
5009
|
activeCommandRef.current = activeCommand;
|
|
4839
5010
|
}, [activeCommand]);
|
|
4840
|
-
|
|
5011
|
+
useEffect6(() => {
|
|
4841
5012
|
execOutputRef.current = execOutput;
|
|
4842
5013
|
}, [execOutput]);
|
|
4843
5014
|
const [autoAcceptWrites, setAutoAcceptWrites] = useState7(false);
|
|
@@ -4868,7 +5039,7 @@ function App() {
|
|
|
4868
5039
|
const [messages, setMessages] = useState7(() => {
|
|
4869
5040
|
const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
|
|
4870
5041
|
const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
|
|
4871
|
-
const isHomeDir = process.cwd() ===
|
|
5042
|
+
const isHomeDir = process.cwd() === os4.homedir();
|
|
4872
5043
|
const isSystemDir = (() => {
|
|
4873
5044
|
const cwd = process.cwd().toLowerCase();
|
|
4874
5045
|
if (process.platform === "win32") {
|
|
@@ -4896,7 +5067,7 @@ function App() {
|
|
|
4896
5067
|
id: "home-warning",
|
|
4897
5068
|
role: "system",
|
|
4898
5069
|
text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
|
|
4899
|
-
subText: `You are currently in ${
|
|
5070
|
+
subText: `You are currently in ${os4.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
|
|
4900
5071
|
isHomeWarning: true,
|
|
4901
5072
|
isMeta: true
|
|
4902
5073
|
});
|
|
@@ -5020,7 +5191,7 @@ function App() {
|
|
|
5020
5191
|
setInput((prev) => prev.replace(/\\\r?$/, "").replace(/\r?$/, "") + "\n");
|
|
5021
5192
|
}
|
|
5022
5193
|
});
|
|
5023
|
-
|
|
5194
|
+
useEffect6(() => {
|
|
5024
5195
|
async function init() {
|
|
5025
5196
|
if (process.stdout.isTTY) {
|
|
5026
5197
|
process.stdout.write(`\x1B]0;FluxFlow | Ready\x07`);
|
|
@@ -5039,7 +5210,12 @@ function App() {
|
|
|
5039
5210
|
const saved = await loadSettings();
|
|
5040
5211
|
setMode(saved.mode);
|
|
5041
5212
|
setThinkingLevel(saved.thinkingLevel);
|
|
5042
|
-
|
|
5213
|
+
persistedModelRef.current = saved.activeModel;
|
|
5214
|
+
if (parsedArgs.model) {
|
|
5215
|
+
setActiveModel(parsedArgs.model);
|
|
5216
|
+
} else {
|
|
5217
|
+
setActiveModel(saved.activeModel);
|
|
5218
|
+
}
|
|
5043
5219
|
setShowFullThinking(saved.showFullThinking);
|
|
5044
5220
|
setApiTier(saved.apiTier || "Free");
|
|
5045
5221
|
setQuotas(saved.quotas || { agentLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
|
|
@@ -5053,6 +5229,27 @@ function App() {
|
|
|
5053
5229
|
customUpdateCommand: "",
|
|
5054
5230
|
...saved.systemSettings || {}
|
|
5055
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
|
+
}
|
|
5056
5253
|
setSystemSettings(freshSettings);
|
|
5057
5254
|
setProfileData(saved.profileData);
|
|
5058
5255
|
setImageSettings(saved.imageSettings || { keyType: "Default", quality: "Low-High", apiKey: "" });
|
|
@@ -5065,13 +5262,41 @@ function App() {
|
|
|
5065
5262
|
cleanupOldHistory(saved.systemSettings.autoDeleteHistory);
|
|
5066
5263
|
}
|
|
5067
5264
|
cleanupOldLogs(LOGS_DIR);
|
|
5068
|
-
|
|
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
|
+
}
|
|
5069
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
|
+
}
|
|
5070
5295
|
setIsInitializing(false);
|
|
5071
5296
|
}
|
|
5072
5297
|
init();
|
|
5073
5298
|
}, []);
|
|
5074
|
-
|
|
5299
|
+
useEffect6(() => {
|
|
5075
5300
|
let timer;
|
|
5076
5301
|
if (confirmExit) {
|
|
5077
5302
|
setExitCountdown(10);
|
|
@@ -5089,19 +5314,20 @@ function App() {
|
|
|
5089
5314
|
if (timer) clearInterval(timer);
|
|
5090
5315
|
};
|
|
5091
5316
|
}, [confirmExit]);
|
|
5092
|
-
|
|
5317
|
+
useEffect6(() => {
|
|
5093
5318
|
if (!isInitializing) {
|
|
5319
|
+
const modelToSave = parsedArgs.model && activeModel === parsedArgs.model ? persistedModelRef.current : activeModel;
|
|
5094
5320
|
saveSettings({
|
|
5095
5321
|
mode,
|
|
5096
5322
|
thinkingLevel,
|
|
5097
|
-
activeModel,
|
|
5323
|
+
activeModel: modelToSave || activeModel,
|
|
5098
5324
|
showFullThinking,
|
|
5099
5325
|
systemSettings,
|
|
5100
5326
|
profileData,
|
|
5101
5327
|
imageSettings
|
|
5102
5328
|
});
|
|
5103
5329
|
}
|
|
5104
|
-
}, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing]);
|
|
5330
|
+
}, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs]);
|
|
5105
5331
|
const handleSetup = async (val) => {
|
|
5106
5332
|
const key = val.trim();
|
|
5107
5333
|
if (key.length >= 30) {
|
|
@@ -5115,7 +5341,7 @@ function App() {
|
|
|
5115
5341
|
}
|
|
5116
5342
|
};
|
|
5117
5343
|
const lastSavedTimeRef = useRef2(SESSION_START_TIME);
|
|
5118
|
-
|
|
5344
|
+
useEffect6(() => {
|
|
5119
5345
|
if (activeView === "exit") {
|
|
5120
5346
|
const flush = async () => {
|
|
5121
5347
|
const now = Date.now();
|
|
@@ -5133,7 +5359,7 @@ function App() {
|
|
|
5133
5359
|
return () => clearTimeout(timer);
|
|
5134
5360
|
}
|
|
5135
5361
|
}, [activeView]);
|
|
5136
|
-
|
|
5362
|
+
useEffect6(() => {
|
|
5137
5363
|
const interval = setInterval(async () => {
|
|
5138
5364
|
if (!isInitializing) {
|
|
5139
5365
|
const now = Date.now();
|
|
@@ -5210,10 +5436,11 @@ function App() {
|
|
|
5210
5436
|
cmd: "/model",
|
|
5211
5437
|
desc: "Switch AI model",
|
|
5212
5438
|
subs: [
|
|
5213
|
-
{ cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default
|
|
5214
|
-
{ 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)" },
|
|
5215
5441
|
{ cmd: "gemini-3-flash-preview", desc: "Fast & Lightweight (Paid, Limited Free quota)" },
|
|
5216
|
-
{ 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)" }
|
|
5217
5444
|
]
|
|
5218
5445
|
},
|
|
5219
5446
|
{ cmd: "/settings", desc: "Configure system prefs" },
|
|
@@ -5240,8 +5467,8 @@ function App() {
|
|
|
5240
5467
|
]
|
|
5241
5468
|
}
|
|
5242
5469
|
];
|
|
5243
|
-
const handleSubmit = async (value) => {
|
|
5244
|
-
if (suggestions.length > 0) {
|
|
5470
|
+
const handleSubmit = async (value, isProgrammatic = false) => {
|
|
5471
|
+
if (!isProgrammatic && suggestions.length > 0) {
|
|
5245
5472
|
const nextMatch = suggestions[selectedIndex] || suggestions[0];
|
|
5246
5473
|
const parts = value.split(" ");
|
|
5247
5474
|
if (parts.length === 1) {
|
|
@@ -5305,7 +5532,8 @@ ${hintText}`, color: "magenta" }];
|
|
|
5305
5532
|
const resumedMsgs = [...target.messages];
|
|
5306
5533
|
const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
|
|
5307
5534
|
if (!hasLogo) {
|
|
5308
|
-
resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text:
|
|
5535
|
+
resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: "\u{1F30A}\u26A1 Resuming Flux Flow Session...", isMeta: true });
|
|
5536
|
+
resumedMsgs.unshift({ id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true });
|
|
5309
5537
|
}
|
|
5310
5538
|
setMessages(resumedMsgs);
|
|
5311
5539
|
setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${targetId}]`, isMeta: true }]);
|
|
@@ -5321,8 +5549,11 @@ ${hintText}`, color: "magenta" }];
|
|
|
5321
5549
|
break;
|
|
5322
5550
|
}
|
|
5323
5551
|
case "/clear": {
|
|
5324
|
-
setMessages([
|
|
5325
|
-
|
|
5552
|
+
setMessages([
|
|
5553
|
+
{ id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true },
|
|
5554
|
+
{ id: "welcome-" + Date.now(), role: "system", text: "\u{1F30A}\u26A1 Welcome back to Flux Flow! Context cleared.", isMeta: true }
|
|
5555
|
+
]);
|
|
5556
|
+
setCompletedIndex(2);
|
|
5326
5557
|
setChatId(generateChatId());
|
|
5327
5558
|
setSessionStats({ tokens: 0 });
|
|
5328
5559
|
setIsExpanded(false);
|
|
@@ -5481,21 +5712,22 @@ ${hintText}`, color: "magenta" }];
|
|
|
5481
5712
|
let formattedLevel;
|
|
5482
5713
|
if (parts[1]) {
|
|
5483
5714
|
let val = parts[1].toLowerCase();
|
|
5715
|
+
const isBypass = parts.includes("--bypass");
|
|
5484
5716
|
formattedLevel = val.charAt(0).toUpperCase() + val.slice(1);
|
|
5485
5717
|
if (val === "xhigh") {
|
|
5486
5718
|
formattedLevel = "xHigh";
|
|
5487
5719
|
}
|
|
5488
|
-
if (mode === "Flow" && (formattedLevel === "Medium" || formattedLevel === "High" || formattedLevel === "xHigh")) {
|
|
5720
|
+
if (!isBypass && mode === "Flow" && (formattedLevel === "Medium" || formattedLevel === "High" || formattedLevel === "xHigh")) {
|
|
5489
5721
|
setMessages((prev) => {
|
|
5490
5722
|
setCompletedIndex(prev.length + 1);
|
|
5491
5723
|
return [...prev, { id: Date.now(), role: "system", text: `\u274C [RESTRICTED] "${formattedLevel}" is restricted in Flow mode. Switch to Flux to enable Higher Thinking Levels.`, isMeta: true }];
|
|
5492
5724
|
});
|
|
5493
5725
|
} else {
|
|
5494
5726
|
setThinkingLevel(formattedLevel);
|
|
5495
|
-
const s2 = emojiSpace(
|
|
5727
|
+
const s2 = emojiSpace(1);
|
|
5496
5728
|
setMessages((prev) => {
|
|
5497
5729
|
setCompletedIndex(prev.length + 1);
|
|
5498
|
-
return [...prev, { id: Date.now(), role: "system", text: `\u{1F527}
|
|
5730
|
+
return [...prev, { id: Date.now(), role: "system", text: `\u{1F527} [SYSTEM] Thinking level set to ${formattedLevel}${isBypass ? ` (Bypass Activated \u{1F575}\uFE0F${s2})` : ""}`, isMeta: true }];
|
|
5499
5731
|
});
|
|
5500
5732
|
}
|
|
5501
5733
|
} else {
|
|
@@ -5584,12 +5816,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
5584
5816
|
setCompletedIndex(prev.length + 1);
|
|
5585
5817
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
5586
5818
|
});
|
|
5587
|
-
if (
|
|
5588
|
-
if (
|
|
5589
|
-
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);
|
|
5590
5822
|
try {
|
|
5591
|
-
const items =
|
|
5592
|
-
if (items.length === 0)
|
|
5823
|
+
const items = fs17.readdirSync(FLUXFLOW_DIR);
|
|
5824
|
+
if (items.length === 0) fs17.removeSync(FLUXFLOW_DIR);
|
|
5593
5825
|
} catch (e) {
|
|
5594
5826
|
}
|
|
5595
5827
|
setTimeout(() => {
|
|
@@ -5628,8 +5860,8 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
5628
5860
|
break;
|
|
5629
5861
|
}
|
|
5630
5862
|
case "/fluxflow": {
|
|
5631
|
-
const
|
|
5632
|
-
if (
|
|
5863
|
+
const args2 = parts.slice(1);
|
|
5864
|
+
if (args2[0] === "init") {
|
|
5633
5865
|
const template = `# FluxFlow Configuration
|
|
5634
5866
|
# This file defines project-specific instructions for the Flux Flow Agent.
|
|
5635
5867
|
|
|
@@ -5646,14 +5878,14 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
5646
5878
|
# SKILLS & WORKFLOWS
|
|
5647
5879
|
- [Define custom step-by-step recipes for this project here]
|
|
5648
5880
|
`;
|
|
5649
|
-
const filePath =
|
|
5650
|
-
if (
|
|
5881
|
+
const filePath = path15.join(process.cwd(), "FluxFlow.md");
|
|
5882
|
+
if (fs17.pathExistsSync(filePath)) {
|
|
5651
5883
|
setMessages((prev) => {
|
|
5652
5884
|
setCompletedIndex(prev.length + 1);
|
|
5653
5885
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
5654
5886
|
});
|
|
5655
5887
|
} else {
|
|
5656
|
-
|
|
5888
|
+
fs17.writeFileSync(filePath, template);
|
|
5657
5889
|
setMessages((prev) => {
|
|
5658
5890
|
setCompletedIndex(prev.length + 1);
|
|
5659
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 }];
|
|
@@ -5764,20 +5996,20 @@ OUTPUT: ${execOutputRef.current}`;
|
|
|
5764
5996
|
setSessionToolFailure((prev) => prev + 1);
|
|
5765
5997
|
}
|
|
5766
5998
|
},
|
|
5767
|
-
onToolApproval: async (tool,
|
|
5999
|
+
onToolApproval: async (tool, args2) => {
|
|
5768
6000
|
const isAuto = autoAcceptWrites || systemSettings.autoExec;
|
|
5769
6001
|
if (tool === "exec_command") {
|
|
5770
|
-
const { command } = parseArgs(
|
|
6002
|
+
const { command } = parseArgs(args2 || "{}");
|
|
5771
6003
|
const safeRegex = /^(echo|ls|dir|pwd|cd|git status|git log|git diff|type|cat|help)\b/i;
|
|
5772
6004
|
if (isAuto || command && safeRegex.test(command.trim())) return "allow";
|
|
5773
6005
|
return new Promise((resolve) => {
|
|
5774
|
-
setPendingApproval({ tool, args, resolve });
|
|
6006
|
+
setPendingApproval({ tool, args: args2, resolve });
|
|
5775
6007
|
setActiveView("terminalApproval");
|
|
5776
6008
|
});
|
|
5777
6009
|
}
|
|
5778
6010
|
if (isAuto) return "allow";
|
|
5779
6011
|
return new Promise((resolve) => {
|
|
5780
|
-
setPendingApproval({ tool, args, resolve });
|
|
6012
|
+
setPendingApproval({ tool, args: args2, resolve });
|
|
5781
6013
|
setActiveView("approval");
|
|
5782
6014
|
});
|
|
5783
6015
|
},
|
|
@@ -6076,7 +6308,7 @@ Selection: ${val}`,
|
|
|
6076
6308
|
}
|
|
6077
6309
|
return currentList.filter((s) => s.cmd.toLowerCase().includes(query));
|
|
6078
6310
|
}, [input]);
|
|
6079
|
-
|
|
6311
|
+
useEffect6(() => {
|
|
6080
6312
|
setSelectedIndex(0);
|
|
6081
6313
|
}, [suggestions]);
|
|
6082
6314
|
const renderActiveView = () => {
|
|
@@ -6392,6 +6624,7 @@ Selection: ${val}`,
|
|
|
6392
6624
|
return /* @__PURE__ */ React10.createElement(
|
|
6393
6625
|
ProfileForm,
|
|
6394
6626
|
{
|
|
6627
|
+
initialData: profileData,
|
|
6395
6628
|
onSave: (profile) => {
|
|
6396
6629
|
setProfileData(profile);
|
|
6397
6630
|
setMessages((prev) => [...prev, { id: Date.now(), role: "system", text: `\u2705 Profile updated: ${profile.name} (${profile.nickname})` }]);
|
|
@@ -6409,7 +6642,7 @@ Selection: ${val}`,
|
|
|
6409
6642
|
setResolutionData(null);
|
|
6410
6643
|
setActiveView("chat");
|
|
6411
6644
|
setTimeout(() => {
|
|
6412
|
-
handleSubmit(val);
|
|
6645
|
+
handleSubmit(val, true);
|
|
6413
6646
|
}, 500);
|
|
6414
6647
|
},
|
|
6415
6648
|
onEdit: (val) => {
|
|
@@ -6421,9 +6654,9 @@ Selection: ${val}`,
|
|
|
6421
6654
|
));
|
|
6422
6655
|
case "approval":
|
|
6423
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 ---"), (() => {
|
|
6424
|
-
const
|
|
6425
|
-
const oldVal =
|
|
6426
|
-
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;
|
|
6427
6660
|
if (oldVal && newVal) {
|
|
6428
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"))));
|
|
6429
6662
|
}
|
|
@@ -6675,10 +6908,10 @@ var init_app = __esm({
|
|
|
6675
6908
|
init_text();
|
|
6676
6909
|
SESSION_START_TIME = Date.now();
|
|
6677
6910
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
6678
|
-
packageJsonPath =
|
|
6679
|
-
packageJson = JSON.parse(
|
|
6911
|
+
packageJsonPath = path15.join(path15.dirname(fileURLToPath(import.meta.url)), "../package.json");
|
|
6912
|
+
packageJson = JSON.parse(fs17.readFileSync(packageJsonPath, "utf8"));
|
|
6680
6913
|
versionFluxflow = packageJson.version;
|
|
6681
|
-
updatedOn = "2026-05-
|
|
6914
|
+
updatedOn = packageJson.date || "2026-05-20";
|
|
6682
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(
|
|
6683
6916
|
CommandMenu,
|
|
6684
6917
|
{
|
|
@@ -6740,5 +6973,5 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
6740
6973
|
console.warn = (...args) => !isNoise(args) && originalWarn(...args);
|
|
6741
6974
|
console.error = (...args) => !isNoise(args) && originalError(...args);
|
|
6742
6975
|
process.stdout.write("\x1Bc");
|
|
6743
|
-
render(/* @__PURE__ */ React11.createElement(App2,
|
|
6976
|
+
render(/* @__PURE__ */ React11.createElement(App2, { args: process.argv.slice(2) }), { exitOnCtrlC: false });
|
|
6744
6977
|
}
|