fluxflow-cli 1.13.6 → 1.14.1
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 +1275 -916
- 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
|
|
@@ -1129,7 +1134,7 @@ ${projectContextBlock}
|
|
|
1129
1134
|
-- FORMATTING --
|
|
1130
1135
|
- Clean, concise responses
|
|
1131
1136
|
- Tables: GFM (Max 4 cols, short rows)
|
|
1132
|
-
- NO LaTeX. Code blocks for literature
|
|
1137
|
+
- NO LaTeX. Code blocks for literature${mode === "Flux" ? "" : ". Kaomojis"}
|
|
1133
1138
|
|
|
1134
1139
|
-- RESPONSE RULES --
|
|
1135
1140
|
- End with [turn: continue] for more steps or [turn: finish] when done
|
|
@@ -1165,15 +1170,165 @@ 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) return;
|
|
1229
|
+
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
1230
|
+
ledger.push(currentTransaction);
|
|
1231
|
+
if (ledger.length > 500) {
|
|
1232
|
+
const removed = ledger.shift();
|
|
1233
|
+
if (removed.changes) {
|
|
1234
|
+
for (const change of removed.changes) {
|
|
1235
|
+
if (change.backupFile) {
|
|
1236
|
+
const backupPath = path4.join(BACKUPS_DIR, removed.chatId, change.backupFile);
|
|
1237
|
+
await fs5.remove(backupPath);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
1243
|
+
currentTransaction = null;
|
|
1244
|
+
},
|
|
1245
|
+
/**
|
|
1246
|
+
* Reverts the codebase to a state immediately before the target transaction.
|
|
1247
|
+
* Reverts the target transaction and all subsequent ones in reverse sequential order.
|
|
1248
|
+
* Returns the target prompt text so it can be loaded back into the user input.
|
|
1249
|
+
*/
|
|
1250
|
+
async rollbackToBefore(txId) {
|
|
1251
|
+
const ledger = readEncryptedJson(LEDGER_FILE, null);
|
|
1252
|
+
if (!ledger) throw new Error("No transaction ledger found.");
|
|
1253
|
+
const targetIndex = ledger.findIndex((t) => t.id === txId);
|
|
1254
|
+
if (targetIndex === -1) throw new Error(`Transaction [${txId}] not found.`);
|
|
1255
|
+
const chatId = ledger[targetIndex].chatId;
|
|
1256
|
+
const targetPrompt = ledger[targetIndex].prompt;
|
|
1257
|
+
const toRevert = ledger.slice(targetIndex).filter((t) => t.chatId === chatId && !t.reverted).reverse();
|
|
1258
|
+
for (const tx of toRevert) {
|
|
1259
|
+
for (const change of [...tx.changes].reverse()) {
|
|
1260
|
+
if (change.type === "create") {
|
|
1261
|
+
if (await fs5.pathExists(change.filePath)) {
|
|
1262
|
+
await fs5.remove(change.filePath);
|
|
1263
|
+
}
|
|
1264
|
+
} else if (change.type === "update") {
|
|
1265
|
+
const backupPath = path4.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
1266
|
+
if (await fs5.pathExists(backupPath)) {
|
|
1267
|
+
const encrypted = await fs5.readFile(backupPath, "utf8");
|
|
1268
|
+
const decrypted = decryptAes(encrypted);
|
|
1269
|
+
await fs5.writeFile(change.filePath, decrypted, "utf8");
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
tx.reverted = true;
|
|
1274
|
+
}
|
|
1275
|
+
for (const tx of toRevert) {
|
|
1276
|
+
for (const change of tx.changes) {
|
|
1277
|
+
if (change.backupFile) {
|
|
1278
|
+
const backupPath = path4.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
1279
|
+
await fs5.remove(backupPath);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
const updatedLedger = ledger.filter((t) => !toRevert.some((r) => r.id === t.id));
|
|
1284
|
+
writeEncryptedJson(LEDGER_FILE, updatedLedger);
|
|
1285
|
+
return {
|
|
1286
|
+
success: true,
|
|
1287
|
+
chatId,
|
|
1288
|
+
targetPrompt
|
|
1289
|
+
};
|
|
1290
|
+
},
|
|
1291
|
+
/**
|
|
1292
|
+
* Gets all non-reverted prompt transactions for a specific chat.
|
|
1293
|
+
*/
|
|
1294
|
+
async getChatHistory(chatId) {
|
|
1295
|
+
try {
|
|
1296
|
+
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
1297
|
+
return ledger.filter((t) => t.chatId === chatId && !t.reverted);
|
|
1298
|
+
} catch (e) {
|
|
1299
|
+
return [];
|
|
1300
|
+
}
|
|
1301
|
+
},
|
|
1302
|
+
/**
|
|
1303
|
+
* Cleans up all transaction logs and backups associated with a deleted chat.
|
|
1304
|
+
*/
|
|
1305
|
+
async deleteChatBackups(chatId) {
|
|
1306
|
+
try {
|
|
1307
|
+
const chatBackupDir = path4.join(BACKUPS_DIR, chatId);
|
|
1308
|
+
await fs5.remove(chatBackupDir);
|
|
1309
|
+
let ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
1310
|
+
const originalLength = ledger.length;
|
|
1311
|
+
ledger = ledger.filter((t) => t.chatId !== chatId);
|
|
1312
|
+
if (ledger.length !== originalLength) {
|
|
1313
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
1314
|
+
}
|
|
1315
|
+
} catch (e) {
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
// src/utils/history.js
|
|
1323
|
+
import fs6 from "fs-extra";
|
|
1324
|
+
import path5 from "path";
|
|
1171
1325
|
import { nanoid } from "nanoid";
|
|
1172
1326
|
var WRITE_LOCK, withLock, loadHistory, saveChat, saveChatTitle, deleteChat, generateChatId, cleanupOldHistory, parseCustomDate, cleanupLogFile, cleanupOldLogs, getTruncatedHistory;
|
|
1173
1327
|
var init_history = __esm({
|
|
1174
1328
|
"src/utils/history.js"() {
|
|
1175
1329
|
init_crypto();
|
|
1176
1330
|
init_paths();
|
|
1331
|
+
init_revert();
|
|
1177
1332
|
WRITE_LOCK = Promise.resolve();
|
|
1178
1333
|
withLock = (op) => {
|
|
1179
1334
|
const nextLock = WRITE_LOCK.then(async () => {
|
|
@@ -1189,7 +1344,7 @@ var init_history = __esm({
|
|
|
1189
1344
|
return nextLock;
|
|
1190
1345
|
};
|
|
1191
1346
|
loadHistory = async () => {
|
|
1192
|
-
if (await
|
|
1347
|
+
if (await fs6.pathExists(HISTORY_FILE)) {
|
|
1193
1348
|
try {
|
|
1194
1349
|
return readEncryptedJson(HISTORY_FILE, {});
|
|
1195
1350
|
} catch (e) {
|
|
@@ -1239,6 +1394,7 @@ var init_history = __esm({
|
|
|
1239
1394
|
delete cache[id];
|
|
1240
1395
|
writeEncryptedJson(TEMP_MEM_CHAT_FILE, cache);
|
|
1241
1396
|
}
|
|
1397
|
+
await RevertManager.deleteChatBackups(id);
|
|
1242
1398
|
return history;
|
|
1243
1399
|
});
|
|
1244
1400
|
};
|
|
@@ -1308,8 +1464,8 @@ var init_history = __esm({
|
|
|
1308
1464
|
};
|
|
1309
1465
|
cleanupLogFile = async (filePath) => {
|
|
1310
1466
|
try {
|
|
1311
|
-
if (!await
|
|
1312
|
-
const content = await
|
|
1467
|
+
if (!await fs6.pathExists(filePath)) return;
|
|
1468
|
+
const content = await fs6.readFile(filePath, "utf8");
|
|
1313
1469
|
if (!content.trim()) return;
|
|
1314
1470
|
const lines = content.split("\n");
|
|
1315
1471
|
const entries = [];
|
|
@@ -1349,26 +1505,26 @@ var init_history = __esm({
|
|
|
1349
1505
|
}
|
|
1350
1506
|
const finalContent = keptEntries.join("\n").trim();
|
|
1351
1507
|
if (finalContent) {
|
|
1352
|
-
await
|
|
1508
|
+
await fs6.writeFile(filePath, finalContent + "\n", "utf8");
|
|
1353
1509
|
} else {
|
|
1354
|
-
await
|
|
1510
|
+
await fs6.writeFile(filePath, "", "utf8");
|
|
1355
1511
|
}
|
|
1356
1512
|
} catch (e) {
|
|
1357
1513
|
}
|
|
1358
1514
|
};
|
|
1359
1515
|
cleanupOldLogs = async (logsDir) => {
|
|
1360
1516
|
try {
|
|
1361
|
-
if (!await
|
|
1517
|
+
if (!await fs6.pathExists(logsDir)) return;
|
|
1362
1518
|
const cleanRecursive = async (dir) => {
|
|
1363
|
-
const files = await
|
|
1519
|
+
const files = await fs6.readdir(dir);
|
|
1364
1520
|
for (const file of files) {
|
|
1365
|
-
const fullPath =
|
|
1366
|
-
const stat = await
|
|
1521
|
+
const fullPath = path5.join(dir, file);
|
|
1522
|
+
const stat = await fs6.stat(fullPath);
|
|
1367
1523
|
if (stat.isDirectory()) {
|
|
1368
1524
|
await cleanRecursive(fullPath);
|
|
1369
|
-
const subFiles = await
|
|
1525
|
+
const subFiles = await fs6.readdir(fullPath);
|
|
1370
1526
|
if (subFiles.length === 0) {
|
|
1371
|
-
await
|
|
1527
|
+
await fs6.remove(fullPath);
|
|
1372
1528
|
}
|
|
1373
1529
|
} else if (file.endsWith(".log")) {
|
|
1374
1530
|
await cleanupLogFile(fullPath);
|
|
@@ -1391,8 +1547,8 @@ var init_history = __esm({
|
|
|
1391
1547
|
});
|
|
1392
1548
|
|
|
1393
1549
|
// src/utils/usage.js
|
|
1394
|
-
import
|
|
1395
|
-
import
|
|
1550
|
+
import fs7 from "fs-extra";
|
|
1551
|
+
import path6 from "path";
|
|
1396
1552
|
import os3 from "os";
|
|
1397
1553
|
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
1554
|
var init_usage = __esm({
|
|
@@ -1401,14 +1557,14 @@ var init_usage = __esm({
|
|
|
1401
1557
|
init_crypto();
|
|
1402
1558
|
getLocalBackupPath = () => {
|
|
1403
1559
|
if (process.platform === "win32") {
|
|
1404
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
1405
|
-
return
|
|
1560
|
+
const localAppData = process.env.LOCALAPPDATA || path6.join(os3.homedir(), "AppData", "Local");
|
|
1561
|
+
return path6.join(localAppData, "FxFl", "backups", "backup.json");
|
|
1406
1562
|
}
|
|
1407
1563
|
if (process.platform === "darwin") {
|
|
1408
|
-
return
|
|
1564
|
+
return path6.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
|
|
1409
1565
|
}
|
|
1410
|
-
const xdgDataHome = process.env.XDG_DATA_HOME ||
|
|
1411
|
-
return
|
|
1566
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || path6.join(os3.homedir(), ".local", "share");
|
|
1567
|
+
return path6.join(xdgDataHome, "fxfl", "backups", "backup.json");
|
|
1412
1568
|
};
|
|
1413
1569
|
BACKUP_FILE = getLocalBackupPath();
|
|
1414
1570
|
generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
@@ -1433,8 +1589,8 @@ var init_usage = __esm({
|
|
|
1433
1589
|
let primaryData = null;
|
|
1434
1590
|
let backupData = null;
|
|
1435
1591
|
try {
|
|
1436
|
-
if (await
|
|
1437
|
-
const rawContent = (await
|
|
1592
|
+
if (await fs7.exists(tempFile)) {
|
|
1593
|
+
const rawContent = (await fs7.readFile(tempFile, "utf8")).trim();
|
|
1438
1594
|
let parsed = null;
|
|
1439
1595
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1440
1596
|
parsed = JSON.parse(rawContent);
|
|
@@ -1444,26 +1600,26 @@ var init_usage = __esm({
|
|
|
1444
1600
|
if (parsed && parsed.date && parsed.stats) {
|
|
1445
1601
|
primaryData = parsed;
|
|
1446
1602
|
try {
|
|
1447
|
-
await
|
|
1603
|
+
await fs7.rename(tempFile, USAGE_FILE);
|
|
1448
1604
|
} catch (e) {
|
|
1449
1605
|
}
|
|
1450
1606
|
} else {
|
|
1451
1607
|
try {
|
|
1452
|
-
await
|
|
1608
|
+
await fs7.remove(tempFile);
|
|
1453
1609
|
} catch (e) {
|
|
1454
1610
|
}
|
|
1455
1611
|
}
|
|
1456
1612
|
}
|
|
1457
1613
|
} catch (err) {
|
|
1458
1614
|
try {
|
|
1459
|
-
await
|
|
1615
|
+
await fs7.remove(tempFile);
|
|
1460
1616
|
} catch (e) {
|
|
1461
1617
|
}
|
|
1462
1618
|
}
|
|
1463
1619
|
if (!primaryData) {
|
|
1464
1620
|
try {
|
|
1465
|
-
if (await
|
|
1466
|
-
const rawContent = (await
|
|
1621
|
+
if (await fs7.exists(USAGE_FILE)) {
|
|
1622
|
+
const rawContent = (await fs7.readFile(USAGE_FILE, "utf8")).trim();
|
|
1467
1623
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1468
1624
|
primaryData = JSON.parse(rawContent);
|
|
1469
1625
|
} else {
|
|
@@ -1474,8 +1630,8 @@ var init_usage = __esm({
|
|
|
1474
1630
|
}
|
|
1475
1631
|
}
|
|
1476
1632
|
try {
|
|
1477
|
-
if (await
|
|
1478
|
-
const rawContent = (await
|
|
1633
|
+
if (await fs7.exists(BACKUP_FILE)) {
|
|
1634
|
+
const rawContent = (await fs7.readFile(BACKUP_FILE, "utf8")).trim();
|
|
1479
1635
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1480
1636
|
backupData = JSON.parse(rawContent);
|
|
1481
1637
|
} else {
|
|
@@ -1489,8 +1645,8 @@ var init_usage = __esm({
|
|
|
1489
1645
|
if (primaryData.saveId !== backupData.saveId) {
|
|
1490
1646
|
resolvedData = primaryData;
|
|
1491
1647
|
try {
|
|
1492
|
-
await
|
|
1493
|
-
await
|
|
1648
|
+
await fs7.ensureDir(path6.dirname(BACKUP_FILE));
|
|
1649
|
+
await fs7.copy(USAGE_FILE, BACKUP_FILE);
|
|
1494
1650
|
} catch (e) {
|
|
1495
1651
|
}
|
|
1496
1652
|
} else {
|
|
@@ -1499,15 +1655,15 @@ var init_usage = __esm({
|
|
|
1499
1655
|
} else if (primaryData && !backupData) {
|
|
1500
1656
|
resolvedData = primaryData;
|
|
1501
1657
|
try {
|
|
1502
|
-
await
|
|
1503
|
-
await
|
|
1658
|
+
await fs7.ensureDir(path6.dirname(BACKUP_FILE));
|
|
1659
|
+
await fs7.copy(USAGE_FILE, BACKUP_FILE);
|
|
1504
1660
|
} catch (e) {
|
|
1505
1661
|
}
|
|
1506
1662
|
} else if (!primaryData && backupData) {
|
|
1507
1663
|
resolvedData = backupData;
|
|
1508
1664
|
try {
|
|
1509
|
-
await
|
|
1510
|
-
await
|
|
1665
|
+
await fs7.ensureDir(path6.dirname(USAGE_FILE));
|
|
1666
|
+
await fs7.copy(BACKUP_FILE, USAGE_FILE);
|
|
1511
1667
|
} catch (e) {
|
|
1512
1668
|
}
|
|
1513
1669
|
}
|
|
@@ -1526,11 +1682,11 @@ var init_usage = __esm({
|
|
|
1526
1682
|
flushUsage = async () => {
|
|
1527
1683
|
if (!isDirty || !cachedUsage) return;
|
|
1528
1684
|
try {
|
|
1529
|
-
await
|
|
1685
|
+
await fs7.ensureDir(path6.dirname(USAGE_FILE));
|
|
1530
1686
|
let diskData = null;
|
|
1531
1687
|
try {
|
|
1532
|
-
if (await
|
|
1533
|
-
const rawContent = (await
|
|
1688
|
+
if (await fs7.exists(USAGE_FILE)) {
|
|
1689
|
+
const rawContent = (await fs7.readFile(USAGE_FILE, "utf8")).trim();
|
|
1534
1690
|
if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
|
|
1535
1691
|
diskData = JSON.parse(rawContent);
|
|
1536
1692
|
} else {
|
|
@@ -1561,14 +1717,14 @@ var init_usage = __esm({
|
|
|
1561
1717
|
cachedUsage.saveId = generateSaveId();
|
|
1562
1718
|
const tempFile = USAGE_FILE + ".tmp";
|
|
1563
1719
|
const encryptedStr = encryptAes(JSON.stringify(cachedUsage, null, 2));
|
|
1564
|
-
await
|
|
1565
|
-
const fd = await
|
|
1566
|
-
await
|
|
1567
|
-
await
|
|
1568
|
-
await
|
|
1720
|
+
await fs7.writeFile(tempFile, encryptedStr, "utf8");
|
|
1721
|
+
const fd = await fs7.open(tempFile, "r+");
|
|
1722
|
+
await fs7.fsync(fd);
|
|
1723
|
+
await fs7.close(fd);
|
|
1724
|
+
await fs7.rename(tempFile, USAGE_FILE);
|
|
1569
1725
|
try {
|
|
1570
|
-
await
|
|
1571
|
-
await
|
|
1726
|
+
await fs7.ensureDir(path6.dirname(BACKUP_FILE));
|
|
1727
|
+
await fs7.copy(USAGE_FILE, BACKUP_FILE);
|
|
1572
1728
|
} catch (backupErr) {
|
|
1573
1729
|
}
|
|
1574
1730
|
isDirty = false;
|
|
@@ -2221,8 +2377,8 @@ var init_chat = __esm({
|
|
|
2221
2377
|
});
|
|
2222
2378
|
|
|
2223
2379
|
// src/tools/view_file.js
|
|
2224
|
-
import
|
|
2225
|
-
import
|
|
2380
|
+
import fs8 from "fs";
|
|
2381
|
+
import path7 from "path";
|
|
2226
2382
|
var view_file;
|
|
2227
2383
|
var init_view_file = __esm({
|
|
2228
2384
|
"src/tools/view_file.js"() {
|
|
@@ -2234,16 +2390,16 @@ var init_view_file = __esm({
|
|
|
2234
2390
|
const finalStart = sLine || 1;
|
|
2235
2391
|
const finalEnd = eLine || (sLine ? sLine + 800 : 800);
|
|
2236
2392
|
if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
|
|
2237
|
-
const absolutePath =
|
|
2393
|
+
const absolutePath = path7.resolve(process.cwd(), targetPath);
|
|
2238
2394
|
try {
|
|
2239
|
-
if (!
|
|
2395
|
+
if (!fs8.existsSync(absolutePath)) {
|
|
2240
2396
|
return `ERROR: File [${targetPath}] does not exist.`;
|
|
2241
2397
|
}
|
|
2242
|
-
const stats =
|
|
2398
|
+
const stats = fs8.statSync(absolutePath);
|
|
2243
2399
|
if (stats.isDirectory()) {
|
|
2244
2400
|
return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
|
|
2245
2401
|
}
|
|
2246
|
-
const ext =
|
|
2402
|
+
const ext = path7.extname(targetPath).toLowerCase();
|
|
2247
2403
|
const videoExtensions = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".mpeg", ".mpg"];
|
|
2248
2404
|
if (videoExtensions.includes(ext)) {
|
|
2249
2405
|
const format = ext.slice(1).toUpperCase();
|
|
@@ -2259,7 +2415,7 @@ var init_view_file = __esm({
|
|
|
2259
2415
|
".doc": "application/msword"
|
|
2260
2416
|
};
|
|
2261
2417
|
if (mimeMap[ext]) {
|
|
2262
|
-
const buffer =
|
|
2418
|
+
const buffer = fs8.readFileSync(absolutePath);
|
|
2263
2419
|
const base64 = buffer.toString("base64");
|
|
2264
2420
|
const mimeType = mimeMap[ext];
|
|
2265
2421
|
return {
|
|
@@ -2272,7 +2428,7 @@ var init_view_file = __esm({
|
|
|
2272
2428
|
}
|
|
2273
2429
|
};
|
|
2274
2430
|
}
|
|
2275
|
-
let content =
|
|
2431
|
+
let content = fs8.readFileSync(absolutePath, "utf8");
|
|
2276
2432
|
if (content.startsWith("\uFEFF")) {
|
|
2277
2433
|
content = content.slice(1);
|
|
2278
2434
|
}
|
|
@@ -2295,24 +2451,26 @@ ${code}`;
|
|
|
2295
2451
|
});
|
|
2296
2452
|
|
|
2297
2453
|
// src/tools/write_file.js
|
|
2298
|
-
import
|
|
2299
|
-
import
|
|
2454
|
+
import fs9 from "fs";
|
|
2455
|
+
import path8 from "path";
|
|
2300
2456
|
var write_file;
|
|
2301
2457
|
var init_write_file = __esm({
|
|
2302
2458
|
"src/tools/write_file.js"() {
|
|
2303
2459
|
init_arg_parser();
|
|
2460
|
+
init_revert();
|
|
2304
2461
|
write_file = async (args) => {
|
|
2305
2462
|
let { path: targetPath, content } = parseArgs(args);
|
|
2306
2463
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_file.';
|
|
2307
2464
|
if (content === void 0) return 'ERROR: Missing "content" argument for write_file.';
|
|
2308
2465
|
content = content.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2309
|
-
const absolutePath =
|
|
2310
|
-
const parentDir =
|
|
2466
|
+
const absolutePath = path8.resolve(process.cwd(), targetPath);
|
|
2467
|
+
const parentDir = path8.dirname(absolutePath);
|
|
2311
2468
|
try {
|
|
2469
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
2312
2470
|
let ancestry = "";
|
|
2313
|
-
if (
|
|
2471
|
+
if (fs9.existsSync(absolutePath)) {
|
|
2314
2472
|
try {
|
|
2315
|
-
const oldData =
|
|
2473
|
+
const oldData = fs9.readFileSync(absolutePath, "utf8");
|
|
2316
2474
|
const lines = oldData.split(/\r?\n/);
|
|
2317
2475
|
ancestry = `Old File contents:
|
|
2318
2476
|
${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
@@ -2324,15 +2482,15 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
2324
2482
|
`;
|
|
2325
2483
|
}
|
|
2326
2484
|
}
|
|
2327
|
-
if (!
|
|
2328
|
-
|
|
2485
|
+
if (!fs9.existsSync(parentDir)) {
|
|
2486
|
+
fs9.mkdirSync(parentDir, { recursive: true });
|
|
2329
2487
|
}
|
|
2330
2488
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2331
2489
|
const processedContent = strip(content);
|
|
2332
2490
|
const lineCount = processedContent.split(/\r?\n/).length;
|
|
2333
2491
|
const originalSize = Buffer.byteLength(processedContent, "utf8");
|
|
2334
|
-
|
|
2335
|
-
let verifiedContent =
|
|
2492
|
+
fs9.writeFileSync(absolutePath, processedContent, "utf8");
|
|
2493
|
+
let verifiedContent = fs9.readFileSync(absolutePath, "utf8");
|
|
2336
2494
|
const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
|
|
2337
2495
|
const verifiedLines = verifiedContent.split(/\r?\n/);
|
|
2338
2496
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -2368,32 +2526,37 @@ Check if Starting and Ending matches your write.`;
|
|
|
2368
2526
|
});
|
|
2369
2527
|
|
|
2370
2528
|
// src/tools/update_file.js
|
|
2371
|
-
import
|
|
2372
|
-
import
|
|
2529
|
+
import fs10 from "fs";
|
|
2530
|
+
import path9 from "path";
|
|
2373
2531
|
var update_file;
|
|
2374
2532
|
var init_update_file = __esm({
|
|
2375
2533
|
"src/tools/update_file.js"() {
|
|
2376
2534
|
init_arg_parser();
|
|
2535
|
+
init_revert();
|
|
2377
2536
|
update_file = async (args) => {
|
|
2378
|
-
|
|
2537
|
+
const parsed = parseArgs(args);
|
|
2538
|
+
const targetPath = parsed.path;
|
|
2539
|
+
let content_to_replace = parsed.content_to_replace !== void 0 ? parsed.content_to_replace : parsed.replaceContent;
|
|
2540
|
+
let content_to_add = parsed.content_to_add !== void 0 ? parsed.content_to_add : parsed.newContent;
|
|
2379
2541
|
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 "
|
|
2542
|
+
if (content_to_replace === void 0) return 'ERROR: Missing "replaceContent" argument.';
|
|
2543
|
+
if (content_to_add === void 0) return 'ERROR: Missing "newContent" argument.';
|
|
2382
2544
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2383
2545
|
content_to_replace = strip(content_to_replace);
|
|
2384
2546
|
content_to_add = strip(content_to_add);
|
|
2385
|
-
const absolutePath =
|
|
2547
|
+
const absolutePath = path9.resolve(process.cwd(), targetPath);
|
|
2386
2548
|
try {
|
|
2387
|
-
if (!
|
|
2549
|
+
if (!fs10.existsSync(absolutePath)) {
|
|
2388
2550
|
return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
|
|
2389
2551
|
}
|
|
2390
|
-
|
|
2552
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
2553
|
+
let diskContent = fs10.readFileSync(absolutePath, "utf8");
|
|
2391
2554
|
if (diskContent.startsWith("\uFEFF")) {
|
|
2392
2555
|
diskContent = diskContent.slice(1);
|
|
2393
2556
|
}
|
|
2394
2557
|
const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2395
2558
|
if (diskContent !== normalizedDisk) {
|
|
2396
|
-
|
|
2559
|
+
fs10.writeFileSync(absolutePath, normalizedDisk, "utf8");
|
|
2397
2560
|
diskContent = normalizedDisk;
|
|
2398
2561
|
}
|
|
2399
2562
|
const currentContent = diskContent;
|
|
@@ -2462,7 +2625,7 @@ var init_update_file = __esm({
|
|
|
2462
2625
|
const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
|
|
2463
2626
|
const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
|
|
2464
2627
|
const finalContentToReplace = firstMatchContent;
|
|
2465
|
-
|
|
2628
|
+
fs10.writeFileSync(absolutePath, newFileContent, "utf8");
|
|
2466
2629
|
const allOriginalLines = currentContent.split(/\r?\n/);
|
|
2467
2630
|
const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
|
|
2468
2631
|
const oldLines = content_to_replace.split(/\r?\n/);
|
|
@@ -2725,34 +2888,34 @@ ${finalOutput}`);
|
|
|
2725
2888
|
});
|
|
2726
2889
|
|
|
2727
2890
|
// src/tools/read_folder.js
|
|
2728
|
-
import
|
|
2729
|
-
import
|
|
2891
|
+
import fs11 from "fs";
|
|
2892
|
+
import path10 from "path";
|
|
2730
2893
|
var read_folder;
|
|
2731
2894
|
var init_read_folder = __esm({
|
|
2732
2895
|
"src/tools/read_folder.js"() {
|
|
2733
2896
|
init_arg_parser();
|
|
2734
2897
|
read_folder = async (args) => {
|
|
2735
2898
|
const { path: targetPath = "." } = parseArgs(args);
|
|
2736
|
-
const absolutePath =
|
|
2899
|
+
const absolutePath = path10.resolve(process.cwd(), targetPath);
|
|
2737
2900
|
try {
|
|
2738
|
-
if (!
|
|
2901
|
+
if (!fs11.existsSync(absolutePath)) {
|
|
2739
2902
|
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2740
2903
|
}
|
|
2741
|
-
const stats =
|
|
2904
|
+
const stats = fs11.statSync(absolutePath);
|
|
2742
2905
|
if (!stats.isDirectory()) {
|
|
2743
2906
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2744
2907
|
}
|
|
2745
|
-
const files =
|
|
2908
|
+
const files = fs11.readdirSync(absolutePath);
|
|
2746
2909
|
const totalItems = files.length;
|
|
2747
2910
|
const maxDisplay = 100;
|
|
2748
2911
|
const displayItems = files.slice(0, maxDisplay);
|
|
2749
2912
|
const folderData = [];
|
|
2750
2913
|
for (const file of displayItems) {
|
|
2751
|
-
const fPath =
|
|
2914
|
+
const fPath = path10.join(absolutePath, file);
|
|
2752
2915
|
let indicator = "\u{1F4C4}";
|
|
2753
2916
|
let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
|
|
2754
2917
|
try {
|
|
2755
|
-
const fStats =
|
|
2918
|
+
const fStats = fs11.statSync(fPath);
|
|
2756
2919
|
info = {
|
|
2757
2920
|
name: file,
|
|
2758
2921
|
type: fStats.isDirectory() ? "directory" : "file",
|
|
@@ -2835,13 +2998,14 @@ var init_ask_user = __esm({
|
|
|
2835
2998
|
|
|
2836
2999
|
// src/tools/write_pdf.js
|
|
2837
3000
|
import puppeteer3 from "puppeteer";
|
|
2838
|
-
import
|
|
2839
|
-
import
|
|
3001
|
+
import path11 from "path";
|
|
3002
|
+
import fs12 from "fs-extra";
|
|
2840
3003
|
import { PDFDocument } from "pdf-lib";
|
|
2841
3004
|
var write_pdf;
|
|
2842
3005
|
var init_write_pdf = __esm({
|
|
2843
3006
|
"src/tools/write_pdf.js"() {
|
|
2844
3007
|
init_arg_parser();
|
|
3008
|
+
init_revert();
|
|
2845
3009
|
write_pdf = async (args) => {
|
|
2846
3010
|
const {
|
|
2847
3011
|
path: targetPath,
|
|
@@ -2851,10 +3015,11 @@ var init_write_pdf = __esm({
|
|
|
2851
3015
|
} = parseArgs(args);
|
|
2852
3016
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
|
|
2853
3017
|
if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
|
|
2854
|
-
const absolutePath =
|
|
3018
|
+
const absolutePath = path11.resolve(process.cwd(), targetPath);
|
|
2855
3019
|
let browser = null;
|
|
2856
3020
|
try {
|
|
2857
|
-
await
|
|
3021
|
+
await fs12.ensureDir(path11.dirname(absolutePath));
|
|
3022
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
2858
3023
|
browser = await puppeteer3.launch({
|
|
2859
3024
|
headless: true,
|
|
2860
3025
|
args: [
|
|
@@ -2872,11 +3037,11 @@ var init_write_pdf = __esm({
|
|
|
2872
3037
|
return null;
|
|
2873
3038
|
}
|
|
2874
3039
|
try {
|
|
2875
|
-
const imgPath =
|
|
2876
|
-
if (await
|
|
2877
|
-
const ext =
|
|
3040
|
+
const imgPath = path11.resolve(process.cwd(), originalSrc);
|
|
3041
|
+
if (await fs12.pathExists(imgPath)) {
|
|
3042
|
+
const ext = path11.extname(imgPath).toLowerCase().replace(".", "") || "png";
|
|
2878
3043
|
const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
|
|
2879
|
-
const base64 = await
|
|
3044
|
+
const base64 = await fs12.readFile(imgPath, "base64");
|
|
2880
3045
|
return `data:image/${mime};base64,${base64}`;
|
|
2881
3046
|
}
|
|
2882
3047
|
} catch (e) {
|
|
@@ -2891,9 +3056,9 @@ var init_write_pdf = __esm({
|
|
|
2891
3056
|
const fullTag = match[0];
|
|
2892
3057
|
if (originalHref && fullTag.toLowerCase().includes("stylesheet") && !originalHref.startsWith("http://") && !originalHref.startsWith("https://") && !originalHref.startsWith("data:")) {
|
|
2893
3058
|
try {
|
|
2894
|
-
const cssPath =
|
|
2895
|
-
if (await
|
|
2896
|
-
const cssContent = await
|
|
3059
|
+
const cssPath = path11.resolve(process.cwd(), originalHref);
|
|
3060
|
+
if (await fs12.pathExists(cssPath)) {
|
|
3061
|
+
const cssContent = await fs12.readFile(cssPath, "utf-8");
|
|
2897
3062
|
cssCache[fullTag] = `<style>${cssContent}</style>`;
|
|
2898
3063
|
}
|
|
2899
3064
|
} catch (e) {
|
|
@@ -2974,7 +3139,7 @@ var init_write_pdf = __esm({
|
|
|
2974
3139
|
printBackground: true
|
|
2975
3140
|
});
|
|
2976
3141
|
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
2977
|
-
const fileName =
|
|
3142
|
+
const fileName = path11.basename(targetPath);
|
|
2978
3143
|
pdfDoc.setTitle(`FluxFlow_${fileName}`);
|
|
2979
3144
|
pdfDoc.setAuthor("FluxFlow CLI");
|
|
2980
3145
|
pdfDoc.setSubject("Generated with Agentic AI System");
|
|
@@ -2982,8 +3147,8 @@ var init_write_pdf = __esm({
|
|
|
2982
3147
|
pdfDoc.setCreator("FluxFlow PDF Engine");
|
|
2983
3148
|
pdfDoc.setProducer("FluxFlow (Generative AI)");
|
|
2984
3149
|
const finalPdfBytes = await pdfDoc.save();
|
|
2985
|
-
await
|
|
2986
|
-
const stats = await
|
|
3150
|
+
await fs12.writeFile(absolutePath, finalPdfBytes);
|
|
3151
|
+
const stats = await fs12.stat(absolutePath);
|
|
2987
3152
|
return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
|
|
2988
3153
|
} catch (err) {
|
|
2989
3154
|
return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
|
|
@@ -2995,13 +3160,14 @@ var init_write_pdf = __esm({
|
|
|
2995
3160
|
});
|
|
2996
3161
|
|
|
2997
3162
|
// src/tools/write_docx.js
|
|
2998
|
-
import
|
|
2999
|
-
import
|
|
3163
|
+
import fs13 from "fs-extra";
|
|
3164
|
+
import path12 from "path";
|
|
3000
3165
|
import HTMLtoDOCX from "html-to-docx";
|
|
3001
3166
|
var write_docx;
|
|
3002
3167
|
var init_write_docx = __esm({
|
|
3003
3168
|
"src/tools/write_docx.js"() {
|
|
3004
3169
|
init_arg_parser();
|
|
3170
|
+
init_revert();
|
|
3005
3171
|
write_docx = async (args) => {
|
|
3006
3172
|
const {
|
|
3007
3173
|
path: targetPath,
|
|
@@ -3009,10 +3175,11 @@ var init_write_docx = __esm({
|
|
|
3009
3175
|
} = parseArgs(args);
|
|
3010
3176
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
|
|
3011
3177
|
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
3012
|
-
const absolutePath =
|
|
3178
|
+
const absolutePath = path12.resolve(process.cwd(), targetPath);
|
|
3013
3179
|
try {
|
|
3014
|
-
await
|
|
3015
|
-
|
|
3180
|
+
await fs13.ensureDir(path12.dirname(absolutePath));
|
|
3181
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
3182
|
+
const fileName = path12.basename(targetPath);
|
|
3016
3183
|
const fullHtml = content.includes("<html") ? content : `
|
|
3017
3184
|
<!DOCTYPE html>
|
|
3018
3185
|
<html lang="en">
|
|
@@ -3033,7 +3200,7 @@ var init_write_docx = __esm({
|
|
|
3033
3200
|
footer: true,
|
|
3034
3201
|
pageNumber: true
|
|
3035
3202
|
});
|
|
3036
|
-
await
|
|
3203
|
+
await fs13.writeFile(absolutePath, docxBuffer);
|
|
3037
3204
|
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
3038
3205
|
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
3039
3206
|
} catch (err) {
|
|
@@ -3100,8 +3267,8 @@ var init_search_keyword = __esm({
|
|
|
3100
3267
|
});
|
|
3101
3268
|
|
|
3102
3269
|
// src/utils/settings.js
|
|
3103
|
-
import
|
|
3104
|
-
import
|
|
3270
|
+
import fs14 from "fs-extra";
|
|
3271
|
+
import path13 from "path";
|
|
3105
3272
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
3106
3273
|
var init_settings = __esm({
|
|
3107
3274
|
"src/utils/settings.js"() {
|
|
@@ -3143,7 +3310,7 @@ var init_settings = __esm({
|
|
|
3143
3310
|
loadSettings = async () => {
|
|
3144
3311
|
let settingsObj = { ...DEFAULT_SETTINGS };
|
|
3145
3312
|
try {
|
|
3146
|
-
if (await
|
|
3313
|
+
if (await fs14.exists(SETTINGS_FILE)) {
|
|
3147
3314
|
const saved = readAesEncryptedJson(SETTINGS_FILE);
|
|
3148
3315
|
if (saved.imageSettings && saved.imageSettings.apiKey) {
|
|
3149
3316
|
try {
|
|
@@ -3188,12 +3355,12 @@ var init_settings = __esm({
|
|
|
3188
3355
|
const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
3189
3356
|
const folders = ["logs", "secret"];
|
|
3190
3357
|
for (const folder of folders) {
|
|
3191
|
-
const src =
|
|
3192
|
-
const dest =
|
|
3358
|
+
const src = path13.join(FLUXFLOW_DIR2, folder);
|
|
3359
|
+
const dest = path13.join(newPath, folder);
|
|
3193
3360
|
try {
|
|
3194
|
-
if (await
|
|
3195
|
-
await
|
|
3196
|
-
await
|
|
3361
|
+
if (await fs14.exists(src)) {
|
|
3362
|
+
await fs14.ensureDir(dest);
|
|
3363
|
+
await fs14.copy(src, dest, { overwrite: true });
|
|
3197
3364
|
}
|
|
3198
3365
|
} catch (err) {
|
|
3199
3366
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -3219,7 +3386,7 @@ var init_settings = __esm({
|
|
|
3219
3386
|
if (updated.imageSettings) {
|
|
3220
3387
|
updated.imageSettings = { ...updated.imageSettings, apiKey: "" };
|
|
3221
3388
|
}
|
|
3222
|
-
await
|
|
3389
|
+
await fs14.ensureDir(path13.dirname(SETTINGS_FILE));
|
|
3223
3390
|
writeAesEncryptedJson(SETTINGS_FILE, updated);
|
|
3224
3391
|
return true;
|
|
3225
3392
|
} catch (err) {
|
|
@@ -3239,8 +3406,8 @@ var init_fallback_key = __esm({
|
|
|
3239
3406
|
});
|
|
3240
3407
|
|
|
3241
3408
|
// src/tools/generate_image.js
|
|
3242
|
-
import
|
|
3243
|
-
import
|
|
3409
|
+
import fs15 from "fs-extra";
|
|
3410
|
+
import path14 from "path";
|
|
3244
3411
|
var injectPngMetadata, generate_image;
|
|
3245
3412
|
var init_generate_image = __esm({
|
|
3246
3413
|
"src/tools/generate_image.js"() {
|
|
@@ -3248,6 +3415,7 @@ var init_generate_image = __esm({
|
|
|
3248
3415
|
init_settings();
|
|
3249
3416
|
init_usage();
|
|
3250
3417
|
init_fallback_key();
|
|
3418
|
+
init_revert();
|
|
3251
3419
|
injectPngMetadata = (buffer, metadata = {}) => {
|
|
3252
3420
|
try {
|
|
3253
3421
|
if (buffer.length < 8 || buffer[0] !== 137 || buffer[1] !== 80 || buffer[2] !== 78 || buffer[3] !== 71) {
|
|
@@ -3419,9 +3587,10 @@ var init_generate_image = __esm({
|
|
|
3419
3587
|
"Seed": String(seed)
|
|
3420
3588
|
};
|
|
3421
3589
|
finalBuffer = injectPngMetadata(finalBuffer, metadata);
|
|
3422
|
-
const absolutePath =
|
|
3423
|
-
await
|
|
3424
|
-
await
|
|
3590
|
+
const absolutePath = path14.resolve(process.cwd(), outputPath);
|
|
3591
|
+
await fs15.ensureDir(path14.dirname(absolutePath));
|
|
3592
|
+
await RevertManager.recordFileChange(absolutePath);
|
|
3593
|
+
await fs15.writeFile(absolutePath, finalBuffer);
|
|
3425
3594
|
await recordImageGeneration(settings);
|
|
3426
3595
|
return `SUCCESS: Image successfully generated from prompt [${prompt}] and saved to [${outputPath}].`;
|
|
3427
3596
|
} catch (err) {
|
|
@@ -3590,8 +3759,8 @@ var init_tools = __esm({
|
|
|
3590
3759
|
|
|
3591
3760
|
// src/utils/ai.js
|
|
3592
3761
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
3593
|
-
import
|
|
3594
|
-
import
|
|
3762
|
+
import path15 from "path";
|
|
3763
|
+
import fs16 from "fs";
|
|
3595
3764
|
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, consolidatePastMemories, getAIStream;
|
|
3596
3765
|
var init_ai = __esm({
|
|
3597
3766
|
"src/utils/ai.js"() {
|
|
@@ -3603,6 +3772,7 @@ var init_ai = __esm({
|
|
|
3603
3772
|
init_arg_parser();
|
|
3604
3773
|
init_terminal();
|
|
3605
3774
|
init_paths();
|
|
3775
|
+
init_revert();
|
|
3606
3776
|
client = null;
|
|
3607
3777
|
TERMINATION_SIGNAL = false;
|
|
3608
3778
|
signalTermination = () => {
|
|
@@ -3627,7 +3797,7 @@ var init_ai = __esm({
|
|
|
3627
3797
|
try {
|
|
3628
3798
|
const pArgs = parseArgs(argsStr);
|
|
3629
3799
|
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
3630
|
-
return filePath ?
|
|
3800
|
+
return filePath ? path15.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
|
|
3631
3801
|
} catch (e) {
|
|
3632
3802
|
return null;
|
|
3633
3803
|
}
|
|
@@ -3754,16 +3924,15 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3754
3924
|
}
|
|
3755
3925
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
3756
3926
|
const result = await dispatchTool(toolName, janitorToolCall.args, toolContext);
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3927
|
+
if (toolName.toLowerCase() === "memory") {
|
|
3928
|
+
const isUserAction = janitorToolCall.args.includes("action='user'") || janitorToolCall.args.includes('action="user"');
|
|
3929
|
+
if (isUserAction && !result.startsWith("ERROR")) {
|
|
3930
|
+
if (onMemoryUpdated) onMemoryUpdated();
|
|
3931
|
+
if (process.stdout.isTTY) {
|
|
3932
|
+
process.stdout.write(`\x1B]0;Memory Updated\x07`);
|
|
3933
|
+
}
|
|
3934
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3765
3935
|
}
|
|
3766
|
-
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3767
3936
|
}
|
|
3768
3937
|
}
|
|
3769
3938
|
if (!scoreToolCalled) {
|
|
@@ -3795,9 +3964,9 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3795
3964
|
process.stdout.write(`\x1B]0;Finalizing Error\x07`);
|
|
3796
3965
|
}
|
|
3797
3966
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3798
|
-
const janitorErrDir =
|
|
3799
|
-
if (!
|
|
3800
|
-
|
|
3967
|
+
const janitorErrDir = path15.join(LOGS_DIR, "janitor");
|
|
3968
|
+
if (!fs16.existsSync(janitorErrDir)) fs16.mkdirSync(janitorErrDir, { recursive: true });
|
|
3969
|
+
fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
|
|
3801
3970
|
|
|
3802
3971
|
`);
|
|
3803
3972
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -3806,8 +3975,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3806
3975
|
}
|
|
3807
3976
|
}
|
|
3808
3977
|
if (attempts) {
|
|
3809
|
-
const janitorErrDir =
|
|
3810
|
-
|
|
3978
|
+
const janitorErrDir = path15.join(LOGS_DIR, "janitor");
|
|
3979
|
+
fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
3811
3980
|
|
|
3812
3981
|
|
|
3813
3982
|
`);
|
|
@@ -4108,10 +4277,10 @@ ${newMemoryListStr}
|
|
|
4108
4277
|
}
|
|
4109
4278
|
}
|
|
4110
4279
|
} catch (err) {
|
|
4111
|
-
const janitorLogDir =
|
|
4112
|
-
if (!
|
|
4113
|
-
|
|
4114
|
-
|
|
4280
|
+
const janitorLogDir = path15.join(LOGS_DIR, "janitor");
|
|
4281
|
+
if (!fs16.existsSync(janitorLogDir)) fs16.mkdirSync(janitorLogDir, { recursive: true });
|
|
4282
|
+
fs16.appendFileSync(
|
|
4283
|
+
path15.join(janitorLogDir, "error.log"),
|
|
4115
4284
|
`[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${err.message}
|
|
4116
4285
|
`
|
|
4117
4286
|
);
|
|
@@ -4125,340 +4294,322 @@ ${newMemoryListStr}
|
|
|
4125
4294
|
const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
|
|
4126
4295
|
const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
|
|
4127
4296
|
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..." };
|
|
4297
|
+
let agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
|
|
4298
|
+
agentText = agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
|
|
4299
|
+
await RevertManager.startTransaction(chatId, agentText);
|
|
4300
|
+
try {
|
|
4301
|
+
let modifiedHistory = [...history.slice(0, -1)];
|
|
4302
|
+
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 254e3) {
|
|
4303
|
+
modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
|
|
4166
4304
|
}
|
|
4167
|
-
if (
|
|
4168
|
-
yield { type: "status", content: "
|
|
4169
|
-
await
|
|
4170
|
-
break;
|
|
4305
|
+
if (isFirstPrompt && isMemoryEnabled) {
|
|
4306
|
+
yield { type: "status", content: "Condensing past chat memories..." };
|
|
4307
|
+
await consolidatePastMemories(chatId, settings);
|
|
4171
4308
|
}
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4309
|
+
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
4310
|
+
const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
4311
|
+
const otherRawMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems);
|
|
4312
|
+
const cachedSummaries = Object.entries(cacheStorage).filter(([id]) => id !== chatId).slice(-20).map(([id, summary]) => `[Chat Summary]: ${summary}`);
|
|
4313
|
+
const otherMemories = [...cachedSummaries, ...otherRawMemories].map((mem) => `- ${mem}`).join("\n");
|
|
4314
|
+
const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
|
|
4315
|
+
const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
|
|
4316
|
+
const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
|
|
4317
|
+
const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
|
|
4318
|
+
const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", hour12: true });
|
|
4319
|
+
const firstUserMsg = `${memoryPrompt}
|
|
4320
|
+
[METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v${versionFluxflow2}
|
|
4321
|
+
${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();
|
|
4322
|
+
modifiedHistory.push({ role: "user", text: firstUserMsg });
|
|
4323
|
+
let lastUsage = null;
|
|
4324
|
+
const MAX_LOOPS = mode === "Flux" ? 70 : 7;
|
|
4325
|
+
const MAX_RETRIES = 16;
|
|
4326
|
+
yield { type: "status", content: "Connecting..." };
|
|
4327
|
+
TERMINATION_SIGNAL = false;
|
|
4328
|
+
let fullAgentResponseChunks = [];
|
|
4329
|
+
let wasToolCalledInLastLoop = false;
|
|
4330
|
+
modifiedHistory.forEach((msg) => {
|
|
4331
|
+
if (msg.text && msg.role === "agent") {
|
|
4332
|
+
msg.text = msg.text.replace(/<(think|thought)>[\s\S]*?<\/(think|thought)>/gi, "").trim();
|
|
4333
|
+
}
|
|
4334
|
+
});
|
|
4335
|
+
for (let loop = 0; loop <= MAX_LOOPS; loop++) {
|
|
4336
|
+
if (loop > 0) {
|
|
4337
|
+
yield { type: "status", content: "Processed. Reconnecting..." };
|
|
4338
|
+
}
|
|
4339
|
+
if (TERMINATION_SIGNAL) {
|
|
4340
|
+
yield { type: "status", content: "Termination Signal Received." };
|
|
4341
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
4342
|
+
break;
|
|
4343
|
+
}
|
|
4344
|
+
if (steeringCallback) {
|
|
4345
|
+
const hint = await steeringCallback();
|
|
4346
|
+
if (hint) {
|
|
4347
|
+
if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "user") {
|
|
4348
|
+
modifiedHistory[modifiedHistory.length - 1].text += `
|
|
4177
4349
|
|
|
4178
4350
|
[STEERING HINT]: ${hint}`;
|
|
4179
|
-
|
|
4180
|
-
|
|
4351
|
+
} else {
|
|
4352
|
+
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}` });
|
|
4353
|
+
}
|
|
4354
|
+
yield { type: "status", content: "Steering Hint Injected." };
|
|
4181
4355
|
}
|
|
4182
|
-
yield { type: "status", content: "Steering Hint Injected." };
|
|
4183
4356
|
}
|
|
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
|
-
|
|
4357
|
+
let stream;
|
|
4358
|
+
let success = false;
|
|
4359
|
+
let retryCount = 1;
|
|
4360
|
+
let inStreamRetryCount = 1;
|
|
4361
|
+
let turnText = "";
|
|
4362
|
+
let lastToolSniffed = null;
|
|
4363
|
+
let lastToolDetail = null;
|
|
4364
|
+
let lastToolEventTime = null;
|
|
4365
|
+
let lastToolFinishedAt = 0;
|
|
4366
|
+
let toolResults = [];
|
|
4367
|
+
let toolCallPointer = 0;
|
|
4368
|
+
let anyToolExecutedInThisTurn = false;
|
|
4369
|
+
let isThinkingLoop = false;
|
|
4370
|
+
let isStutteringLoop = false;
|
|
4371
|
+
let isGeneralLoop = false;
|
|
4372
|
+
let isInitialAttempt = true;
|
|
4373
|
+
let accumulatedContext = "";
|
|
4374
|
+
let dedupeBuffer = "";
|
|
4375
|
+
let isDedupeActive = false;
|
|
4376
|
+
while (retryCount <= MAX_RETRIES && inStreamRetryCount <= MAX_RETRIES && !success && !TERMINATION_SIGNAL) {
|
|
4377
|
+
try {
|
|
4378
|
+
turnText = "";
|
|
4379
|
+
if (isInitialAttempt) {
|
|
4380
|
+
if (process.stdout.isTTY) {
|
|
4381
|
+
process.stdout.write(`\x1B]0;Working...\x07`);
|
|
4382
|
+
}
|
|
4383
|
+
yield { type: "turn_reset", content: true };
|
|
4384
|
+
yield { type: "spinner", content: true };
|
|
4385
|
+
isInitialAttempt = false;
|
|
4386
|
+
if (inStreamRetryCount === 1) {
|
|
4387
|
+
accumulatedContext = "";
|
|
4388
|
+
}
|
|
4210
4389
|
}
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4390
|
+
const contents = modifiedHistory.filter((msg) => (msg.role === "user" || msg.role === "agent" || msg.role === "system") && !String(msg.id).startsWith("welcome") && !msg.isMeta).map((msg) => {
|
|
4391
|
+
const parts = [{ text: msg.text }];
|
|
4392
|
+
if (msg.binaryPart) {
|
|
4393
|
+
parts.push(msg.binaryPart);
|
|
4394
|
+
}
|
|
4395
|
+
return {
|
|
4396
|
+
role: msg.role === "user" || msg.role === "system" ? "user" : "model",
|
|
4397
|
+
parts
|
|
4398
|
+
};
|
|
4399
|
+
});
|
|
4400
|
+
if (!await checkQuota("agent", settings)) {
|
|
4401
|
+
throw new Error("Error: Daily Quota Exausted for Agent");
|
|
4216
4402
|
}
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4403
|
+
let targetModel = modelName;
|
|
4404
|
+
if (retryCount === MAX_RETRIES - 1) {
|
|
4405
|
+
targetModel = "gemini-3-flash-preview";
|
|
4406
|
+
yield { type: "model_update", content: "Trying with fallback model" };
|
|
4407
|
+
} else if (retryCount === MAX_RETRIES) {
|
|
4408
|
+
targetModel = "gemini-3.5-flash";
|
|
4409
|
+
yield { type: "model_update", content: "Trying with fallback model" };
|
|
4410
|
+
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
4411
|
+
targetModel = "gemma-4-31b-it";
|
|
4412
|
+
yield { type: "model_update", content: "Trying with fallback Gemma Model" };
|
|
4413
|
+
} else if (retryCount > 0) {
|
|
4414
|
+
yield { type: "model_update", content: null };
|
|
4222
4415
|
}
|
|
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 = `
|
|
4416
|
+
const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
|
|
4417
|
+
const jitInstruction = `
|
|
4246
4418
|
|
|
4247
4419
|
[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
|
-
|
|
4420
|
+
const lastUserMsg = contents[contents.length - 1];
|
|
4421
|
+
let addedMarker = false;
|
|
4422
|
+
if (lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text?.startsWith("[TOOL RESULT]")) {
|
|
4423
|
+
lastUserMsg.parts[0].text += jitInstruction;
|
|
4424
|
+
addedMarker = true;
|
|
4425
|
+
}
|
|
4426
|
+
const stepThreshold = Math.floor(MAX_LOOPS * (mode === "Flux" ? 0.95 : 0.7));
|
|
4427
|
+
const currentStep = loop + 1;
|
|
4428
|
+
if (currentStep >= stepThreshold && lastUserMsg && lastUserMsg.parts?.[0]) {
|
|
4429
|
+
lastUserMsg.parts[0].text += `
|
|
4258
4430
|
[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
4431
|
}
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4432
|
+
stream = await client.models.generateContentStream({
|
|
4433
|
+
model: targetModel || "gemma-4-31b-it",
|
|
4434
|
+
contents,
|
|
4435
|
+
config: {
|
|
4436
|
+
systemInstruction: currentSystemInstruction,
|
|
4437
|
+
temperature: mode === "Flux" ? 1 : 1.4,
|
|
4438
|
+
maxOutputTokens: 32768,
|
|
4439
|
+
mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
|
|
4440
|
+
safetySettings: [
|
|
4441
|
+
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4442
|
+
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4443
|
+
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4444
|
+
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
4445
|
+
],
|
|
4446
|
+
thinkingConfig: { includeThoughts: false, thinkingLevel: targetModel.includes("pro") ? ThinkingLevel.HIGH : ThinkingLevel.MINIMAL }
|
|
4447
|
+
}
|
|
4448
|
+
});
|
|
4449
|
+
if (addedMarker && contents[contents.length - 1]?.parts?.[0]) {
|
|
4450
|
+
contents[contents.length - 1].parts[0].text = contents[contents.length - 1].parts[0].text.replace(jitInstruction, "").trim();
|
|
4294
4451
|
}
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4452
|
+
turnText = "";
|
|
4453
|
+
lastToolSniffed = null;
|
|
4454
|
+
lastToolEventTime = null;
|
|
4455
|
+
toolResults = [];
|
|
4456
|
+
toolCallPointer = 0;
|
|
4457
|
+
yield { type: "model_update", content: null };
|
|
4458
|
+
yield { type: "status", content: "Working..." };
|
|
4459
|
+
dedupeBuffer = "";
|
|
4460
|
+
isDedupeActive = accumulatedContext.length > 0;
|
|
4461
|
+
for await (const chunk of stream) {
|
|
4462
|
+
if (TERMINATION_SIGNAL) {
|
|
4463
|
+
yield { type: "status", content: "Termination Signal Received." };
|
|
4464
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4465
|
+
break;
|
|
4466
|
+
}
|
|
4467
|
+
if (chunk.text) {
|
|
4468
|
+
if (isDedupeActive) {
|
|
4469
|
+
dedupeBuffer += chunk.text;
|
|
4470
|
+
if (dedupeBuffer.length >= 30) {
|
|
4471
|
+
let overlapLen = 0;
|
|
4472
|
+
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4473
|
+
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4474
|
+
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4475
|
+
overlapLen = len;
|
|
4476
|
+
break;
|
|
4477
|
+
}
|
|
4305
4478
|
}
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4479
|
+
const cleanText = dedupeBuffer.substring(overlapLen);
|
|
4480
|
+
if (cleanText) {
|
|
4481
|
+
const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
|
|
4482
|
+
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, "");
|
|
4483
|
+
if (dedupeClean) {
|
|
4484
|
+
turnText += dedupeClean;
|
|
4485
|
+
yield { type: "text", content: dedupeClean };
|
|
4486
|
+
}
|
|
4314
4487
|
}
|
|
4488
|
+
isDedupeActive = false;
|
|
4489
|
+
dedupeBuffer = "";
|
|
4315
4490
|
}
|
|
4316
|
-
|
|
4317
|
-
|
|
4491
|
+
continue;
|
|
4492
|
+
} else {
|
|
4493
|
+
turnText += chunk.text;
|
|
4494
|
+
yield { type: "text", content: chunk.text };
|
|
4318
4495
|
}
|
|
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, "/"));
|
|
4496
|
+
const signalSafeText3 = getSanitizedText(turnText);
|
|
4497
|
+
const toolContext = getActiveToolContext(turnText);
|
|
4498
|
+
if (toolContext.inside) {
|
|
4499
|
+
if (!lastToolEventTime) lastToolEventTime = Date.now();
|
|
4500
|
+
const rawToolName = toolContext.toolName;
|
|
4501
|
+
const NORMALIZE_MAP = {
|
|
4502
|
+
"Ask": "ask",
|
|
4503
|
+
"WebSearch": "web_search",
|
|
4504
|
+
"WebScrape": "web_scrape",
|
|
4505
|
+
"ReadFile": "view_file",
|
|
4506
|
+
"ReadFolder": "read_folder",
|
|
4507
|
+
"WriteFile": "write_file",
|
|
4508
|
+
"PatchFile": "update_file",
|
|
4509
|
+
"WritePDF": "write_pdf",
|
|
4510
|
+
"WriteDoc": "write_docx",
|
|
4511
|
+
"Run": "exec_command",
|
|
4512
|
+
"SearchKeyword": "search_keyword",
|
|
4513
|
+
"Memory": "memory",
|
|
4514
|
+
"Chat": "chat",
|
|
4515
|
+
"chat": "chat",
|
|
4516
|
+
"GenerateImage": "generate_image",
|
|
4517
|
+
"generate_image": "generate_image"
|
|
4518
|
+
};
|
|
4519
|
+
const potentialTool = NORMALIZE_MAP[rawToolName] || rawToolName;
|
|
4520
|
+
const partialArgs = toolContext.args || "";
|
|
4521
|
+
let detail = null;
|
|
4522
|
+
if (["write_file", "update_file", "view_file", "read_folder", "write_pdf", "write_docx", "search_keyword", "generate_image"].includes(potentialTool)) {
|
|
4523
|
+
const pArgs = parseArgs(partialArgs);
|
|
4524
|
+
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
4525
|
+
const keyword = pArgs.keyword;
|
|
4526
|
+
if (keyword) {
|
|
4527
|
+
detail = keyword.replace(/["']/g, "");
|
|
4528
|
+
} else if (filePath) {
|
|
4529
|
+
detail = path15.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
|
|
4530
|
+
} else {
|
|
4531
|
+
const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
|
|
4532
|
+
if (m) {
|
|
4533
|
+
const val = m[1].replace(/["']/g, "");
|
|
4534
|
+
detail = potentialTool === "search_keyword" ? val : path15.basename(val.replace(/\\/g, "/"));
|
|
4535
|
+
}
|
|
4363
4536
|
}
|
|
4364
4537
|
}
|
|
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;
|
|
4538
|
+
const currentLabel = `${TOOL_LABELS2[potentialTool] || potentialTool}${detail ? ` (${detail})` : ""}`;
|
|
4539
|
+
if (potentialTool !== lastToolSniffed || detail !== lastToolDetail) {
|
|
4540
|
+
lastToolSniffed = potentialTool;
|
|
4541
|
+
lastToolDetail = detail;
|
|
4542
|
+
yield { type: "status", content: `${currentLabel}...` };
|
|
4543
|
+
if (process.stdout.isTTY) {
|
|
4544
|
+
const TOOL_TITLES = {
|
|
4545
|
+
"web_search": "Searching Web",
|
|
4546
|
+
"web_scrape": "Reading Website",
|
|
4547
|
+
"view_file": "Reading File",
|
|
4548
|
+
"read_folder": "Listing Folder",
|
|
4549
|
+
"list_files": "Listing Folder",
|
|
4550
|
+
"write_file": "Writing File",
|
|
4551
|
+
"update_file": "Updating File",
|
|
4552
|
+
"write_pdf": "Creating PDF",
|
|
4553
|
+
"write_docx": "Creating Word Doc",
|
|
4554
|
+
"search_keyword": "Searching Keywords",
|
|
4555
|
+
"exec_command": "Running Command",
|
|
4556
|
+
"ask": "Asking User",
|
|
4557
|
+
"memory": "Updating Memory",
|
|
4558
|
+
"generate_image": "Generating Image"
|
|
4559
|
+
};
|
|
4560
|
+
const toolTitle = TOOL_TITLES[potentialTool] || "Working";
|
|
4561
|
+
process.stdout.write(`\x1B]0;${toolTitle}...\x07`);
|
|
4443
4562
|
}
|
|
4444
4563
|
}
|
|
4445
|
-
if (isRepeating) {
|
|
4446
|
-
stutterDetected = true;
|
|
4447
|
-
break;
|
|
4448
|
-
}
|
|
4449
4564
|
}
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
const
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4565
|
+
const contextSafeText = getContextSafeText(turnText, false);
|
|
4566
|
+
const thinkBlocks = contextSafeText.match(/<think>([\s\S]*?)(?:<\/think>|$)/gi) || [];
|
|
4567
|
+
const thinkContent = thinkBlocks.join("").trim();
|
|
4568
|
+
const sentences = thinkContent.split(/[.!?]\s+/);
|
|
4569
|
+
const uniqueSentences = new Set(sentences);
|
|
4570
|
+
const repetitionRatio = sentences.length > 10 ? (sentences.length - uniqueSentences.size) / sentences.length : 0;
|
|
4571
|
+
const wordCount = thinkContent.split(/\s+/).filter((w) => w.length > 0).length;
|
|
4572
|
+
let repetitionThresholdThinking = 0.4;
|
|
4573
|
+
let repetitionThresholdResponse = 0.6;
|
|
4574
|
+
const thinkingCaps = {
|
|
4575
|
+
"low": 200,
|
|
4576
|
+
"medium": 500,
|
|
4577
|
+
"high": 2e3,
|
|
4578
|
+
"max": 3500,
|
|
4579
|
+
"xhigh": 3500
|
|
4580
|
+
};
|
|
4581
|
+
const cap = thinkingCaps[thinkingLevel?.toLowerCase()] || 2500;
|
|
4582
|
+
let isOverVerboseThinking = wordCount > cap;
|
|
4583
|
+
if (repetitionRatio > repetitionThresholdThinking || isOverVerboseThinking) {
|
|
4584
|
+
const reason = repetitionRatio > repetitionThresholdThinking ? "Thinking Loop Detected" : "Thinking Budget Exceeded";
|
|
4585
|
+
yield { type: "status", content: `${reason}. Re-centering...` };
|
|
4586
|
+
isThinkingLoop = true;
|
|
4587
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4588
|
+
break;
|
|
4589
|
+
}
|
|
4590
|
+
const responseContent = signalSafeText3.trim();
|
|
4591
|
+
const respSentences = responseContent.split(/[.!?]\s+/);
|
|
4592
|
+
const uniqueRespSentences = new Set(respSentences);
|
|
4593
|
+
const respRepetitionRatio = respSentences.length > 10 ? (respSentences.length - uniqueRespSentences.size) / respSentences.length : 0;
|
|
4594
|
+
if (respRepetitionRatio > repetitionThresholdResponse) {
|
|
4595
|
+
yield { type: "status", content: `Response Loop Detected. Re-centering...` };
|
|
4596
|
+
isThinkingLoop = false;
|
|
4597
|
+
isGeneralLoop = true;
|
|
4598
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4599
|
+
break;
|
|
4600
|
+
}
|
|
4601
|
+
const allWords = contextSafeText.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
|
|
4602
|
+
let stutterDetected = false;
|
|
4603
|
+
if (allWords.length > 5) {
|
|
4604
|
+
for (let p = 1; p <= 15; p++) {
|
|
4605
|
+
const R = Math.max(3, Math.ceil(8 / p));
|
|
4606
|
+
if (allWords.length < p * R) continue;
|
|
4458
4607
|
let isRepeating = true;
|
|
4608
|
+
const pattern = allWords.slice(allWords.length - p);
|
|
4609
|
+
const patternStr = pattern.join(" ");
|
|
4459
4610
|
for (let r = 1; r < R; r++) {
|
|
4460
|
-
const prevPattern =
|
|
4461
|
-
if (prevPattern !==
|
|
4611
|
+
const prevPattern = allWords.slice(allWords.length - p * (r + 1), allWords.length - p * r);
|
|
4612
|
+
if (prevPattern.join(" ") !== patternStr) {
|
|
4462
4613
|
isRepeating = false;
|
|
4463
4614
|
break;
|
|
4464
4615
|
}
|
|
@@ -4469,400 +4620,424 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CORE
|
|
|
4469
4620
|
}
|
|
4470
4621
|
}
|
|
4471
4622
|
}
|
|
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);
|
|
4623
|
+
if (!stutterDetected) {
|
|
4624
|
+
const cleanChars = contextSafeText.toLowerCase().replace(/[^a-z0-9]/gi, "");
|
|
4625
|
+
if (cleanChars.length >= 10) {
|
|
4626
|
+
for (let p = 1; p <= 10; p++) {
|
|
4627
|
+
const R = Math.max(4, Math.ceil(12 / p));
|
|
4628
|
+
if (cleanChars.length < p * R) continue;
|
|
4629
|
+
const pattern = cleanChars.substring(cleanChars.length - p);
|
|
4630
|
+
let isRepeating = true;
|
|
4631
|
+
for (let r = 1; r < R; r++) {
|
|
4632
|
+
const prevPattern = cleanChars.substring(cleanChars.length - p * (r + 1), cleanChars.length - p * r);
|
|
4633
|
+
if (prevPattern !== pattern) {
|
|
4634
|
+
isRepeating = false;
|
|
4635
|
+
break;
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
if (isRepeating) {
|
|
4639
|
+
stutterDetected = true;
|
|
4640
|
+
break;
|
|
4641
|
+
}
|
|
4528
4642
|
}
|
|
4529
|
-
} catch (e) {
|
|
4530
4643
|
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4644
|
+
}
|
|
4645
|
+
if (stutterDetected) {
|
|
4646
|
+
yield { type: "status", content: `Stuttering Detected. Re-centering...` };
|
|
4647
|
+
isThinkingLoop = false;
|
|
4648
|
+
isStutteringLoop = true;
|
|
4649
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4650
|
+
break;
|
|
4651
|
+
}
|
|
4652
|
+
const toolActionableText = turnText.replace(/<think>[\s\S]*?(?:<\/think>|$)/gi, "");
|
|
4653
|
+
const allToolsFound = detectToolCalls(toolActionableText);
|
|
4654
|
+
while (allToolsFound.length > toolCallPointer) {
|
|
4655
|
+
const toolCall = allToolsFound[toolCallPointer];
|
|
4656
|
+
const NORMALIZE_MAP = {
|
|
4657
|
+
"Ask": "ask",
|
|
4658
|
+
"WebSearch": "web_search",
|
|
4659
|
+
"WebScrape": "web_scrape",
|
|
4660
|
+
"ReadFile": "view_file",
|
|
4661
|
+
"ReadFolder": "read_folder",
|
|
4662
|
+
"WriteFile": "write_file",
|
|
4663
|
+
"PatchFile": "update_file",
|
|
4664
|
+
"WritePDF": "write_pdf",
|
|
4665
|
+
"WriteDoc": "write_docx",
|
|
4666
|
+
"Run": "exec_command",
|
|
4667
|
+
"SearchKeyword": "search_keyword",
|
|
4668
|
+
"Memory": "memory",
|
|
4669
|
+
"Chat": "chat",
|
|
4670
|
+
"chat": "chat",
|
|
4671
|
+
"GenerateImage": "generate_image",
|
|
4672
|
+
"generate_image": "generate_image"
|
|
4673
|
+
};
|
|
4674
|
+
const normToolName = NORMALIZE_MAP[toolCall.toolName] || toolCall.toolName;
|
|
4675
|
+
const displayLabel = TOOL_LABELS2[normToolName] || toolCall.toolName;
|
|
4676
|
+
const detail = getToolDetail(normToolName, toolCall.args);
|
|
4677
|
+
yield { type: "status", content: `${displayLabel}${detail ? ` (${detail})` : ""}...` };
|
|
4678
|
+
let label = "";
|
|
4679
|
+
if (normToolName === "web_search") {
|
|
4680
|
+
const { query, limit = 10 } = parseArgs(toolCall.args);
|
|
4681
|
+
label = `\u{1F50D} SEARCHED: "${query}" (${limit})`.toUpperCase();
|
|
4682
|
+
} else if (normToolName === "web_scrape") {
|
|
4683
|
+
const url = parseArgs(toolCall.args).url || "...";
|
|
4684
|
+
label = `\u{1F4D6} READ SITE: ${url}`.toUpperCase();
|
|
4685
|
+
} else if (normToolName === "view_file") {
|
|
4686
|
+
const { path: targetPath2, StartLine, EndLine, start_line, end_line } = parseArgs(toolCall.args);
|
|
4687
|
+
const rawStart = StartLine || start_line;
|
|
4688
|
+
const rawEnd = EndLine || end_line;
|
|
4689
|
+
const sLine = parseInt(rawStart) || 1;
|
|
4690
|
+
const eLine = parseInt(rawEnd) || (rawStart ? sLine + 800 : 800);
|
|
4691
|
+
let totalLines = "...";
|
|
4692
|
+
let actualEndLine = eLine;
|
|
4693
|
+
try {
|
|
4694
|
+
const absPath = path15.resolve(process.cwd(), targetPath2);
|
|
4695
|
+
if (fs16.existsSync(absPath)) {
|
|
4696
|
+
const content = fs16.readFileSync(absPath, "utf8");
|
|
4697
|
+
const lines = content.split("\n").length;
|
|
4698
|
+
totalLines = lines;
|
|
4699
|
+
actualEndLine = Math.min(eLine, lines);
|
|
4700
|
+
}
|
|
4701
|
+
} catch (e) {
|
|
4702
|
+
}
|
|
4703
|
+
const pathLower = targetPath2.toLowerCase();
|
|
4704
|
+
const isPdf = pathLower.endsWith(".pdf");
|
|
4705
|
+
const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
|
|
4706
|
+
if (isPdf) {
|
|
4707
|
+
label = `\u{1F4C4} ANALYZED PDF: ${targetPath2}`.toUpperCase();
|
|
4708
|
+
} else if (isImage) {
|
|
4709
|
+
label = `\u{1F4F8} ANALYZED IMAGE: ${targetPath2}`.toUpperCase();
|
|
4710
|
+
} else {
|
|
4711
|
+
label = `\u{1F4C4} ANALYZED FILE: ${targetPath2} | LINES: ${sLine}-${actualEndLine} OF ${totalLines}`.toUpperCase();
|
|
4712
|
+
}
|
|
4713
|
+
} else if (normToolName === "list_files" || normToolName === "read_folder") {
|
|
4714
|
+
const action = normToolName === "list_files" ? "LIST" : "ANALYSED";
|
|
4715
|
+
label = `\u{1F4C2} ${action} FOLDER: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
|
|
4716
|
+
} else if (normToolName === "write_file" || normToolName === "update_file") {
|
|
4717
|
+
const action = normToolName === "write_file" ? "WRITTEN" : "UPDATED FILE";
|
|
4718
|
+
label = `\u{1F4BE} ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4719
|
+
} else if (normToolName === "write_pdf") {
|
|
4720
|
+
label = `\u{1F4D1} PDF CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4721
|
+
} else if (normToolName === "write_docx") {
|
|
4722
|
+
label = `\u{1F4DD} DOCX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
4723
|
+
} else if (normToolName === "search_keyword") {
|
|
4724
|
+
const { keyword } = parseArgs(toolCall.args);
|
|
4725
|
+
label = `\u{1F50E} KEYWORD SEARCHED: "${keyword}"`.toUpperCase();
|
|
4726
|
+
} else if (normToolName === "generate_image") {
|
|
4727
|
+
const { path: argPath, outputPath, output } = parseArgs(toolCall.args);
|
|
4728
|
+
label = `\u{1F3A8} IMAGE GENERATED: ${argPath || outputPath || output || "generated_image.png"}`.toUpperCase();
|
|
4729
|
+
} else if (normToolName === "exec_command" || normToolName === "ask") {
|
|
4730
|
+
label = "";
|
|
4538
4731
|
} else {
|
|
4539
|
-
label =
|
|
4732
|
+
label = `EXECUTED: ${toolCall.toolName}`.toUpperCase();
|
|
4540
4733
|
}
|
|
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}
|
|
4734
|
+
if (label) {
|
|
4735
|
+
const boxWidth = Math.min(label.length + 4, 115);
|
|
4736
|
+
const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
|
|
4737
|
+
const boxMid = `\u2502 ${label.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`;
|
|
4738
|
+
const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
|
|
4739
|
+
yield { type: "visual_feedback", content: `${boxTop}
|
|
4568
4740
|
${boxMid}
|
|
4569
4741
|
${boxBottom}` };
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4742
|
+
}
|
|
4743
|
+
if (normToolName === "exec_command") {
|
|
4744
|
+
const { command } = parseArgs(toolCall.args);
|
|
4745
|
+
if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
|
|
4746
|
+
const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
|
|
4747
|
+
const currentDrive = path15.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
4748
|
+
const isViolating = riskyPatterns.some((pattern) => {
|
|
4749
|
+
if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
|
|
4750
|
+
const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
|
|
4751
|
+
return driveMatch && driveMatch[0].toLowerCase() !== currentDrive;
|
|
4752
|
+
}
|
|
4753
|
+
return pattern.test(command);
|
|
4754
|
+
});
|
|
4755
|
+
if (isViolating) {
|
|
4756
|
+
const denyMsg = `Access Denied. Terminal is prohibited from accessing system drives (C://) or external directories while "External Workspace Access" is disabled.`;
|
|
4757
|
+
toolResults.push({ role: "user", text: `[TOOL RESULT]: ERROR: ${denyMsg}` });
|
|
4758
|
+
yield { type: "tool_result", content: `[TOOL RESULT]: ERROR: ${denyMsg}` };
|
|
4759
|
+
toolCallPointer++;
|
|
4760
|
+
continue;
|
|
4580
4761
|
}
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4762
|
+
}
|
|
4763
|
+
if (settings.onExecStart) settings.onExecStart(command || "Unknown");
|
|
4764
|
+
yield { type: "exec_start" };
|
|
4765
|
+
}
|
|
4766
|
+
const parsedArgs = parseArgs(toolCall.args);
|
|
4767
|
+
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
4768
|
+
if (targetPath) {
|
|
4769
|
+
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
4770
|
+
const absoluteTarget = path15.resolve(targetPath);
|
|
4771
|
+
const absoluteCwd = path15.resolve(process.cwd());
|
|
4772
|
+
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
4773
|
+
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.`;
|
|
4774
|
+
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
4775
|
yield { type: "tool_result", content: `[TOOL RESULT]: ERROR: ${denyMsg}` };
|
|
4587
4776
|
toolCallPointer++;
|
|
4588
4777
|
continue;
|
|
4589
4778
|
}
|
|
4590
4779
|
}
|
|
4591
|
-
if (settings.
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4780
|
+
if (settings.onToolApproval) {
|
|
4781
|
+
let shouldPrompt = normToolName === "write_file" || normToolName === "update_file" || normToolName === "exec_command";
|
|
4782
|
+
if (shouldPrompt) {
|
|
4783
|
+
const approval = await settings.onToolApproval(normToolName, toolCall.args);
|
|
4784
|
+
if (approval === "deny") {
|
|
4785
|
+
if (normToolName === "exec_command" && settings.onExecEnd) settings.onExecEnd();
|
|
4786
|
+
const denyMsg = `Permission Denied: User rejected the ${normToolName === "exec_command" ? "terminal execution" : "file edit"}.`;
|
|
4787
|
+
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**" : ""}` });
|
|
4788
|
+
yield { type: "tool_result", content: `[TOOL RESULT]: DENIED: ${denyMsg}` };
|
|
4789
|
+
await incrementUsage("toolDenied");
|
|
4790
|
+
if (settings.onToolResult) settings.onToolResult("denied", normToolName);
|
|
4791
|
+
toolCallPointer++;
|
|
4792
|
+
continue;
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4606
4795
|
}
|
|
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;
|
|
4796
|
+
if (lastToolFinishedAt > 0) {
|
|
4797
|
+
const timeSinceLastTool = Date.now() - lastToolFinishedAt;
|
|
4798
|
+
if (timeSinceLastTool < 1e3) {
|
|
4799
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 - timeSinceLastTool));
|
|
4621
4800
|
}
|
|
4622
4801
|
}
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4802
|
+
const effectiveStart = lastToolEventTime || Date.now();
|
|
4803
|
+
yield { type: "spinner", content: false };
|
|
4804
|
+
let result = await dispatchTool(normToolName, toolCall.args, {
|
|
4805
|
+
chatId,
|
|
4806
|
+
history,
|
|
4807
|
+
onChunk: (chunk2) => settings.onExecChunk ? settings.onExecChunk(chunk2) : null,
|
|
4808
|
+
onAskUser: settings.onAskUser
|
|
4809
|
+
});
|
|
4810
|
+
yield { type: "spinner", content: true };
|
|
4811
|
+
if (process.stdout.isTTY) {
|
|
4812
|
+
process.stdout.write(`\x1B]0;Working...\x07`);
|
|
4628
4813
|
}
|
|
4814
|
+
const toolEnd = Date.now();
|
|
4815
|
+
lastToolFinishedAt = toolEnd;
|
|
4816
|
+
yield { type: "tool_time", content: toolEnd - effectiveStart };
|
|
4817
|
+
lastToolEventTime = toolEnd;
|
|
4818
|
+
let binaryPart = null;
|
|
4819
|
+
if (typeof result === "object" && result.binaryPart) {
|
|
4820
|
+
binaryPart = result.binaryPart;
|
|
4821
|
+
result = result.text;
|
|
4822
|
+
}
|
|
4823
|
+
if (normToolName === "exec_command" && settings.onExecEnd) {
|
|
4824
|
+
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
4825
|
+
settings.onExecEnd();
|
|
4826
|
+
}
|
|
4827
|
+
const isDenied = result && result.startsWith("DENIED:");
|
|
4828
|
+
const isSuccess = result && !result.startsWith("ERROR:") && !isDenied;
|
|
4829
|
+
if (isSuccess) {
|
|
4830
|
+
await incrementUsage("toolSuccess");
|
|
4831
|
+
if (settings.onToolResult) settings.onToolResult("success", normToolName);
|
|
4832
|
+
} else if (isDenied) {
|
|
4833
|
+
} else {
|
|
4834
|
+
await incrementUsage("toolFailure");
|
|
4835
|
+
if (settings.onToolResult) settings.onToolResult("failure", normToolName);
|
|
4836
|
+
}
|
|
4837
|
+
const aiContent = `[TOOL RESULT]: ${(result || "").toString().split(/\r?\n/).filter((line) => !line.includes("[UI_CONTEXT]")).join("\n")}`;
|
|
4838
|
+
toolResults.push({ role: "user", text: aiContent, binaryPart });
|
|
4839
|
+
anyToolExecutedInThisTurn = true;
|
|
4840
|
+
let uiContent = `[TOOL RESULT]: ${result || ""}`;
|
|
4841
|
+
if (normToolName === "view_file" || normToolName === "web_scrape") {
|
|
4842
|
+
uiContent = `[TOOL RESULT]: ${label} (Context Locked for UI Clarity)`;
|
|
4843
|
+
}
|
|
4844
|
+
yield { type: "tool_result", content: uiContent, aiContent, binaryPart, toolName: normToolName };
|
|
4845
|
+
if (normToolName === "memory" && result.includes("SUCCESS")) yield { type: "memory_updated" };
|
|
4846
|
+
toolCallPointer++;
|
|
4629
4847
|
}
|
|
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
4848
|
}
|
|
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;
|
|
4849
|
+
lastUsage = chunk.usageMetadata;
|
|
4850
|
+
if (lastUsage) {
|
|
4851
|
+
yield { type: "liveTokens", content: lastUsage.totalTokenCount };
|
|
4689
4852
|
}
|
|
4690
4853
|
}
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
const
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4854
|
+
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4855
|
+
let overlapLen = 0;
|
|
4856
|
+
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4857
|
+
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4858
|
+
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4859
|
+
overlapLen = len;
|
|
4860
|
+
break;
|
|
4861
|
+
}
|
|
4698
4862
|
}
|
|
4863
|
+
const cleanText = dedupeBuffer.substring(overlapLen);
|
|
4864
|
+
if (cleanText) {
|
|
4865
|
+
const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
|
|
4866
|
+
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, "");
|
|
4867
|
+
if (dedupeClean) {
|
|
4868
|
+
turnText += dedupeClean;
|
|
4869
|
+
yield { type: "text", content: dedupeClean };
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
isDedupeActive = false;
|
|
4873
|
+
dedupeBuffer = "";
|
|
4874
|
+
}
|
|
4875
|
+
if (TERMINATION_SIGNAL) break;
|
|
4876
|
+
const signalSafeText2 = (turnText || "").trim();
|
|
4877
|
+
const hasFinish2 = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
4878
|
+
const hasContinue = /\[\s*(turn\s*:)?\s*continue\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
4879
|
+
const didCallTool = toolResults.length > 0 || lastToolSniffed !== null;
|
|
4880
|
+
const pureOutputText = signalSafeText2.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
|
|
4881
|
+
const endsNormally = /[.!?}"'`’“”]$|```$/s.test(pureOutputText);
|
|
4882
|
+
if (!hasFinish2 && !hasContinue && !didCallTool && signalSafeText2.length > 0 && !endsNormally && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop) {
|
|
4883
|
+
throw new Error("Silent stream cutoff (500): Model stream closed cleanly but cut off mid-sentence without signals.");
|
|
4699
4884
|
}
|
|
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
4885
|
success = true;
|
|
4718
4886
|
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
|
-
}
|
|
4887
|
+
} catch (err) {
|
|
4888
|
+
if (String(err).includes("Incomplete JSON segment at the end")) {
|
|
4889
|
+
success = true;
|
|
4890
|
+
await incrementUsage("agent");
|
|
4891
|
+
break;
|
|
4729
4892
|
}
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
const
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4893
|
+
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
4894
|
+
let overlapLen = 0;
|
|
4895
|
+
const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
|
|
4896
|
+
for (let len = maxPossibleOverlap; len > 0; len--) {
|
|
4897
|
+
if (accumulatedContext.endsWith(dedupeBuffer.substring(0, len))) {
|
|
4898
|
+
overlapLen = len;
|
|
4899
|
+
break;
|
|
4900
|
+
}
|
|
4736
4901
|
}
|
|
4902
|
+
const cleanText = dedupeBuffer.substring(overlapLen);
|
|
4903
|
+
if (cleanText) {
|
|
4904
|
+
const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
|
|
4905
|
+
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, "");
|
|
4906
|
+
if (dedupeClean) {
|
|
4907
|
+
turnText += dedupeClean;
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
isDedupeActive = false;
|
|
4911
|
+
dedupeBuffer = "";
|
|
4737
4912
|
}
|
|
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}
|
|
4913
|
+
const errMsg = err.status || err.error && err.error.message || String(err);
|
|
4914
|
+
const errLog = String(err);
|
|
4915
|
+
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
4916
|
+
const agentErrDir = path15.join(LOGS_DIR, "agent");
|
|
4917
|
+
if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
|
|
4918
|
+
fs16.appendFileSync(path15.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
4747
4919
|
|
|
4748
4920
|
----------------------------------------------------------------------
|
|
4749
4921
|
|
|
4750
4922
|
`);
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4923
|
+
const status = err.status || err.statusCode || err.code;
|
|
4924
|
+
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)));
|
|
4925
|
+
if (!isRetryable) {
|
|
4926
|
+
if (retryCount < MAX_RETRIES - 3) {
|
|
4927
|
+
throw err;
|
|
4928
|
+
}
|
|
4756
4929
|
}
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
text: `${tr.text}
|
|
4930
|
+
if (turnText.trim().length > 0 || inStreamRetryCount > 1) {
|
|
4931
|
+
if (inStreamRetryCount <= MAX_RETRIES) {
|
|
4932
|
+
inStreamRetryCount++;
|
|
4933
|
+
const waitTime = Math.min(1e3 * Math.pow(2, inStreamRetryCount - 1), 24e3);
|
|
4934
|
+
if (turnText.trim().length > 0) {
|
|
4935
|
+
modifiedHistory.push({ role: "agent", text: turnText });
|
|
4936
|
+
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.";
|
|
4937
|
+
if (toolResults.length > 0) {
|
|
4938
|
+
toolResults.forEach((tr, idx) => {
|
|
4939
|
+
if (idx === toolResults.length - 1) {
|
|
4940
|
+
modifiedHistory.push({
|
|
4941
|
+
...tr,
|
|
4942
|
+
text: `${tr.text}
|
|
4771
4943
|
|
|
4772
4944
|
${recoveryText}`
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4945
|
+
});
|
|
4946
|
+
} else {
|
|
4947
|
+
modifiedHistory.push(tr);
|
|
4948
|
+
}
|
|
4949
|
+
});
|
|
4950
|
+
} else {
|
|
4951
|
+
modifiedHistory.push({ role: "user", text: recoveryText });
|
|
4952
|
+
}
|
|
4953
|
+
accumulatedContext += turnText;
|
|
4780
4954
|
}
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4955
|
+
for (let i = waitTime / 1e3; i > 0; i--) {
|
|
4956
|
+
yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
|
|
4957
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
4958
|
+
}
|
|
4959
|
+
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
4960
|
+
} else {
|
|
4961
|
+
throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
|
|
4962
|
+
Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4786
4963
|
}
|
|
4787
|
-
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
4788
4964
|
} else {
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4965
|
+
if (retryCount <= MAX_RETRIES) {
|
|
4966
|
+
retryCount++;
|
|
4967
|
+
inStreamRetryCount = 1;
|
|
4968
|
+
accumulatedContext = "";
|
|
4969
|
+
const waitTime = Math.min(1e3 * Math.pow(2, retryCount - 1), 32e3);
|
|
4970
|
+
isInitialAttempt = true;
|
|
4971
|
+
yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${(waitTime / 1e3).toFixed(0)}s]...` };
|
|
4972
|
+
for (let i = waitTime / 1e3; i > 0; i--) {
|
|
4973
|
+
yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${i}s]...` };
|
|
4974
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
4975
|
+
}
|
|
4976
|
+
yield { type: "status", content: `Retrying Connection...` };
|
|
4977
|
+
} else {
|
|
4978
|
+
throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
4979
|
+
Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
|
|
4803
4980
|
}
|
|
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
4981
|
}
|
|
4809
4982
|
}
|
|
4810
4983
|
}
|
|
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}
|
|
4984
|
+
if (lastUsage) {
|
|
4985
|
+
await addToUsage("tokens", lastUsage.totalTokenCount || 0);
|
|
4986
|
+
yield { type: "usage", content: lastUsage };
|
|
4987
|
+
}
|
|
4988
|
+
fullAgentResponseChunks.push(turnText);
|
|
4989
|
+
let textToProcess = turnText;
|
|
4990
|
+
const thinkMatch = turnText.match(/<think>([\s\S]*?)<\/think>/i);
|
|
4991
|
+
if (thinkMatch) {
|
|
4992
|
+
textToProcess = turnText.replace(/<think>[\s\S]*?<\/think>/i, "");
|
|
4993
|
+
}
|
|
4994
|
+
const signalSafeText = getSanitizedText(turnText);
|
|
4995
|
+
const hasFinish = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText.toLowerCase());
|
|
4996
|
+
const shouldContinue = toolCallPointer > 0;
|
|
4997
|
+
yield { type: "status", content: "Working..." };
|
|
4998
|
+
const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
|
|
4999
|
+
let isActuallyFinished = hasFinish && !shouldContinue;
|
|
5000
|
+
if (isActuallyFinished) {
|
|
5001
|
+
const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
|
|
5002
|
+
const cleanedFullResponse = fullAgentTextRaw.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
5003
|
+
yield {
|
|
5004
|
+
type: "interactive_turn_finished",
|
|
5005
|
+
data: {
|
|
5006
|
+
agentText,
|
|
5007
|
+
fullAgentTextRaw,
|
|
5008
|
+
history: [...modifiedHistory],
|
|
5009
|
+
needTitle
|
|
5010
|
+
}
|
|
5011
|
+
};
|
|
5012
|
+
const timestamp = `Responded on ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
|
|
5013
|
+
const finalWithTime = `${cleanedFullResponse}
|
|
4842
5014
|
|
|
4843
5015
|
${timestamp}`;
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5016
|
+
if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "agent") {
|
|
5017
|
+
modifiedHistory[modifiedHistory.length - 1].text = finalWithTime;
|
|
5018
|
+
} else {
|
|
5019
|
+
modifiedHistory.push({ role: "agent", text: finalWithTime });
|
|
5020
|
+
}
|
|
4848
5021
|
}
|
|
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.` });
|
|
5022
|
+
if (isActuallyFinished) break;
|
|
5023
|
+
const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
|
|
5024
|
+
modifiedHistory.push({ role: "agent", text: nextAgentMsg });
|
|
5025
|
+
if (toolResults.length > 0 || anyToolExecutedInThisTurn) {
|
|
5026
|
+
toolResults.forEach((tr) => modifiedHistory.push(tr));
|
|
4858
5027
|
} else {
|
|
4859
|
-
|
|
5028
|
+
if (wasToolCalledInLastLoop) {
|
|
5029
|
+
modifiedHistory.push({ role: "user", text: `[SYSTEM] System executed the tool with no explicit result, continue with your task or use [turn: finish] if completed.` });
|
|
5030
|
+
} else {
|
|
5031
|
+
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."}`}` });
|
|
5032
|
+
}
|
|
5033
|
+
isThinkingLoop = false;
|
|
5034
|
+
isStutteringLoop = false;
|
|
5035
|
+
isGeneralLoop = false;
|
|
4860
5036
|
}
|
|
4861
|
-
|
|
4862
|
-
isStutteringLoop = false;
|
|
4863
|
-
isGeneralLoop = false;
|
|
5037
|
+
wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
|
|
4864
5038
|
}
|
|
4865
|
-
|
|
5039
|
+
} finally {
|
|
5040
|
+
await RevertManager.commitTransaction();
|
|
4866
5041
|
}
|
|
4867
5042
|
yield { type: "status", content: null };
|
|
4868
5043
|
};
|
|
@@ -5113,11 +5288,92 @@ var init_UpdateProcessor = __esm({
|
|
|
5113
5288
|
}
|
|
5114
5289
|
});
|
|
5115
5290
|
|
|
5291
|
+
// src/components/RevertModal.jsx
|
|
5292
|
+
import React10, { useState as useState7 } from "react";
|
|
5293
|
+
import { Box as Box10, Text as Text10, useInput as useInput4 } from "ink";
|
|
5294
|
+
function RevertModal({ prompts, onSelect, onClose }) {
|
|
5295
|
+
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
5296
|
+
useInput4((input, key) => {
|
|
5297
|
+
if (key.escape) onClose();
|
|
5298
|
+
if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
5299
|
+
if (key.downArrow) setSelectedIndex((prev) => Math.min(prompts.length - 1, prev + 1));
|
|
5300
|
+
if (key.return && prompts[selectedIndex]) onSelect(prompts[selectedIndex].id);
|
|
5301
|
+
});
|
|
5302
|
+
const s = emojiSpace(2);
|
|
5303
|
+
const MAX_VISIBLE = 10;
|
|
5304
|
+
let startIndex = 0;
|
|
5305
|
+
if (prompts.length > MAX_VISIBLE) {
|
|
5306
|
+
const half = Math.floor(MAX_VISIBLE / 2);
|
|
5307
|
+
startIndex = selectedIndex - half;
|
|
5308
|
+
if (startIndex < 0) {
|
|
5309
|
+
startIndex = 0;
|
|
5310
|
+
} else if (startIndex + MAX_VISIBLE > prompts.length) {
|
|
5311
|
+
startIndex = prompts.length - MAX_VISIBLE;
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
const visiblePrompts = prompts.slice(startIndex, startIndex + MAX_VISIBLE);
|
|
5315
|
+
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) => {
|
|
5316
|
+
const actualIndex = startIndex + index;
|
|
5317
|
+
const isSelected = actualIndex === selectedIndex;
|
|
5318
|
+
const dateStr = formatDate2(p.timestamp);
|
|
5319
|
+
const fileCount = p.changes ? p.changes.length : 0;
|
|
5320
|
+
return /* @__PURE__ */ React10.createElement(
|
|
5321
|
+
Box10,
|
|
5322
|
+
{
|
|
5323
|
+
key: p.id,
|
|
5324
|
+
paddingX: 1,
|
|
5325
|
+
backgroundColor: isSelected ? "#1a2a3a" : void 0,
|
|
5326
|
+
width: "100%"
|
|
5327
|
+
},
|
|
5328
|
+
/* @__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]")))
|
|
5329
|
+
);
|
|
5330
|
+
}), 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(
|
|
5331
|
+
Box10,
|
|
5332
|
+
{
|
|
5333
|
+
marginTop: 1,
|
|
5334
|
+
paddingX: 1,
|
|
5335
|
+
borderStyle: "single",
|
|
5336
|
+
borderLeft: false,
|
|
5337
|
+
borderRight: false,
|
|
5338
|
+
borderBottom: false,
|
|
5339
|
+
borderColor: "cyan"
|
|
5340
|
+
},
|
|
5341
|
+
/* @__PURE__ */ React10.createElement(Text10, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 Enter select undo point \u2022 Esc close")
|
|
5342
|
+
));
|
|
5343
|
+
}
|
|
5344
|
+
function formatPromptPreview(prompt) {
|
|
5345
|
+
if (!prompt) return "";
|
|
5346
|
+
const firstLine = prompt.split("\n")[0] || "";
|
|
5347
|
+
const words = firstLine.split(/\s+/).filter(Boolean);
|
|
5348
|
+
if (words.length > 50) {
|
|
5349
|
+
return words.slice(0, 50).join(" ") + "...";
|
|
5350
|
+
}
|
|
5351
|
+
if (prompt.includes("\n")) {
|
|
5352
|
+
return firstLine + "...";
|
|
5353
|
+
}
|
|
5354
|
+
return firstLine;
|
|
5355
|
+
}
|
|
5356
|
+
function formatDate2(timestamp) {
|
|
5357
|
+
if (!timestamp) return "N/A";
|
|
5358
|
+
const d = new Date(timestamp);
|
|
5359
|
+
if (isNaN(d.getTime())) return "N/A";
|
|
5360
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
5361
|
+
const hh = pad(d.getHours());
|
|
5362
|
+
const min = pad(d.getMinutes());
|
|
5363
|
+
const sec = pad(d.getSeconds());
|
|
5364
|
+
return `${hh}:${min}:${sec}`;
|
|
5365
|
+
}
|
|
5366
|
+
var init_RevertModal = __esm({
|
|
5367
|
+
"src/components/RevertModal.jsx"() {
|
|
5368
|
+
init_terminal();
|
|
5369
|
+
}
|
|
5370
|
+
});
|
|
5371
|
+
|
|
5116
5372
|
// src/utils/setup.js
|
|
5117
5373
|
import puppeteer4 from "puppeteer";
|
|
5118
5374
|
import { exec as exec3 } from "child_process";
|
|
5119
5375
|
import { promisify } from "util";
|
|
5120
|
-
import
|
|
5376
|
+
import fs17 from "fs";
|
|
5121
5377
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
5122
5378
|
var init_setup = __esm({
|
|
5123
5379
|
"src/utils/setup.js"() {
|
|
@@ -5125,7 +5381,7 @@ var init_setup = __esm({
|
|
|
5125
5381
|
checkPuppeteerReady = () => {
|
|
5126
5382
|
try {
|
|
5127
5383
|
const exePath = puppeteer4.executablePath();
|
|
5128
|
-
const exists = exePath &&
|
|
5384
|
+
const exists = exePath && fs17.existsSync(exePath);
|
|
5129
5385
|
if (exists) return true;
|
|
5130
5386
|
} catch (e) {
|
|
5131
5387
|
return false;
|
|
@@ -5156,28 +5412,28 @@ __export(app_exports, {
|
|
|
5156
5412
|
default: () => App
|
|
5157
5413
|
});
|
|
5158
5414
|
import os4 from "os";
|
|
5159
|
-
import
|
|
5160
|
-
import { Box as
|
|
5415
|
+
import React11, { useState as useState8, useEffect as useEffect6, useRef as useRef2, useMemo } from "react";
|
|
5416
|
+
import { Box as Box11, Text as Text11, useInput as useInput5, useStdout } from "ink";
|
|
5161
5417
|
import Spinner2 from "ink-spinner";
|
|
5162
|
-
import
|
|
5163
|
-
import
|
|
5418
|
+
import fs18 from "fs-extra";
|
|
5419
|
+
import path16 from "path";
|
|
5164
5420
|
import { exec as exec4 } from "child_process";
|
|
5165
5421
|
import { fileURLToPath } from "url";
|
|
5166
5422
|
import { MultilineInput } from "ink-multiline-input";
|
|
5167
5423
|
import TextInput3 from "ink-text-input";
|
|
5168
5424
|
import gradient from "gradient-string";
|
|
5169
5425
|
function App({ args = [] }) {
|
|
5170
|
-
const [confirmExit, setConfirmExit] =
|
|
5171
|
-
const [exitCountdown, setExitCountdown] =
|
|
5426
|
+
const [confirmExit, setConfirmExit] = useState8(false);
|
|
5427
|
+
const [exitCountdown, setExitCountdown] = useState8(10);
|
|
5172
5428
|
const { stdout } = useStdout();
|
|
5173
|
-
const [input, setInput] =
|
|
5174
|
-
const [isExpanded, setIsExpanded] =
|
|
5175
|
-
const [mode, setMode] =
|
|
5176
|
-
const [terminalSize, setTerminalSize] =
|
|
5429
|
+
const [input, setInput] = useState8("");
|
|
5430
|
+
const [isExpanded, setIsExpanded] = useState8(false);
|
|
5431
|
+
const [mode, setMode] = useState8("Flux");
|
|
5432
|
+
const [terminalSize, setTerminalSize] = useState8({
|
|
5177
5433
|
columns: stdout?.columns || 80,
|
|
5178
5434
|
rows: stdout?.rows || 24
|
|
5179
5435
|
});
|
|
5180
|
-
const [selectedIndex, setSelectedIndex] =
|
|
5436
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
5181
5437
|
const persistedModelRef = useRef2(null);
|
|
5182
5438
|
const parsedArgs = useMemo(() => {
|
|
5183
5439
|
const parsed = {};
|
|
@@ -5281,37 +5537,37 @@ function App({ args = [] }) {
|
|
|
5281
5537
|
stdout.off("resize", handleResize);
|
|
5282
5538
|
};
|
|
5283
5539
|
}, [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] =
|
|
5540
|
+
const [thinkingLevel, setThinkingLevel] = useState8("Medium");
|
|
5541
|
+
const [latestVer, setLatestVer] = useState8(null);
|
|
5542
|
+
const [showFullThinking, setShowFullThinking] = useState8(false);
|
|
5543
|
+
const [activeModel, setActiveModel] = useState8("gemma-4-31b-it");
|
|
5544
|
+
const [janitorModel, setJanitorModel] = useState8("gemma-4-26b-a4b-it");
|
|
5545
|
+
const [isInitializing, setIsInitializing] = useState8(true);
|
|
5546
|
+
const [apiKey, setApiKey] = useState8(null);
|
|
5547
|
+
const [tempKey, setTempKey] = useState8("");
|
|
5548
|
+
const [activeView, setActiveView] = useState8("chat");
|
|
5549
|
+
const [apiTier, setApiTier] = useState8("Free");
|
|
5550
|
+
const [quotas, setQuotas] = useState8({ agentLimit: 1500, backgroundLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
|
|
5551
|
+
const [inputConfig, setInputConfig] = useState8(null);
|
|
5552
|
+
const [systemSettings, setSystemSettings] = useState8({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
|
|
5553
|
+
const [profileData, setProfileData] = useState8({ name: null, nickname: null, instructions: null });
|
|
5554
|
+
const [imageSettings, setImageSettings] = useState8({ keyType: "Default", quality: "Low-High", apiKey: "" });
|
|
5555
|
+
const [sessionStats, setSessionStats] = useState8({ tokens: 0 });
|
|
5556
|
+
const [sessionAgentCalls, setSessionAgentCalls] = useState8(0);
|
|
5557
|
+
const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState8(0);
|
|
5558
|
+
const [sessionTotalTokens, setSessionTotalTokens] = useState8(0);
|
|
5559
|
+
const [sessionToolSuccess, setSessionToolSuccess] = useState8(0);
|
|
5560
|
+
const [sessionToolFailure, setSessionToolFailure] = useState8(0);
|
|
5561
|
+
const [sessionToolDenied, setSessionToolDenied] = useState8(0);
|
|
5562
|
+
const [sessionApiTime, setSessionApiTime] = useState8(0);
|
|
5563
|
+
const [sessionToolTime, setSessionToolTime] = useState8(0);
|
|
5564
|
+
const [sessionImageCount, setSessionImageCount] = useState8(0);
|
|
5565
|
+
const [sessionImageCredits, setSessionImageCredits] = useState8(0);
|
|
5566
|
+
const [dailyUsage, setDailyUsage] = useState8(null);
|
|
5567
|
+
const [chatId, setChatId] = useState8(generateChatId());
|
|
5568
|
+
const [activeCommand, setActiveCommand] = useState8(null);
|
|
5569
|
+
const [execOutput, setExecOutput] = useState8("");
|
|
5570
|
+
const [isTerminalFocused, setIsTerminalFocused] = useState8(false);
|
|
5315
5571
|
useEffect6(() => {
|
|
5316
5572
|
if (apiTier !== "Free" && activeModel === "gemma-4-31b-it") {
|
|
5317
5573
|
setActiveModel("gemini-3-flash-preview");
|
|
@@ -5341,9 +5597,9 @@ function App({ args = [] }) {
|
|
|
5341
5597
|
useEffect6(() => {
|
|
5342
5598
|
execOutputRef.current = execOutput;
|
|
5343
5599
|
}, [execOutput]);
|
|
5344
|
-
const [autoAcceptWrites, setAutoAcceptWrites] =
|
|
5345
|
-
const [pendingApproval, setPendingApproval] =
|
|
5346
|
-
const [pendingAsk, setPendingAsk] =
|
|
5600
|
+
const [autoAcceptWrites, setAutoAcceptWrites] = useState8(false);
|
|
5601
|
+
const [pendingApproval, setPendingApproval] = useState8(null);
|
|
5602
|
+
const [pendingAsk, setPendingAsk] = useState8(null);
|
|
5347
5603
|
const formatDuration = (totalSecs) => {
|
|
5348
5604
|
const h = Math.floor(totalSecs / 3600);
|
|
5349
5605
|
const m = Math.floor(totalSecs % 3600 / 60);
|
|
@@ -5358,15 +5614,18 @@ function App({ args = [] }) {
|
|
|
5358
5614
|
if (ms < 1e3) return `${ms}ms`;
|
|
5359
5615
|
return formatDuration(Math.floor(ms / 1e3));
|
|
5360
5616
|
};
|
|
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 [
|
|
5617
|
+
const [statusText, setStatusText] = useState8(null);
|
|
5618
|
+
const [isSpinnerActive, setIsSpinnerActive] = useState8(true);
|
|
5619
|
+
const [isProcessing, setIsProcessing] = useState8(false);
|
|
5620
|
+
const [escPressed, setEscPressed] = useState8(false);
|
|
5621
|
+
const [escTimer, setEscTimer] = useState8(null);
|
|
5622
|
+
const [escPressCount, setEscPressCount] = useState8(0);
|
|
5623
|
+
const [recentPrompts, setRecentPrompts] = useState8([]);
|
|
5624
|
+
const escDoubleTimerRef = useRef2(null);
|
|
5625
|
+
const [queuedPrompt, setQueuedPrompt] = useState8(null);
|
|
5626
|
+
const [resolutionData, setResolutionData] = useState8(null);
|
|
5627
|
+
const [tempModelOverride, setTempModelOverride] = useState8(null);
|
|
5628
|
+
const [messages, setMessages] = useState8(() => {
|
|
5370
5629
|
const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
|
|
5371
5630
|
const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
|
|
5372
5631
|
const isHomeDir = process.cwd() === os4.homedir();
|
|
@@ -5405,7 +5664,7 @@ function App({ args = [] }) {
|
|
|
5405
5664
|
return msgs;
|
|
5406
5665
|
});
|
|
5407
5666
|
const queuedPromptRef = useRef2(null);
|
|
5408
|
-
const [completedIndex, setCompletedIndex] =
|
|
5667
|
+
const [completedIndex, setCompletedIndex] = useState8(messages.length);
|
|
5409
5668
|
const windowedHistory = useMemo(() => {
|
|
5410
5669
|
const MAX_HISTORY_LINES = 2e3;
|
|
5411
5670
|
const width = terminalSize.columns || 80;
|
|
@@ -5440,7 +5699,7 @@ function App({ args = [] }) {
|
|
|
5440
5699
|
return acc + Math.max(1, Math.ceil(line.length / wrapWidth));
|
|
5441
5700
|
}, 0);
|
|
5442
5701
|
const maxLines = Math.max(1, wrappedLinesCount);
|
|
5443
|
-
|
|
5702
|
+
useInput5((inputText, key) => {
|
|
5444
5703
|
if (key.tab && activeCommand) {
|
|
5445
5704
|
setIsTerminalFocused((prev) => !prev);
|
|
5446
5705
|
return;
|
|
@@ -5485,8 +5744,36 @@ function App({ args = [] }) {
|
|
|
5485
5744
|
setEscPressed(false);
|
|
5486
5745
|
if (escTimer) clearTimeout(escTimer);
|
|
5487
5746
|
}
|
|
5488
|
-
} else
|
|
5489
|
-
|
|
5747
|
+
} else {
|
|
5748
|
+
if (activeView === "revert") {
|
|
5749
|
+
setActiveView("chat");
|
|
5750
|
+
setEscPressCount(0);
|
|
5751
|
+
} else if (activeView !== "chat") {
|
|
5752
|
+
setActiveView("chat");
|
|
5753
|
+
} else {
|
|
5754
|
+
setEscPressCount((prev) => {
|
|
5755
|
+
const nextCount = prev + 1;
|
|
5756
|
+
if (nextCount === 1) {
|
|
5757
|
+
if (escDoubleTimerRef.current) clearTimeout(escDoubleTimerRef.current);
|
|
5758
|
+
escDoubleTimerRef.current = setTimeout(() => setEscPressCount(0), 1e3);
|
|
5759
|
+
} else if (nextCount === 2) {
|
|
5760
|
+
if (escDoubleTimerRef.current) clearTimeout(escDoubleTimerRef.current);
|
|
5761
|
+
setEscPressCount(0);
|
|
5762
|
+
RevertManager.getChatHistory(chatId).then((prompts) => {
|
|
5763
|
+
if (prompts.length > 0) {
|
|
5764
|
+
setRecentPrompts(prompts.reverse());
|
|
5765
|
+
setActiveView("revert");
|
|
5766
|
+
} else {
|
|
5767
|
+
setMessages((prev2) => {
|
|
5768
|
+
setCompletedIndex(prev2.length + 1);
|
|
5769
|
+
return [...prev2, { id: "revert-empty-" + Date.now(), role: "system", text: "\u2139\uFE0F No revert checkpoints found for this session.", isMeta: true }];
|
|
5770
|
+
});
|
|
5771
|
+
}
|
|
5772
|
+
});
|
|
5773
|
+
}
|
|
5774
|
+
return nextCount;
|
|
5775
|
+
});
|
|
5776
|
+
}
|
|
5490
5777
|
}
|
|
5491
5778
|
}
|
|
5492
5779
|
if (suggestions.length > 0 && activeView === "chat") {
|
|
@@ -5707,6 +5994,7 @@ function App({ args = [] }) {
|
|
|
5707
5994
|
{ cmd: "/help", desc: "Show all available commands" },
|
|
5708
5995
|
{ cmd: "/clear", desc: "Clear terminal screen" },
|
|
5709
5996
|
{ cmd: "/resume", desc: "Load previous session" },
|
|
5997
|
+
{ cmd: "/revert", desc: "Revert codebase back to a checkpoint" },
|
|
5710
5998
|
{ cmd: "/save", desc: "Force save current chat" },
|
|
5711
5999
|
{ cmd: "/export", desc: "Export current chat in a .txt file" },
|
|
5712
6000
|
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
@@ -5889,6 +6177,21 @@ ${hintText}`, color: "magenta" }];
|
|
|
5889
6177
|
setIsExpanded(false);
|
|
5890
6178
|
break;
|
|
5891
6179
|
}
|
|
6180
|
+
case "/revert": {
|
|
6181
|
+
RevertManager.getChatHistory(chatId).then((prompts) => {
|
|
6182
|
+
if (prompts.length > 0) {
|
|
6183
|
+
setRecentPrompts(prompts.reverse());
|
|
6184
|
+
setActiveView("revert");
|
|
6185
|
+
} else {
|
|
6186
|
+
const s2 = emojiSpace(2);
|
|
6187
|
+
setMessages((prev) => {
|
|
6188
|
+
setCompletedIndex(prev.length + 1);
|
|
6189
|
+
return [...prev, { id: "revert-empty-" + Date.now(), role: "system", text: `No revert checkpoints found for this session.`, isMeta: true }];
|
|
6190
|
+
});
|
|
6191
|
+
}
|
|
6192
|
+
});
|
|
6193
|
+
break;
|
|
6194
|
+
}
|
|
5892
6195
|
case "/mode": {
|
|
5893
6196
|
if (parts[1]) {
|
|
5894
6197
|
const newMode = parts[1].toLowerCase() === "flow" ? "Flow" : "Flux";
|
|
@@ -6124,7 +6427,7 @@ ${hintText}`, color: "magenta" }];
|
|
|
6124
6427
|
}
|
|
6125
6428
|
case "/export": {
|
|
6126
6429
|
const exportFile = `export-fluxflow-${chatId}.txt`;
|
|
6127
|
-
const exportPath =
|
|
6430
|
+
const exportPath = path16.join(process.cwd(), exportFile);
|
|
6128
6431
|
const exportLines = [];
|
|
6129
6432
|
let insideAgentBlock = false;
|
|
6130
6433
|
for (let i = 0; i < messages.length; i++) {
|
|
@@ -6175,7 +6478,7 @@ ${hintText}`, color: "magenta" }];
|
|
|
6175
6478
|
}
|
|
6176
6479
|
}
|
|
6177
6480
|
const fileContent = exportLines.join("\n");
|
|
6178
|
-
|
|
6481
|
+
fs18.writeFileSync(exportPath, fileContent, "utf8");
|
|
6179
6482
|
setMessages((prev) => {
|
|
6180
6483
|
setCompletedIndex(prev.length + 1);
|
|
6181
6484
|
return [...prev, {
|
|
@@ -6211,12 +6514,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
6211
6514
|
setCompletedIndex(prev.length + 1);
|
|
6212
6515
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
6213
6516
|
});
|
|
6214
|
-
if (
|
|
6215
|
-
if (
|
|
6216
|
-
if (
|
|
6517
|
+
if (fs18.existsSync(LOGS_DIR)) fs18.removeSync(LOGS_DIR);
|
|
6518
|
+
if (fs18.existsSync(SECRET_DIR)) fs18.removeSync(SECRET_DIR);
|
|
6519
|
+
if (fs18.existsSync(SETTINGS_FILE)) fs18.removeSync(SETTINGS_FILE);
|
|
6217
6520
|
try {
|
|
6218
|
-
const items =
|
|
6219
|
-
if (items.length === 0)
|
|
6521
|
+
const items = fs18.readdirSync(FLUXFLOW_DIR);
|
|
6522
|
+
if (items.length === 0) fs18.removeSync(FLUXFLOW_DIR);
|
|
6220
6523
|
} catch (e) {
|
|
6221
6524
|
}
|
|
6222
6525
|
setTimeout(() => {
|
|
@@ -6273,14 +6576,14 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
6273
6576
|
# SKILLS & WORKFLOWS
|
|
6274
6577
|
- [Define custom step-by-step recipes for this project here]
|
|
6275
6578
|
`;
|
|
6276
|
-
const filePath =
|
|
6277
|
-
if (
|
|
6579
|
+
const filePath = path16.join(process.cwd(), "FluxFlow.md");
|
|
6580
|
+
if (fs18.pathExistsSync(filePath)) {
|
|
6278
6581
|
setMessages((prev) => {
|
|
6279
6582
|
setCompletedIndex(prev.length + 1);
|
|
6280
6583
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
6281
6584
|
});
|
|
6282
6585
|
} else {
|
|
6283
|
-
|
|
6586
|
+
fs18.writeFileSync(filePath, template);
|
|
6284
6587
|
setMessages((prev) => {
|
|
6285
6588
|
setCompletedIndex(prev.length + 1);
|
|
6286
6589
|
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 +7012,7 @@ Selection: ${val}`,
|
|
|
6709
7012
|
const renderActiveView = () => {
|
|
6710
7013
|
switch (activeView) {
|
|
6711
7014
|
case "settings":
|
|
6712
|
-
return /* @__PURE__ */
|
|
7015
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6713
7016
|
CommandMenu,
|
|
6714
7017
|
{
|
|
6715
7018
|
title: "System Settings",
|
|
@@ -6777,7 +7080,7 @@ Selection: ${val}`,
|
|
|
6777
7080
|
}
|
|
6778
7081
|
);
|
|
6779
7082
|
case "apiTier":
|
|
6780
|
-
return /* @__PURE__ */
|
|
7083
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6781
7084
|
CommandMenu,
|
|
6782
7085
|
{
|
|
6783
7086
|
title: `API Tier: ${apiTier}`,
|
|
@@ -6810,7 +7113,7 @@ Selection: ${val}`,
|
|
|
6810
7113
|
}
|
|
6811
7114
|
);
|
|
6812
7115
|
case "input":
|
|
6813
|
-
return /* @__PURE__ */
|
|
7116
|
+
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
7117
|
TextInput3,
|
|
6815
7118
|
{
|
|
6816
7119
|
value: inputConfig?.value || "",
|
|
@@ -6863,11 +7166,11 @@ Selection: ${val}`,
|
|
|
6863
7166
|
}
|
|
6864
7167
|
}
|
|
6865
7168
|
}
|
|
6866
|
-
)), /* @__PURE__ */
|
|
7169
|
+
)), /* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, "(Press Enter to confirm selection)")));
|
|
6867
7170
|
case "stats":
|
|
6868
|
-
return /* @__PURE__ */
|
|
7171
|
+
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
7172
|
case "autoExecDanger":
|
|
6870
|
-
return /* @__PURE__ */
|
|
7173
|
+
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
7174
|
CommandMenu,
|
|
6872
7175
|
{
|
|
6873
7176
|
title: "Confirm Intent",
|
|
@@ -6884,7 +7187,7 @@ Selection: ${val}`,
|
|
|
6884
7187
|
}
|
|
6885
7188
|
)));
|
|
6886
7189
|
case "externalDanger":
|
|
6887
|
-
return /* @__PURE__ */
|
|
7190
|
+
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
7191
|
CommandMenu,
|
|
6889
7192
|
{
|
|
6890
7193
|
title: "Confirm Intent",
|
|
@@ -6901,7 +7204,7 @@ Selection: ${val}`,
|
|
|
6901
7204
|
}
|
|
6902
7205
|
)));
|
|
6903
7206
|
case "doubleDanger":
|
|
6904
|
-
return /* @__PURE__ */
|
|
7207
|
+
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
7208
|
CommandMenu,
|
|
6906
7209
|
{
|
|
6907
7210
|
title: "Final Confirmation",
|
|
@@ -6918,7 +7221,7 @@ Selection: ${val}`,
|
|
|
6918
7221
|
}
|
|
6919
7222
|
)));
|
|
6920
7223
|
case "key":
|
|
6921
|
-
return /* @__PURE__ */
|
|
7224
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6922
7225
|
CommandMenu,
|
|
6923
7226
|
{
|
|
6924
7227
|
title: "\u{1F511} API KEY MANAGEMENT",
|
|
@@ -6942,10 +7245,10 @@ Selection: ${val}`,
|
|
|
6942
7245
|
}
|
|
6943
7246
|
);
|
|
6944
7247
|
case "deleteKey":
|
|
6945
|
-
return /* @__PURE__ */
|
|
7248
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1 }, (() => {
|
|
6946
7249
|
const s = emojiSpace(2);
|
|
6947
|
-
return /* @__PURE__ */
|
|
6948
|
-
})(), /* @__PURE__ */
|
|
7250
|
+
return /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true }, "\u26D4", s, "DANGER: PURGE API KEY");
|
|
7251
|
+
})(), /* @__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
7252
|
CommandMenu,
|
|
6950
7253
|
{
|
|
6951
7254
|
title: "Are you absolutely sure?",
|
|
@@ -6969,7 +7272,7 @@ Selection: ${val}`,
|
|
|
6969
7272
|
case "exit":
|
|
6970
7273
|
return null;
|
|
6971
7274
|
case "ask":
|
|
6972
|
-
return /* @__PURE__ */
|
|
7275
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%" }, /* @__PURE__ */ React11.createElement(
|
|
6973
7276
|
AskUserModal_default,
|
|
6974
7277
|
{
|
|
6975
7278
|
question: pendingAsk?.question,
|
|
@@ -6983,8 +7286,62 @@ Selection: ${val}`,
|
|
|
6983
7286
|
}
|
|
6984
7287
|
}
|
|
6985
7288
|
));
|
|
7289
|
+
case "revert":
|
|
7290
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(
|
|
7291
|
+
RevertModal,
|
|
7292
|
+
{
|
|
7293
|
+
prompts: recentPrompts,
|
|
7294
|
+
onSelect: async (txId) => {
|
|
7295
|
+
try {
|
|
7296
|
+
const result = await RevertManager.rollbackToBefore(txId);
|
|
7297
|
+
if (result.success) {
|
|
7298
|
+
const { targetPrompt } = result;
|
|
7299
|
+
const targetIdx = messages.findIndex(
|
|
7300
|
+
(m) => m.role === "user" && m.text && (m.text.startsWith(targetPrompt) || m.text.includes(targetPrompt))
|
|
7301
|
+
);
|
|
7302
|
+
let newMsgs = [...messages];
|
|
7303
|
+
if (targetIdx !== -1) {
|
|
7304
|
+
newMsgs = messages.slice(0, targetIdx);
|
|
7305
|
+
}
|
|
7306
|
+
setMessages(newMsgs);
|
|
7307
|
+
setCompletedIndex(newMsgs.length);
|
|
7308
|
+
setInput(targetPrompt);
|
|
7309
|
+
setIsExpanded(targetPrompt.split("\n").length > 2);
|
|
7310
|
+
const historyToSave = newMsgs.filter((m) => !String(m.id).startsWith("welcome") && !m.isMeta);
|
|
7311
|
+
await saveChat(chatId, null, historyToSave);
|
|
7312
|
+
const s = emojiSpace(2);
|
|
7313
|
+
setMessages((prev) => {
|
|
7314
|
+
const finalMsgs = [...prev, {
|
|
7315
|
+
id: "revert-ok-" + Date.now(),
|
|
7316
|
+
role: "system",
|
|
7317
|
+
text: `\u{1F504}${s}[TIME TRAVEL] Codebase rolled back successfully! Reverted prompt loaded to input box.`,
|
|
7318
|
+
isMeta: true
|
|
7319
|
+
}];
|
|
7320
|
+
setCompletedIndex(finalMsgs.length);
|
|
7321
|
+
return finalMsgs;
|
|
7322
|
+
});
|
|
7323
|
+
setActiveView("chat");
|
|
7324
|
+
}
|
|
7325
|
+
} catch (err) {
|
|
7326
|
+
const s = emojiSpace(2);
|
|
7327
|
+
setMessages((prev) => {
|
|
7328
|
+
const finalMsgs = [...prev, {
|
|
7329
|
+
id: "revert-err-" + Date.now(),
|
|
7330
|
+
role: "system",
|
|
7331
|
+
text: `\u274C${s}[TIME TRAVEL ERROR] Failed to rollback: ${err.message}`,
|
|
7332
|
+
isMeta: true
|
|
7333
|
+
}];
|
|
7334
|
+
setCompletedIndex(finalMsgs.length);
|
|
7335
|
+
return finalMsgs;
|
|
7336
|
+
});
|
|
7337
|
+
setActiveView("chat");
|
|
7338
|
+
}
|
|
7339
|
+
},
|
|
7340
|
+
onClose: () => setActiveView("chat")
|
|
7341
|
+
}
|
|
7342
|
+
));
|
|
6986
7343
|
case "resume":
|
|
6987
|
-
return /* @__PURE__ */
|
|
7344
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(
|
|
6988
7345
|
ResumeModal,
|
|
6989
7346
|
{
|
|
6990
7347
|
onSelect: async (id) => {
|
|
@@ -7014,9 +7371,9 @@ Selection: ${val}`,
|
|
|
7014
7371
|
}
|
|
7015
7372
|
));
|
|
7016
7373
|
case "memory":
|
|
7017
|
-
return /* @__PURE__ */
|
|
7374
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(MemoryModal, { onClose: () => setActiveView("chat") }));
|
|
7018
7375
|
case "profile":
|
|
7019
|
-
return /* @__PURE__ */
|
|
7376
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7020
7377
|
ProfileForm,
|
|
7021
7378
|
{
|
|
7022
7379
|
initialData: profileData,
|
|
@@ -7029,7 +7386,7 @@ Selection: ${val}`,
|
|
|
7029
7386
|
}
|
|
7030
7387
|
);
|
|
7031
7388
|
case "resolution":
|
|
7032
|
-
return /* @__PURE__ */
|
|
7389
|
+
return /* @__PURE__ */ React11.createElement(Box11, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React11.createElement(
|
|
7033
7390
|
ResolutionModal,
|
|
7034
7391
|
{
|
|
7035
7392
|
data: resolutionData,
|
|
@@ -7048,15 +7405,15 @@ Selection: ${val}`,
|
|
|
7048
7405
|
}
|
|
7049
7406
|
));
|
|
7050
7407
|
case "approval":
|
|
7051
|
-
return /* @__PURE__ */
|
|
7408
|
+
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
7409
|
const args2 = parseArgs(pendingApproval?.args || "{}");
|
|
7053
7410
|
const oldVal = args2.TargetContent || args2.content_to_replace || null;
|
|
7054
7411
|
const newVal = args2.content || args2.ReplacementContent || args2.content_to_add || args2.replacementContent || null;
|
|
7055
7412
|
if (oldVal && newVal) {
|
|
7056
|
-
return /* @__PURE__ */
|
|
7413
|
+
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
7414
|
}
|
|
7058
|
-
return /* @__PURE__ */
|
|
7059
|
-
})()), /* @__PURE__ */
|
|
7415
|
+
return /* @__PURE__ */ React11.createElement(Text11, { color: "white", wrap: "anywhere" }, newVal.replace(/\[\/n\]?/g, "\\n") || "Updating file content...");
|
|
7416
|
+
})()), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
|
|
7060
7417
|
CommandMenu,
|
|
7061
7418
|
{
|
|
7062
7419
|
title: "Action Required",
|
|
@@ -7075,7 +7432,7 @@ Selection: ${val}`,
|
|
|
7075
7432
|
}
|
|
7076
7433
|
)));
|
|
7077
7434
|
case "updateManager":
|
|
7078
|
-
return /* @__PURE__ */
|
|
7435
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7079
7436
|
CommandMenu,
|
|
7080
7437
|
{
|
|
7081
7438
|
title: "Select Preferred Update Manager",
|
|
@@ -7112,7 +7469,7 @@ Selection: ${val}`,
|
|
|
7112
7469
|
}
|
|
7113
7470
|
);
|
|
7114
7471
|
case "update":
|
|
7115
|
-
return /* @__PURE__ */
|
|
7472
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7116
7473
|
UpdateProcessor_default,
|
|
7117
7474
|
{
|
|
7118
7475
|
latest: latestVer,
|
|
@@ -7138,7 +7495,7 @@ Selection: ${val}`,
|
|
|
7138
7495
|
}
|
|
7139
7496
|
);
|
|
7140
7497
|
case "terminalApproval":
|
|
7141
|
-
return /* @__PURE__ */
|
|
7498
|
+
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
7499
|
CommandMenu,
|
|
7143
7500
|
{
|
|
7144
7501
|
title: "Risk Assessment Required",
|
|
@@ -7154,8 +7511,8 @@ Selection: ${val}`,
|
|
|
7154
7511
|
}
|
|
7155
7512
|
)));
|
|
7156
7513
|
default:
|
|
7157
|
-
return /* @__PURE__ */
|
|
7158
|
-
|
|
7514
|
+
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(
|
|
7515
|
+
Box11,
|
|
7159
7516
|
{
|
|
7160
7517
|
borderStyle: "round",
|
|
7161
7518
|
borderColor: isProcessing ? "magenta" : "cyan",
|
|
@@ -7163,7 +7520,7 @@ Selection: ${val}`,
|
|
|
7163
7520
|
paddingY: 0,
|
|
7164
7521
|
width: "100%"
|
|
7165
7522
|
},
|
|
7166
|
-
/* @__PURE__ */
|
|
7523
|
+
/* @__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
7524
|
MultilineInput,
|
|
7168
7525
|
{
|
|
7169
7526
|
value: "",
|
|
@@ -7180,7 +7537,7 @@ Selection: ${val}`,
|
|
|
7180
7537
|
newline: (key) => key.return && key.shift || key.return && key.ctrl || key.return && key.leftAlt || key.return && key.rightAlt
|
|
7181
7538
|
}
|
|
7182
7539
|
}
|
|
7183
|
-
)))) : /* @__PURE__ */
|
|
7540
|
+
)))) : /* @__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
7541
|
MultilineInput,
|
|
7185
7542
|
{
|
|
7186
7543
|
focus: !isTerminalFocused,
|
|
@@ -7200,14 +7557,14 @@ Selection: ${val}`,
|
|
|
7200
7557
|
));
|
|
7201
7558
|
}
|
|
7202
7559
|
};
|
|
7203
|
-
return /* @__PURE__ */
|
|
7560
|
+
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
7561
|
ChatLayout_default,
|
|
7205
7562
|
{
|
|
7206
7563
|
messages: messages.slice(completedIndex),
|
|
7207
7564
|
showFullThinking,
|
|
7208
7565
|
columns: Math.max(20, (stdout?.columns || 80) - 1)
|
|
7209
7566
|
}
|
|
7210
|
-
), activeCommand && /* @__PURE__ */
|
|
7567
|
+
), 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
7568
|
TextInput3,
|
|
7212
7569
|
{
|
|
7213
7570
|
value: tempKey,
|
|
@@ -7215,7 +7572,7 @@ Selection: ${val}`,
|
|
|
7215
7572
|
onSubmit: handleSetup,
|
|
7216
7573
|
mask: "*"
|
|
7217
7574
|
}
|
|
7218
|
-
))), /* @__PURE__ */
|
|
7575
|
+
))), /* @__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
7576
|
StatusBar_default,
|
|
7220
7577
|
{
|
|
7221
7578
|
mode,
|
|
@@ -7232,14 +7589,14 @@ Selection: ${val}`,
|
|
|
7232
7589
|
const agentActiveMs = sessionApiTime + sessionToolTime;
|
|
7233
7590
|
const apiPercent = agentActiveMs > 0 ? (sessionApiTime / agentActiveMs * 100).toFixed(1) : "0.0";
|
|
7234
7591
|
const toolPercent = agentActiveMs > 0 ? (sessionToolTime / agentActiveMs * 100).toFixed(1) : "0.0";
|
|
7235
|
-
return /* @__PURE__ */
|
|
7592
|
+
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
7593
|
})(), suggestions.length > 0 && (() => {
|
|
7237
7594
|
const windowSize = 5;
|
|
7238
7595
|
const startIdx = Math.max(0, Math.min(selectedIndex - 2, suggestions.length - windowSize));
|
|
7239
7596
|
const visible = suggestions.slice(startIdx, startIdx + windowSize);
|
|
7240
7597
|
const remaining = suggestions.length - (startIdx + visible.length);
|
|
7241
|
-
return /* @__PURE__ */
|
|
7242
|
-
|
|
7598
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7599
|
+
Box11,
|
|
7243
7600
|
{
|
|
7244
7601
|
flexDirection: "column",
|
|
7245
7602
|
borderStyle: "round",
|
|
@@ -7248,22 +7605,22 @@ Selection: ${val}`,
|
|
|
7248
7605
|
paddingY: 0,
|
|
7249
7606
|
width: "100%"
|
|
7250
7607
|
},
|
|
7251
|
-
/* @__PURE__ */
|
|
7608
|
+
/* @__PURE__ */ React11.createElement(Box11, { paddingX: 1, marginBottom: 0 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", bold: true, dimColor: true }, "\u{1F50D} COMMAND SUGGESTIONS")),
|
|
7252
7609
|
visible.map((s, i) => {
|
|
7253
7610
|
const actualIdx = startIdx + i;
|
|
7254
7611
|
const isActive = actualIdx === selectedIndex;
|
|
7255
7612
|
const isGemmaDisabled = s.cmd === "gemma-4-31b-it" && apiTier !== "Free";
|
|
7256
|
-
return /* @__PURE__ */
|
|
7257
|
-
|
|
7613
|
+
return /* @__PURE__ */ React11.createElement(
|
|
7614
|
+
Box11,
|
|
7258
7615
|
{
|
|
7259
7616
|
key: s.cmd,
|
|
7260
7617
|
flexDirection: "row",
|
|
7261
7618
|
backgroundColor: isActive ? "#2a2a2a" : void 0,
|
|
7262
7619
|
paddingX: 1
|
|
7263
7620
|
},
|
|
7264
|
-
/* @__PURE__ */
|
|
7265
|
-
/* @__PURE__ */
|
|
7266
|
-
|
|
7621
|
+
/* @__PURE__ */ React11.createElement(Box11, { width: 3 }, /* @__PURE__ */ React11.createElement(Text11, { color: isActive ? "cyan" : "gray", bold: isActive }, isActive ? " \u276F" : " ")),
|
|
7622
|
+
/* @__PURE__ */ React11.createElement(Box11, { width: 32 }, /* @__PURE__ */ React11.createElement(
|
|
7623
|
+
Text11,
|
|
7267
7624
|
{
|
|
7268
7625
|
color: isGemmaDisabled ? "gray" : isActive ? "yellow" : "white",
|
|
7269
7626
|
bold: isActive,
|
|
@@ -7271,10 +7628,10 @@ Selection: ${val}`,
|
|
|
7271
7628
|
},
|
|
7272
7629
|
s.cmd
|
|
7273
7630
|
)),
|
|
7274
|
-
/* @__PURE__ */
|
|
7631
|
+
/* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", italic: true, dimColor: !isActive }, s.desc))
|
|
7275
7632
|
);
|
|
7276
7633
|
}),
|
|
7277
|
-
suggestions.length > 5 && /* @__PURE__ */
|
|
7634
|
+
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
7635
|
);
|
|
7279
7636
|
})()));
|
|
7280
7637
|
}
|
|
@@ -7293,6 +7650,8 @@ var init_app = __esm({
|
|
|
7293
7650
|
init_ResumeModal();
|
|
7294
7651
|
init_MemoryModal();
|
|
7295
7652
|
init_UpdateProcessor();
|
|
7653
|
+
init_revert();
|
|
7654
|
+
init_RevertModal();
|
|
7296
7655
|
init_usage();
|
|
7297
7656
|
init_TerminalBox();
|
|
7298
7657
|
init_arg_parser();
|
|
@@ -7303,11 +7662,11 @@ var init_app = __esm({
|
|
|
7303
7662
|
init_text();
|
|
7304
7663
|
SESSION_START_TIME = Date.now();
|
|
7305
7664
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
7306
|
-
packageJsonPath =
|
|
7307
|
-
packageJson = JSON.parse(
|
|
7665
|
+
packageJsonPath = path16.join(path16.dirname(fileURLToPath(import.meta.url)), "../package.json");
|
|
7666
|
+
packageJson = JSON.parse(fs18.readFileSync(packageJsonPath, "utf8"));
|
|
7308
7667
|
versionFluxflow = packageJson.version;
|
|
7309
7668
|
updatedOn = packageJson.date || "2026-05-20";
|
|
7310
|
-
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */
|
|
7669
|
+
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
7670
|
CommandMenu,
|
|
7312
7671
|
{
|
|
7313
7672
|
title: "Select Action",
|
|
@@ -7410,7 +7769,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
7410
7769
|
], { stdio: "inherit" });
|
|
7411
7770
|
cp.on("exit", (code) => process.exit(code || 0));
|
|
7412
7771
|
} else {
|
|
7413
|
-
const { default:
|
|
7772
|
+
const { default: React12 } = await import("react");
|
|
7414
7773
|
const { render } = await import("ink");
|
|
7415
7774
|
const { default: App2 } = await Promise.resolve().then(() => (init_app(), app_exports));
|
|
7416
7775
|
process.env.NODE_NO_WARNINGS = "1";
|
|
@@ -7433,5 +7792,5 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
7433
7792
|
console.warn = (...args) => !isNoise(args) && originalWarn(...args);
|
|
7434
7793
|
console.error = (...args) => !isNoise(args) && originalError(...args);
|
|
7435
7794
|
process.stdout.write("\x1Bc");
|
|
7436
|
-
render(/* @__PURE__ */
|
|
7795
|
+
render(/* @__PURE__ */ React12.createElement(App2, { args: process.argv.slice(2) }), { exitOnCtrlC: false });
|
|
7437
7796
|
}
|