fluxflow-cli 1.13.6 → 1.14.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 +6 -0
- package/dist/fluxflow.js +1277 -915
- package/package.json +1 -1
package/dist/fluxflow.js
CHANGED
|
@@ -463,6 +463,7 @@ var init_ChatLayout = __esm({
|
|
|
463
463
|
{ cmd: "/help", desc: "Show all available commands" },
|
|
464
464
|
{ cmd: "/clear", desc: "Clear terminal screen" },
|
|
465
465
|
{ cmd: "/resume", desc: "Load previous session" },
|
|
466
|
+
{ cmd: "/revert", desc: "Revert codebase to checkpoint" },
|
|
466
467
|
{ cmd: "/save", desc: "Force save current chat" },
|
|
467
468
|
{ cmd: "/export", desc: "Export current chat in a .txt file" },
|
|
468
469
|
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
@@ -814,9 +815,11 @@ var init_crypto = __esm({
|
|
|
814
815
|
// src/utils/paths.js
|
|
815
816
|
var paths_exports = {};
|
|
816
817
|
__export(paths_exports, {
|
|
818
|
+
BACKUPS_DIR: () => BACKUPS_DIR,
|
|
817
819
|
DATA_DIR: () => DATA_DIR,
|
|
818
820
|
FLUXFLOW_DIR: () => FLUXFLOW_DIR,
|
|
819
821
|
HISTORY_FILE: () => HISTORY_FILE,
|
|
822
|
+
LEDGER_FILE: () => LEDGER_FILE,
|
|
820
823
|
LOGS_DIR: () => LOGS_DIR,
|
|
821
824
|
MEMORIES_FILE: () => MEMORIES_FILE,
|
|
822
825
|
SECRET_DIR: () => SECRET_DIR,
|
|
@@ -829,7 +832,7 @@ import os2 from "os";
|
|
|
829
832
|
import path2 from "path";
|
|
830
833
|
import fs2 from "fs";
|
|
831
834
|
import crypto2 from "crypto";
|
|
832
|
-
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE;
|
|
835
|
+
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE;
|
|
833
836
|
var init_paths = __esm({
|
|
834
837
|
"src/utils/paths.js"() {
|
|
835
838
|
FLUXFLOW_DIR = path2.join(os2.homedir(), ".fluxflow");
|
|
@@ -870,6 +873,8 @@ var init_paths = __esm({
|
|
|
870
873
|
MEMORIES_FILE = path2.join(SECRET_DIR, "memories.json");
|
|
871
874
|
TEMP_MEM_FILE = path2.join(SECRET_DIR, "memory-temp.json");
|
|
872
875
|
TEMP_MEM_CHAT_FILE = path2.join(SECRET_DIR, "temp-memory-chat.json");
|
|
876
|
+
BACKUPS_DIR = path2.join(DATA_DIR, "backups");
|
|
877
|
+
LEDGER_FILE = path2.join(SECRET_DIR, "ledger.json");
|
|
873
878
|
}
|
|
874
879
|
});
|
|
875
880
|
|
|
@@ -962,21 +967,21 @@ Suggest best options; don't ask for preferences. System handles the rest
|
|
|
962
967
|
${mode === "Flux" ? `- FILE TOOLS (path = relative to CWD) -
|
|
963
968
|
1. [tool:functions.ReadFile(path="...", start_line=N, end_line=N)]. Reads contents. Supports images/docs. User gives image/doc: VIEW FIRST
|
|
964
969
|
2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
|
|
965
|
-
3. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist?
|
|
966
|
-
4. [tool:functions.PatchFile(path="...",
|
|
967
|
-
5. [tool:functions.WritePDF(path="...", content="...", orientation="...")].
|
|
970
|
+
3. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile
|
|
971
|
+
4. [tool:functions.PatchFile(path="...", replaceContent="exact old content", newContent="new content")]. Surgical patching. Unsure replaceContent? ReadFile > guessing
|
|
972
|
+
5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout (100vh/vw). No manual footers
|
|
968
973
|
6. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word doc. Proper margins and page breaks
|
|
969
|
-
7. [tool:functions.Run(command="...")]. Runs a ${osDetected === "Windows" ? "Windows CMD" : "Bash"} command. Destructive/Irreversible ops ->
|
|
974
|
+
7. [tool:functions.Run(command="...")]. Runs a ${osDetected === "Windows" ? "Windows CMD" : "Bash"} command. Destructive/Irreversible ops -> Ask user
|
|
970
975
|
8. [tool:functions.SearchKeyword(keyword="...")]. Global search. Finds definitions/logic without reading every file
|
|
971
976
|
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
|
|
972
977
|
|
|
973
978
|
- VERIFY RESULT CONTENTS. Fix errors. No hallucinations
|
|
974
|
-
- File tools >
|
|
979
|
+
- File tools > long chat
|
|
975
980
|
|
|
976
981
|
- Escape quotes: \\" for code strings
|
|
977
982
|
- Literal escapes: Double-escape sequences (e.g., \\\\n, \\\\t)
|
|
978
983
|
- File structure: Real newlines for code formatting`.trim() : `
|
|
979
|
-
-
|
|
984
|
+
- FILE TOOLS ARE NOT AVAILABLE IN FLOW MODE`.trim()}
|
|
980
985
|
|
|
981
986
|
- Results: Passed as [TOOL RESULT] (system)
|
|
982
987
|
- Tool calls: End with [turn: continue]. Only use [turn: finish] after verifying goals
|
|
@@ -1165,15 +1170,168 @@ Current date and Time: ${(/* @__PURE__ */ new Date()).toLocaleString([], { year:
|
|
|
1165
1170
|
}
|
|
1166
1171
|
});
|
|
1167
1172
|
|
|
1168
|
-
// src/utils/
|
|
1173
|
+
// src/utils/revert.js
|
|
1169
1174
|
import fs5 from "fs-extra";
|
|
1170
1175
|
import path4 from "path";
|
|
1176
|
+
var currentTransaction, RevertManager;
|
|
1177
|
+
var init_revert = __esm({
|
|
1178
|
+
"src/utils/revert.js"() {
|
|
1179
|
+
init_paths();
|
|
1180
|
+
init_crypto();
|
|
1181
|
+
fs5.ensureDirSync(BACKUPS_DIR);
|
|
1182
|
+
currentTransaction = null;
|
|
1183
|
+
RevertManager = {
|
|
1184
|
+
/**
|
|
1185
|
+
* Initializes a new transaction before a prompt starts processing.
|
|
1186
|
+
*/
|
|
1187
|
+
async startTransaction(chatId, promptText) {
|
|
1188
|
+
currentTransaction = {
|
|
1189
|
+
id: `tx_prompt_${Date.now()}`,
|
|
1190
|
+
chatId,
|
|
1191
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1192
|
+
prompt: promptText.trim(),
|
|
1193
|
+
changes: [],
|
|
1194
|
+
reverted: false
|
|
1195
|
+
};
|
|
1196
|
+
},
|
|
1197
|
+
/**
|
|
1198
|
+
* Records a file change under the active prompt transaction.
|
|
1199
|
+
*/
|
|
1200
|
+
async recordFileChange(absolutePath) {
|
|
1201
|
+
if (!currentTransaction) return;
|
|
1202
|
+
const alreadyBackedUp = currentTransaction.changes.some((c) => c.filePath === absolutePath);
|
|
1203
|
+
if (alreadyBackedUp) return;
|
|
1204
|
+
const fileExists = await fs5.pathExists(absolutePath);
|
|
1205
|
+
let type = "create";
|
|
1206
|
+
let backupFile = null;
|
|
1207
|
+
if (fileExists) {
|
|
1208
|
+
type = "update";
|
|
1209
|
+
const fileName = path4.basename(absolutePath);
|
|
1210
|
+
backupFile = `${currentTransaction.id}_${fileName}.bak`;
|
|
1211
|
+
const chatBackupDir = path4.join(BACKUPS_DIR, currentTransaction.chatId);
|
|
1212
|
+
await fs5.ensureDir(chatBackupDir);
|
|
1213
|
+
const backupPath = path4.join(chatBackupDir, backupFile);
|
|
1214
|
+
const content = await fs5.readFile(absolutePath, "utf8");
|
|
1215
|
+
const encrypted = encryptAes(content);
|
|
1216
|
+
await fs5.writeFile(backupPath, encrypted, "utf8");
|
|
1217
|
+
}
|
|
1218
|
+
currentTransaction.changes.push({
|
|
1219
|
+
filePath: absolutePath,
|
|
1220
|
+
type,
|
|
1221
|
+
backupFile
|
|
1222
|
+
});
|
|
1223
|
+
},
|
|
1224
|
+
/**
|
|
1225
|
+
* Finalizes the transaction and saves it to ledger.json.
|
|
1226
|
+
*/
|
|
1227
|
+
async commitTransaction() {
|
|
1228
|
+
if (!currentTransaction || currentTransaction.changes.length === 0) {
|
|
1229
|
+
currentTransaction = null;
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
1233
|
+
ledger.push(currentTransaction);
|
|
1234
|
+
if (ledger.length > 500) {
|
|
1235
|
+
const removed = ledger.shift();
|
|
1236
|
+
if (removed.changes) {
|
|
1237
|
+
for (const change of removed.changes) {
|
|
1238
|
+
if (change.backupFile) {
|
|
1239
|
+
const backupPath = path4.join(BACKUPS_DIR, removed.chatId, change.backupFile);
|
|
1240
|
+
await fs5.remove(backupPath);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
1246
|
+
currentTransaction = null;
|
|
1247
|
+
},
|
|
1248
|
+
/**
|
|
1249
|
+
* Reverts the codebase to a state immediately before the target transaction.
|
|
1250
|
+
* Reverts the target transaction and all subsequent ones in reverse sequential order.
|
|
1251
|
+
* Returns the target prompt text so it can be loaded back into the user input.
|
|
1252
|
+
*/
|
|
1253
|
+
async rollbackToBefore(txId) {
|
|
1254
|
+
const ledger = readEncryptedJson(LEDGER_FILE, null);
|
|
1255
|
+
if (!ledger) throw new Error("No transaction ledger found.");
|
|
1256
|
+
const targetIndex = ledger.findIndex((t) => t.id === txId);
|
|
1257
|
+
if (targetIndex === -1) throw new Error(`Transaction [${txId}] not found.`);
|
|
1258
|
+
const chatId = ledger[targetIndex].chatId;
|
|
1259
|
+
const targetPrompt = ledger[targetIndex].prompt;
|
|
1260
|
+
const toRevert = ledger.slice(targetIndex).filter((t) => t.chatId === chatId && !t.reverted).reverse();
|
|
1261
|
+
for (const tx of toRevert) {
|
|
1262
|
+
for (const change of [...tx.changes].reverse()) {
|
|
1263
|
+
if (change.type === "create") {
|
|
1264
|
+
if (await fs5.pathExists(change.filePath)) {
|
|
1265
|
+
await fs5.remove(change.filePath);
|
|
1266
|
+
}
|
|
1267
|
+
} else if (change.type === "update") {
|
|
1268
|
+
const backupPath = path4.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
1269
|
+
if (await fs5.pathExists(backupPath)) {
|
|
1270
|
+
const encrypted = await fs5.readFile(backupPath, "utf8");
|
|
1271
|
+
const decrypted = decryptAes(encrypted);
|
|
1272
|
+
await fs5.writeFile(change.filePath, decrypted, "utf8");
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
tx.reverted = true;
|
|
1277
|
+
}
|
|
1278
|
+
for (const tx of toRevert) {
|
|
1279
|
+
for (const change of tx.changes) {
|
|
1280
|
+
if (change.backupFile) {
|
|
1281
|
+
const backupPath = path4.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
1282
|
+
await fs5.remove(backupPath);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
const updatedLedger = ledger.filter((t) => !toRevert.some((r) => r.id === t.id));
|
|
1287
|
+
writeEncryptedJson(LEDGER_FILE, updatedLedger);
|
|
1288
|
+
return {
|
|
1289
|
+
success: true,
|
|
1290
|
+
chatId,
|
|
1291
|
+
targetPrompt
|
|
1292
|
+
};
|
|
1293
|
+
},
|
|
1294
|
+
/**
|
|
1295
|
+
* Gets all non-reverted prompt transactions for a specific chat.
|
|
1296
|
+
*/
|
|
1297
|
+
async getChatHistory(chatId) {
|
|
1298
|
+
try {
|
|
1299
|
+
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
1300
|
+
return ledger.filter((t) => t.chatId === chatId && !t.reverted);
|
|
1301
|
+
} catch (e) {
|
|
1302
|
+
return [];
|
|
1303
|
+
}
|
|
1304
|
+
},
|
|
1305
|
+
/**
|
|
1306
|
+
* Cleans up all transaction logs and backups associated with a deleted chat.
|
|
1307
|
+
*/
|
|
1308
|
+
async deleteChatBackups(chatId) {
|
|
1309
|
+
try {
|
|
1310
|
+
const chatBackupDir = path4.join(BACKUPS_DIR, chatId);
|
|
1311
|
+
await fs5.remove(chatBackupDir);
|
|
1312
|
+
let ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
1313
|
+
const originalLength = ledger.length;
|
|
1314
|
+
ledger = ledger.filter((t) => t.chatId !== chatId);
|
|
1315
|
+
if (ledger.length !== originalLength) {
|
|
1316
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
1317
|
+
}
|
|
1318
|
+
} catch (e) {
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
// src/utils/history.js
|
|
1326
|
+
import fs6 from "fs-extra";
|
|
1327
|
+
import path5 from "path";
|
|
1171
1328
|
import { nanoid } from "nanoid";
|
|
1172
1329
|
var WRITE_LOCK, withLock, loadHistory, saveChat, saveChatTitle, deleteChat, generateChatId, cleanupOldHistory, parseCustomDate, cleanupLogFile, cleanupOldLogs, getTruncatedHistory;
|
|
1173
1330
|
var init_history = __esm({
|
|
1174
1331
|
"src/utils/history.js"() {
|
|
1175
1332
|
init_crypto();
|
|
1176
1333
|
init_paths();
|
|
1334
|
+
init_revert();
|
|
1177
1335
|
WRITE_LOCK = Promise.resolve();
|
|
1178
1336
|
withLock = (op) => {
|
|
1179
1337
|
const nextLock = WRITE_LOCK.then(async () => {
|
|
@@ -1189,7 +1347,7 @@ var init_history = __esm({
|
|
|
1189
1347
|
return nextLock;
|
|
1190
1348
|
};
|
|
1191
1349
|
loadHistory = async () => {
|
|
1192
|
-
if (await
|
|
1350
|
+
if (await fs6.pathExists(HISTORY_FILE)) {
|
|
1193
1351
|
try {
|
|
1194
1352
|
return readEncryptedJson(HISTORY_FILE, {});
|
|
1195
1353
|
} catch (e) {
|
|
@@ -1239,6 +1397,7 @@ var init_history = __esm({
|
|
|
1239
1397
|
delete cache[id];
|
|
1240
1398
|
writeEncryptedJson(TEMP_MEM_CHAT_FILE, cache);
|
|
1241
1399
|
}
|
|
1400
|
+
await RevertManager.deleteChatBackups(id);
|
|
1242
1401
|
return history;
|
|
1243
1402
|
});
|
|
1244
1403
|
};
|
|
@@ -1308,8 +1467,8 @@ var init_history = __esm({
|
|
|
1308
1467
|
};
|
|
1309
1468
|
cleanupLogFile = async (filePath) => {
|
|
1310
1469
|
try {
|
|
1311
|
-
if (!await
|
|
1312
|
-
const content = await
|
|
1470
|
+
if (!await fs6.pathExists(filePath)) return;
|
|
1471
|
+
const content = await fs6.readFile(filePath, "utf8");
|
|
1313
1472
|
if (!content.trim()) return;
|
|
1314
1473
|
const lines = content.split("\n");
|
|
1315
1474
|
const entries = [];
|
|
@@ -1349,26 +1508,26 @@ var init_history = __esm({
|
|
|
1349
1508
|
}
|
|
1350
1509
|
const finalContent = keptEntries.join("\n").trim();
|
|
1351
1510
|
if (finalContent) {
|
|
1352
|
-
await
|
|
1511
|
+
await fs6.writeFile(filePath, finalContent + "\n", "utf8");
|
|
1353
1512
|
} else {
|
|
1354
|
-
await
|
|
1513
|
+
await fs6.writeFile(filePath, "", "utf8");
|
|
1355
1514
|
}
|
|
1356
1515
|
} catch (e) {
|
|
1357
1516
|
}
|
|
1358
1517
|
};
|
|
1359
1518
|
cleanupOldLogs = async (logsDir) => {
|
|
1360
1519
|
try {
|
|
1361
|
-
if (!await
|
|
1520
|
+
if (!await fs6.pathExists(logsDir)) return;
|
|
1362
1521
|
const cleanRecursive = async (dir) => {
|
|
1363
|
-
const files = await
|
|
1522
|
+
const files = await fs6.readdir(dir);
|
|
1364
1523
|
for (const file of files) {
|
|
1365
|
-
const fullPath =
|
|
1366
|
-
const stat = await
|
|
1524
|
+
const fullPath = path5.join(dir, file);
|
|
1525
|
+
const stat = await fs6.stat(fullPath);
|
|
1367
1526
|
if (stat.isDirectory()) {
|
|
1368
1527
|
await cleanRecursive(fullPath);
|
|
1369
|
-
const subFiles = await
|
|
1528
|
+
const subFiles = await fs6.readdir(fullPath);
|
|
1370
1529
|
if (subFiles.length === 0) {
|
|
1371
|
-
await
|
|
1530
|
+
await fs6.remove(fullPath);
|
|
1372
1531
|
}
|
|
1373
1532
|
} else if (file.endsWith(".log")) {
|
|
1374
1533
|
await cleanupLogFile(fullPath);
|
|
@@ -1391,8 +1550,8 @@ var init_history = __esm({
|
|
|
1391
1550
|
});
|
|
1392
1551
|
|
|
1393
1552
|
// src/utils/usage.js
|
|
1394
|
-
import
|
|
1395
|
-
import
|
|
1553
|
+
import fs7 from "fs-extra";
|
|
1554
|
+
import path6 from "path";
|
|
1396
1555
|
import os3 from "os";
|
|
1397
1556
|
var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
|
|
1398
1557
|
var init_usage = __esm({
|
|
@@ -1401,14 +1560,14 @@ var init_usage = __esm({
|
|
|
1401
1560
|
init_crypto();
|
|
1402
1561
|
getLocalBackupPath = () => {
|
|
1403
1562
|
if (process.platform === "win32") {
|
|
1404
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
1405
|
-
return
|
|
1563
|
+
const localAppData = process.env.LOCALAPPDATA || path6.join(os3.homedir(), "AppData", "Local");
|
|
1564
|
+
return path6.join(localAppData, "FxFl", "backups", "backup.json");
|
|
1406
1565
|
}
|
|
1407
1566
|
if (process.platform === "darwin") {
|
|
1408
|
-
return
|
|
1567
|
+
return path6.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
|
|
1409
1568
|
}
|
|
1410
|
-
const xdgDataHome = process.env.XDG_DATA_HOME ||
|
|
1411
|
-
return
|
|
1569
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || path6.join(os3.homedir(), ".local", "share");
|
|
1570
|
+
return path6.join(xdgDataHome, "fxfl", "backups", "backup.json");
|
|
1412
1571
|
};
|
|
1413
1572
|
BACKUP_FILE = getLocalBackupPath();
|
|
1414
1573
|
generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
@@ -1433,8 +1592,8 @@ var init_usage = __esm({
|
|
|
1433
1592
|
let primaryData = null;
|
|
1434
1593
|
let backupData = null;
|
|
1435
1594
|
try {
|
|
1436
|
-
if (await
|
|
1437
|
-
const rawContent = (await
|
|
1595
|
+
if (await fs7.exists(tempFile)) {
|
|
1596
|
+
const rawContent = (await fs7.readFile(tempFile, "utf8")).trim();
|
|
1438
1597
|
let parsed = null;
|
|
1439
1598
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1440
1599
|
parsed = JSON.parse(rawContent);
|
|
@@ -1444,26 +1603,26 @@ var init_usage = __esm({
|
|
|
1444
1603
|
if (parsed && parsed.date && parsed.stats) {
|
|
1445
1604
|
primaryData = parsed;
|
|
1446
1605
|
try {
|
|
1447
|
-
await
|
|
1606
|
+
await fs7.rename(tempFile, USAGE_FILE);
|
|
1448
1607
|
} catch (e) {
|
|
1449
1608
|
}
|
|
1450
1609
|
} else {
|
|
1451
1610
|
try {
|
|
1452
|
-
await
|
|
1611
|
+
await fs7.remove(tempFile);
|
|
1453
1612
|
} catch (e) {
|
|
1454
1613
|
}
|
|
1455
1614
|
}
|
|
1456
1615
|
}
|
|
1457
1616
|
} catch (err) {
|
|
1458
1617
|
try {
|
|
1459
|
-
await
|
|
1618
|
+
await fs7.remove(tempFile);
|
|
1460
1619
|
} catch (e) {
|
|
1461
1620
|
}
|
|
1462
1621
|
}
|
|
1463
1622
|
if (!primaryData) {
|
|
1464
1623
|
try {
|
|
1465
|
-
if (await
|
|
1466
|
-
const rawContent = (await
|
|
1624
|
+
if (await fs7.exists(USAGE_FILE)) {
|
|
1625
|
+
const rawContent = (await fs7.readFile(USAGE_FILE, "utf8")).trim();
|
|
1467
1626
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1468
1627
|
primaryData = JSON.parse(rawContent);
|
|
1469
1628
|
} else {
|
|
@@ -1474,8 +1633,8 @@ var init_usage = __esm({
|
|
|
1474
1633
|
}
|
|
1475
1634
|
}
|
|
1476
1635
|
try {
|
|
1477
|
-
if (await
|
|
1478
|
-
const rawContent = (await
|
|
1636
|
+
if (await fs7.exists(BACKUP_FILE)) {
|
|
1637
|
+
const rawContent = (await fs7.readFile(BACKUP_FILE, "utf8")).trim();
|
|
1479
1638
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1480
1639
|
backupData = JSON.parse(rawContent);
|
|
1481
1640
|
} else {
|
|
@@ -1489,8 +1648,8 @@ var init_usage = __esm({
|
|
|
1489
1648
|
if (primaryData.saveId !== backupData.saveId) {
|
|
1490
1649
|
resolvedData = primaryData;
|
|
1491
1650
|
try {
|
|
1492
|
-
await
|
|
1493
|
-
await
|
|
1651
|
+
await fs7.ensureDir(path6.dirname(BACKUP_FILE));
|
|
1652
|
+
await fs7.copy(USAGE_FILE, BACKUP_FILE);
|
|
1494
1653
|
} catch (e) {
|
|
1495
1654
|
}
|
|
1496
1655
|
} else {
|
|
@@ -1499,15 +1658,15 @@ var init_usage = __esm({
|
|
|
1499
1658
|
} else if (primaryData && !backupData) {
|
|
1500
1659
|
resolvedData = primaryData;
|
|
1501
1660
|
try {
|
|
1502
|
-
await
|
|
1503
|
-
await
|
|
1661
|
+
await fs7.ensureDir(path6.dirname(BACKUP_FILE));
|
|
1662
|
+
await fs7.copy(USAGE_FILE, BACKUP_FILE);
|
|
1504
1663
|
} catch (e) {
|
|
1505
1664
|
}
|
|
1506
1665
|
} else if (!primaryData && backupData) {
|
|
1507
1666
|
resolvedData = backupData;
|
|
1508
1667
|
try {
|
|
1509
|
-
await
|
|
1510
|
-
await
|
|
1668
|
+
await fs7.ensureDir(path6.dirname(USAGE_FILE));
|
|
1669
|
+
await fs7.copy(BACKUP_FILE, USAGE_FILE);
|
|
1511
1670
|
} catch (e) {
|
|
1512
1671
|
}
|
|
1513
1672
|
}
|
|
@@ -1526,11 +1685,11 @@ var init_usage = __esm({
|
|
|
1526
1685
|
flushUsage = async () => {
|
|
1527
1686
|
if (!isDirty || !cachedUsage) return;
|
|
1528
1687
|
try {
|
|
1529
|
-
await
|
|
1688
|
+
await fs7.ensureDir(path6.dirname(USAGE_FILE));
|
|
1530
1689
|
let diskData = null;
|
|
1531
1690
|
try {
|
|
1532
|
-
if (await
|
|
1533
|
-
const rawContent = (await
|
|
1691
|
+
if (await fs7.exists(USAGE_FILE)) {
|
|
1692
|
+
const rawContent = (await fs7.readFile(USAGE_FILE, "utf8")).trim();
|
|
1534
1693
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1535
1694
|
diskData = JSON.parse(rawContent);
|
|
1536
1695
|
} else {
|
|
@@ -1561,14 +1720,14 @@ var init_usage = __esm({
|
|
|
1561
1720
|
cachedUsage.saveId = generateSaveId();
|
|
1562
1721
|
const tempFile = USAGE_FILE + ".tmp";
|
|
1563
1722
|
const encryptedStr = encryptAes(JSON.stringify(cachedUsage, null, 2));
|
|
1564
|
-
await
|
|
1565
|
-
const fd = await
|
|
1566
|
-
await
|
|
1567
|
-
await
|
|
1568
|
-
await
|
|
1723
|
+
await fs7.writeFile(tempFile, encryptedStr, "utf8");
|
|
1724
|
+
const fd = await fs7.open(tempFile, "r+");
|
|
1725
|
+
await fs7.fsync(fd);
|
|
1726
|
+
await fs7.close(fd);
|
|
1727
|
+
await fs7.rename(tempFile, USAGE_FILE);
|
|
1569
1728
|
try {
|
|
1570
|
-
await
|
|
1571
|
-
await
|
|
1729
|
+
await fs7.ensureDir(path6.dirname(BACKUP_FILE));
|
|
1730
|
+
await fs7.copy(USAGE_FILE, BACKUP_FILE);
|
|
1572
1731
|
} catch (backupErr) {
|
|
1573
1732
|
}
|
|
1574
1733
|
isDirty = false;
|
|
@@ -2221,8 +2380,8 @@ var init_chat = __esm({
|
|
|
2221
2380
|
});
|
|
2222
2381
|
|
|
2223
2382
|
// src/tools/view_file.js
|
|
2224
|
-
import
|
|
2225
|
-
import
|
|
2383
|
+
import fs8 from "fs";
|
|
2384
|
+
import path7 from "path";
|
|
2226
2385
|
var view_file;
|
|
2227
2386
|
var init_view_file = __esm({
|
|
2228
2387
|
"src/tools/view_file.js"() {
|
|
@@ -2234,16 +2393,16 @@ var init_view_file = __esm({
|
|
|
2234
2393
|
const finalStart = sLine || 1;
|
|
2235
2394
|
const finalEnd = eLine || (sLine ? sLine + 800 : 800);
|
|
2236
2395
|
if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
|
|
2237
|
-
const absolutePath =
|
|
2396
|
+
const absolutePath = path7.resolve(process.cwd(), targetPath);
|
|
2238
2397
|
try {
|
|
2239
|
-
if (!
|
|
2398
|
+
if (!fs8.existsSync(absolutePath)) {
|
|
2240
2399
|
return `ERROR: File [${targetPath}] does not exist.`;
|
|
2241
2400
|
}
|
|
2242
|
-
const stats =
|
|
2401
|
+
const stats = fs8.statSync(absolutePath);
|
|
2243
2402
|
if (stats.isDirectory()) {
|
|
2244
2403
|
return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
|
|
2245
2404
|
}
|
|
2246
|
-
const ext =
|
|
2405
|
+
const ext = path7.extname(targetPath).toLowerCase();
|
|
2247
2406
|
const videoExtensions = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".mpeg", ".mpg"];
|
|
2248
2407
|
if (videoExtensions.includes(ext)) {
|
|
2249
2408
|
const format = ext.slice(1).toUpperCase();
|
|
@@ -2259,7 +2418,7 @@ var init_view_file = __esm({
|
|
|
2259
2418
|
".doc": "application/msword"
|
|
2260
2419
|
};
|
|
2261
2420
|
if (mimeMap[ext]) {
|
|
2262
|
-
const buffer =
|
|
2421
|
+
const buffer = fs8.readFileSync(absolutePath);
|
|
2263
2422
|
const base64 = buffer.toString("base64");
|
|
2264
2423
|
const mimeType = mimeMap[ext];
|
|
2265
2424
|
return {
|
|
@@ -2272,7 +2431,7 @@ var init_view_file = __esm({
|
|
|
2272
2431
|
}
|
|
2273
2432
|
};
|
|
2274
2433
|
}
|
|
2275
|
-
let content =
|
|
2434
|
+
let content = fs8.readFileSync(absolutePath, "utf8");
|
|
2276
2435
|
if (content.startsWith("\uFEFF")) {
|
|
2277
2436
|
content = content.slice(1);
|
|
2278
2437
|
}
|
|
@@ -2295,24 +2454,26 @@ ${code}`;
|
|
|
2295
2454
|
});
|
|
2296
2455
|
|
|
2297
2456
|
// src/tools/write_file.js
|
|
2298
|
-
import
|
|
2299
|
-
import
|
|
2457
|
+
import fs9 from "fs";
|
|
2458
|
+
import path8 from "path";
|
|
2300
2459
|
var write_file;
|
|
2301
2460
|
var init_write_file = __esm({
|
|
2302
2461
|
"src/tools/write_file.js"() {
|
|
2303
2462
|
init_arg_parser();
|
|
2463
|
+
init_revert();
|
|
2304
2464
|
write_file = async (args) => {
|
|
2305
2465
|
let { path: targetPath, content } = parseArgs(args);
|
|
2306
2466
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_file.';
|
|
2307
2467
|
if (content === void 0) return 'ERROR: Missing "content" argument for write_file.';
|
|
2308
2468
|
content = content.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2309
|
-
const absolutePath =
|
|
2310
|
-
const parentDir =
|
|
2469
|
+
const absolutePath = path8.resolve(process.cwd(), targetPath);
|
|
2470
|
+
const parentDir = path8.dirname(absolutePath);
|
|
2311
2471
|
try {
|
|
2472
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
2312
2473
|
let ancestry = "";
|
|
2313
|
-
if (
|
|
2474
|
+
if (fs9.existsSync(absolutePath)) {
|
|
2314
2475
|
try {
|
|
2315
|
-
const oldData =
|
|
2476
|
+
const oldData = fs9.readFileSync(absolutePath, "utf8");
|
|
2316
2477
|
const lines = oldData.split(/\r?\n/);
|
|
2317
2478
|
ancestry = `Old File contents:
|
|
2318
2479
|
${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
@@ -2324,15 +2485,15 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
2324
2485
|
`;
|
|
2325
2486
|
}
|
|
2326
2487
|
}
|
|
2327
|
-
if (!
|
|
2328
|
-
|
|
2488
|
+
if (!fs9.existsSync(parentDir)) {
|
|
2489
|
+
fs9.mkdirSync(parentDir, { recursive: true });
|
|
2329
2490
|
}
|
|
2330
2491
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2331
2492
|
const processedContent = strip(content);
|
|
2332
2493
|
const lineCount = processedContent.split(/\r?\n/).length;
|
|
2333
2494
|
const originalSize = Buffer.byteLength(processedContent, "utf8");
|
|
2334
|
-
|
|
2335
|
-
let verifiedContent =
|
|
2495
|
+
fs9.writeFileSync(absolutePath, processedContent, "utf8");
|
|
2496
|
+
let verifiedContent = fs9.readFileSync(absolutePath, "utf8");
|
|
2336
2497
|
const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
|
|
2337
2498
|
const verifiedLines = verifiedContent.split(/\r?\n/);
|
|
2338
2499
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -2368,32 +2529,37 @@ Check if Starting and Ending matches your write.`;
|
|
|
2368
2529
|
});
|
|
2369
2530
|
|
|
2370
2531
|
// src/tools/update_file.js
|
|
2371
|
-
import
|
|
2372
|
-
import
|
|
2532
|
+
import fs10 from "fs";
|
|
2533
|
+
import path9 from "path";
|
|
2373
2534
|
var update_file;
|
|
2374
2535
|
var init_update_file = __esm({
|
|
2375
2536
|
"src/tools/update_file.js"() {
|
|
2376
2537
|
init_arg_parser();
|
|
2538
|
+
init_revert();
|
|
2377
2539
|
update_file = async (args) => {
|
|
2378
|
-
|
|
2540
|
+
const parsed = parseArgs(args);
|
|
2541
|
+
const targetPath = parsed.path;
|
|
2542
|
+
let content_to_replace = parsed.content_to_replace !== void 0 ? parsed.content_to_replace : parsed.replaceContent;
|
|
2543
|
+
let content_to_add = parsed.content_to_add !== void 0 ? parsed.content_to_add : parsed.newContent;
|
|
2379
2544
|
if (!targetPath) return 'ERROR: Missing "path" argument for update_file.';
|
|
2380
|
-
if (content_to_replace === void 0) return 'ERROR: Missing "
|
|
2381
|
-
if (content_to_add === void 0) return 'ERROR: Missing "
|
|
2545
|
+
if (content_to_replace === void 0) return 'ERROR: Missing "replaceContent" argument.';
|
|
2546
|
+
if (content_to_add === void 0) return 'ERROR: Missing "newContent" argument.';
|
|
2382
2547
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2383
2548
|
content_to_replace = strip(content_to_replace);
|
|
2384
2549
|
content_to_add = strip(content_to_add);
|
|
2385
|
-
const absolutePath =
|
|
2550
|
+
const absolutePath = path9.resolve(process.cwd(), targetPath);
|
|
2386
2551
|
try {
|
|
2387
|
-
if (!
|
|
2552
|
+
if (!fs10.existsSync(absolutePath)) {
|
|
2388
2553
|
return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
|
|
2389
2554
|
}
|
|
2390
|
-
|
|
2555
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
2556
|
+
let diskContent = fs10.readFileSync(absolutePath, "utf8");
|
|
2391
2557
|
if (diskContent.startsWith("\uFEFF")) {
|
|
2392
2558
|
diskContent = diskContent.slice(1);
|
|
2393
2559
|
}
|
|
2394
2560
|
const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2395
2561
|
if (diskContent !== normalizedDisk) {
|
|
2396
|
-
|
|
2562
|
+
fs10.writeFileSync(absolutePath, normalizedDisk, "utf8");
|
|
2397
2563
|
diskContent = normalizedDisk;
|
|
2398
2564
|
}
|
|
2399
2565
|
const currentContent = diskContent;
|
|
@@ -2462,7 +2628,7 @@ var init_update_file = __esm({
|
|
|
2462
2628
|
const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
|
|
2463
2629
|
const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
|
|
2464
2630
|
const finalContentToReplace = firstMatchContent;
|
|
2465
|
-
|
|
2631
|
+
fs10.writeFileSync(absolutePath, newFileContent, "utf8");
|
|
2466
2632
|
const allOriginalLines = currentContent.split(/\r?\n/);
|
|
2467
2633
|
const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
|
|
2468
2634
|
const oldLines = content_to_replace.split(/\r?\n/);
|
|
@@ -2725,34 +2891,34 @@ ${finalOutput}`);
|
|
|
2725
2891
|
});
|
|
2726
2892
|
|
|
2727
2893
|
// src/tools/read_folder.js
|
|
2728
|
-
import
|
|
2729
|
-
import
|
|
2894
|
+
import fs11 from "fs";
|
|
2895
|
+
import path10 from "path";
|
|
2730
2896
|
var read_folder;
|
|
2731
2897
|
var init_read_folder = __esm({
|
|
2732
2898
|
"src/tools/read_folder.js"() {
|
|
2733
2899
|
init_arg_parser();
|
|
2734
2900
|
read_folder = async (args) => {
|
|
2735
2901
|
const { path: targetPath = "." } = parseArgs(args);
|
|
2736
|
-
const absolutePath =
|
|
2902
|
+
const absolutePath = path10.resolve(process.cwd(), targetPath);
|
|
2737
2903
|
try {
|
|
2738
|
-
if (!
|
|
2904
|
+
if (!fs11.existsSync(absolutePath)) {
|
|
2739
2905
|
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2740
2906
|
}
|
|
2741
|
-
const stats =
|
|
2907
|
+
const stats = fs11.statSync(absolutePath);
|
|
2742
2908
|
if (!stats.isDirectory()) {
|
|
2743
2909
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2744
2910
|
}
|
|
2745
|
-
const files =
|
|
2911
|
+
const files = fs11.readdirSync(absolutePath);
|
|
2746
2912
|
const totalItems = files.length;
|
|
2747
2913
|
const maxDisplay = 100;
|
|
2748
2914
|
const displayItems = files.slice(0, maxDisplay);
|
|
2749
2915
|
const folderData = [];
|
|
2750
2916
|
for (const file of displayItems) {
|
|
2751
|
-
const fPath =
|
|
2917
|
+
const fPath = path10.join(absolutePath, file);
|
|
2752
2918
|
let indicator = "\u{1F4C4}";
|
|
2753
2919
|
let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
|
|
2754
2920
|
try {
|
|
2755
|
-
const fStats =
|
|
2921
|
+
const fStats = fs11.statSync(fPath);
|
|
2756
2922
|
info = {
|
|
2757
2923
|
name: file,
|
|
2758
2924
|
type: fStats.isDirectory() ? "directory" : "file",
|
|
@@ -2835,13 +3001,14 @@ var init_ask_user = __esm({
|
|
|
2835
3001
|
|
|
2836
3002
|
// src/tools/write_pdf.js
|
|
2837
3003
|
import puppeteer3 from "puppeteer";
|
|
2838
|
-
import
|
|
2839
|
-
import
|
|
3004
|
+
import path11 from "path";
|
|
3005
|
+
import fs12 from "fs-extra";
|
|
2840
3006
|
import { PDFDocument } from "pdf-lib";
|
|
2841
3007
|
var write_pdf;
|
|
2842
3008
|
var init_write_pdf = __esm({
|
|
2843
3009
|
"src/tools/write_pdf.js"() {
|
|
2844
3010
|
init_arg_parser();
|
|
3011
|
+
init_revert();
|
|
2845
3012
|
write_pdf = async (args) => {
|
|
2846
3013
|
const {
|
|
2847
3014
|
path: targetPath,
|
|
@@ -2851,10 +3018,11 @@ var init_write_pdf = __esm({
|
|
|
2851
3018
|
} = parseArgs(args);
|
|
2852
3019
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
|
|
2853
3020
|
if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
|
|
2854
|
-
const absolutePath =
|
|
3021
|
+
const absolutePath = path11.resolve(process.cwd(), targetPath);
|
|
2855
3022
|
let browser = null;
|
|
2856
3023
|
try {
|
|
2857
|
-
await
|
|
3024
|
+
await fs12.ensureDir(path11.dirname(absolutePath));
|
|
3025
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
2858
3026
|
browser = await puppeteer3.launch({
|
|
2859
3027
|
headless: true,
|
|
2860
3028
|
args: [
|
|
@@ -2872,11 +3040,11 @@ var init_write_pdf = __esm({
|
|
|
2872
3040
|
return null;
|
|
2873
3041
|
}
|
|
2874
3042
|
try {
|
|
2875
|
-
const imgPath =
|
|
2876
|
-
if (await
|
|
2877
|
-
const ext =
|
|
3043
|
+
const imgPath = path11.resolve(process.cwd(), originalSrc);
|
|
3044
|
+
if (await fs12.pathExists(imgPath)) {
|
|
3045
|
+
const ext = path11.extname(imgPath).toLowerCase().replace(".", "") || "png";
|
|
2878
3046
|
const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
|
|
2879
|
-
const base64 = await
|
|
3047
|
+
const base64 = await fs12.readFile(imgPath, "base64");
|
|
2880
3048
|
return `data:image/${mime};base64,${base64}`;
|
|
2881
3049
|
}
|
|
2882
3050
|
} catch (e) {
|
|
@@ -2891,9 +3059,9 @@ var init_write_pdf = __esm({
|
|
|
2891
3059
|
const fullTag = match[0];
|
|
2892
3060
|
if (originalHref && fullTag.toLowerCase().includes("stylesheet") && !originalHref.startsWith("http://") && !originalHref.startsWith("https://") && !originalHref.startsWith("data:")) {
|
|
2893
3061
|
try {
|
|
2894
|
-
const cssPath =
|
|
2895
|
-
if (await
|
|
2896
|
-
const cssContent = await
|
|
3062
|
+
const cssPath = path11.resolve(process.cwd(), originalHref);
|
|
3063
|
+
if (await fs12.pathExists(cssPath)) {
|
|
3064
|
+
const cssContent = await fs12.readFile(cssPath, "utf-8");
|
|
2897
3065
|
cssCache[fullTag] = `<style>${cssContent}</style>`;
|
|
2898
3066
|
}
|
|
2899
3067
|
} catch (e) {
|
|
@@ -2974,7 +3142,7 @@ var init_write_pdf = __esm({
|
|
|
2974
3142
|
printBackground: true
|
|
2975
3143
|
});
|
|
2976
3144
|
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
2977
|
-
const fileName =
|
|
3145
|
+
const fileName = path11.basename(targetPath);
|
|
2978
3146
|
pdfDoc.setTitle(`FluxFlow_${fileName}`);
|
|
2979
3147
|
pdfDoc.setAuthor("FluxFlow CLI");
|
|
2980
3148
|
pdfDoc.setSubject("Generated with Agentic AI System");
|
|
@@ -2982,8 +3150,8 @@ var init_write_pdf = __esm({
|
|
|
2982
3150
|
pdfDoc.setCreator("FluxFlow PDF Engine");
|
|
2983
3151
|
pdfDoc.setProducer("FluxFlow (Generative AI)");
|
|
2984
3152
|
const finalPdfBytes = await pdfDoc.save();
|
|
2985
|
-
await
|
|
2986
|
-
const stats = await
|
|
3153
|
+
await fs12.writeFile(absolutePath, finalPdfBytes);
|
|
3154
|
+
const stats = await fs12.stat(absolutePath);
|
|
2987
3155
|
return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
|
|
2988
3156
|
} catch (err) {
|
|
2989
3157
|
return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
|
|
@@ -2995,13 +3163,14 @@ var init_write_pdf = __esm({
|
|
|
2995
3163
|
});
|
|
2996
3164
|
|
|
2997
3165
|
// src/tools/write_docx.js
|
|
2998
|
-
import
|
|
2999
|
-
import
|
|
3166
|
+
import fs13 from "fs-extra";
|
|
3167
|
+
import path12 from "path";
|
|
3000
3168
|
import HTMLtoDOCX from "html-to-docx";
|
|
3001
3169
|
var write_docx;
|
|
3002
3170
|
var init_write_docx = __esm({
|
|
3003
3171
|
"src/tools/write_docx.js"() {
|
|
3004
3172
|
init_arg_parser();
|
|
3173
|
+
init_revert();
|
|
3005
3174
|
write_docx = async (args) => {
|
|
3006
3175
|
const {
|
|
3007
3176
|
path: targetPath,
|
|
@@ -3009,10 +3178,11 @@ var init_write_docx = __esm({
|
|
|
3009
3178
|
} = parseArgs(args);
|
|
3010
3179
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
|
|
3011
3180
|
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
3012
|
-
const absolutePath =
|
|
3181
|
+
const absolutePath = path12.resolve(process.cwd(), targetPath);
|
|
3013
3182
|
try {
|
|
3014
|
-
await
|
|
3015
|
-
|
|
3183
|
+
await fs13.ensureDir(path12.dirname(absolutePath));
|
|
3184
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
3185
|
+
const fileName = path12.basename(targetPath);
|
|
3016
3186
|
const fullHtml = content.includes("<html") ? content : `
|
|
3017
3187
|
<!DOCTYPE html>
|
|
3018
3188
|
<html lang="en">
|
|
@@ -3033,7 +3203,7 @@ var init_write_docx = __esm({
|
|
|
3033
3203
|
footer: true,
|
|
3034
3204
|
pageNumber: true
|
|
3035
3205
|
});
|
|
3036
|
-
await
|
|
3206
|
+
await fs13.writeFile(absolutePath, docxBuffer);
|
|
3037
3207
|
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
3038
3208
|
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
3039
3209
|
} catch (err) {
|
|
@@ -3100,8 +3270,8 @@ var init_search_keyword = __esm({
|
|
|
3100
3270
|
});
|
|
3101
3271
|
|
|
3102
3272
|
// src/utils/settings.js
|
|
3103
|
-
import
|
|
3104
|
-
import
|
|
3273
|
+
import fs14 from "fs-extra";
|
|
3274
|
+
import path13 from "path";
|
|
3105
3275
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
3106
3276
|
var init_settings = __esm({
|
|
3107
3277
|
"src/utils/settings.js"() {
|
|
@@ -3143,7 +3313,7 @@ var init_settings = __esm({
|
|
|
3143
3313
|
loadSettings = async () => {
|
|
3144
3314
|
let settingsObj = { ...DEFAULT_SETTINGS };
|
|
3145
3315
|
try {
|
|
3146
|
-
if (await
|
|
3316
|
+
if (await fs14.exists(SETTINGS_FILE)) {
|
|
3147
3317
|
const saved = readAesEncryptedJson(SETTINGS_FILE);
|
|
3148
3318
|
if (saved.imageSettings && saved.imageSettings.apiKey) {
|
|
3149
3319
|
try {
|
|
@@ -3188,12 +3358,12 @@ var init_settings = __esm({
|
|
|
3188
3358
|
const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
3189
3359
|
const folders = ["logs", "secret"];
|
|
3190
3360
|
for (const folder of folders) {
|
|
3191
|
-
const src =
|
|
3192
|
-
const dest =
|
|
3361
|
+
const src = path13.join(FLUXFLOW_DIR2, folder);
|
|
3362
|
+
const dest = path13.join(newPath, folder);
|
|
3193
3363
|
try {
|
|
3194
|
-
if (await
|
|
3195
|
-
await
|
|
3196
|
-
await
|
|
3364
|
+
if (await fs14.exists(src)) {
|
|
3365
|
+
await fs14.ensureDir(dest);
|
|
3366
|
+
await fs14.copy(src, dest, { overwrite: true });
|
|
3197
3367
|
}
|
|
3198
3368
|
} catch (err) {
|
|
3199
3369
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -3219,7 +3389,7 @@ var init_settings = __esm({
|
|
|
3219
3389
|
if (updated.imageSettings) {
|
|
3220
3390
|
updated.imageSettings = { ...updated.imageSettings, apiKey: "" };
|
|
3221
3391
|
}
|
|
3222
|
-
await
|
|
3392
|
+
await fs14.ensureDir(path13.dirname(SETTINGS_FILE));
|
|
3223
3393
|
writeAesEncryptedJson(SETTINGS_FILE, updated);
|
|
3224
3394
|
return true;
|
|
3225
3395
|
} catch (err) {
|
|
@@ -3239,8 +3409,8 @@ var init_fallback_key = __esm({
|
|
|
3239
3409
|
});
|
|
3240
3410
|
|
|
3241
3411
|
// src/tools/generate_image.js
|
|
3242
|
-
import
|
|
3243
|
-
import
|
|
3412
|
+
import fs15 from "fs-extra";
|
|
3413
|
+
import path14 from "path";
|
|
3244
3414
|
var injectPngMetadata, generate_image;
|
|
3245
3415
|
var init_generate_image = __esm({
|
|
3246
3416
|
"src/tools/generate_image.js"() {
|
|
@@ -3248,6 +3418,7 @@ var init_generate_image = __esm({
|
|
|
3248
3418
|
init_settings();
|
|
3249
3419
|
init_usage();
|
|
3250
3420
|
init_fallback_key();
|
|
3421
|
+
init_revert();
|
|
3251
3422
|
injectPngMetadata = (buffer, metadata = {}) => {
|
|
3252
3423
|
try {
|
|
3253
3424
|
if (buffer.length < 8 || buffer[0] !== 137 || buffer[1] !== 80 || buffer[2] !== 78 || buffer[3] !== 71) {
|
|
@@ -3419,9 +3590,10 @@ var init_generate_image = __esm({
|
|
|
3419
3590
|
"Seed": String(seed)
|
|
3420
3591
|
};
|
|
3421
3592
|
finalBuffer = injectPngMetadata(finalBuffer, metadata);
|
|
3422
|
-
const absolutePath =
|
|
3423
|
-
await
|
|
3424
|
-
await
|
|
3593
|
+
const absolutePath = path14.resolve(process.cwd(), outputPath);
|
|
3594
|
+
await fs15.ensureDir(path14.dirname(absolutePath));
|
|
3595
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
3596
|
+
await fs15.writeFile(absolutePath, finalBuffer);
|
|
3425
3597
|
await recordImageGeneration(settings);
|
|
3426
3598
|
return `SUCCESS: Image successfully generated from prompt [${prompt}] and saved to [${outputPath}].`;
|
|
3427
3599
|
} catch (err) {
|
|
@@ -3590,8 +3762,8 @@ var init_tools = __esm({
|
|
|
3590
3762
|
|
|
3591
3763
|
// src/utils/ai.js
|
|
3592
3764
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
3593
|
-
import
|
|
3594
|
-
import
|
|
3765
|
+
import path15 from "path";
|
|
3766
|
+
import fs16 from "fs";
|
|
3595
3767
|
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, consolidatePastMemories, getAIStream;
|
|
3596
3768
|
var init_ai = __esm({
|
|
3597
3769
|
"src/utils/ai.js"() {
|
|
@@ -3603,6 +3775,7 @@ var init_ai = __esm({
|
|
|
3603
3775
|
init_arg_parser();
|
|
3604
3776
|
init_terminal();
|
|
3605
3777
|
init_paths();
|
|
3778
|
+
init_revert();
|
|
3606
3779
|
client = null;
|
|
3607
3780
|
TERMINATION_SIGNAL = false;
|
|
3608
3781
|
signalTermination = () => {
|
|
@@ -3627,7 +3800,7 @@ var init_ai = __esm({
|
|
|
3627
3800
|
try {
|
|
3628
3801
|
const pArgs = parseArgs(argsStr);
|
|
3629
3802
|
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
3630
|
-
return filePath ?
|
|
3803
|
+
return filePath ? path15.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
|
|
3631
3804
|
} catch (e) {
|
|
3632
3805
|
return null;
|
|
3633
3806
|
}
|
|
@@ -3754,16 +3927,15 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3754
3927
|
}
|
|
3755
3928
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
3756
3929
|
const result = await dispatchTool(toolName, janitorToolCall.args, toolContext);
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3930
|
+
if (toolName.toLowerCase() === "memory") {
|
|
3931
|
+
const isUserAction = janitorToolCall.args.includes("action='user'") || janitorToolCall.args.includes('action="user"');
|
|
3932
|
+
if (isUserAction && !result.startsWith("ERROR")) {
|
|
3933
|
+
if (onMemoryUpdated) onMemoryUpdated();
|
|
3934
|
+
if (process.stdout.isTTY) {
|
|
3935
|
+
process.stdout.write(`\x1B]0;Memory Updated\x07`);
|
|
3936
|
+
}
|
|
3937
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3765
3938
|
}
|
|
3766
|
-
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3767
3939
|
}
|
|
3768
3940
|
}
|
|
3769
3941
|
if (!scoreToolCalled) {
|
|
@@ -3795,9 +3967,9 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3795
3967
|
process.stdout.write(`\x1B]0;Finalizing Error\x07`);
|
|
3796
3968
|
}
|
|
3797
3969
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3798
|
-
const janitorErrDir =
|
|
3799
|
-
if (!
|
|
3800
|
-
|
|
3970
|
+
const janitorErrDir = path15.join(LOGS_DIR, "janitor");
|
|
3971
|
+
if (!fs16.existsSync(janitorErrDir)) fs16.mkdirSync(janitorErrDir, { recursive: true });
|
|
3972
|
+
fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
|
|
3801
3973
|
|
|
3802
3974
|
`);
|
|
3803
3975
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -3806,8 +3978,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3806
3978
|
}
|
|
3807
3979
|
}
|
|
3808
3980
|
if (attempts) {
|
|
3809
|
-
const janitorErrDir =
|
|
3810
|
-
|
|
3981
|
+
const janitorErrDir = path15.join(LOGS_DIR, "janitor");
|
|
3982
|
+
fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
3811
3983
|
|
|
3812
3984
|
|
|
3813
3985
|
`);
|
|
@@ -4108,10 +4280,10 @@ ${newMemoryListStr}
|
|
|
4108
4280
|
}
|
|
4109
4281
|
}
|
|
4110
4282
|
} catch (err) {
|
|
4111
|
-
const janitorLogDir =
|
|
4112
|
-
if (!
|
|
4113
|
-
|
|
4114
|
-
|
|
4283
|
+
const janitorLogDir = path15.join(LOGS_DIR, "janitor");
|
|
4284
|
+
if (!fs16.existsSync(janitorLogDir)) fs16.mkdirSync(janitorLogDir, { recursive: true });
|
|
4285
|
+
fs16.appendFileSync(
|
|
4286
|
+
path15.join(janitorLogDir, "error.log"),
|
|
4115
4287
|
`[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${err.message}
|
|
4116
4288
|
`
|
|
4117
4289
|
);
|
|
@@ -4125,340 +4297,322 @@ ${newMemoryListStr}
|
|
|
4125
4297
|
const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
|
|
4126
4298
|
const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
|
|
4127
4299
|
const needTitle = isFirstPrompt || hasTitleSignal;
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
await consolidatePastMemories(chatId, settings);
|
|
4136
|
-
}
|
|
4137
|
-
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
4138
|
-
const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
4139
|
-
const otherRawMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems);
|
|
4140
|
-
const cachedSummaries = Object.entries(cacheStorage).filter(([id]) => id !== chatId).slice(-20).map(([id, summary]) => `[Chat Summary]: ${summary}`);
|
|
4141
|
-
const otherMemories = [...cachedSummaries, ...otherRawMemories].map((mem) => `- ${mem}`).join("\n");
|
|
4142
|
-
const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
|
|
4143
|
-
const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
|
|
4144
|
-
const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
|
|
4145
|
-
const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
|
|
4146
|
-
const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", hour12: true });
|
|
4147
|
-
const firstUserMsg = `${memoryPrompt}
|
|
4148
|
-
[METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v${versionFluxflow2}
|
|
4149
|
-
${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CORE PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}[USER] ${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}`.trim();
|
|
4150
|
-
modifiedHistory.push({ role: "user", text: firstUserMsg });
|
|
4151
|
-
let lastUsage = null;
|
|
4152
|
-
const MAX_LOOPS = mode === "Flux" ? 70 : 7;
|
|
4153
|
-
const MAX_RETRIES = 16;
|
|
4154
|
-
yield { type: "status", content: "Connecting..." };
|
|
4155
|
-
TERMINATION_SIGNAL = false;
|
|
4156
|
-
let fullAgentResponseChunks = [];
|
|
4157
|
-
let wasToolCalledInLastLoop = false;
|
|
4158
|
-
modifiedHistory.forEach((msg) => {
|
|
4159
|
-
if (msg.text && msg.role === "agent") {
|
|
4160
|
-
msg.text = msg.text.replace(/<(think|thought)>[\s\S]*?<\/(think|thought)>/gi, "").trim();
|
|
4161
|
-
}
|
|
4162
|
-
});
|
|
4163
|
-
for (let loop = 0; loop <= MAX_LOOPS; loop++) {
|
|
4164
|
-
if (loop > 0) {
|
|
4165
|
-
yield { type: "status", content: "Processed. Reconnecting..." };
|
|
4300
|
+
let agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
|
|
4301
|
+
agentText = agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
|
|
4302
|
+
await RevertManager.startTransaction(chatId, agentText);
|
|
4303
|
+
try {
|
|
4304
|
+
let modifiedHistory = [...history.slice(0, -1)];
|
|
4305
|
+
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 254e3) {
|
|
4306
|
+
modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
|
|
4166
4307
|
}
|
|
4167
|
-
if (
|
|
4168
|
-
yield { type: "status", content: "
|
|
4169
|
-
await
|
|
4170
|
-
break;
|
|
4308
|
+
if (isFirstPrompt && isMemoryEnabled) {
|
|
4309
|
+
yield { type: "status", content: "Condensing past chat memories..." };
|
|
4310
|
+
await consolidatePastMemories(chatId, settings);
|
|
4171
4311
|
}
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4312
|
+
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
4313
|
+
const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
4314
|
+
const otherRawMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems);
|
|
4315
|
+
const cachedSummaries = Object.entries(cacheStorage).filter(([id]) => id !== chatId).slice(-20).map(([id, summary]) => `[Chat Summary]: ${summary}`);
|
|
4316
|
+
const otherMemories = [...cachedSummaries, ...otherRawMemories].map((mem) => `- ${mem}`).join("\n");
|
|
4317
|
+
const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
|
|
4318
|
+
const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
|
|
4319
|
+
const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
|
|
4320
|
+
const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
|
|
4321
|
+
const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", hour12: true });
|
|
4322
|
+
const firstUserMsg = `${memoryPrompt}
|
|
4323
|
+
[METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v${versionFluxflow2}
|
|
4324
|
+
${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CORE PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}[USER] ${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}`.trim();
|
|
4325
|
+
modifiedHistory.push({ role: "user", text: firstUserMsg });
|
|
4326
|
+
let lastUsage = null;
|
|
4327
|
+
const MAX_LOOPS = mode === "Flux" ? 70 : 7;
|
|
4328
|
+
const MAX_RETRIES = 16;
|
|
4329
|
+
yield { type: "status", content: "Connecting..." };
|
|
4330
|
+
TERMINATION_SIGNAL = false;
|
|
4331
|
+
let fullAgentResponseChunks = [];
|
|
4332
|
+
let wasToolCalledInLastLoop = false;
|
|
4333
|
+
modifiedHistory.forEach((msg) => {
|
|
4334
|
+
if (msg.text && msg.role === "agent") {
|
|
4335
|
+
msg.text = msg.text.replace(/<(think|thought)>[\s\S]*?<\/(think|thought)>/gi, "").trim();
|
|
4336
|
+
}
|
|
4337
|
+
});
|
|
4338
|
+
for (let loop = 0; loop <= MAX_LOOPS; loop++) {
|
|
4339
|
+
if (loop > 0) {
|
|
4340
|
+
yield { type: "status", content: "Processed. Reconnecting..." };
|
|
4341
|
+
}
|
|
4342
|
+
if (TERMINATION_SIGNAL) {
|
|
4343
|
+
yield { type: "status", content: "Termination Signal Received." };
|
|
4344
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
4345
|
+
break;
|
|
4346
|
+
}
|
|
4347
|
+
if (steeringCallback) {
|
|
4348
|
+
const hint = await steeringCallback();
|
|
4349
|
+
if (hint) {
|
|
4350
|
+
if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "user") {
|
|
4351
|
+
modifiedHistory[modifiedHistory.length - 1].text += `
|
|
4177
4352
|
|
|
4178
4353
|
[STEERING HINT]: ${hint}`;
|
|
4179
|
-
|
|
4180
|
-
|
|
4354
|
+
} else {
|
|
4355
|
+
modifiedHistory.push({ role: "user", text: `${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRICT PRIORITY. DO NOT START A RESPONSE WITHOUT THINKING**\n" : ""}[STEERING HINT]: ${hint}` });
|
|
4356
|
+
}
|
|
4357
|
+
yield { type: "status", content: "Steering Hint Injected." };
|
|
4181
4358
|
}
|
|
4182
|
-
yield { type: "status", content: "Steering Hint Injected." };
|
|
4183
4359
|
}
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4360
|
+
let stream;
|
|
4361
|
+
let success = false;
|
|
4362
|
+
let retryCount = 1;
|
|
4363
|
+
let inStreamRetryCount = 1;
|
|
4364
|
+
let turnText = "";
|
|
4365
|
+
let lastToolSniffed = null;
|
|
4366
|
+
let lastToolDetail = null;
|
|
4367
|
+
let lastToolEventTime = null;
|
|
4368
|
+
let lastToolFinishedAt = 0;
|
|
4369
|
+
let toolResults = [];
|
|
4370
|
+
let toolCallPointer = 0;
|
|
4371
|
+
let anyToolExecutedInThisTurn = false;
|
|
4372
|
+
let isThinkingLoop = false;
|
|
4373
|
+
let isStutteringLoop = false;
|
|
4374
|
+
let isGeneralLoop = false;
|
|
4375
|
+
let isInitialAttempt = true;
|
|
4376
|
+
let accumulatedContext = "";
|
|
4377
|
+
let dedupeBuffer = "";
|
|
4378
|
+
let isDedupeActive = false;
|
|
4379
|
+
while (retryCount <= MAX_RETRIES && inStreamRetryCount <= MAX_RETRIES && !success && !TERMINATION_SIGNAL) {
|
|
4380
|
+
try {
|
|
4381
|
+
turnText = "";
|
|
4382
|
+
if (isInitialAttempt) {
|
|
4383
|
+
if (process.stdout.isTTY) {
|
|
4384
|
+
process.stdout.write(`\x1B]0;Working...\x07`);
|
|
4385
|
+
}
|
|
4386
|
+
yield { type: "turn_reset", content: true };
|
|
4387
|
+
yield { type: "spinner", content: true };
|
|
4388
|
+
isInitialAttempt = false;
|
|
4389
|
+
if (inStreamRetryCount === 1) {
|
|
4390
|
+
accumulatedContext = "";
|
|
4391
|
+
}
|
|
4210
4392
|
}
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4393
|
+
const contents = modifiedHistory.filter((msg) => (msg.role === "user" || msg.role === "agent" || msg.role === "system") && !String(msg.id).startsWith("welcome") && !msg.isMeta).map((msg) => {
|
|
4394
|
+
const parts = [{ text: msg.text }];
|
|
4395
|
+
if (msg.binaryPart) {
|
|
4396
|
+
parts.push(msg.binaryPart);
|
|
4397
|
+
}
|
|
4398
|
+
return {
|
|
4399
|
+
role: msg.role === "user" || msg.role === "system" ? "user" : "model",
|
|
4400
|
+
parts
|
|
4401
|
+
};
|
|
4402
|
+
});
|
|
4403
|
+
if (!await checkQuota("agent", settings)) {
|
|
4404
|
+
throw new Error("Error: Daily Quota Exausted for Agent");
|
|
4216
4405
|
}
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4406
|
+
let targetModel = modelName;
|
|
4407
|
+
if (retryCount === MAX_RETRIES - 1) {
|
|
4408
|
+
targetModel = "gemini-3-flash-preview";
|
|
4409
|
+
yield { type: "model_update", content: "Trying with fallback model" };
|
|
4410
|
+
} else if (retryCount === MAX_RETRIES) {
|
|
4411
|
+
targetModel = "gemini-3.5-flash";
|
|
4412
|
+
yield { type: "model_update", content: "Trying with fallback model" };
|
|
4413
|
+
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
4414
|
+
targetModel = "gemma-4-31b-it";
|
|
4415
|
+
yield { type: "model_update", content: "Trying with fallback Gemma Model" };
|
|
4416
|
+
} else if (retryCount > 0) {
|
|
4417
|
+
yield { type: "model_update", content: null };
|
|
4222
4418
|
}
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
parts
|
|
4226
|
-
};
|
|
4227
|
-
});
|
|
4228
|
-
if (!await checkQuota("agent", settings)) {
|
|
4229
|
-
throw new Error("Error: Daily Quota Exausted for Agent");
|
|
4230
|
-
}
|
|
4231
|
-
let targetModel = modelName;
|
|
4232
|
-
if (retryCount === MAX_RETRIES - 1) {
|
|
4233
|
-
targetModel = "gemini-3-flash-preview";
|
|
4234
|
-
yield { type: "model_update", content: "Trying with fallback model" };
|
|
4235
|
-
} else if (retryCount === MAX_RETRIES) {
|
|
4236
|
-
targetModel = "gemini-3.5-flash";
|
|
4237
|
-
yield { type: "model_update", content: "Trying with fallback model" };
|
|
4238
|
-
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
4239
|
-
targetModel = "gemma-4-31b-it";
|
|
4240
|
-
yield { type: "model_update", content: "Trying with fallback Gemma Model" };
|
|
4241
|
-
} else if (retryCount > 0) {
|
|
4242
|
-
yield { type: "model_update", content: null };
|
|
4243
|
-
}
|
|
4244
|
-
const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
|
|
4245
|
-
const jitInstruction = `
|
|
4419
|
+
const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
|
|
4420
|
+
const jitInstruction = `
|
|
4246
4421
|
|
|
4247
4422
|
[SYSTEM] Tool result received. Analyze output and proceed with your turn.${thinkingLevel != "Fast" ? "**STRICTLY MAINTAIN THINKING PROTOCOL. DO NOT START A RESPONSE WITHOUT THINKING**" : ""}`;
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4423
|
+
const lastUserMsg = contents[contents.length - 1];
|
|
4424
|
+
let addedMarker = false;
|
|
4425
|
+
if (lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text?.startsWith("[TOOL RESULT]")) {
|
|
4426
|
+
lastUserMsg.parts[0].text += jitInstruction;
|
|
4427
|
+
addedMarker = true;
|
|
4428
|
+
}
|
|
4429
|
+
const stepThreshold = Math.floor(MAX_LOOPS * (mode === "Flux" ? 0.95 : 0.7));
|
|
4430
|
+
const currentStep = loop + 1;
|
|
4431
|
+
if (currentStep >= stepThreshold && lastUserMsg && lastUserMsg.parts?.[0]) {
|
|
4432
|
+
lastUserMsg.parts[0].text += `
|
|
4258
4433
|
[SYSTEM] WARNING, Turn Limit Impending: Step ${currentStep}/${MAX_LOOPS}. Wrap up quickly/prompt user to continue & use [turn:finish] quickly.`;
|
|
4259
|
-
}
|
|
4260
|
-
stream = await client.models.generateContentStream({
|
|
4261
|
-
model: targetModel || "gemma-4-31b-it",
|
|
4262
|
-
contents,
|
|
4263
|
-
config: {
|
|
4264
|
-
systemInstruction: currentSystemInstruction,
|
|
4265
|
-
temperature: mode === "Flux" ? 1 : 1.4,
|
|
4266
|
-
maxOutputTokens: 32768,
|
|
4267
|
-
mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
|
|
4268
|
-
safetySettings: [
|
|
4269
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4270
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4271
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4272
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
4273
|
-
],
|
|
4274
|
-
thinkingConfig: { includeThoughts: false, thinkingLevel: targetModel.includes("pro") ? ThinkingLevel.HIGH : ThinkingLevel.MINIMAL }
|
|
4275
4434
|
}
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4435
|
+
stream = await client.models.generateContentStream({
|
|
4436
|
+
model: targetModel || "gemma-4-31b-it",
|
|
4437
|
+
contents,
|
|
4438
|
+
config: {
|
|
4439
|
+
systemInstruction: currentSystemInstruction,
|
|
4440
|
+
temperature: mode === "Flux" ? 1 : 1.4,
|
|
4441
|
+
maxOutputTokens: 32768,
|
|
4442
|
+
mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
|
|
4443
|
+
safetySettings: [
|
|
4444
|
+
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4445
|
+
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4446
|
+
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4447
|
+
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
4448
|
+
],
|
|
4449
|
+
thinkingConfig: { includeThoughts: false, thinkingLevel: targetModel.includes("pro") ? ThinkingLevel.HIGH : ThinkingLevel.MINIMAL }
|
|
4450
|
+
}
|
|
4451
|
+
});
|
|
4452
|
+
if (addedMarker && contents[contents.length - 1]?.parts?.[0]) {
|
|
4453
|
+
contents[contents.length - 1].parts[0].text = contents[contents.length - 1].parts[0].text.replace(jitInstruction, "").trim();
|
|
4294
4454
|
}
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4455
|
+
turnText = "";
|
|
4456
|
+
lastToolSniffed = null;
|
|
4457
|
+
lastToolEventTime = null;
|
|
4458
|
+
toolResults = [];
|
|
4459
|
+
toolCallPointer = 0;
|
|
4460
|
+
yield { type: "model_update", content: null };
|
|
4461
|
+
yield { type: "status", content: "Working..." };
|
|
4462
|
+
dedupeBuffer = "";
|
|
4463
|
+
isDedupeActive = accumulatedContext.length > 0;
|
|
4464
|
+
for await (const chunk of stream) {
|
|
4465
|
+
if (TERMINATION_SIGNAL) {
|
|
4466
|
+
yield { type: "status", content: "Termination Signal Received." };
|
|
4467
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4468
|
+
break;
|
|
4469
|
+
}
|
|
4470
|
+
if (chunk.text) {
|
|
4471
|
+
if (isDedupeActive) {
|
|
4472
|
+
dedupeBuffer += chunk.text;
|
|
4473
|
+
if (dedupeBuffer.length >= 30) {
|
|
4474
|
+
let overlapLen = 0;
|
|
4475
|
+
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4476
|
+
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4477
|
+
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4478
|
+
overlapLen = len;
|
|
4479
|
+
break;
|
|
4480
|
+
}
|
|
4305
4481
|
}
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4482
|
+
const cleanText = dedupeBuffer.substring(overlapLen);
|
|
4483
|
+
if (cleanText) {
|
|
4484
|
+
const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
|
|
4485
|
+
const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*<(think|thought)>\s*/gi, "") : cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
|
|
4486
|
+
if (dedupeClean) {
|
|
4487
|
+
turnText += dedupeClean;
|
|
4488
|
+
yield { type: "text", content: dedupeClean };
|
|
4489
|
+
}
|
|
4314
4490
|
}
|
|
4491
|
+
isDedupeActive = false;
|
|
4492
|
+
dedupeBuffer = "";
|
|
4315
4493
|
}
|
|
4316
|
-
|
|
4317
|
-
|
|
4494
|
+
continue;
|
|
4495
|
+
} else {
|
|
4496
|
+
turnText += chunk.text;
|
|
4497
|
+
yield { type: "text", content: chunk.text };
|
|
4318
4498
|
}
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
"
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
|
|
4360
|
-
if (m) {
|
|
4361
|
-
const val = m[1].replace(/["']/g, "");
|
|
4362
|
-
detail = potentialTool === "search_keyword" ? val : path14.basename(val.replace(/\\/g, "/"));
|
|
4499
|
+
const signalSafeText3 = getSanitizedText(turnText);
|
|
4500
|
+
const toolContext = getActiveToolContext(turnText);
|
|
4501
|
+
if (toolContext.inside) {
|
|
4502
|
+
if (!lastToolEventTime) lastToolEventTime = Date.now();
|
|
4503
|
+
const rawToolName = toolContext.toolName;
|
|
4504
|
+
const NORMALIZE_MAP = {
|
|
4505
|
+
"Ask": "ask",
|
|
4506
|
+
"WebSearch": "web_search",
|
|
4507
|
+
"WebScrape": "web_scrape",
|
|
4508
|
+
"ReadFile": "view_file",
|
|
4509
|
+
"ReadFolder": "read_folder",
|
|
4510
|
+
"WriteFile": "write_file",
|
|
4511
|
+
"PatchFile": "update_file",
|
|
4512
|
+
"WritePDF": "write_pdf",
|
|
4513
|
+
"WriteDoc": "write_docx",
|
|
4514
|
+
"Run": "exec_command",
|
|
4515
|
+
"SearchKeyword": "search_keyword",
|
|
4516
|
+
"Memory": "memory",
|
|
4517
|
+
"Chat": "chat",
|
|
4518
|
+
"chat": "chat",
|
|
4519
|
+
"GenerateImage": "generate_image",
|
|
4520
|
+
"generate_image": "generate_image"
|
|
4521
|
+
};
|
|
4522
|
+
const potentialTool = NORMALIZE_MAP[rawToolName] || rawToolName;
|
|
4523
|
+
const partialArgs = toolContext.args || "";
|
|
4524
|
+
let detail = null;
|
|
4525
|
+
if (["write_file", "update_file", "view_file", "read_folder", "write_pdf", "write_docx", "search_keyword", "generate_image"].includes(potentialTool)) {
|
|
4526
|
+
const pArgs = parseArgs(partialArgs);
|
|
4527
|
+
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
4528
|
+
const keyword = pArgs.keyword;
|
|
4529
|
+
if (keyword) {
|
|
4530
|
+
detail = keyword.replace(/["']/g, "");
|
|
4531
|
+
} else if (filePath) {
|
|
4532
|
+
detail = path15.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
|
|
4533
|
+
} else {
|
|
4534
|
+
const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
|
|
4535
|
+
if (m) {
|
|
4536
|
+
const val = m[1].replace(/["']/g, "");
|
|
4537
|
+
detail = potentialTool === "search_keyword" ? val : path15.basename(val.replace(/\\/g, "/"));
|
|
4538
|
+
}
|
|
4363
4539
|
}
|
|
4364
4540
|
}
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
process.stdout.write(`\x1B]0;${toolTitle}...\x07`);
|
|
4390
|
-
}
|
|
4391
|
-
}
|
|
4392
|
-
}
|
|
4393
|
-
const contextSafeText = getContextSafeText(turnText, false);
|
|
4394
|
-
const thinkBlocks = contextSafeText.match(/<think>([\s\S]*?)(?:<\/think>|$)/gi) || [];
|
|
4395
|
-
const thinkContent = thinkBlocks.join("").trim();
|
|
4396
|
-
const sentences = thinkContent.split(/[.!?]\s+/);
|
|
4397
|
-
const uniqueSentences = new Set(sentences);
|
|
4398
|
-
const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
|
|
4399
|
-
const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
|
|
4400
|
-
let repetitionThresholdThinking = 0.4;
|
|
4401
|
-
let repetitionThresholdResponse = 0.6;
|
|
4402
|
-
const thinkingCaps = {
|
|
4403
|
-
"low": 200,
|
|
4404
|
-
"medium": 500,
|
|
4405
|
-
"high": 2e3,
|
|
4406
|
-
"max": 3500,
|
|
4407
|
-
"xhigh": 3500
|
|
4408
|
-
};
|
|
4409
|
-
const cap = thinkingCaps[thinkingLevel?.toLowerCase()] || 2500;
|
|
4410
|
-
let isOverVerboseThinking = wordCount > cap;
|
|
4411
|
-
if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
|
|
4412
|
-
const reason = repetitionRatio > repetitionThresholdThinking ? "Thinking Loop Detected" : "Thinking Budget Exceeded";
|
|
4413
|
-
yield { type: "status", content: `${reason}. Re-centering...` };
|
|
4414
|
-
isThinkingLoop = true;
|
|
4415
|
-
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4416
|
-
break;
|
|
4417
|
-
}
|
|
4418
|
-
const responseContent = signalSafeText3.trim();
|
|
4419
|
-
const respSentences = responseContent.split(/[.!?]\s+/);
|
|
4420
|
-
const uniqueRespSentences = new Set(respSentences);
|
|
4421
|
-
const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
|
|
4422
|
-
if (respRepetitionRatio > repetitionThresholdResponse) {
|
|
4423
|
-
yield { type: "status", content: `Response Loop Detected. Re-centering...` };
|
|
4424
|
-
isThinkingLoop = false;
|
|
4425
|
-
isGeneralLoop = true;
|
|
4426
|
-
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4427
|
-
break;
|
|
4428
|
-
}
|
|
4429
|
-
const allWords = contextSafeText.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
|
|
4430
|
-
let stutterDetected = false;
|
|
4431
|
-
if (allWords.length > 5) {
|
|
4432
|
-
for (let p = 1; p <= 15; p++) {
|
|
4433
|
-
const R = Math.max(3, Math.ceil(8 / p));
|
|
4434
|
-
if (allWords.length < p * R) continue;
|
|
4435
|
-
let isRepeating = true;
|
|
4436
|
-
const pattern = allWords.slice(allWords.length - p);
|
|
4437
|
-
const patternStr = pattern.join(" ");
|
|
4438
|
-
for (let r = 1; r < R; r++) {
|
|
4439
|
-
const prevPattern = allWords.slice(allWords.length - p * (r + 1), allWords.length - p * r);
|
|
4440
|
-
if (prevPattern.join(" ") !== patternStr) {
|
|
4441
|
-
isRepeating = false;
|
|
4442
|
-
break;
|
|
4541
|
+
const currentLabel = `${TOOL_LABELS2[potentialTool] || potentialTool}${detail ? ` (${detail})` : ""}`;
|
|
4542
|
+
if (potentialTool !== lastToolSniffed || detail !== lastToolDetail) {
|
|
4543
|
+
lastToolSniffed = potentialTool;
|
|
4544
|
+
lastToolDetail = detail;
|
|
4545
|
+
yield { type: "status", content: `${currentLabel}...` };
|
|
4546
|
+
if (process.stdout.isTTY) {
|
|
4547
|
+
const TOOL_TITLES = {
|
|
4548
|
+
"web_search": "Searching Web",
|
|
4549
|
+
"web_scrape": "Reading Website",
|
|
4550
|
+
"view_file": "Reading File",
|
|
4551
|
+
"read_folder": "Listing Folder",
|
|
4552
|
+
"list_files": "Listing Folder",
|
|
4553
|
+
"write_file": "Writing File",
|
|
4554
|
+
"update_file": "Updating File",
|
|
4555
|
+
"write_pdf": "Creating PDF",
|
|
4556
|
+
"write_docx": "Creating Word Doc",
|
|
4557
|
+
"search_keyword": "Searching Keywords",
|
|
4558
|
+
"exec_command": "Running Command",
|
|
4559
|
+
"ask": "Asking User",
|
|
4560
|
+
"memory": "Updating Memory",
|
|
4561
|
+
"generate_image": "Generating Image"
|
|
4562
|
+
};
|
|
4563
|
+
const toolTitle = TOOL_TITLES[potentialTool] || "Working";
|
|
4564
|
+
process.stdout.write(`\x1B]0;${toolTitle}...\x07`);
|
|
4443
4565
|
}
|
|
4444
4566
|
}
|
|
4445
|
-
if (isRepeating) {
|
|
4446
|
-
stutterDetected = true;
|
|
4447
|
-
break;
|
|
4448
|
-
}
|
|
4449
4567
|
}
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
const
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4568
|
+
const contextSafeText = getContextSafeText(turnText, false);
|
|
4569
|
+
const thinkBlocks = contextSafeText.match(/<think>([\s\S]*?)(?:<\/think>|$)/gi) || [];
|
|
4570
|
+
const thinkContent = thinkBlocks.join("").trim();
|
|
4571
|
+
const sentences = thinkContent.split(/[.!?]\s+/);
|
|
4572
|
+
const uniqueSentences = new Set(sentences);
|
|
4573
|
+
const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
|
|
4574
|
+
const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
|
|
4575
|
+
let repetitionThresholdThinking = 0.4;
|
|
4576
|
+
let repetitionThresholdResponse = 0.6;
|
|
4577
|
+
const thinkingCaps = {
|
|
4578
|
+
"low": 200,
|
|
4579
|
+
"medium": 500,
|
|
4580
|
+
"high": 2e3,
|
|
4581
|
+
"max": 3500,
|
|
4582
|
+
"xhigh": 3500
|
|
4583
|
+
};
|
|
4584
|
+
const cap = thinkingCaps[thinkingLevel?.toLowerCase()] || 2500;
|
|
4585
|
+
let isOverVerboseThinking = wordCount > cap;
|
|
4586
|
+
if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
|
|
4587
|
+
const reason = repetitionRatio > repetitionThresholdThinking ? "Thinking Loop Detected" : "Thinking Budget Exceeded";
|
|
4588
|
+
yield { type: "status", content: `${reason}. Re-centering...` };
|
|
4589
|
+
isThinkingLoop = true;
|
|
4590
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4591
|
+
break;
|
|
4592
|
+
}
|
|
4593
|
+
const responseContent = signalSafeText3.trim();
|
|
4594
|
+
const respSentences = responseContent.split(/[.!?]\s+/);
|
|
4595
|
+
const uniqueRespSentences = new Set(respSentences);
|
|
4596
|
+
const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
|
|
4597
|
+
if (respRepetitionRatio > repetitionThresholdResponse) {
|
|
4598
|
+
yield { type: "status", content: `Response Loop Detected. Re-centering...` };
|
|
4599
|
+
isThinkingLoop = false;
|
|
4600
|
+
isGeneralLoop = true;
|
|
4601
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4602
|
+
break;
|
|
4603
|
+
}
|
|
4604
|
+
const allWords = contextSafeText.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
|
|
4605
|
+
let stutterDetected = false;
|
|
4606
|
+
if (allWords.length > 5) {
|
|
4607
|
+
for (let p = 1; p <= 15; p++) {
|
|
4608
|
+
const R = Math.max(3, Math.ceil(8 / p));
|
|
4609
|
+
if (allWords.length < p * R) continue;
|
|
4458
4610
|
let isRepeating = true;
|
|
4611
|
+
const pattern = allWords.slice(allWords.length - p);
|
|
4612
|
+
const patternStr = pattern.join(" ");
|
|
4459
4613
|
for (let r = 1; r < R; r++) {
|
|
4460
|
-
const prevPattern =
|
|
4461
|
-
if (prevPattern !==
|
|
4614
|
+
const prevPattern = allWords.slice(allWords.length - p * (r + 1), allWords.length - p * r);
|
|
4615
|
+
if (prevPattern.join(" ") !== patternStr) {
|
|
4462
4616
|
isRepeating = false;
|
|
4463
4617
|
break;
|
|
4464
4618
|
}
|
|
@@ -4469,400 +4623,424 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CORE
|
|
|
4469
4623
|
}
|
|
4470
4624
|
}
|
|
4471
4625
|
}
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
"PatchFile": "update_file",
|
|
4492
|
-
"WritePDF": "write_pdf",
|
|
4493
|
-
"WriteDoc": "write_docx",
|
|
4494
|
-
"Run": "exec_command",
|
|
4495
|
-
"SearchKeyword": "search_keyword",
|
|
4496
|
-
"Memory": "memory",
|
|
4497
|
-
"Chat": "chat",
|
|
4498
|
-
"chat": "chat",
|
|
4499
|
-
"GenerateImage": "generate_image",
|
|
4500
|
-
"generate_image": "generate_image"
|
|
4501
|
-
};
|
|
4502
|
-
const normToolName = NORMALIZE_MAP[toolCall.toolName] || toolCall.toolName;
|
|
4503
|
-
const displayLabel = TOOL_LABELS2[normToolName] || toolCall.toolName;
|
|
4504
|
-
const detail = getToolDetail(normToolName, toolCall.args);
|
|
4505
|
-
yield { type: "status", content: `${displayLabel}${detail ? ` (${detail})` : ""}...` };
|
|
4506
|
-
let label = "";
|
|
4507
|
-
if (normToolName === "web_search") {
|
|
4508
|
-
const { query, limit = 10 } = parseArgs(toolCall.args);
|
|
4509
|
-
label = `\u{1F50D} SEARCHED: "${query}" (${limit})`.toUpperCase();
|
|
4510
|
-
} else if (normToolName === "web_scrape") {
|
|
4511
|
-
const url = parseArgs(toolCall.args).url || "...";
|
|
4512
|
-
label = `\u{1F4D6} READ SITE: ${url}`.toUpperCase();
|
|
4513
|
-
} else if (normToolName === "view_file") {
|
|
4514
|
-
const { path: targetPath2, StartLine, EndLine, start_line, end_line } = parseArgs(toolCall.args);
|
|
4515
|
-
const rawStart = StartLine || start_line;
|
|
4516
|
-
const rawEnd = EndLine || end_line;
|
|
4517
|
-
const sLine = parseInt(rawStart) || 1;
|
|
4518
|
-
const eLine = parseInt(rawEnd) || (rawStart ? sLine + 800 : 800);
|
|
4519
|
-
let totalLines = "...";
|
|
4520
|
-
let actualEndLine = eLine;
|
|
4521
|
-
try {
|
|
4522
|
-
const absPath = path14.resolve(process.cwd(), targetPath2);
|
|
4523
|
-
if (fs15.existsSync(absPath)) {
|
|
4524
|
-
const content = fs15.readFileSync(absPath, "utf8");
|
|
4525
|
-
const lines = content.split("\n").length;
|
|
4526
|
-
totalLines = lines;
|
|
4527
|
-
actualEndLine = Math.min(eLine, lines);
|
|
4626
|
+
if (!stutterDetected) {
|
|
4627
|
+
const cleanChars = contextSafeText.toLowerCase().replace(/[^a-z0-9]/gi, "");
|
|
4628
|
+
if (cleanChars.length >= 10) {
|
|
4629
|
+
for (let p = 1; p <= 10; p++) {
|
|
4630
|
+
const R = Math.max(4, Math.ceil(12 / p));
|
|
4631
|
+
if (cleanChars.length < p * R) continue;
|
|
4632
|
+
const pattern = cleanChars.substring(cleanChars.length - p);
|
|
4633
|
+
let isRepeating = true;
|
|
4634
|
+
for (let r = 1; r < R; r++) {
|
|
4635
|
+
const prevPattern = cleanChars.substring(cleanChars.length - p * (r + 1), cleanChars.length - p * r);
|
|
4636
|
+
if (prevPattern !== pattern) {
|
|
4637
|
+
isRepeating = false;
|
|
4638
|
+
break;
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
if (isRepeating) {
|
|
4642
|
+
stutterDetected = true;
|
|
4643
|
+
break;
|
|
4644
|
+
}
|
|
4528
4645
|
}
|
|
4529
|
-
} catch (e) {
|
|
4530
4646
|
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4647
|
+
}
|
|
4648
|
+
if (stutterDetected) {
|
|
4649
|
+
yield { type: "status", content: `Stuttering Detected. Re-centering...` };
|
|
4650
|
+
isThinkingLoop = false;
|
|
4651
|
+
isStutteringLoop = true;
|
|
4652
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4653
|
+
break;
|
|
4654
|
+
}
|
|
4655
|
+
const toolActionableText = turnText.replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "");
|
|
4656
|
+
const allToolsFound = detectToolCalls(toolActionableText);
|
|
4657
|
+
while (allToolsFound.length > toolCallPointer) {
|
|
4658
|
+
const toolCall = allToolsFound[toolCallPointer];
|
|
4659
|
+
const NORMALIZE_MAP = {
|
|
4660
|
+
"Ask": "ask",
|
|
4661
|
+
"WebSearch": "web_search",
|
|
4662
|
+
"WebScrape": "web_scrape",
|
|
4663
|
+
"ReadFile": "view_file",
|
|
4664
|
+
"ReadFolder": "read_folder",
|
|
4665
|
+
"WriteFile": "write_file",
|
|
4666
|
+
"PatchFile": "update_file",
|
|
4667
|
+
"WritePDF": "write_pdf",
|
|
4668
|
+
"WriteDoc": "write_docx",
|
|
4669
|
+
"Run": "exec_command",
|
|
4670
|
+
"SearchKeyword": "search_keyword",
|
|
4671
|
+
"Memory": "memory",
|
|
4672
|
+
"Chat": "chat",
|
|
4673
|
+
"chat": "chat",
|
|
4674
|
+
"GenerateImage": "generate_image",
|
|
4675
|
+
"generate_image": "generate_image"
|
|
4676
|
+
};
|
|
4677
|
+
const normToolName = NORMALIZE_MAP[toolCall.toolName] || toolCall.toolName;
|
|
4678
|
+
const displayLabel = TOOL_LABELS2[normToolName] || toolCall.toolName;
|
|
4679
|
+
const detail = getToolDetail(normToolName, toolCall.args);
|
|
4680
|
+
yield { type: "status", content: `${displayLabel}${detail ? ` (${detail})` : ""}...` };
|
|
4681
|
+
let label = "";
|
|
4682
|
+
if (normToolName === "web_search") {
|
|
4683
|
+
const { query, limit = 10 } = parseArgs(toolCall.args);
|
|
4684
|
+
label = `\u{1F50D} SEARCHED: "${query}" (${limit})`.toUpperCase();
|
|
4685
|
+
} else if (normToolName === "web_scrape") {
|
|
4686
|
+
const url = parseArgs(toolCall.args).url || "...";
|
|
4687
|
+
label = `\u{1F4D6} READ SITE: ${url}`.toUpperCase();
|
|
4688
|
+
} else if (normToolName === "view_file") {
|
|
4689
|
+
const { path: targetPath2, StartLine, EndLine, start_line, end_line } = parseArgs(toolCall.args);
|
|
4690
|
+
const rawStart = StartLine || start_line;
|
|
4691
|
+
const rawEnd = EndLine || end_line;
|
|
4692
|
+
const sLine = parseInt(rawStart) || 1;
|
|
4693
|
+
const eLine = parseInt(rawEnd) || (rawStart ? sLine + 800 : 800);
|
|
4694
|
+
let totalLines = "...";
|
|
4695
|
+
let actualEndLine = eLine;
|
|
4696
|
+
try {
|
|
4697
|
+
const absPath = path15.resolve(process.cwd(), targetPath2);
|
|
4698
|
+
if (fs16.existsSync(absPath)) {
|
|
4699
|
+
const content = fs16.readFileSync(absPath, "utf8");
|
|
4700
|
+
const lines = content.split("\n").length;
|
|
4701
|
+
totalLines = lines;
|
|
4702
|
+
actualEndLine = Math.min(eLine, lines);
|
|
4703
|
+
}
|
|
4704
|
+
} catch (e) {
|
|
4705
|
+
}
|
|
4706
|
+
const pathLower = targetPath2.toLowerCase();
|
|
4707
|
+
const isPdf = pathLower.endsWith(".pdf");
|
|
4708
|
+
const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
|
|
4709
|
+
if (isPdf) {
|
|
4710
|
+
label = `\u{1F4C4} ANALYZED PDF: ${targetPath2}`.toUpperCase();
|
|
4711
|
+
} else if (isImage) {
|
|
4712
|
+
label = `\u{1F4F8} ANALYZED IMAGE: ${targetPath2}`.toUpperCase();
|
|
4713
|
+
} else {
|
|
4714
|
+
label = `\u{1F4C4} ANALYZED FILE: ${targetPath2} | LINES: ${sLine}-${actualEndLine} OF ${totalLines}`.toUpperCase();
|
|
4715
|
+
}
|
|
4716
|
+
} else if (normToolName === "list_files" || normToolName === "read_folder") {
|
|
4717
|
+
const action = normToolName === "list_files" ? "LIST" : "ANALYSED";
|
|
4718
|
+
label = `\u{1F4C2} ${action} FOLDER: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
|
|
4719
|
+
} else if (normToolName === "write_file" || normToolName === "update_file") {
|
|
4720
|
+
const action = normToolName === "write_file" ? "WRITTEN" : "UPDATED FILE";
|
|
4721
|
+
label = `\u{1F4BE} ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4722
|
+
} else if (normToolName === "write_pdf") {
|
|
4723
|
+
label = `\u{1F4D1} PDF CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4724
|
+
} else if (normToolName === "write_docx") {
|
|
4725
|
+
label = `\u{1F4DD} DOCX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4726
|
+
} else if (normToolName === "search_keyword") {
|
|
4727
|
+
const { keyword } = parseArgs(toolCall.args);
|
|
4728
|
+
label = `\u{1F50E} KEYWORD SEARCHED: "${keyword}"`.toUpperCase();
|
|
4729
|
+
} else if (normToolName === "generate_image") {
|
|
4730
|
+
const { path: argPath, outputPath, output } = parseArgs(toolCall.args);
|
|
4731
|
+
label = `\u{1F3A8} IMAGE GENERATED: ${argPath || outputPath || output || "generated_image.png"}`.toUpperCase();
|
|
4732
|
+
} else if (normToolName === "exec_command" || normToolName === "ask") {
|
|
4733
|
+
label = "";
|
|
4538
4734
|
} else {
|
|
4539
|
-
label =
|
|
4735
|
+
label = `EXECUTED: ${toolCall.toolName}`.toUpperCase();
|
|
4540
4736
|
}
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
} else if (normToolName === "write_pdf") {
|
|
4548
|
-
label = `\u{1F4D1} PDF CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4549
|
-
} else if (normToolName === "write_docx") {
|
|
4550
|
-
label = `\u{1F4DD} DOCX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4551
|
-
} else if (normToolName === "search_keyword") {
|
|
4552
|
-
const { keyword } = parseArgs(toolCall.args);
|
|
4553
|
-
label = `\u{1F50E} KEYWORD SEARCHED: "${keyword}"`.toUpperCase();
|
|
4554
|
-
} else if (normToolName === "generate_image") {
|
|
4555
|
-
const { path: argPath, outputPath, output } = parseArgs(toolCall.args);
|
|
4556
|
-
label = `\u{1F3A8} IMAGE GENERATED: ${argPath || outputPath || output || "generated_image.png"}`.toUpperCase();
|
|
4557
|
-
} else if (normToolName === "exec_command" || normToolName === "ask") {
|
|
4558
|
-
label = "";
|
|
4559
|
-
} else {
|
|
4560
|
-
label = `EXECUTED: ${toolCall.toolName}`.toUpperCase();
|
|
4561
|
-
}
|
|
4562
|
-
if (label) {
|
|
4563
|
-
const boxWidth = Math.min(label.length + 4, 115);
|
|
4564
|
-
const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
|
|
4565
|
-
const boxMid = `\u2502 ${label.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
|
|
4566
|
-
const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
|
|
4567
|
-
yield { type: "visual_feedback", content: `${boxTop}
|
|
4737
|
+
if (label) {
|
|
4738
|
+
const boxWidth = Math.min(label.length + 4, 115);
|
|
4739
|
+
const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
|
|
4740
|
+
const boxMid = `\u2502 ${label.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
|
|
4741
|
+
const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
|
|
4742
|
+
yield { type: "visual_feedback", content: `${boxTop}
|
|
4568
4743
|
${boxMid}
|
|
4569
4744
|
${boxBottom}` };
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4745
|
+
}
|
|
4746
|
+
if (normToolName === "exec_command") {
|
|
4747
|
+
const { command } = parseArgs(toolCall.args);
|
|
4748
|
+
if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
|
|
4749
|
+
const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
|
|
4750
|
+
const currentDrive = path15.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
4751
|
+
const isViolating = riskyPatterns.some((pattern) => {
|
|
4752
|
+
if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
|
|
4753
|
+
const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
|
|
4754
|
+
return driveMatch && driveMatch[0].toLowerCase() !== currentDrive;
|
|
4755
|
+
}
|
|
4756
|
+
return pattern.test(command);
|
|
4757
|
+
});
|
|
4758
|
+
if (isViolating) {
|
|
4759
|
+
const denyMsg = `Access Denied. Terminal is prohibited from accessing system drives (C://) or external directories while "External Workspace Access" is disabled.`;
|
|
4760
|
+
toolResults.push({ role: "user", text: `[TOOL RESULT]: ERROR: ${denyMsg}` });
|
|
4761
|
+
yield { type: "tool_result", content: `[TOOL RESULT]: ERROR: ${denyMsg}` };
|
|
4762
|
+
toolCallPointer++;
|
|
4763
|
+
continue;
|
|
4580
4764
|
}
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4765
|
+
}
|
|
4766
|
+
if (settings.onExecStart) settings.onExecStart(command || "Unknown");
|
|
4767
|
+
yield { type: "exec_start" };
|
|
4768
|
+
}
|
|
4769
|
+
const parsedArgs = parseArgs(toolCall.args);
|
|
4770
|
+
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
4771
|
+
if (targetPath) {
|
|
4772
|
+
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
4773
|
+
const absoluteTarget = path15.resolve(targetPath);
|
|
4774
|
+
const absoluteCwd = path15.resolve(process.cwd());
|
|
4775
|
+
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
4776
|
+
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.`;
|
|
4777
|
+
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**" : ""}` });
|
|
4586
4778
|
yield { type: "tool_result", content: `[TOOL RESULT]: ERROR: ${denyMsg}` };
|
|
4587
4779
|
toolCallPointer++;
|
|
4588
4780
|
continue;
|
|
4589
4781
|
}
|
|
4590
4782
|
}
|
|
4591
|
-
if (settings.
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4783
|
+
if (settings.onToolApproval) {
|
|
4784
|
+
let shouldPrompt = normToolName === "write_file" || normToolName === "update_file" || normToolName === "exec_command";
|
|
4785
|
+
if (shouldPrompt) {
|
|
4786
|
+
const approval = await settings.onToolApproval(normToolName, toolCall.args);
|
|
4787
|
+
if (approval === "deny") {
|
|
4788
|
+
if (normToolName === "exec_command" && settings.onExecEnd) settings.onExecEnd();
|
|
4789
|
+
const denyMsg = `Permission Denied: User rejected the ${normToolName === "exec_command" ? "terminal execution" : "file edit"}.`;
|
|
4790
|
+
toolResults.push({ role: "user", text: `[TOOL RESULT]: DENIED: ${denyMsg}${thinkingLevel != "Fast" ? "\n\n[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRICT PRIORITY. DO NOT START A RESPONSE WITHOUT THINKING**" : ""}` });
|
|
4791
|
+
yield { type: "tool_result", content: `[TOOL RESULT]: DENIED: ${denyMsg}` };
|
|
4792
|
+
await incrementUsage("toolDenied");
|
|
4793
|
+
if (settings.onToolResult) settings.onToolResult("denied", normToolName);
|
|
4794
|
+
toolCallPointer++;
|
|
4795
|
+
continue;
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4606
4798
|
}
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
const approval = await settings.onToolApproval(normToolName, toolCall.args);
|
|
4612
|
-
if (approval === "deny") {
|
|
4613
|
-
if (normToolName === "exec_command" && settings.onExecEnd) settings.onExecEnd();
|
|
4614
|
-
const denyMsg = `Permission Denied: User rejected the ${normToolName === "exec_command" ? "terminal execution" : "file edit"}.`;
|
|
4615
|
-
toolResults.push({ role: "user", text: `[TOOL RESULT]: DENIED: ${denyMsg}${thinkingLevel != "Fast" ? "\n\n[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRICT PRIORITY. DO NOT START A RESPONSE WITHOUT THINKING**" : ""}` });
|
|
4616
|
-
yield { type: "tool_result", content: `[TOOL RESULT]: DENIED: ${denyMsg}` };
|
|
4617
|
-
await incrementUsage("toolDenied");
|
|
4618
|
-
if (settings.onToolResult) settings.onToolResult("denied", normToolName);
|
|
4619
|
-
toolCallPointer++;
|
|
4620
|
-
continue;
|
|
4799
|
+
if (lastToolFinishedAt > 0) {
|
|
4800
|
+
const timeSinceLastTool = Date.now() - lastToolFinishedAt;
|
|
4801
|
+
if (timeSinceLastTool < 1e3) {
|
|
4802
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 - timeSinceLastTool));
|
|
4621
4803
|
}
|
|
4622
4804
|
}
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4805
|
+
const effectiveStart = lastToolEventTime || Date.now();
|
|
4806
|
+
yield { type: "spinner", content: false };
|
|
4807
|
+
let result = await dispatchTool(normToolName, toolCall.args, {
|
|
4808
|
+
chatId,
|
|
4809
|
+
history,
|
|
4810
|
+
onChunk: (chunk2) => settings.onExecChunk ? settings.onExecChunk(chunk2) : null,
|
|
4811
|
+
onAskUser: settings.onAskUser
|
|
4812
|
+
});
|
|
4813
|
+
yield { type: "spinner", content: true };
|
|
4814
|
+
if (process.stdout.isTTY) {
|
|
4815
|
+
process.stdout.write(`\x1B]0;Working...\x07`);
|
|
4628
4816
|
}
|
|
4817
|
+
const toolEnd = Date.now();
|
|
4818
|
+
lastToolFinishedAt = toolEnd;
|
|
4819
|
+
yield { type: "tool_time", content: toolEnd - effectiveStart };
|
|
4820
|
+
lastToolEventTime = toolEnd;
|
|
4821
|
+
let binaryPart = null;
|
|
4822
|
+
if (typeof result === "object" && result.binaryPart) {
|
|
4823
|
+
binaryPart = result.binaryPart;
|
|
4824
|
+
result = result.text;
|
|
4825
|
+
}
|
|
4826
|
+
if (normToolName === "exec_command" && settings.onExecEnd) {
|
|
4827
|
+
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
4828
|
+
settings.onExecEnd();
|
|
4829
|
+
}
|
|
4830
|
+
const isDenied = result && result.startsWith("DENIED:");
|
|
4831
|
+
const isSuccess = result && !result.startsWith("ERROR:") && !isDenied;
|
|
4832
|
+
if (isSuccess) {
|
|
4833
|
+
await incrementUsage("toolSuccess");
|
|
4834
|
+
if (settings.onToolResult) settings.onToolResult("success", normToolName);
|
|
4835
|
+
} else if (isDenied) {
|
|
4836
|
+
} else {
|
|
4837
|
+
await incrementUsage("toolFailure");
|
|
4838
|
+
if (settings.onToolResult) settings.onToolResult("failure", normToolName);
|
|
4839
|
+
}
|
|
4840
|
+
const aiContent = `[TOOL RESULT]: ${(result || "").toString().split(/\r?\n/).filter((line) => !line.includes("[UI_CONTEXT]")).join("\n")}`;
|
|
4841
|
+
toolResults.push({ role: "user", text: aiContent, binaryPart });
|
|
4842
|
+
anyToolExecutedInThisTurn = true;
|
|
4843
|
+
let uiContent = `[TOOL RESULT]: ${result || ""}`;
|
|
4844
|
+
if (normToolName === "view_file" || normToolName === "web_scrape") {
|
|
4845
|
+
uiContent = `[TOOL RESULT]: ${label} (Context Locked for UI Clarity)`;
|
|
4846
|
+
}
|
|
4847
|
+
yield { type: "tool_result", content: uiContent, aiContent, binaryPart, toolName: normToolName };
|
|
4848
|
+
if (normToolName === "memory" && result.includes("SUCCESS")) yield { type: "memory_updated" };
|
|
4849
|
+
toolCallPointer++;
|
|
4629
4850
|
}
|
|
4630
|
-
const effectiveStart = lastToolEventTime || Date.now();
|
|
4631
|
-
yield { type: "spinner", content: false };
|
|
4632
|
-
let result = await dispatchTool(normToolName, toolCall.args, {
|
|
4633
|
-
chatId,
|
|
4634
|
-
history,
|
|
4635
|
-
onChunk: (chunk2) => settings.onExecChunk ? settings.onExecChunk(chunk2) : null,
|
|
4636
|
-
onAskUser: settings.onAskUser
|
|
4637
|
-
});
|
|
4638
|
-
yield { type: "spinner", content: true };
|
|
4639
|
-
if (process.stdout.isTTY) {
|
|
4640
|
-
process.stdout.write(`\x1B]0;Working...\x07`);
|
|
4641
|
-
}
|
|
4642
|
-
const toolEnd = Date.now();
|
|
4643
|
-
lastToolFinishedAt = toolEnd;
|
|
4644
|
-
yield { type: "tool_time", content: toolEnd - effectiveStart };
|
|
4645
|
-
lastToolEventTime = toolEnd;
|
|
4646
|
-
let binaryPart = null;
|
|
4647
|
-
if (typeof result === "object" && result.binaryPart) {
|
|
4648
|
-
binaryPart = result.binaryPart;
|
|
4649
|
-
result = result.text;
|
|
4650
|
-
}
|
|
4651
|
-
if (normToolName === "exec_command" && settings.onExecEnd) {
|
|
4652
|
-
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
4653
|
-
settings.onExecEnd();
|
|
4654
|
-
}
|
|
4655
|
-
const isDenied = result && result.startsWith("DENIED:");
|
|
4656
|
-
const isSuccess = result && !result.startsWith("ERROR:") && !isDenied;
|
|
4657
|
-
if (isSuccess) {
|
|
4658
|
-
await incrementUsage("toolSuccess");
|
|
4659
|
-
if (settings.onToolResult) settings.onToolResult("success", normToolName);
|
|
4660
|
-
} else if (isDenied) {
|
|
4661
|
-
} else {
|
|
4662
|
-
await incrementUsage("toolFailure");
|
|
4663
|
-
if (settings.onToolResult) settings.onToolResult("failure", normToolName);
|
|
4664
|
-
}
|
|
4665
|
-
const aiContent = `[TOOL RESULT]: ${(result || "").toString().split(/\r?\n/).filter((line) => !line.includes("[UI_CONTEXT]")).join("\n")}`;
|
|
4666
|
-
toolResults.push({ role: "user", text: aiContent, binaryPart });
|
|
4667
|
-
anyToolExecutedInThisTurn = true;
|
|
4668
|
-
let uiContent = `[TOOL RESULT]: ${result || ""}`;
|
|
4669
|
-
if (normToolName === "view_file" || normToolName === "web_scrape") {
|
|
4670
|
-
uiContent = `[TOOL RESULT]: ${label} (Context Locked for UI Clarity)`;
|
|
4671
|
-
}
|
|
4672
|
-
yield { type: "tool_result", content: uiContent, aiContent, binaryPart, toolName: normToolName };
|
|
4673
|
-
if (normToolName === "memory" && result.includes("SUCCESS")) yield { type: "memory_updated" };
|
|
4674
|
-
toolCallPointer++;
|
|
4675
4851
|
}
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
yield { type: "liveTokens", content: lastUsage.totalTokenCount };
|
|
4680
|
-
}
|
|
4681
|
-
}
|
|
4682
|
-
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4683
|
-
let overlapLen = 0;
|
|
4684
|
-
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4685
|
-
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4686
|
-
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4687
|
-
overlapLen = len;
|
|
4688
|
-
break;
|
|
4852
|
+
lastUsage = chunk.usageMetadata;
|
|
4853
|
+
if (lastUsage) {
|
|
4854
|
+
yield { type: "liveTokens", content: lastUsage.totalTokenCount };
|
|
4689
4855
|
}
|
|
4690
4856
|
}
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
const
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4857
|
+
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4858
|
+
let overlapLen = 0;
|
|
4859
|
+
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4860
|
+
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4861
|
+
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4862
|
+
overlapLen = len;
|
|
4863
|
+
break;
|
|
4864
|
+
}
|
|
4698
4865
|
}
|
|
4866
|
+
const cleanText = dedupeBuffer.substring(overlapLen);
|
|
4867
|
+
if (cleanText) {
|
|
4868
|
+
const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
|
|
4869
|
+
const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*<(think|thought)>\s*/gi, "") : cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
|
|
4870
|
+
if (dedupeClean) {
|
|
4871
|
+
turnText += dedupeClean;
|
|
4872
|
+
yield { type: "text", content: dedupeClean };
|
|
4873
|
+
}
|
|
4874
|
+
}
|
|
4875
|
+
isDedupeActive = false;
|
|
4876
|
+
dedupeBuffer = "";
|
|
4877
|
+
}
|
|
4878
|
+
if (TERMINATION_SIGNAL) break;
|
|
4879
|
+
const signalSafeText2 = (turnText || "").trim();
|
|
4880
|
+
const hasFinish2 = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
4881
|
+
const hasContinue = /\[\s*(turn\s*:)?\s*continue\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
4882
|
+
const didCallTool = toolResults.length > 0 || lastToolSniffed !== null;
|
|
4883
|
+
const pureOutputText = signalSafeText2.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
|
|
4884
|
+
const endsNormally = /[.!?}"'`’“”]$|```$/s.test(pureOutputText);
|
|
4885
|
+
if (!hasFinish2 && !hasContinue && !didCallTool && signalSafeText2.length > 0 && !endsNormally && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop) {
|
|
4886
|
+
throw new Error("Silent stream cutoff (500): Model stream closed cleanly but cut off mid-sentence without signals.");
|
|
4699
4887
|
}
|
|
4700
|
-
isDedupeActive = false;
|
|
4701
|
-
dedupeBuffer = "";
|
|
4702
|
-
}
|
|
4703
|
-
if (TERMINATION_SIGNAL) break;
|
|
4704
|
-
const signalSafeText2 = (turnText || "").trim();
|
|
4705
|
-
const hasFinish2 = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
4706
|
-
const hasContinue = /\[\s*(turn\s*:)?\s*continue\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
4707
|
-
const didCallTool = toolResults.length > 0 || lastToolSniffed !== null;
|
|
4708
|
-
const pureOutputText = signalSafeText2.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
|
|
4709
|
-
const endsNormally = /[.!?}"'`’“”]$|```$/s.test(pureOutputText);
|
|
4710
|
-
if (!hasFinish2 && !hasContinue && !didCallTool && signalSafeText2.length > 0 && !endsNormally && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop) {
|
|
4711
|
-
throw new Error("Silent stream cutoff (500): Model stream closed cleanly but cut off mid-sentence without signals.");
|
|
4712
|
-
}
|
|
4713
|
-
success = true;
|
|
4714
|
-
await incrementUsage("agent");
|
|
4715
|
-
} catch (err) {
|
|
4716
|
-
if (String(err).includes("Incomplete JSON segment at the end")) {
|
|
4717
4888
|
success = true;
|
|
4718
4889
|
await incrementUsage("agent");
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4725
|
-
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4726
|
-
overlapLen = len;
|
|
4727
|
-
break;
|
|
4728
|
-
}
|
|
4890
|
+
} catch (err) {
|
|
4891
|
+
if (String(err).includes("Incomplete JSON segment at the end")) {
|
|
4892
|
+
success = true;
|
|
4893
|
+
await incrementUsage("agent");
|
|
4894
|
+
break;
|
|
4729
4895
|
}
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
const
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4896
|
+
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4897
|
+
let overlapLen = 0;
|
|
4898
|
+
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4899
|
+
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4900
|
+
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4901
|
+
overlapLen = len;
|
|
4902
|
+
break;
|
|
4903
|
+
}
|
|
4736
4904
|
}
|
|
4905
|
+
const cleanText = dedupeBuffer.substring(overlapLen);
|
|
4906
|
+
if (cleanText) {
|
|
4907
|
+
const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
|
|
4908
|
+
const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*<(think|thought)>\s*/gi, "") : cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
|
|
4909
|
+
if (dedupeClean) {
|
|
4910
|
+
turnText += dedupeClean;
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
isDedupeActive = false;
|
|
4914
|
+
dedupeBuffer = "";
|
|
4737
4915
|
}
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
const agentErrDir = path14.join(LOGS_DIR, "agent");
|
|
4745
|
-
if (!fs15.existsSync(agentErrDir)) fs15.mkdirSync(agentErrDir, { recursive: true });
|
|
4746
|
-
fs15.appendFileSync(path14.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
4916
|
+
const errMsg = err.status || err.error && err.error.message || String(err);
|
|
4917
|
+
const errLog = String(err);
|
|
4918
|
+
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
4919
|
+
const agentErrDir = path15.join(LOGS_DIR, "agent");
|
|
4920
|
+
if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
|
|
4921
|
+
fs16.appendFileSync(path15.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
4747
4922
|
|
|
4748
4923
|
----------------------------------------------------------------------
|
|
4749
4924
|
|
|
4750
4925
|
`);
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4926
|
+
const status = err.status || err.statusCode || err.code;
|
|
4927
|
+
const isRetryable = status && (status >= 500 && status < 600 || status === 408) || !status && (/status[ :]+(5\d\d|408)/i.test(String(err)) || /code[ :]+(5\d\d|408)/i.test(String(err)) || /(500|503|408)/.test(String(err)));
|
|
4928
|
+
if (!isRetryable) {
|
|
4929
|
+
if (retryCount < MAX_RETRIES - 3) {
|
|
4930
|
+
throw err;
|
|
4931
|
+
}
|
|
4756
4932
|
}
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
text: `${tr.text}
|
|
4933
|
+
if (turnText.trim().length > 0 || inStreamRetryCount > 1) {
|
|
4934
|
+
if (inStreamRetryCount <= MAX_RETRIES) {
|
|
4935
|
+
inStreamRetryCount++;
|
|
4936
|
+
const waitTime = Math.min(1e3 * Math.pow(2, inStreamRetryCount - 1), 24e3);
|
|
4937
|
+
if (turnText.trim().length > 0) {
|
|
4938
|
+
modifiedHistory.push({ role: "agent", text: turnText });
|
|
4939
|
+
const recoveryText = "[SYSTEM: STREAM RECOVERY]\n- SEAMLESS CONTINUATION: Resume immediately. Pick up from last words with zero gap/disruption.\n- NO REPETITION: Do not repeat any text already written.\n- NO RE-THINK: Do not restart or open <think> if reasoning already started.\n- MID-TOOL SAFETY: If cutoff was mid-tool call, restart that tool call from start.\n- STEALTH: Do not mention/apologize for cutoff.\n- KEEP LENGTH: Maintain standard depth/length.";
|
|
4940
|
+
if (toolResults.length > 0) {
|
|
4941
|
+
toolResults.forEach((tr, idx) => {
|
|
4942
|
+
if (idx === toolResults.length - 1) {
|
|
4943
|
+
modifiedHistory.push({
|
|
4944
|
+
...tr,
|
|
4945
|
+
text: `${tr.text}
|
|
4771
4946
|
|
|
4772
4947
|
${recoveryText}`
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4948
|
+
});
|
|
4949
|
+
} else {
|
|
4950
|
+
modifiedHistory.push(tr);
|
|
4951
|
+
}
|
|
4952
|
+
});
|
|
4953
|
+
} else {
|
|
4954
|
+
modifiedHistory.push({ role: "user", text: recoveryText });
|
|
4955
|
+
}
|
|
4956
|
+
accumulatedContext += turnText;
|
|
4780
4957
|
}
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4958
|
+
for (let i = waitTime / 1e3; i > 0; i--) {
|
|
4959
|
+
yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
|
|
4960
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
4961
|
+
}
|
|
4962
|
+
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
4963
|
+
} else {
|
|
4964
|
+
throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
|
|
4965
|
+
Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4786
4966
|
}
|
|
4787
|
-
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
4788
4967
|
} else {
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4968
|
+
if (retryCount <= MAX_RETRIES) {
|
|
4969
|
+
retryCount++;
|
|
4970
|
+
inStreamRetryCount = 1;
|
|
4971
|
+
accumulatedContext = "";
|
|
4972
|
+
const waitTime = Math.min(1e3 * Math.pow(2, retryCount - 1), 32e3);
|
|
4973
|
+
isInitialAttempt = true;
|
|
4974
|
+
yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${(waitTime / 1e3).toFixed(0)}s]...` };
|
|
4975
|
+
for (let i = waitTime / 1e3; i > 0; i--) {
|
|
4976
|
+
yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${i}s]...` };
|
|
4977
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
4978
|
+
}
|
|
4979
|
+
yield { type: "status", content: `Retrying Connection...` };
|
|
4980
|
+
} else {
|
|
4981
|
+
throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
4982
|
+
Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4803
4983
|
}
|
|
4804
|
-
yield { type: "status", content: `Retrying Connection...` };
|
|
4805
|
-
} else {
|
|
4806
|
-
throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
4807
|
-
Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4808
4984
|
}
|
|
4809
4985
|
}
|
|
4810
4986
|
}
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
}
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
const finalWithTime = `${cleanedFullResponse}
|
|
4987
|
+
if (lastUsage) {
|
|
4988
|
+
await addToUsage("tokens", lastUsage.totalTokenCount || 0);
|
|
4989
|
+
yield { type: "usage", content: lastUsage };
|
|
4990
|
+
}
|
|
4991
|
+
fullAgentResponseChunks.push(turnText);
|
|
4992
|
+
let textToProcess = turnText;
|
|
4993
|
+
const thinkMatch = turnText.match(/<think>([\s\S]*?)<\/think>/i);
|
|
4994
|
+
if (thinkMatch) {
|
|
4995
|
+
textToProcess = turnText.replace(/<think>[\s\S]*?<\/think>/i, "");
|
|
4996
|
+
}
|
|
4997
|
+
const signalSafeText = getSanitizedText(turnText);
|
|
4998
|
+
const hasFinish = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText.toLowerCase());
|
|
4999
|
+
const shouldContinue = toolCallPointer > 0;
|
|
5000
|
+
yield { type: "status", content: "Working..." };
|
|
5001
|
+
const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
|
|
5002
|
+
let isActuallyFinished = hasFinish && !shouldContinue;
|
|
5003
|
+
if (isActuallyFinished) {
|
|
5004
|
+
const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
|
|
5005
|
+
const cleanedFullResponse = fullAgentTextRaw.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
5006
|
+
yield {
|
|
5007
|
+
type: "interactive_turn_finished",
|
|
5008
|
+
data: {
|
|
5009
|
+
agentText,
|
|
5010
|
+
fullAgentTextRaw,
|
|
5011
|
+
history: [...modifiedHistory],
|
|
5012
|
+
needTitle
|
|
5013
|
+
}
|
|
5014
|
+
};
|
|
5015
|
+
const timestamp = `Responded on ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
|
|
5016
|
+
const finalWithTime = `${cleanedFullResponse}
|
|
4842
5017
|
|
|
4843
5018
|
${timestamp}`;
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5019
|
+
if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "agent") {
|
|
5020
|
+
modifiedHistory[modifiedHistory.length - 1].text = finalWithTime;
|
|
5021
|
+
} else {
|
|
5022
|
+
modifiedHistory.push({ role: "agent", text: finalWithTime });
|
|
5023
|
+
}
|
|
4848
5024
|
}
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
toolResults.forEach((tr) => modifiedHistory.push(tr));
|
|
4855
|
-
} else {
|
|
4856
|
-
if (wasToolCalledInLastLoop) {
|
|
4857
|
-
modifiedHistory.push({ role: "user", text: `[SYSTEM] System executed the tool with no explicit result, continue with your task or use [turn: finish] if completed.` });
|
|
5025
|
+
if (isActuallyFinished) break;
|
|
5026
|
+
const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
|
|
5027
|
+
modifiedHistory.push({ role: "agent", text: nextAgentMsg });
|
|
5028
|
+
if (toolResults.length > 0 || anyToolExecutedInThisTurn) {
|
|
5029
|
+
toolResults.forEach((tr) => modifiedHistory.push(tr));
|
|
4858
5030
|
} else {
|
|
4859
|
-
|
|
5031
|
+
if (wasToolCalledInLastLoop) {
|
|
5032
|
+
modifiedHistory.push({ role: "user", text: `[SYSTEM] System executed the tool with no explicit result, continue with your task or use [turn: finish] if completed.` });
|
|
5033
|
+
} else {
|
|
5034
|
+
modifiedHistory.push({ role: "user", text: `[SYSTEM] ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? " OVER-THINKING" : " LOOP"} DETECTED by Internal System${isThinkingLoop ? " for current EFFORT_LEVEL" : ""}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
|
|
5035
|
+
}
|
|
5036
|
+
isThinkingLoop = false;
|
|
5037
|
+
isStutteringLoop = false;
|
|
5038
|
+
isGeneralLoop = false;
|
|
4860
5039
|
}
|
|
4861
|
-
|
|
4862
|
-
isStutteringLoop = false;
|
|
4863
|
-
isGeneralLoop = false;
|
|
5040
|
+
wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
|
|
4864
5041
|
}
|
|
4865
|
-
|
|
5042
|
+
} finally {
|
|
5043
|
+
await RevertManager.commitTransaction();
|
|
4866
5044
|
}
|
|
4867
5045
|
yield { type: "status", content: null };
|
|
4868
5046
|
};
|
|
@@ -5113,11 +5291,92 @@ var init_UpdateProcessor = __esm({
|
|
|
5113
5291
|
}
|
|
5114
5292
|
});
|
|
5115
5293
|
|
|
5294
|
+
// src/components/RevertModal.jsx
|
|
5295
|
+
import React10, { useState as useState7 } from "react";
|
|
5296
|
+
import { Box as Box10, Text as Text10, useInput as useInput4 } from "ink";
|
|
5297
|
+
function RevertModal({ prompts, onSelect, onClose }) {
|
|
5298
|
+
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
5299
|
+
useInput4((input, key) => {
|
|
5300
|
+
if (key.escape) onClose();
|
|
5301
|
+
if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
5302
|
+
if (key.downArrow) setSelectedIndex((prev) => Math.min(prompts.length - 1, prev + 1));
|
|
5303
|
+
if (key.return && prompts[selectedIndex]) onSelect(prompts[selectedIndex].id);
|
|
5304
|
+
});
|
|
5305
|
+
const s = emojiSpace(2);
|
|
5306
|
+
const MAX_VISIBLE = 10;
|
|
5307
|
+
let startIndex = 0;
|
|
5308
|
+
if (prompts.length > MAX_VISIBLE) {
|
|
5309
|
+
const half = Math.floor(MAX_VISIBLE / 2);
|
|
5310
|
+
startIndex = selectedIndex - half;
|
|
5311
|
+
if (startIndex < 0) {
|
|
5312
|
+
startIndex = 0;
|
|
5313
|
+
} else if (startIndex + MAX_VISIBLE > prompts.length) {
|
|
5314
|
+
startIndex = prompts.length - MAX_VISIBLE;
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
const visiblePrompts = prompts.slice(startIndex, startIndex + MAX_VISIBLE);
|
|
5318
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 0, width: 95 }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan", bold: true }, "\u{1F504} CODEBASE TIME TRAVEL: SELECT UNDO POINT")), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "Select a prompt to revert the codebase back to the state ", /* @__PURE__ */ React10.createElement(Text10, { bold: true, color: "blue" }, "immediately before"), " it was executed:")), prompts.length === 0 ? /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, "No prompt checkpoints found for this session.")) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", width: "100%" }, startIndex > 0 && /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true }, "\u25B2 (+", startIndex, " more prompts above)")), visiblePrompts.map((p, index) => {
|
|
5319
|
+
const actualIndex = startIndex + index;
|
|
5320
|
+
const isSelected = actualIndex === selectedIndex;
|
|
5321
|
+
const dateStr = formatDate2(p.timestamp);
|
|
5322
|
+
const fileCount = p.changes ? p.changes.length : 0;
|
|
5323
|
+
return /* @__PURE__ */ React10.createElement(
|
|
5324
|
+
Box10,
|
|
5325
|
+
{
|
|
5326
|
+
key: p.id,
|
|
5327
|
+
paddingX: 1,
|
|
5328
|
+
backgroundColor: isSelected ? "#1a2a3a" : void 0,
|
|
5329
|
+
width: "100%"
|
|
5330
|
+
},
|
|
5331
|
+
/* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", '"', formatPromptPreview(p.prompt), '"', /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: !isSelected }, " [", dateStr, " \u2022 ", fileCount, " file(s) changed]")))
|
|
5332
|
+
);
|
|
5333
|
+
}), startIndex + MAX_VISIBLE < prompts.length && /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray", dimColor: true }, "\u25BC (+", prompts.length - (startIndex + MAX_VISIBLE), " more prompts below)"))), /* @__PURE__ */ React10.createElement(
|
|
5334
|
+
Box10,
|
|
5335
|
+
{
|
|
5336
|
+
marginTop: 1,
|
|
5337
|
+
paddingX: 1,
|
|
5338
|
+
borderStyle: "single",
|
|
5339
|
+
borderLeft: false,
|
|
5340
|
+
borderRight: false,
|
|
5341
|
+
borderBottom: false,
|
|
5342
|
+
borderColor: "cyan"
|
|
5343
|
+
},
|
|
5344
|
+
/* @__PURE__ */ React10.createElement(Text10, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 Enter select undo point \u2022 Esc close")
|
|
5345
|
+
));
|
|
5346
|
+
}
|
|
5347
|
+
function formatPromptPreview(prompt) {
|
|
5348
|
+
if (!prompt) return "";
|
|
5349
|
+
const firstLine = prompt.split("\n")[0] || "";
|
|
5350
|
+
const words = firstLine.split(/\s+/).filter(Boolean);
|
|
5351
|
+
if (words.length > 50) {
|
|
5352
|
+
return words.slice(0, 50).join(" ") + "...";
|
|
5353
|
+
}
|
|
5354
|
+
if (prompt.includes("\n")) {
|
|
5355
|
+
return firstLine + "...";
|
|
5356
|
+
}
|
|
5357
|
+
return firstLine;
|
|
5358
|
+
}
|
|
5359
|
+
function formatDate2(timestamp) {
|
|
5360
|
+
if (!timestamp) return "N/A";
|
|
5361
|
+
const d = new Date(timestamp);
|
|
5362
|
+
if (isNaN(d.getTime())) return "N/A";
|
|
5363
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
5364
|
+
const hh = pad(d.getHours());
|
|
5365
|
+
const min = pad(d.getMinutes());
|
|
5366
|
+
const sec = pad(d.getSeconds());
|
|
5367
|
+
return `${hh}:${min}:${sec}`;
|
|
5368
|
+
}
|
|
5369
|
+
var init_RevertModal = __esm({
|
|
5370
|
+
"src/components/RevertModal.jsx"() {
|
|
5371
|
+
init_terminal();
|
|
5372
|
+
}
|
|
5373
|
+
});
|
|
5374
|
+
|
|
5116
5375
|
// src/utils/setup.js
|
|
5117
5376
|
import puppeteer4 from "puppeteer";
|
|
5118
5377
|
import { exec as exec3 } from "child_process";
|
|
5119
5378
|
import { promisify } from "util";
|
|
5120
|
-
import
|
|
5379
|
+
import fs17 from "fs";
|
|
5121
5380
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
5122
5381
|
var init_setup = __esm({
|
|
5123
5382
|
"src/utils/setup.js"() {
|
|
@@ -5125,7 +5384,7 @@ var init_setup = __esm({
|
|
|
5125
5384
|
checkPuppeteerReady = () => {
|
|
5126
5385
|
try {
|
|
5127
5386
|
const exePath = puppeteer4.executablePath();
|
|
5128
|
-
const exists = exePath &&
|
|
5387
|
+
const exists = exePath && fs17.existsSync(exePath);
|
|
5129
5388
|
if (exists) return true;
|
|
5130
5389
|
} catch (e) {
|
|
5131
5390
|
return false;
|
|
@@ -5156,28 +5415,28 @@ __export(app_exports, {
|
|
|
5156
5415
|
default: () => App
|
|
5157
5416
|
});
|
|
5158
5417
|
import os4 from "os";
|
|
5159
|
-
import
|
|
5160
|
-
import { Box as
|
|
5418
|
+
import React11, { useState as useState8, useEffect as useEffect6, useRef as useRef2, useMemo } from "react";
|
|
5419
|
+
import { Box as Box11, Text as Text11, useInput as useInput5, useStdout } from "ink";
|
|
5161
5420
|
import Spinner2 from "ink-spinner";
|
|
5162
|
-
import
|
|
5163
|
-
import
|
|
5421
|
+
import fs18 from "fs-extra";
|
|
5422
|
+
import path16 from "path";
|
|
5164
5423
|
import { exec as exec4 } from "child_process";
|
|
5165
5424
|
import { fileURLToPath } from "url";
|
|
5166
5425
|
import { MultilineInput } from "ink-multiline-input";
|
|
5167
5426
|
import TextInput3 from "ink-text-input";
|
|
5168
5427
|
import gradient from "gradient-string";
|
|
5169
5428
|
function App({ args = [] }) {
|
|
5170
|
-
const [confirmExit, setConfirmExit] =
|
|
5171
|
-
const [exitCountdown, setExitCountdown] =
|
|
5429
|
+
const [confirmExit, setConfirmExit] = useState8(false);
|
|
5430
|
+
const [exitCountdown, setExitCountdown] = useState8(10);
|
|
5172
5431
|
const { stdout } = useStdout();
|
|
5173
|
-
const [input, setInput] =
|
|
5174
|
-
const [isExpanded, setIsExpanded] =
|
|
5175
|
-
const [mode, setMode] =
|
|
5176
|
-
const [terminalSize, setTerminalSize] =
|
|
5432
|
+
const [input, setInput] = useState8("");
|
|
5433
|
+
const [isExpanded, setIsExpanded] = useState8(false);
|
|
5434
|
+
const [mode, setMode] = useState8("Flux");
|
|
5435
|
+
const [terminalSize, setTerminalSize] = useState8({
|
|
5177
5436
|
columns: stdout?.columns || 80,
|
|
5178
5437
|
rows: stdout?.rows || 24
|
|
5179
5438
|
});
|
|
5180
|
-
const [selectedIndex, setSelectedIndex] =
|
|
5439
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
5181
5440
|
const persistedModelRef = useRef2(null);
|
|
5182
5441
|
const parsedArgs = useMemo(() => {
|
|
5183
5442
|
const parsed = {};
|
|
@@ -5281,37 +5540,37 @@ function App({ args = [] }) {
|
|
|
5281
5540
|
stdout.off("resize", handleResize);
|
|
5282
5541
|
};
|
|
5283
5542
|
}, [stdout]);
|
|
5284
|
-
const [thinkingLevel, setThinkingLevel] =
|
|
5285
|
-
const [latestVer, setLatestVer] =
|
|
5286
|
-
const [showFullThinking, setShowFullThinking] =
|
|
5287
|
-
const [activeModel, setActiveModel] =
|
|
5288
|
-
const [janitorModel, setJanitorModel] =
|
|
5289
|
-
const [isInitializing, setIsInitializing] =
|
|
5290
|
-
const [apiKey, setApiKey] =
|
|
5291
|
-
const [tempKey, setTempKey] =
|
|
5292
|
-
const [activeView, setActiveView] =
|
|
5293
|
-
const [apiTier, setApiTier] =
|
|
5294
|
-
const [quotas, setQuotas] =
|
|
5295
|
-
const [inputConfig, setInputConfig] =
|
|
5296
|
-
const [systemSettings, setSystemSettings] =
|
|
5297
|
-
const [profileData, setProfileData] =
|
|
5298
|
-
const [imageSettings, setImageSettings] =
|
|
5299
|
-
const [sessionStats, setSessionStats] =
|
|
5300
|
-
const [sessionAgentCalls, setSessionAgentCalls] =
|
|
5301
|
-
const [sessionBackgroundCalls, setSessionBackgroundCalls] =
|
|
5302
|
-
const [sessionTotalTokens, setSessionTotalTokens] =
|
|
5303
|
-
const [sessionToolSuccess, setSessionToolSuccess] =
|
|
5304
|
-
const [sessionToolFailure, setSessionToolFailure] =
|
|
5305
|
-
const [sessionToolDenied, setSessionToolDenied] =
|
|
5306
|
-
const [sessionApiTime, setSessionApiTime] =
|
|
5307
|
-
const [sessionToolTime, setSessionToolTime] =
|
|
5308
|
-
const [sessionImageCount, setSessionImageCount] =
|
|
5309
|
-
const [sessionImageCredits, setSessionImageCredits] =
|
|
5310
|
-
const [dailyUsage, setDailyUsage] =
|
|
5311
|
-
const [chatId, setChatId] =
|
|
5312
|
-
const [activeCommand, setActiveCommand] =
|
|
5313
|
-
const [execOutput, setExecOutput] =
|
|
5314
|
-
const [isTerminalFocused, setIsTerminalFocused] =
|
|
5543
|
+
const [thinkingLevel, setThinkingLevel] = useState8("Medium");
|
|
5544
|
+
const [latestVer, setLatestVer] = useState8(null);
|
|
5545
|
+
const [showFullThinking, setShowFullThinking] = useState8(false);
|
|
5546
|
+
const [activeModel, setActiveModel] = useState8("gemma-4-31b-it");
|
|
5547
|
+
const [janitorModel, setJanitorModel] = useState8("gemma-4-26b-a4b-it");
|
|
5548
|
+
const [isInitializing, setIsInitializing] = useState8(true);
|
|
5549
|
+
const [apiKey, setApiKey] = useState8(null);
|
|
5550
|
+
const [tempKey, setTempKey] = useState8("");
|
|
5551
|
+
const [activeView, setActiveView] = useState8("chat");
|
|
5552
|
+
const [apiTier, setApiTier] = useState8("Free");
|
|
5553
|
+
const [quotas, setQuotas] = useState8({ agentLimit: 1500, backgroundLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
|
|
5554
|
+
const [inputConfig, setInputConfig] = useState8(null);
|
|
5555
|
+
const [systemSettings, setSystemSettings] = useState8({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
|
|
5556
|
+
const [profileData, setProfileData] = useState8({ name: null, nickname: null, instructions: null });
|
|
5557
|
+
const [imageSettings, setImageSettings] = useState8({ keyType: "Default", quality: "Low-High", apiKey: "" });
|
|
5558
|
+
const [sessionStats, setSessionStats] = useState8({ tokens: 0 });
|
|
5559
|
+
const [sessionAgentCalls, setSessionAgentCalls] = useState8(0);
|
|
5560
|
+
const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState8(0);
|
|
5561
|
+
const [sessionTotalTokens, setSessionTotalTokens] = useState8(0);
|
|
5562
|
+
const [sessionToolSuccess, setSessionToolSuccess] = useState8(0);
|
|
5563
|
+
const [sessionToolFailure, setSessionToolFailure] = useState8(0);
|
|
5564
|
+
const [sessionToolDenied, setSessionToolDenied] = useState8(0);
|
|
5565
|
+
const [sessionApiTime, setSessionApiTime] = useState8(0);
|
|
5566
|
+
const [sessionToolTime, setSessionToolTime] = useState8(0);
|
|
5567
|
+
const [sessionImageCount, setSessionImageCount] = useState8(0);
|
|
5568
|
+
const [sessionImageCredits, setSessionImageCredits] = useState8(0);
|
|
5569
|
+
const [dailyUsage, setDailyUsage] = useState8(null);
|
|
5570
|
+
const [chatId, setChatId] = useState8(generateChatId());
|
|
5571
|
+
const [activeCommand, setActiveCommand] = useState8(null);
|
|
5572
|
+
const [execOutput, setExecOutput] = useState8("");
|
|
5573
|
+
const [isTerminalFocused, setIsTerminalFocused] = useState8(false);
|
|
5315
5574
|
useEffect6(() => {
|
|
5316
5575
|
if (apiTier !== "Free" && activeModel === "gemma-4-31b-it") {
|
|
5317
5576
|
setActiveModel("gemini-3-flash-preview");
|
|
@@ -5341,9 +5600,9 @@ function App({ args = [] }) {
|
|
|
5341
5600
|
useEffect6(() => {
|
|
5342
5601
|
execOutputRef.current = execOutput;
|
|
5343
5602
|
}, [execOutput]);
|
|
5344
|
-
const [autoAcceptWrites, setAutoAcceptWrites] =
|
|
5345
|
-
const [pendingApproval, setPendingApproval] =
|
|
5346
|
-
const [pendingAsk, setPendingAsk] =
|
|
5603
|
+
const [autoAcceptWrites, setAutoAcceptWrites] = useState8(false);
|
|
5604
|
+
const [pendingApproval, setPendingApproval] = useState8(null);
|
|
5605
|
+
const [pendingAsk, setPendingAsk] = useState8(null);
|
|
5347
5606
|
const formatDuration = (totalSecs) => {
|
|
5348
5607
|
const h = Math.floor(totalSecs / 3600);
|
|
5349
5608
|
const m = Math.floor(totalSecs % 3600 / 60);
|
|
@@ -5358,15 +5617,18 @@ function App({ args = [] }) {
|
|
|
5358
5617
|
if (ms < 1e3) return `${ms}ms`;
|
|
5359
5618
|
return formatDuration(Math.floor(ms / 1e3));
|
|
5360
5619
|
};
|
|
5361
|
-
const [statusText, setStatusText] =
|
|
5362
|
-
const [isSpinnerActive, setIsSpinnerActive] =
|
|
5363
|
-
const [isProcessing, setIsProcessing] =
|
|
5364
|
-
const [escPressed, setEscPressed] =
|
|
5365
|
-
const [escTimer, setEscTimer] =
|
|
5366
|
-
const [
|
|
5367
|
-
const [
|
|
5368
|
-
const
|
|
5369
|
-
const [
|
|
5620
|
+
const [statusText, setStatusText] = useState8(null);
|
|
5621
|
+
const [isSpinnerActive, setIsSpinnerActive] = useState8(true);
|
|
5622
|
+
const [isProcessing, setIsProcessing] = useState8(false);
|
|
5623
|
+
const [escPressed, setEscPressed] = useState8(false);
|
|
5624
|
+
const [escTimer, setEscTimer] = useState8(null);
|
|
5625
|
+
const [escPressCount, setEscPressCount] = useState8(0);
|
|
5626
|
+
const [recentPrompts, setRecentPrompts] = useState8([]);
|
|
5627
|
+
const escDoubleTimerRef = useRef2(null);
|
|
5628
|
+
const [queuedPrompt, setQueuedPrompt] = useState8(null);
|
|
5629
|
+
const [resolutionData, setResolutionData] = useState8(null);
|
|
5630
|
+
const [tempModelOverride, setTempModelOverride] = useState8(null);
|
|
5631
|
+
const [messages, setMessages] = useState8(() => {
|
|
5370
5632
|
const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
|
|
5371
5633
|
const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
|
|
5372
5634
|
const isHomeDir = process.cwd() === os4.homedir();
|
|
@@ -5405,7 +5667,7 @@ function App({ args = [] }) {
|
|
|
5405
5667
|
return msgs;
|
|
5406
5668
|
});
|
|
5407
5669
|
const queuedPromptRef = useRef2(null);
|
|
5408
|
-
const [completedIndex, setCompletedIndex] =
|
|
5670
|
+
const [completedIndex, setCompletedIndex] = useState8(messages.length);
|
|
5409
5671
|
const windowedHistory = useMemo(() => {
|
|
5410
5672
|
const MAX_HISTORY_LINES = 2e3;
|
|
5411
5673
|
const width = terminalSize.columns || 80;
|
|
@@ -5440,7 +5702,7 @@ function App({ args = [] }) {
|
|
|
5440
5702
|
return acc + Math.max(1, Math.ceil(line.length / wrapWidth));
|
|
5441
5703
|
}, 0);
|
|
5442
5704
|
const maxLines = Math.max(1, wrappedLinesCount);
|
|
5443
|
-
|
|
5705
|
+
useInput5((inputText, key) => {
|
|
5444
5706
|
if (key.tab && activeCommand) {
|
|
5445
5707
|
setIsTerminalFocused((prev) => !prev);
|
|
5446
5708
|
return;
|
|
@@ -5485,8 +5747,36 @@ function App({ args = [] }) {
|
|
|
5485
5747
|
setEscPressed(false);
|
|
5486
5748
|
if (escTimer) clearTimeout(escTimer);
|
|
5487
5749
|
}
|
|
5488
|
-
} else
|
|
5489
|
-
|
|
5750
|
+
} else {
|
|
5751
|
+
if (activeView === "revert") {
|
|
5752
|
+
setActiveView("chat");
|
|
5753
|
+
setEscPressCount(0);
|
|
5754
|
+
} else if (activeView !== "chat") {
|
|
5755
|
+
setActiveView("chat");
|
|
5756
|
+
} else {
|
|
5757
|
+
setEscPressCount((prev) => {
|
|
5758
|
+
const nextCount = prev + 1;
|
|
5759
|
+
if (nextCount === 1) {
|
|
5760
|
+
if (escDoubleTimerRef.current) clearTimeout(escDoubleTimerRef.current);
|
|
5761
|
+
escDoubleTimerRef.current = setTimeout(() => setEscPressCount(0), 1e3);
|
|
5762
|
+
} else if (nextCount === 2) {
|
|
5763
|
+
if (escDoubleTimerRef.current) clearTimeout(escDoubleTimerRef.current);
|
|
5764
|
+
setEscPressCount(0);
|
|
5765
|
+
RevertManager.getChatHistory(chatId).then((prompts) => {
|
|
5766
|
+
if (prompts.length > 0) {
|
|
5767
|
+
setRecentPrompts(prompts.reverse());
|
|
5768
|
+
setActiveView("revert");
|
|
5769
|
+
} else {
|
|
5770
|
+
setMessages((prev2) => {
|
|
5771
|
+
setCompletedIndex(prev2.length + 1);
|
|
5772
|
+
return [...prev2, { id: "revert-empty-" + Date.now(), role: "system", text: "\u2139\uFE0F No revert checkpoints found for this session.", isMeta: true }];
|
|
5773
|
+
});
|
|
5774
|
+
}
|
|
5775
|
+
});
|
|
5776
|
+
}
|
|
5777
|
+
return nextCount;
|
|
5778
|
+
});
|
|
5779
|
+
}
|
|
5490
5780
|
}
|
|
5491
5781
|
}
|
|
5492
5782
|
if (suggestions.length > 0 && activeView === "chat") {
|
|
@@ -5707,6 +5997,7 @@ function App({ args = [] }) {
|
|
|
5707
5997
|
{ cmd: "/help", desc: "Show all available commands" },
|
|
5708
5998
|
{ cmd: "/clear", desc: "Clear terminal screen" },
|
|
5709
5999
|
{ cmd: "/resume", desc: "Load previous session" },
|
|
6000
|
+
{ cmd: "/revert", desc: "Revert codebase back to a checkpoint" },
|
|
5710
6001
|
{ cmd: "/save", desc: "Force save current chat" },
|
|
5711
6002
|
{ cmd: "/export", desc: "Export current chat in a .txt file" },
|
|
5712
6003
|
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
@@ -5889,6 +6180,21 @@ ${hintText}`, color: "magenta" }];
|
|
|
5889
6180
|
setIsExpanded(false);
|
|
5890
6181
|
break;
|
|
5891
6182
|
}
|
|
6183
|
+
case "/revert": {
|
|
6184
|
+
RevertManager.getChatHistory(chatId).then((prompts) => {
|
|
6185
|
+
if (prompts.length > 0) {
|
|
6186
|
+
setRecentPrompts(prompts.reverse());
|
|
6187
|
+
setActiveView("revert");
|
|
6188
|
+
} else {
|
|
6189
|
+
const s2 = emojiSpace(2);
|
|
6190
|
+
setMessages((prev) => {
|
|
6191
|
+
setCompletedIndex(prev.length + 1);
|
|
6192
|
+
return [...prev, { id: "revert-empty-" + Date.now(), role: "system", text: `No revert checkpoints found for this session.`, isMeta: true }];
|
|
6193
|
+
});
|
|
6194
|
+
}
|
|
6195
|
+
});
|
|
6196
|
+
break;
|
|
6197
|
+
}
|
|
5892
6198
|
case "/mode": {
|
|
5893
6199
|
if (parts[1]) {
|
|
5894
6200
|
const newMode = parts[1].toLowerCase() === "flow" ? "Flow" : "Flux";
|
|
@@ -6124,7 +6430,7 @@ ${hintText}`, color: "magenta" }];
|
|
|
6124
6430
|
}
|
|
6125
6431
|
case "/export": {
|
|
6126
6432
|
const exportFile = `export-fluxflow-${chatId}.txt`;
|
|
6127
|
-
const exportPath =
|
|
6433
|
+
const exportPath = path16.join(process.cwd(), exportFile);
|
|
6128
6434
|
const exportLines = [];
|
|
6129
6435
|
let insideAgentBlock = false;
|
|
6130
6436
|
for (let i = 0; i < messages.length; i++) {
|
|
@@ -6175,7 +6481,7 @@ ${hintText}`, color: "magenta" }];
|
|
|
6175
6481
|
}
|
|
6176
6482
|
}
|
|
6177
6483
|
const fileContent = exportLines.join("\n");
|
|
6178
|
-
|
|
6484
|
+
fs18.writeFileSync(exportPath, fileContent, "utf8");
|
|
6179
6485
|
setMessages((prev) => {
|
|
6180
6486
|
setCompletedIndex(prev.length + 1);
|
|
6181
6487
|
return [...prev, {
|
|
@@ -6211,12 +6517,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
6211
6517
|
setCompletedIndex(prev.length + 1);
|
|
6212
6518
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
6213
6519
|
});
|
|
6214
|
-
if (
|
|
6215
|
-
if (
|
|
6216
|
-
if (
|
|
6520
|
+
if (fs18.existsSync(LOGS_DIR)) fs18.removeSync(LOGS_DIR);
|
|
6521
|
+
if (fs18.existsSync(SECRET_DIR)) fs18.removeSync(SECRET_DIR);
|
|
6522
|
+
if (fs18.existsSync(SETTINGS_FILE)) fs18.removeSync(SETTINGS_FILE);
|
|
6217
6523
|
try {
|
|
6218
|
-
const items =
|
|
6219
|
-
if (items.length === 0)
|
|
6524
|
+
const items = fs18.readdirSync(FLUXFLOW_DIR);
|
|
6525
|
+
if (items.length === 0) fs18.removeSync(FLUXFLOW_DIR);
|
|
6220
6526
|
} catch (e) {
|
|
6221
6527
|
}
|
|
6222
6528
|
setTimeout(() => {
|
|
@@ -6273,14 +6579,14 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
6273
6579
|
# SKILLS & WORKFLOWS
|
|
6274
6580
|
- [Define custom step-by-step recipes for this project here]
|
|
6275
6581
|
`;
|
|
6276
|
-
const filePath =
|
|
6277
|
-
if (
|
|
6582
|
+
const filePath = path16.join(process.cwd(), "FluxFlow.md");
|
|
6583
|
+
if (fs18.pathExistsSync(filePath)) {
|
|
6278
6584
|
setMessages((prev) => {
|
|
6279
6585
|
setCompletedIndex(prev.length + 1);
|
|
6280
6586
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
6281
6587
|
});
|
|
6282
6588
|
} else {
|
|
6283
|
-
|
|
6589
|
+
fs18.writeFileSync(filePath, template);
|
|
6284
6590
|
setMessages((prev) => {
|
|
6285
6591
|
setCompletedIndex(prev.length + 1);
|
|
6286
6592
|
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 }];
|
|
@@ -6709,7 +7015,7 @@ Selection: ${val}`,
|
|
|
6709
7015
|
const renderActiveView = () => {
|
|
6710
7016
|
switch (activeView) {
|
|
6711
7017
|
case "settings":
|
|
6712
|
-
return /* @__PURE__ */
|
|
7018
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6713
7019
|
CommandMenu,
|
|
6714
7020
|
{
|
|
6715
7021
|
title: "System Settings",
|
|
@@ -6777,7 +7083,7 @@ Selection: ${val}`,
|
|
|
6777
7083
|
}
|
|
6778
7084
|
);
|
|
6779
7085
|
case "apiTier":
|
|
6780
|
-
return /* @__PURE__ */
|
|
7086
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6781
7087
|
CommandMenu,
|
|
6782
7088
|
{
|
|
6783
7089
|
title: `API Tier: ${apiTier}`,
|
|
@@ -6810,7 +7116,7 @@ Selection: ${val}`,
|
|
|
6810
7116
|
}
|
|
6811
7117
|
);
|
|
6812
7118
|
case "input":
|
|
6813
|
-
return /* @__PURE__ */
|
|
7119
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "magenta", bold: true }, "\u{1F527} DATA CONFIGURATION")), inputConfig?.note && /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "yellow", dimColor: true, italic: true }, inputConfig.note)), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", bold: true }, inputConfig?.label, " "), /* @__PURE__ */ React11.createElement(
|
|
6814
7120
|
TextInput3,
|
|
6815
7121
|
{
|
|
6816
7122
|
value: inputConfig?.value || "",
|
|
@@ -6863,11 +7169,11 @@ Selection: ${val}`,
|
|
|
6863
7169
|
}
|
|
6864
7170
|
}
|
|
6865
7171
|
}
|
|
6866
|
-
)), /* @__PURE__ */
|
|
7172
|
+
)), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, "(Press Enter to confirm selection)")));
|
|
6867
7173
|
case "stats":
|
|
6868
|
-
return /* @__PURE__ */
|
|
7174
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, width: Math.min(100, (stdout?.columns || 100) - 2) }, /* @__PURE__ */ React11.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "white", bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Session Duration:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, sessionAgentCalls)), /* @__PURE__ */ React11.createElement(Box11, { marginLeft: 2 }, /* @__PURE__ */ React11.createElement(Box11, { width: 23 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React11.createElement(Box11, { marginLeft: 2 }, /* @__PURE__ */ React11.createElement(Box11, { width: 23 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, sessionBackgroundCalls)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, sessionImageCount || 0)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits")), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Tool Calls (Sess):")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( "), /* @__PURE__ */ React11.createElement(Text11, { color: "green" }, "\u2713 ", sessionToolSuccess), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " "), /* @__PURE__ */ React11.createElement(Text11, { color: "yellow" }, "\u2298 ", sessionToolDenied), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " "), /* @__PURE__ */ React11.createElement(Text11, { color: "red" }, "\u2715 ", sessionToolFailure), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " )"))), /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "white", bold: true, underline: true }, "DAILY USAGE TRACKER"), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Wall Time Today:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatDuration(dailyUsage?.duration || 0))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, dailyUsage?.agent || 0)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, dailyUsage?.background || 0)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Tokens Used Today:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatTokens(dailyUsage?.tokens || 0))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Images Made Today:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, dailyUsage?.imageCalls?.length || 0)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Image Credits Today:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, Number(((dailyUsage?.imageCalls?.reduce((sum, c) => sum + c.cost, 0) || 0) * 1e3).toFixed(0)), " credits")), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 25 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Tool Calls Today:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, (dailyUsage?.toolSuccess || 0) + (dailyUsage?.toolFailure || 0) + (dailyUsage?.toolDenied || 0), " ( "), /* @__PURE__ */ React11.createElement(Text11, { color: "green" }, "\u2713 ", dailyUsage?.toolSuccess || 0), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " "), /* @__PURE__ */ React11.createElement(Text11, { color: "yellow" }, "\u2298 ", dailyUsage?.toolDenied || 0), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " "), /* @__PURE__ */ React11.createElement(Text11, { color: "red" }, "\u2715 ", dailyUsage?.toolFailure || 0), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " )"))), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true, marginTop: 1, italic: true }, "(Press ESC to return to chat)"));
|
|
6869
7175
|
case "autoExecDanger":
|
|
6870
|
-
return /* @__PURE__ */
|
|
7176
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { color: "yellow", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: AUTO-EXEC MODE"), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1 }, "Turning this ON allows the agent to execute terminal commands automatically without requiring your approval for each step."), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React11.createElement(Text11, null, "\u2022 The agent may execute destructive commands (rm -rf, etc.) by mistake."), /* @__PURE__ */ React11.createElement(Text11, null, "\u2022 Unintended system changes if the agent hallucinates a path or command."), /* @__PURE__ */ React11.createElement(Text11, null, "\u2022 Reduced control over the agent's step-by-step decision making."), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
6871
7177
|
CommandMenu,
|
|
6872
7178
|
{
|
|
6873
7179
|
title: "Confirm Intent",
|
|
@@ -6884,7 +7190,7 @@ Selection: ${val}`,
|
|
|
6884
7190
|
}
|
|
6885
7191
|
)));
|
|
6886
7192
|
case "externalDanger":
|
|
6887
|
-
return /* @__PURE__ */
|
|
7193
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: EXTERNAL WORKSPACE ACCESS"), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1 }, "Turning this ON allows the agent to execute tools (Read/Write/Exec) outside of the current active workspace directory."), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React11.createElement(Text11, null, "\u2022 Access to sensitive system files (SSH keys, Browser data, etc.)"), /* @__PURE__ */ React11.createElement(Text11, null, "\u2022 Potential for accidental or malicious deletion of OS-critical files."), /* @__PURE__ */ React11.createElement(Text11, null, "\u2022 Unauthorized script execution across your entire file system."), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
6888
7194
|
CommandMenu,
|
|
6889
7195
|
{
|
|
6890
7196
|
title: "Confirm Intent",
|
|
@@ -6901,7 +7207,7 @@ Selection: ${val}`,
|
|
|
6901
7207
|
}
|
|
6902
7208
|
)));
|
|
6903
7209
|
case "doubleDanger":
|
|
6904
|
-
return /* @__PURE__ */
|
|
7210
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true, underline: true }, "\u26D4 CRITICAL SECURITY WARNING: COMBINED SYSTEM RISK"), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1 }, "You are attempting to enable BOTH [Auto-Exec] and [External Workspace Access] simultaneously."), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, color: "red", bold: true }, "THIS IS NOT RECOMMENDED."), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, color: "yellow" }, "THE CRITICAL RISK:"), /* @__PURE__ */ React11.createElement(Text11, null, "The agent will have the power to execute any command across your entire system WITHOUT your approval or supervision."), /* @__PURE__ */ React11.createElement(Text11, { color: "red", italic: true, marginTop: 1 }, "A single hallucination or error could result in full system wipe or data theft."), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
6905
7211
|
CommandMenu,
|
|
6906
7212
|
{
|
|
6907
7213
|
title: "Final Confirmation",
|
|
@@ -6918,7 +7224,7 @@ Selection: ${val}`,
|
|
|
6918
7224
|
}
|
|
6919
7225
|
)));
|
|
6920
7226
|
case "key":
|
|
6921
|
-
return /* @__PURE__ */
|
|
7227
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6922
7228
|
CommandMenu,
|
|
6923
7229
|
{
|
|
6924
7230
|
title: "\u{1F511} API KEY MANAGEMENT",
|
|
@@ -6942,10 +7248,10 @@ Selection: ${val}`,
|
|
|
6942
7248
|
}
|
|
6943
7249
|
);
|
|
6944
7250
|
case "deleteKey":
|
|
6945
|
-
return /* @__PURE__ */
|
|
7251
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1 }, (() => {
|
|
6946
7252
|
const s = emojiSpace(2);
|
|
6947
|
-
return /* @__PURE__ */
|
|
6948
|
-
})(), /* @__PURE__ */
|
|
7253
|
+
return /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true }, "\u26D4", s, "DANGER: PURGE API KEY");
|
|
7254
|
+
})(), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1 }, "This will permanently delete the saved API key from the project vault. You will need to enter it again to use Flux."), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
6949
7255
|
CommandMenu,
|
|
6950
7256
|
{
|
|
6951
7257
|
title: "Are you absolutely sure?",
|
|
@@ -6969,7 +7275,7 @@ Selection: ${val}`,
|
|
|
6969
7275
|
case "exit":
|
|
6970
7276
|
return null;
|
|
6971
7277
|
case "ask":
|
|
6972
|
-
return /* @__PURE__ */
|
|
7278
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%" }, /* @__PURE__ */ React11.createElement(
|
|
6973
7279
|
AskUserModal_default,
|
|
6974
7280
|
{
|
|
6975
7281
|
question: pendingAsk?.question,
|
|
@@ -6983,8 +7289,62 @@ Selection: ${val}`,
|
|
|
6983
7289
|
}
|
|
6984
7290
|
}
|
|
6985
7291
|
));
|
|
7292
|
+
case "revert":
|
|
7293
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(
|
|
7294
|
+
RevertModal,
|
|
7295
|
+
{
|
|
7296
|
+
prompts: recentPrompts,
|
|
7297
|
+
onSelect: async (txId) => {
|
|
7298
|
+
try {
|
|
7299
|
+
const result = await RevertManager.rollbackToBefore(txId);
|
|
7300
|
+
if (result.success) {
|
|
7301
|
+
const { targetPrompt } = result;
|
|
7302
|
+
const targetIdx = messages.findIndex(
|
|
7303
|
+
(m) => m.role === "user" && m.text && (m.text.startsWith(targetPrompt) || m.text.includes(targetPrompt))
|
|
7304
|
+
);
|
|
7305
|
+
let newMsgs = [...messages];
|
|
7306
|
+
if (targetIdx !== -1) {
|
|
7307
|
+
newMsgs = messages.slice(0, targetIdx);
|
|
7308
|
+
}
|
|
7309
|
+
setMessages(newMsgs);
|
|
7310
|
+
setCompletedIndex(newMsgs.length);
|
|
7311
|
+
setInput(targetPrompt);
|
|
7312
|
+
setIsExpanded(targetPrompt.split("\n").length > 2);
|
|
7313
|
+
const historyToSave = newMsgs.filter((m) => !String(m.id).startsWith("welcome") && !m.isMeta);
|
|
7314
|
+
await saveChat(chatId, null, historyToSave);
|
|
7315
|
+
const s = emojiSpace(2);
|
|
7316
|
+
setMessages((prev) => {
|
|
7317
|
+
const finalMsgs = [...prev, {
|
|
7318
|
+
id: "revert-ok-" + Date.now(),
|
|
7319
|
+
role: "system",
|
|
7320
|
+
text: `\u{1F504}${s}[TIME TRAVEL] Codebase rolled back successfully! Reverted prompt loaded to input box.`,
|
|
7321
|
+
isMeta: true
|
|
7322
|
+
}];
|
|
7323
|
+
setCompletedIndex(finalMsgs.length);
|
|
7324
|
+
return finalMsgs;
|
|
7325
|
+
});
|
|
7326
|
+
setActiveView("chat");
|
|
7327
|
+
}
|
|
7328
|
+
} catch (err) {
|
|
7329
|
+
const s = emojiSpace(2);
|
|
7330
|
+
setMessages((prev) => {
|
|
7331
|
+
const finalMsgs = [...prev, {
|
|
7332
|
+
id: "revert-err-" + Date.now(),
|
|
7333
|
+
role: "system",
|
|
7334
|
+
text: `\u274C${s}[TIME TRAVEL ERROR] Failed to rollback: ${err.message}`,
|
|
7335
|
+
isMeta: true
|
|
7336
|
+
}];
|
|
7337
|
+
setCompletedIndex(finalMsgs.length);
|
|
7338
|
+
return finalMsgs;
|
|
7339
|
+
});
|
|
7340
|
+
setActiveView("chat");
|
|
7341
|
+
}
|
|
7342
|
+
},
|
|
7343
|
+
onClose: () => setActiveView("chat")
|
|
7344
|
+
}
|
|
7345
|
+
));
|
|
6986
7346
|
case "resume":
|
|
6987
|
-
return /* @__PURE__ */
|
|
7347
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(
|
|
6988
7348
|
ResumeModal,
|
|
6989
7349
|
{
|
|
6990
7350
|
onSelect: async (id) => {
|
|
@@ -7014,9 +7374,9 @@ Selection: ${val}`,
|
|
|
7014
7374
|
}
|
|
7015
7375
|
));
|
|
7016
7376
|
case "memory":
|
|
7017
|
-
return /* @__PURE__ */
|
|
7377
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(MemoryModal, { onClose: () => setActiveView("chat") }));
|
|
7018
7378
|
case "profile":
|
|
7019
|
-
return /* @__PURE__ */
|
|
7379
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7020
7380
|
ProfileForm,
|
|
7021
7381
|
{
|
|
7022
7382
|
initialData: profileData,
|
|
@@ -7029,7 +7389,7 @@ Selection: ${val}`,
|
|
|
7029
7389
|
}
|
|
7030
7390
|
);
|
|
7031
7391
|
case "resolution":
|
|
7032
|
-
return /* @__PURE__ */
|
|
7392
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(
|
|
7033
7393
|
ResolutionModal,
|
|
7034
7394
|
{
|
|
7035
7395
|
data: resolutionData,
|
|
@@ -7048,15 +7408,15 @@ Selection: ${val}`,
|
|
|
7048
7408
|
}
|
|
7049
7409
|
));
|
|
7050
7410
|
case "approval":
|
|
7051
|
-
return /* @__PURE__ */
|
|
7411
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { color: "yellow", bold: true, underline: true }, "\u{1F510} SECURITY GATE: FILE WRITE PERMISSION"), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1 }, "The agent is attempting to modify: ", /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, parseArgs(pendingApproval?.args || "{}").path || "Unknown File")), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1, borderStyle: "single", borderColor: "#333", paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray" }, "--- PROPOSED CONTENT / DIFF ---"), (() => {
|
|
7052
7412
|
const args2 = parseArgs(pendingApproval?.args || "{}");
|
|
7053
7413
|
const oldVal = args2.TargetContent || args2.content_to_replace || null;
|
|
7054
7414
|
const newVal = args2.content || args2.ReplacementContent || args2.content_to_add || args2.replacementContent || null;
|
|
7055
7415
|
if (oldVal && newVal) {
|
|
7056
|
-
return /* @__PURE__ */
|
|
7416
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text11, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal.replace(/\[\/n\]?/g, "\\n"))));
|
|
7057
7417
|
}
|
|
7058
|
-
return /* @__PURE__ */
|
|
7059
|
-
})()), /* @__PURE__ */
|
|
7418
|
+
return /* @__PURE__ */ React11.createElement(Text11, { color: "white", wrap: "anywhere" }, newVal.replace(/\[\/n\]?/g, "\\n") || "Updating file content...");
|
|
7419
|
+
})()), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
7060
7420
|
CommandMenu,
|
|
7061
7421
|
{
|
|
7062
7422
|
title: "Action Required",
|
|
@@ -7075,7 +7435,7 @@ Selection: ${val}`,
|
|
|
7075
7435
|
}
|
|
7076
7436
|
)));
|
|
7077
7437
|
case "updateManager":
|
|
7078
|
-
return /* @__PURE__ */
|
|
7438
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7079
7439
|
CommandMenu,
|
|
7080
7440
|
{
|
|
7081
7441
|
title: "Select Preferred Update Manager",
|
|
@@ -7112,7 +7472,7 @@ Selection: ${val}`,
|
|
|
7112
7472
|
}
|
|
7113
7473
|
);
|
|
7114
7474
|
case "update":
|
|
7115
|
-
return /* @__PURE__ */
|
|
7475
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7116
7476
|
UpdateProcessor_default,
|
|
7117
7477
|
{
|
|
7118
7478
|
latest: latestVer,
|
|
@@ -7138,7 +7498,7 @@ Selection: ${val}`,
|
|
|
7138
7498
|
}
|
|
7139
7499
|
);
|
|
7140
7500
|
case "terminalApproval":
|
|
7141
|
-
return /* @__PURE__ */
|
|
7501
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true, underline: true }, "\u{1F510} SECURITY GATE: TERMINAL COMMAND OVERSIGHT"), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, null, "Agent requested to run: ", /* @__PURE__ */ React11.createElement(Text11, { color: "yellow", bold: true }, parseArgs(pendingApproval?.args || "{}").command || "Unknown Command"))), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
7142
7502
|
CommandMenu,
|
|
7143
7503
|
{
|
|
7144
7504
|
title: "Risk Assessment Required",
|
|
@@ -7154,8 +7514,8 @@ Selection: ${val}`,
|
|
|
7154
7514
|
}
|
|
7155
7515
|
)));
|
|
7156
7516
|
default:
|
|
7157
|
-
return /* @__PURE__ */
|
|
7158
|
-
|
|
7517
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React11.createElement(Box11, null, statusText ? /* @__PURE__ */ React11.createElement(Box11, null, isSpinnerActive && /* @__PURE__ */ React11.createElement(Text11, { color: "magenta" }, /* @__PURE__ */ React11.createElement(Spinner2, { type: "dots" })), /* @__PURE__ */ React11.createElement(Text11, { color: "magenta", bold: true, italic: true }, isSpinnerActive ? " " : "", statusText.toUpperCase())) : /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", dimColor: true, italic: true }, "READY FOR COMMAND...")), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React11.createElement(Text11, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React11.createElement(
|
|
7518
|
+
Box11,
|
|
7159
7519
|
{
|
|
7160
7520
|
borderStyle: "round",
|
|
7161
7521
|
borderColor: isProcessing ? "magenta" : "cyan",
|
|
@@ -7163,7 +7523,7 @@ Selection: ${val}`,
|
|
|
7163
7523
|
paddingY: 0,
|
|
7164
7524
|
width: "100%"
|
|
7165
7525
|
},
|
|
7166
|
-
/* @__PURE__ */
|
|
7526
|
+
/* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", width: "100%" }, maxLines > 2 && !isExpanded ? /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "row", width: "100%", paddingY: 0, height: 1, overflow: "hidden" }, /* @__PURE__ */ React11.createElement(Box11, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", bold: true }, "\u{1F4A0} ")), /* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1, flexDirection: "row" }, /* @__PURE__ */ React11.createElement(Box11, { flexShrink: 0 }, /* @__PURE__ */ React11.createElement(Text11, { color: "magenta", bold: true }, "[PASTED ", maxLines, " LINES]")), /* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React11.createElement(
|
|
7167
7527
|
MultilineInput,
|
|
7168
7528
|
{
|
|
7169
7529
|
value: "",
|
|
@@ -7180,7 +7540,7 @@ Selection: ${val}`,
|
|
|
7180
7540
|
newline: (key) => key.return && key.shift || key.return && key.ctrl || key.return && key.leftAlt || key.return && key.rightAlt
|
|
7181
7541
|
}
|
|
7182
7542
|
}
|
|
7183
|
-
)))) : /* @__PURE__ */
|
|
7543
|
+
)))) : /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React11.createElement(Box11, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React11.createElement(Text11, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\u2726 " : "\u{1F4A0} ")), /* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1 }, /* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1, position: "relative" }, input === "" && /* @__PURE__ */ React11.createElement(Box11, { position: "absolute", paddingLeft: 0 }, activeCommand && !isTerminalFocused ? /* @__PURE__ */ React11.createElement(Text11, { color: "yellow" }, " Press TAB to interact with terminal...") : activeCommand && isTerminalFocused ? /* @__PURE__ */ React11.createElement(Text11, { color: "yellow", bold: true }, " [ TERMINAL FOCUSED ] Type to interact, press TAB to exit...") : escPressCount === 1 ? /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", bold: true }, " Press ESC again to revert codebase to checkpoint...") : /* @__PURE__ */ React11.createElement(Text11, { color: "gray" }, escPressed ? " Press ESC again to cancel the request." : !isProcessing ? ` Send message or /cmd... (${terminalEnv.shortcut} for newline)` : " Enter a prompt to steer the agent.")), /* @__PURE__ */ React11.createElement(
|
|
7184
7544
|
MultilineInput,
|
|
7185
7545
|
{
|
|
7186
7546
|
focus: !isTerminalFocused,
|
|
@@ -7200,14 +7560,14 @@ Selection: ${val}`,
|
|
|
7200
7560
|
));
|
|
7201
7561
|
}
|
|
7202
7562
|
};
|
|
7203
|
-
return /* @__PURE__ */
|
|
7563
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", width: "100%", flexGrow: 1 }, windowedHistory.items.map((msg, idx) => /* @__PURE__ */ React11.createElement(MessageItem, { key: msg.id || idx, msg, showFullThinking, columns: stdout?.columns || 80 }))), /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", padding: 1, width: "100%" }, (activeView === "chat" || ["ask", "approval", "terminalApproval"].includes(activeView)) && /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React11.createElement(
|
|
7204
7564
|
ChatLayout_default,
|
|
7205
7565
|
{
|
|
7206
7566
|
messages: messages.slice(completedIndex),
|
|
7207
7567
|
showFullThinking,
|
|
7208
7568
|
columns: Math.max(20, (stdout?.columns || 80) - 1)
|
|
7209
7569
|
}
|
|
7210
|
-
), activeCommand && /* @__PURE__ */
|
|
7570
|
+
), activeCommand && /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused }))), isInitializing ? /* @__PURE__ */ React11.createElement(Box11, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React11.createElement(Text11, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React11.createElement(Box11, { borderStyle: "round", borderColor: "gray", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "yellow", bold: true }, "\u{1F511}", emojiSpace(2), "API KEY REQUIRED")), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text11, null, "Please enter your Gemini API Key to initialize the agent."), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React11.createElement(
|
|
7211
7571
|
TextInput3,
|
|
7212
7572
|
{
|
|
7213
7573
|
value: tempKey,
|
|
@@ -7215,7 +7575,7 @@ Selection: ${val}`,
|
|
|
7215
7575
|
onSubmit: handleSetup,
|
|
7216
7576
|
mask: "*"
|
|
7217
7577
|
}
|
|
7218
|
-
))), /* @__PURE__ */
|
|
7578
|
+
))), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, "(Press Enter to confirm and initialize)"))) : renderActiveView(), confirmExit && /* @__PURE__ */ React11.createElement(Box11, { borderStyle: "round", borderColor: "red", paddingX: 2, marginY: 0, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true }, "\u{1F534} EXIT CONFIRMATION: "), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, "Press "), /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true }, "CTRL + C"), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " again to exit (", exitCountdown, "s). Press "), /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", bold: true }, "ESC"), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, " to cancel.")), /* @__PURE__ */ React11.createElement(Box11, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React11.createElement(
|
|
7219
7579
|
StatusBar_default,
|
|
7220
7580
|
{
|
|
7221
7581
|
mode,
|
|
@@ -7232,14 +7592,14 @@ Selection: ${val}`,
|
|
|
7232
7592
|
const agentActiveMs = sessionApiTime + sessionToolTime;
|
|
7233
7593
|
const apiPercent = agentActiveMs > 0 ? (sessionApiTime / agentActiveMs * 100).toFixed(1) : "0.0";
|
|
7234
7594
|
const toolPercent = agentActiveMs > 0 ? (sessionToolTime / agentActiveMs * 100).toFixed(1) : "0.0";
|
|
7235
|
-
return /* @__PURE__ */
|
|
7595
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "red", width: Math.min(100, (stdout?.columns || 100) - 2), marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan", bold: true }, "Agent powering down. ", /* @__PURE__ */ React11.createElement(Text11, { color: "magenta" }, "Goodbye!"))), /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text11, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, chatId)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( ", /* @__PURE__ */ React11.createElement(Text11, { color: "green" }, "\u2713 ", sessionToolSuccess), " ", /* @__PURE__ */ React11.createElement(Text11, { color: "yellow" }, "\u2298 ", sessionToolDenied), " ", /* @__PURE__ */ React11.createElement(Text11, { color: "red" }, "\u2715 ", sessionToolFailure), " )")), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, successRate, "%")), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, sessionImageCount || 0)), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Box11, { width: 20 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React11.createElement(Box11, { marginLeft: 2 }, /* @__PURE__ */ React11.createElement(Box11, { width: 18 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React11.createElement(Box11, { marginLeft: 2 }, /* @__PURE__ */ React11.createElement(Box11, { width: 18 }, /* @__PURE__ */ React11.createElement(Text11, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React11.createElement(Text11, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
|
|
7236
7596
|
})(), suggestions.length > 0 && (() => {
|
|
7237
7597
|
const windowSize = 5;
|
|
7238
7598
|
const startIdx = Math.max(0, Math.min(selectedIndex - 2, suggestions.length - windowSize));
|
|
7239
7599
|
const visible = suggestions.slice(startIdx, startIdx + windowSize);
|
|
7240
7600
|
const remaining = suggestions.length - (startIdx + visible.length);
|
|
7241
|
-
return /* @__PURE__ */
|
|
7242
|
-
|
|
7601
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7602
|
+
Box11,
|
|
7243
7603
|
{
|
|
7244
7604
|
flexDirection: "column",
|
|
7245
7605
|
borderStyle: "round",
|
|
@@ -7248,22 +7608,22 @@ Selection: ${val}`,
|
|
|
7248
7608
|
paddingY: 0,
|
|
7249
7609
|
width: "100%"
|
|
7250
7610
|
},
|
|
7251
|
-
/* @__PURE__ */
|
|
7611
|
+
/* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginBottom: 0 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", bold: true, dimColor: true }, "\u{1F50D} COMMAND SUGGESTIONS")),
|
|
7252
7612
|
visible.map((s, i) => {
|
|
7253
7613
|
const actualIdx = startIdx + i;
|
|
7254
7614
|
const isActive = actualIdx === selectedIndex;
|
|
7255
7615
|
const isGemmaDisabled = s.cmd === "gemma-4-31b-it" && apiTier !== "Free";
|
|
7256
|
-
return /* @__PURE__ */
|
|
7257
|
-
|
|
7616
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7617
|
+
Box11,
|
|
7258
7618
|
{
|
|
7259
7619
|
key: s.cmd,
|
|
7260
7620
|
flexDirection: "row",
|
|
7261
7621
|
backgroundColor: isActive ? "#2a2a2a" : void 0,
|
|
7262
7622
|
paddingX: 1
|
|
7263
7623
|
},
|
|
7264
|
-
/* @__PURE__ */
|
|
7265
|
-
/* @__PURE__ */
|
|
7266
|
-
|
|
7624
|
+
/* @__PURE__ */ React11.createElement(Box11, { width: 3 }, /* @__PURE__ */ React11.createElement(Text11, { color: isActive ? "cyan" : "gray", bold: isActive }, isActive ? " \u276F" : " ")),
|
|
7625
|
+
/* @__PURE__ */ React11.createElement(Box11, { width: 32 }, /* @__PURE__ */ React11.createElement(
|
|
7626
|
+
Text11,
|
|
7267
7627
|
{
|
|
7268
7628
|
color: isGemmaDisabled ? "gray" : isActive ? "yellow" : "white",
|
|
7269
7629
|
bold: isActive,
|
|
@@ -7271,10 +7631,10 @@ Selection: ${val}`,
|
|
|
7271
7631
|
},
|
|
7272
7632
|
s.cmd
|
|
7273
7633
|
)),
|
|
7274
|
-
/* @__PURE__ */
|
|
7634
|
+
/* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", italic: true, dimColor: !isActive }, s.desc))
|
|
7275
7635
|
);
|
|
7276
7636
|
}),
|
|
7277
|
-
suggestions.length > 5 && /* @__PURE__ */
|
|
7637
|
+
suggestions.length > 5 && /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, height: 1 }, remaining > 0 ? /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, " ... (", remaining, " more commands available)") : /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, " (End of list)"))
|
|
7278
7638
|
);
|
|
7279
7639
|
})()));
|
|
7280
7640
|
}
|
|
@@ -7293,6 +7653,8 @@ var init_app = __esm({
|
|
|
7293
7653
|
init_ResumeModal();
|
|
7294
7654
|
init_MemoryModal();
|
|
7295
7655
|
init_UpdateProcessor();
|
|
7656
|
+
init_revert();
|
|
7657
|
+
init_RevertModal();
|
|
7296
7658
|
init_usage();
|
|
7297
7659
|
init_TerminalBox();
|
|
7298
7660
|
init_arg_parser();
|
|
@@ -7303,11 +7665,11 @@ var init_app = __esm({
|
|
|
7303
7665
|
init_text();
|
|
7304
7666
|
SESSION_START_TIME = Date.now();
|
|
7305
7667
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
7306
|
-
packageJsonPath =
|
|
7307
|
-
packageJson = JSON.parse(
|
|
7668
|
+
packageJsonPath = path16.join(path16.dirname(fileURLToPath(import.meta.url)), "../package.json");
|
|
7669
|
+
packageJson = JSON.parse(fs18.readFileSync(packageJsonPath, "utf8"));
|
|
7308
7670
|
versionFluxflow = packageJson.version;
|
|
7309
7671
|
updatedOn = packageJson.date || "2026-05-20";
|
|
7310
|
-
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */
|
|
7672
|
+
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React11.createElement(Text11, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 0 }, /* @__PURE__ */ React11.createElement(
|
|
7311
7673
|
CommandMenu,
|
|
7312
7674
|
{
|
|
7313
7675
|
title: "Select Action",
|
|
@@ -7410,7 +7772,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
7410
7772
|
], { stdio: "inherit" });
|
|
7411
7773
|
cp.on("exit", (code) => process.exit(code || 0));
|
|
7412
7774
|
} else {
|
|
7413
|
-
const { default:
|
|
7775
|
+
const { default: React12 } = await import("react");
|
|
7414
7776
|
const { render } = await import("ink");
|
|
7415
7777
|
const { default: App2 } = await Promise.resolve().then(() => (init_app(), app_exports));
|
|
7416
7778
|
process.env.NODE_NO_WARNINGS = "1";
|
|
@@ -7433,5 +7795,5 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
7433
7795
|
console.warn = (...args) => !isNoise(args) && originalWarn(...args);
|
|
7434
7796
|
console.error = (...args) => !isNoise(args) && originalError(...args);
|
|
7435
7797
|
process.stdout.write("\x1Bc");
|
|
7436
|
-
render(/* @__PURE__ */
|
|
7798
|
+
render(/* @__PURE__ */ React12.createElement(App2, { args: process.argv.slice(2) }), { exitOnCtrlC: false });
|
|
7437
7799
|
}
|