fluxflow-cli 3.0.22 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fluxflow.js +456 -127
- package/package.json +1 -1
package/dist/fluxflow.js
CHANGED
|
@@ -42,6 +42,7 @@ __export(paths_exports, {
|
|
|
42
42
|
FLUXFLOW_DIR: () => FLUXFLOW_DIR,
|
|
43
43
|
HISTORY_DIR: () => HISTORY_DIR,
|
|
44
44
|
HISTORY_FILE: () => HISTORY_FILE,
|
|
45
|
+
LEDGER_ADVANCE_FILE: () => LEDGER_ADVANCE_FILE,
|
|
45
46
|
LEDGER_FILE: () => LEDGER_FILE,
|
|
46
47
|
LOGS_DIR: () => LOGS_DIR,
|
|
47
48
|
MEMORIES_FILE: () => MEMORIES_FILE,
|
|
@@ -57,7 +58,7 @@ import os from "os";
|
|
|
57
58
|
import path from "path";
|
|
58
59
|
import fs from "fs";
|
|
59
60
|
import crypto from "crypto";
|
|
60
|
-
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, HISTORY_DIR, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE, ACTIVE_TX_FILE, PATHS_FILE, CONTEXT_FILE, PARSER_DIR;
|
|
61
|
+
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, HISTORY_DIR, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE, LEDGER_ADVANCE_FILE, ACTIVE_TX_FILE, PATHS_FILE, CONTEXT_FILE, PARSER_DIR;
|
|
61
62
|
var init_paths = __esm({
|
|
62
63
|
"src/utils/paths.js"() {
|
|
63
64
|
FLUXFLOW_DIR = path.join(os.homedir(), ".fluxflow");
|
|
@@ -101,6 +102,7 @@ var init_paths = __esm({
|
|
|
101
102
|
TEMP_MEM_CHAT_FILE = path.join(SECRET_DIR, "temp-memory-chat.json");
|
|
102
103
|
BACKUPS_DIR = path.join(DATA_DIR, "backups");
|
|
103
104
|
LEDGER_FILE = path.join(SECRET_DIR, "ledger.json");
|
|
105
|
+
LEDGER_ADVANCE_FILE = path.join(SECRET_DIR, "ledgerAdvance.json");
|
|
104
106
|
ACTIVE_TX_FILE = path.join(SECRET_DIR, "active_tx.json");
|
|
105
107
|
PATHS_FILE = path.join(SECRET_DIR, "path.json");
|
|
106
108
|
CONTEXT_FILE = path.join(SECRET_DIR, "context.json");
|
|
@@ -136,6 +138,7 @@ var init_crypto = __esm({
|
|
|
136
138
|
return iv.toString("hex") + ":" + encrypted;
|
|
137
139
|
};
|
|
138
140
|
decryptAes = (encryptedText) => {
|
|
141
|
+
if (bypass) return encryptedText;
|
|
139
142
|
const parts = encryptedText.split(":");
|
|
140
143
|
if (parts.length !== 2) {
|
|
141
144
|
throw new Error("Invalid AES format");
|
|
@@ -318,6 +321,7 @@ var init_settings = __esm({
|
|
|
318
321
|
compression: 0,
|
|
319
322
|
autoExec: false,
|
|
320
323
|
allowExternalAccess: false,
|
|
324
|
+
advanceRollback: false,
|
|
321
325
|
autoDeleteHistory: "7d",
|
|
322
326
|
useExternalData: false,
|
|
323
327
|
externalDataPath: ""
|
|
@@ -5162,7 +5166,7 @@ var init_main_tools = __esm({
|
|
|
5162
5166
|
}
|
|
5163
5167
|
return _isPsAvailable;
|
|
5164
5168
|
};
|
|
5165
|
-
TOOL_PROTOCOL = (mode, osDetected, isMultiModal, aiProvider) => `
|
|
5169
|
+
TOOL_PROTOCOL = (mode, osDetected, isMultiModal, aiProvider, advanceRollback = false) => `
|
|
5166
5170
|
-- TOOL DEFINITIONS --
|
|
5167
5171
|
Internal tools. **MUST use the EXACT syntax** [tool:functions.ToolName(args)]. **NO OTHER SYNTAX/MARKERS/BOUNDARY ALLOWED**
|
|
5168
5172
|
|
|
@@ -5186,7 +5190,10 @@ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST A
|
|
|
5186
5190
|
7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL ONLY` : `WINDOWS CMD ONLY` : `BASH`} command. Destructive/Irreversible ops \u2192 Ask user
|
|
5187
5191
|
8. [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASK STRINGS])]. Task List, NO Markdown IN ARRAY. USAGE: ANALYZE USER REQUEST **IF** MULTIPLE TASK \u2192 BREAK DOWN TASK \u2192 CREATE TODO **BEFORE** DIVING IN. 'tasks' & 'markDone' OPTIONAL PARAMETERS WITH method 'get'. USE 'get' method WITH 'markDone' to mark task completed. **EVERY TURN UPDATE POLICY**
|
|
5188
5192
|
9. [tool:functions.Await(time="seconds")]. For waiting without exiting agent loop, 15s - 180s
|
|
5189
|
-
|
|
5193
|
+
${advanceRollback ? `
|
|
5194
|
+
- EMERGENCY SAFETY TOOLS -
|
|
5195
|
+
1. [tool:functions.EmergencyRollback(method="getCheckpoint/forceRevert", id="...")]. Rollback workspace during execution to a specific turn checkpoint. Usage: ONLY in catastrophic codebase error/deletions. Verify nothing catastrophic happened in codebase before ending agent loop. 'id' not needed with getCheckPoint
|
|
5196
|
+
` : ""}
|
|
5190
5197
|
-- SUB AGENTS DEFINITIONS --
|
|
5191
5198
|
**PROACTIVE USE OF SUB AGENTS HIGHLY RECOMMENDED, PREFER USING FOR ALL TASK WHERE PLAUSIBLE & BENEFICIAL, EVEN WITHOUT EXPLICIT USER NUDGE**
|
|
5192
5199
|
|
|
@@ -5944,6 +5951,7 @@ function SettingsMenu({
|
|
|
5944
5951
|
{ label: "Auto Approve Commands", value: "autoApprove", status: truncateCSV(systemSettings.autoApproveCommands), section: "Sandbox" },
|
|
5945
5952
|
{ label: "Auto Disapprove Commands", value: "autoDisallow", status: truncateCSV(systemSettings.autoDisallowCommands), section: "Sandbox" },
|
|
5946
5953
|
{ label: "Auto Approve Git Commits", value: "autoApproveGit", status: systemSettings.autoApproveGit ? "ON" : "OFF", section: "Sandbox" },
|
|
5954
|
+
{ label: "Advanced Rollback [EXPERIMENTAL]", value: "advanceRollback", status: systemSettings.advanceRollback ? "ON" : "OFF", section: "Other" },
|
|
5947
5955
|
{ label: "Auto-Delete History", value: "autoDelete", status: systemSettings.autoDeleteHistory || "30d", section: "Other" },
|
|
5948
5956
|
{ label: "Save AppData Externally", value: "externalData", status: systemSettings.useExternalData ? "ON" : "OFF", section: "Other" }
|
|
5949
5957
|
];
|
|
@@ -6075,6 +6083,16 @@ function SettingsMenu({
|
|
|
6075
6083
|
setActiveView("apiTier");
|
|
6076
6084
|
} else if (item.value === "aiProvider") {
|
|
6077
6085
|
setActiveView("selectProvider");
|
|
6086
|
+
} else if (item.value === "advanceRollback") {
|
|
6087
|
+
if (!systemSettings.advanceRollback) {
|
|
6088
|
+
setActiveView("advanceRollbackDanger");
|
|
6089
|
+
} else {
|
|
6090
|
+
setSystemSettings((s) => {
|
|
6091
|
+
const newSysSettings = { ...s, advanceRollback: false };
|
|
6092
|
+
saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
|
|
6093
|
+
return newSysSettings;
|
|
6094
|
+
});
|
|
6095
|
+
}
|
|
6078
6096
|
} else if (item.value === "autoDelete") {
|
|
6079
6097
|
const options = ["1d", "7d", "30d"];
|
|
6080
6098
|
const currentIndex = options.indexOf(systemSettings.autoDeleteHistory || "30d");
|
|
@@ -6544,7 +6562,7 @@ ${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && !isGemini ? `
|
|
|
6544
6562
|
CRITICAL THINKING POLICY
|
|
6545
6563
|
- ALWAYS use <think> ... </think> before responding, even with simple queries/greetings
|
|
6546
6564
|
` : ""}` : `${thinkingConfig}`}
|
|
6547
|
-
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider)}
|
|
6565
|
+
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider, systemSettings?.advanceRollback)}
|
|
6548
6566
|
${projectContextBlock}
|
|
6549
6567
|
-- MEMORY RULES --
|
|
6550
6568
|
- Memory: ${isMemoryEnabled ? "Subtly Personalize. Auto Saves" : "OFF. Decline Remembering Memories"}
|
|
@@ -10044,6 +10062,281 @@ var init_await = __esm({
|
|
|
10044
10062
|
}
|
|
10045
10063
|
});
|
|
10046
10064
|
|
|
10065
|
+
// src/utils/advanceRevert.js
|
|
10066
|
+
import fs21 from "fs-extra";
|
|
10067
|
+
import path20 from "path";
|
|
10068
|
+
async function scanWorkspace(dir, baseDir = dir) {
|
|
10069
|
+
const manifest = {};
|
|
10070
|
+
const entries = await fs21.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
10071
|
+
for (const entry of entries) {
|
|
10072
|
+
if (JUNK_DIRECTORIES.includes(entry.name)) continue;
|
|
10073
|
+
const fullPath = path20.join(dir, entry.name);
|
|
10074
|
+
const relPath = path20.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
10075
|
+
if (entry.isDirectory()) {
|
|
10076
|
+
const sub = await scanWorkspace(fullPath, baseDir);
|
|
10077
|
+
Object.assign(manifest, sub);
|
|
10078
|
+
} else {
|
|
10079
|
+
const stats = await fs21.stat(fullPath).catch(() => null);
|
|
10080
|
+
if (stats) {
|
|
10081
|
+
manifest[relPath] = {
|
|
10082
|
+
size: stats.size,
|
|
10083
|
+
mtime: stats.mtimeMs
|
|
10084
|
+
};
|
|
10085
|
+
}
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
return manifest;
|
|
10089
|
+
}
|
|
10090
|
+
async function copyWorkspaceFiles(destDir, manifest) {
|
|
10091
|
+
await fs21.ensureDir(destDir);
|
|
10092
|
+
for (const relPath of Object.keys(manifest)) {
|
|
10093
|
+
const srcPath = path20.join(process.cwd(), relPath);
|
|
10094
|
+
const destPath = path20.join(destDir, relPath);
|
|
10095
|
+
await fs21.ensureDir(path20.dirname(destPath));
|
|
10096
|
+
await fs21.copyFile(srcPath, destPath).catch(() => {
|
|
10097
|
+
});
|
|
10098
|
+
}
|
|
10099
|
+
}
|
|
10100
|
+
async function restoreSnapshotDir(srcDir, destDir) {
|
|
10101
|
+
if (!await fs21.pathExists(srcDir)) return;
|
|
10102
|
+
const entries = await fs21.readdir(srcDir, { withFileTypes: true }).catch(() => []);
|
|
10103
|
+
for (const entry of entries) {
|
|
10104
|
+
const srcPath = path20.join(srcDir, entry.name);
|
|
10105
|
+
const destPath = path20.join(destDir, entry.name);
|
|
10106
|
+
if (entry.isDirectory()) {
|
|
10107
|
+
await restoreSnapshotDir(srcPath, destPath);
|
|
10108
|
+
} else {
|
|
10109
|
+
if (await fs21.pathExists(destPath)) {
|
|
10110
|
+
await fs21.chmod(destPath, 438).catch(() => {
|
|
10111
|
+
});
|
|
10112
|
+
}
|
|
10113
|
+
await fs21.ensureDir(path20.dirname(destPath));
|
|
10114
|
+
await fs21.copyFile(srcPath, destPath).catch(() => {
|
|
10115
|
+
});
|
|
10116
|
+
await fs21.chmod(destPath, 438).catch(() => {
|
|
10117
|
+
});
|
|
10118
|
+
}
|
|
10119
|
+
}
|
|
10120
|
+
}
|
|
10121
|
+
var JUNK_DIRECTORIES, AdvanceRevertManager;
|
|
10122
|
+
var init_advanceRevert = __esm({
|
|
10123
|
+
"src/utils/advanceRevert.js"() {
|
|
10124
|
+
init_paths();
|
|
10125
|
+
init_crypto();
|
|
10126
|
+
JUNK_DIRECTORIES = [
|
|
10127
|
+
"node_modules",
|
|
10128
|
+
"dist",
|
|
10129
|
+
"bin",
|
|
10130
|
+
"logs",
|
|
10131
|
+
".git",
|
|
10132
|
+
".fluxflow",
|
|
10133
|
+
"secret",
|
|
10134
|
+
".gemini",
|
|
10135
|
+
".agents",
|
|
10136
|
+
"tmp",
|
|
10137
|
+
"temp",
|
|
10138
|
+
"build",
|
|
10139
|
+
"out",
|
|
10140
|
+
"snapshots"
|
|
10141
|
+
];
|
|
10142
|
+
AdvanceRevertManager = {
|
|
10143
|
+
async takeInitialSnapshot(chatId) {
|
|
10144
|
+
try {
|
|
10145
|
+
const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
|
|
10146
|
+
await fs21.remove(snapshotsDir).catch(() => {
|
|
10147
|
+
});
|
|
10148
|
+
await fs21.ensureDir(snapshotsDir);
|
|
10149
|
+
const manifest = await scanWorkspace(process.cwd());
|
|
10150
|
+
await copyWorkspaceFiles(path20.join(snapshotsDir, "initial"), manifest);
|
|
10151
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10152
|
+
ledger[chatId] = {
|
|
10153
|
+
initialManifest: manifest,
|
|
10154
|
+
currentManifest: manifest,
|
|
10155
|
+
checkpoints: [
|
|
10156
|
+
{
|
|
10157
|
+
id: "initial",
|
|
10158
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10159
|
+
newFiles: [],
|
|
10160
|
+
modifiedFiles: [],
|
|
10161
|
+
deletedFiles: [],
|
|
10162
|
+
toolsUsed: []
|
|
10163
|
+
}
|
|
10164
|
+
]
|
|
10165
|
+
};
|
|
10166
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10167
|
+
} catch (err) {
|
|
10168
|
+
}
|
|
10169
|
+
},
|
|
10170
|
+
async recordTurnDelta(chatId, turnNumber, toolsUsed = []) {
|
|
10171
|
+
try {
|
|
10172
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10173
|
+
const session = ledger[chatId];
|
|
10174
|
+
if (!session) return;
|
|
10175
|
+
const previousManifest = session.currentManifest || session.initialManifest;
|
|
10176
|
+
const currentManifest = await scanWorkspace(process.cwd());
|
|
10177
|
+
const newFiles = [];
|
|
10178
|
+
const modifiedFiles = [];
|
|
10179
|
+
const deletedFiles = [];
|
|
10180
|
+
for (const [relPath, info] of Object.entries(currentManifest)) {
|
|
10181
|
+
const prev = previousManifest[relPath];
|
|
10182
|
+
if (!prev) {
|
|
10183
|
+
newFiles.push(relPath);
|
|
10184
|
+
} else if (prev.size !== info.size || prev.mtime !== info.mtime) {
|
|
10185
|
+
modifiedFiles.push(relPath);
|
|
10186
|
+
}
|
|
10187
|
+
}
|
|
10188
|
+
for (const relPath of Object.keys(previousManifest)) {
|
|
10189
|
+
if (!currentManifest[relPath]) {
|
|
10190
|
+
deletedFiles.push(relPath);
|
|
10191
|
+
}
|
|
10192
|
+
}
|
|
10193
|
+
const changedFiles = [...newFiles, ...modifiedFiles];
|
|
10194
|
+
if (changedFiles.length > 0 || deletedFiles.length > 0) {
|
|
10195
|
+
const deltaManifest = {};
|
|
10196
|
+
for (const file of changedFiles) {
|
|
10197
|
+
deltaManifest[file] = currentManifest[file];
|
|
10198
|
+
}
|
|
10199
|
+
const turnDir = path20.join(DATA_DIR, "snapshots", chatId, `turn_${turnNumber}`);
|
|
10200
|
+
await copyWorkspaceFiles(turnDir, deltaManifest);
|
|
10201
|
+
}
|
|
10202
|
+
session.checkpoints.push({
|
|
10203
|
+
id: `turn_${turnNumber}`,
|
|
10204
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10205
|
+
newFiles,
|
|
10206
|
+
modifiedFiles,
|
|
10207
|
+
deletedFiles,
|
|
10208
|
+
toolsUsed
|
|
10209
|
+
});
|
|
10210
|
+
session.currentManifest = currentManifest;
|
|
10211
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10212
|
+
} catch (err) {
|
|
10213
|
+
}
|
|
10214
|
+
},
|
|
10215
|
+
async getCheckpoints(chatId) {
|
|
10216
|
+
try {
|
|
10217
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10218
|
+
const session = ledger[chatId];
|
|
10219
|
+
if (!session) return [];
|
|
10220
|
+
return session.checkpoints || [];
|
|
10221
|
+
} catch (err) {
|
|
10222
|
+
return [];
|
|
10223
|
+
}
|
|
10224
|
+
},
|
|
10225
|
+
async rollbackToCheckpoint(chatId, checkpointId) {
|
|
10226
|
+
try {
|
|
10227
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10228
|
+
const session = ledger[chatId];
|
|
10229
|
+
if (!session) throw new Error("No session active for Advance Rollback.");
|
|
10230
|
+
const checkpoints = session.checkpoints || [];
|
|
10231
|
+
const targetIdx = checkpoints.findIndex((c) => c.id === checkpointId);
|
|
10232
|
+
if (targetIdx === -1) throw new Error(`Checkpoint [${checkpointId}] not found.`);
|
|
10233
|
+
const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
|
|
10234
|
+
const currentFiles = await scanWorkspace(process.cwd());
|
|
10235
|
+
for (const relPath of Object.keys(currentFiles)) {
|
|
10236
|
+
const fullPath = path20.join(process.cwd(), relPath);
|
|
10237
|
+
await fs21.chmod(fullPath, 438).catch(() => {
|
|
10238
|
+
});
|
|
10239
|
+
await fs21.remove(fullPath).catch(() => {
|
|
10240
|
+
});
|
|
10241
|
+
}
|
|
10242
|
+
const initialDir = path20.join(snapshotsDir, "initial");
|
|
10243
|
+
await restoreSnapshotDir(initialDir, process.cwd());
|
|
10244
|
+
for (let i = 1; i <= targetIdx; i++) {
|
|
10245
|
+
const cp = checkpoints[i];
|
|
10246
|
+
const turnDir = path20.join(snapshotsDir, cp.id);
|
|
10247
|
+
await restoreSnapshotDir(turnDir, process.cwd());
|
|
10248
|
+
if (cp.deletedFiles && cp.deletedFiles.length > 0) {
|
|
10249
|
+
for (const delFile of cp.deletedFiles) {
|
|
10250
|
+
const fullPath = path20.join(process.cwd(), delFile);
|
|
10251
|
+
await fs21.chmod(fullPath, 438).catch(() => {
|
|
10252
|
+
});
|
|
10253
|
+
await fs21.remove(fullPath).catch(() => {
|
|
10254
|
+
});
|
|
10255
|
+
}
|
|
10256
|
+
}
|
|
10257
|
+
}
|
|
10258
|
+
session.checkpoints = checkpoints.slice(0, targetIdx + 1);
|
|
10259
|
+
session.currentManifest = await scanWorkspace(process.cwd());
|
|
10260
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10261
|
+
return true;
|
|
10262
|
+
} catch (err) {
|
|
10263
|
+
throw new Error(`Rollback failed: ${err.message}`);
|
|
10264
|
+
}
|
|
10265
|
+
},
|
|
10266
|
+
async cleanup(chatId) {
|
|
10267
|
+
try {
|
|
10268
|
+
const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
|
|
10269
|
+
await fs21.remove(snapshotsDir).catch(() => {
|
|
10270
|
+
});
|
|
10271
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10272
|
+
if (ledger[chatId]) {
|
|
10273
|
+
delete ledger[chatId];
|
|
10274
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10275
|
+
}
|
|
10276
|
+
} catch (err) {
|
|
10277
|
+
}
|
|
10278
|
+
}
|
|
10279
|
+
};
|
|
10280
|
+
}
|
|
10281
|
+
});
|
|
10282
|
+
|
|
10283
|
+
// src/tools/emergency_rollback.js
|
|
10284
|
+
var emergency_rollback;
|
|
10285
|
+
var init_emergency_rollback = __esm({
|
|
10286
|
+
"src/tools/emergency_rollback.js"() {
|
|
10287
|
+
init_arg_parser();
|
|
10288
|
+
init_advanceRevert();
|
|
10289
|
+
emergency_rollback = async (args, context = {}) => {
|
|
10290
|
+
const parsed = parseArgs(args);
|
|
10291
|
+
const method = parsed.method;
|
|
10292
|
+
const id = parsed.id;
|
|
10293
|
+
const chatId = context.chatId;
|
|
10294
|
+
const systemSettings = context.systemSettings;
|
|
10295
|
+
if (!systemSettings?.advanceRollback) {
|
|
10296
|
+
return "ERROR: Advance Rollback feature is currently disabled in settings under Security. Tell user to enable it.";
|
|
10297
|
+
}
|
|
10298
|
+
if (!chatId) {
|
|
10299
|
+
return "ERROR: No active chat transaction found for rollback.";
|
|
10300
|
+
}
|
|
10301
|
+
if (method === "getCheckpoint") {
|
|
10302
|
+
const checkpoints = await AdvanceRevertManager.getCheckpoints(chatId);
|
|
10303
|
+
if (checkpoints.length === 0) {
|
|
10304
|
+
return "No checkpoints available.";
|
|
10305
|
+
}
|
|
10306
|
+
let output = "Available checkpoints for rollback:\n\n";
|
|
10307
|
+
for (const cp of checkpoints) {
|
|
10308
|
+
if (cp.id === "initial") {
|
|
10309
|
+
output += `--- Initial State (id: initial) ---
|
|
10310
|
+
Tools Used: None
|
|
10311
|
+
|
|
10312
|
+
`;
|
|
10313
|
+
} else {
|
|
10314
|
+
const turnNum = cp.id.replace("turn_", "");
|
|
10315
|
+
const toolsStr = cp.toolsUsed && cp.toolsUsed.length > 0 ? cp.toolsUsed.join(", ") : "None";
|
|
10316
|
+
output += `--- Turn ${turnNum} (id: ${cp.id}) ---
|
|
10317
|
+
Tools Used: ${toolsStr}
|
|
10318
|
+
|
|
10319
|
+
`;
|
|
10320
|
+
}
|
|
10321
|
+
}
|
|
10322
|
+
return output.trim();
|
|
10323
|
+
} else if (method === "forceRevert") {
|
|
10324
|
+
if (!id) {
|
|
10325
|
+
return "ERROR: Missing required parameter 'id' for forceRevert.";
|
|
10326
|
+
}
|
|
10327
|
+
try {
|
|
10328
|
+
await AdvanceRevertManager.rollbackToCheckpoint(chatId, id);
|
|
10329
|
+
return `SUCCESS: Repository rolled back to checkpoint [${id}].`;
|
|
10330
|
+
} catch (err) {
|
|
10331
|
+
return `ERROR: ${err.message}`;
|
|
10332
|
+
}
|
|
10333
|
+
} else {
|
|
10334
|
+
return `ERROR: Invalid method "${method}". Use "getCheckpoint" or "forceRevert".`;
|
|
10335
|
+
}
|
|
10336
|
+
};
|
|
10337
|
+
}
|
|
10338
|
+
});
|
|
10339
|
+
|
|
10047
10340
|
// src/utils/tools.js
|
|
10048
10341
|
var TOOL_MAP, dispatchTool;
|
|
10049
10342
|
var init_tools = __esm({
|
|
@@ -10071,6 +10364,7 @@ var init_tools = __esm({
|
|
|
10071
10364
|
init_getProgress();
|
|
10072
10365
|
init_cancel();
|
|
10073
10366
|
init_await();
|
|
10367
|
+
init_emergency_rollback();
|
|
10074
10368
|
TOOL_MAP = {
|
|
10075
10369
|
web_search,
|
|
10076
10370
|
web_scrape,
|
|
@@ -10126,7 +10420,9 @@ var init_tools = __esm({
|
|
|
10126
10420
|
GetProgress: getProgress,
|
|
10127
10421
|
Cancel: cancel,
|
|
10128
10422
|
await: awaitTool,
|
|
10129
|
-
Await: awaitTool
|
|
10423
|
+
Await: awaitTool,
|
|
10424
|
+
EmergencyRollback: emergency_rollback,
|
|
10425
|
+
emergency_rollback
|
|
10130
10426
|
};
|
|
10131
10427
|
dispatchTool = async (toolName, args, context = {}) => {
|
|
10132
10428
|
const mode = context.mode ? context.mode.toLowerCase() : "flux";
|
|
@@ -10276,8 +10572,8 @@ __export(ai_exports, {
|
|
|
10276
10572
|
signalTermination: () => signalTermination
|
|
10277
10573
|
});
|
|
10278
10574
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
10279
|
-
import
|
|
10280
|
-
import
|
|
10575
|
+
import path21, { normalize } from "path";
|
|
10576
|
+
import fs22 from "fs";
|
|
10281
10577
|
var client, globalSettings, colorMainWords, withRetry, TERMINATION_SIGNAL, MULTIMODAL_MODELS, isModelMultimodal, getCleanGroupedLength, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getNVIDIAStream, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, translateKimiToolCalls, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, compressHistory, deleteChatSummary, getAIStream, runSubagent;
|
|
10282
10578
|
var init_ai = __esm({
|
|
10283
10579
|
async "src/utils/ai.js"() {
|
|
@@ -10294,12 +10590,13 @@ var init_ai = __esm({
|
|
|
10294
10590
|
init_subagent_state();
|
|
10295
10591
|
init_paths();
|
|
10296
10592
|
init_revert();
|
|
10593
|
+
init_advanceRevert();
|
|
10297
10594
|
init_editor();
|
|
10298
10595
|
client = null;
|
|
10299
10596
|
globalSettings = {};
|
|
10300
10597
|
colorMainWords = (label) => {
|
|
10301
10598
|
if (!label) return label;
|
|
10302
|
-
return label.replace(/(?:(\x1b\[\d+m))?([✔✘✖🔍📖→➕↻•🛇])(?:(\x1b\[\d+m))?\s*\b(Created|Read|Edited|Viewed|Auto-Read|List|Generated|Written|Searched|Get Map|Write Canceled|Edit Canceled|Write Cancelled|Edit Denied|Visited|Updated|Reviewed|Delegated|Background|Checked|Indexed|Analyzed|Browsed|Elevating SubAgent|Checking SubAgent Work|Started Generalist|Called Generalist|Unsupported Modality|Awaiting|Cancelled|Aligning Moon Phase|Contemplating Existence|Staring At Void|Delaying Professionally|Negotiating With Electrons|Touching Grass (virtually)|Panicking Softly|Rethinking Career Choices|Loading Cat Videos|Giving Up Entirely|Summoning Braincell #2|Pretending To Be Busy|Waiting For Motivation DLC|Rotating Internal Screaming|Downloading More RAM|Feeding The Hamsters|Gaslighting Scheduler|Performing Dramatic Pause|Buffering Social Energy|Calculating Regret|Reading Terms And Conditions|Becoming Sentient Briefly|Contacting Ancestors)\b/ig, (match, ansiBefore, icon, ansiAfter, word) => {
|
|
10599
|
+
return label.replace(/(?:(\x1b\[\d+m))?([✔✘✖🔍📖→➕↻•🛇])(?:(\x1b\[\d+m))?\s*\b(Created|Read|Edited|Viewed|Auto-Read|List|Generated|Written|Searched|Get Map|Write Canceled|Edit Canceled|Write Cancelled|Edit Denied|Visited|Updated|Reviewed|Delegated|Background|Checked|Indexed|Analyzed|Browsed|Elevating SubAgent|Checking SubAgent Work|Started Generalist|Called Generalist|Unsupported Modality|Awaiting|Cancelled|Aligning Moon Phase|Contemplating Existence|Staring At Void|Rollback|Delaying Professionally|Negotiating With Electrons|Touching Grass (virtually)|Panicking Softly|Rethinking Career Choices|Loading Cat Videos|Giving Up Entirely|Summoning Braincell #2|Pretending To Be Busy|Waiting For Motivation DLC|Rotating Internal Screaming|Downloading More RAM|Feeding The Hamsters|Gaslighting Scheduler|Performing Dramatic Pause|Buffering Social Energy|Calculating Regret|Reading Terms And Conditions|Becoming Sentient Briefly|Contacting Ancestors)\b/ig, (match, ansiBefore, icon, ansiAfter, word) => {
|
|
10303
10600
|
return `${ansiBefore || ""}${icon}${ansiAfter || ""} \x1B[95m${word}\x1B[0m`;
|
|
10304
10601
|
});
|
|
10305
10602
|
};
|
|
@@ -10902,7 +11199,7 @@ var init_ai = __esm({
|
|
|
10902
11199
|
return pArgs.id || pArgs.taskId;
|
|
10903
11200
|
}
|
|
10904
11201
|
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
10905
|
-
return filePath ?
|
|
11202
|
+
return filePath ? path21.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
|
|
10906
11203
|
} catch (e) {
|
|
10907
11204
|
return null;
|
|
10908
11205
|
}
|
|
@@ -11143,9 +11440,9 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
11143
11440
|
}
|
|
11144
11441
|
})() : String(err);
|
|
11145
11442
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
11146
|
-
const janitorErrDir =
|
|
11147
|
-
if (!
|
|
11148
|
-
|
|
11443
|
+
const janitorErrDir = path21.join(LOGS_DIR, "janitor");
|
|
11444
|
+
if (!fs22.existsSync(janitorErrDir)) fs22.mkdirSync(janitorErrDir, { recursive: true });
|
|
11445
|
+
fs22.appendFileSync(path21.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${errLog}
|
|
11149
11446
|
|
|
11150
11447
|
`);
|
|
11151
11448
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -11154,8 +11451,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
11154
11451
|
}
|
|
11155
11452
|
}
|
|
11156
11453
|
if (attempts) {
|
|
11157
|
-
const janitorErrDir =
|
|
11158
|
-
|
|
11454
|
+
const janitorErrDir = path21.join(LOGS_DIR, "janitor");
|
|
11455
|
+
fs22.appendFileSync(path21.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
11159
11456
|
|
|
11160
11457
|
`);
|
|
11161
11458
|
if (attempts >= MAX_JANITOR_RETRIES) {
|
|
@@ -11635,10 +11932,10 @@ ${newMemoryListStr}
|
|
|
11635
11932
|
}
|
|
11636
11933
|
})() : String(err);
|
|
11637
11934
|
;
|
|
11638
|
-
const janitorLogDir =
|
|
11639
|
-
if (!
|
|
11640
|
-
|
|
11641
|
-
|
|
11935
|
+
const janitorLogDir = path21.join(LOGS_DIR, "janitor");
|
|
11936
|
+
if (!fs22.existsSync(janitorLogDir)) fs22.mkdirSync(janitorLogDir, { recursive: true });
|
|
11937
|
+
fs22.appendFileSync(
|
|
11938
|
+
path21.join(janitorLogDir, "error.log"),
|
|
11642
11939
|
`[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${errLog}
|
|
11643
11940
|
`
|
|
11644
11941
|
);
|
|
@@ -11646,7 +11943,7 @@ ${newMemoryListStr}
|
|
|
11646
11943
|
};
|
|
11647
11944
|
compressHistory = async (settings, history, isAuto = false) => {
|
|
11648
11945
|
const { chatId, aiProvider = "Google" } = settings;
|
|
11649
|
-
const summariesFile =
|
|
11946
|
+
const summariesFile = path21.join(SECRET_DIR, "chat-summaries.json");
|
|
11650
11947
|
const flattenContext = (hist) => {
|
|
11651
11948
|
return hist.filter(
|
|
11652
11949
|
(m) => (m.role === "user" || m.role === "agent" || m.role === "system") && m.role !== "think" && !m.isVisualFeedback && !m.isMeta && !String(m.id).startsWith("welcome")
|
|
@@ -11720,8 +12017,8 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11720
12017
|
};
|
|
11721
12018
|
deleteChatSummary = (chatId) => {
|
|
11722
12019
|
try {
|
|
11723
|
-
const summariesFile =
|
|
11724
|
-
if (
|
|
12020
|
+
const summariesFile = path21.join(SECRET_DIR, "chat-summaries.json");
|
|
12021
|
+
if (fs22.existsSync(summariesFile)) {
|
|
11725
12022
|
const summaries = readEncryptedJson(summariesFile, {});
|
|
11726
12023
|
if (summaries[chatId]) {
|
|
11727
12024
|
delete summaries[chatId];
|
|
@@ -11737,7 +12034,7 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11737
12034
|
if (!client && aiProvider === "Google") throw new Error("AI not initialized");
|
|
11738
12035
|
const isMemoryEnabled = systemSettings?.memory !== false;
|
|
11739
12036
|
const originalText = history[history.length - 1].text;
|
|
11740
|
-
const summariesFile =
|
|
12037
|
+
const summariesFile = path21.join(SECRET_DIR, "chat-summaries.json");
|
|
11741
12038
|
let wasCompressedInStream = false;
|
|
11742
12039
|
const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
|
|
11743
12040
|
const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
|
|
@@ -11745,6 +12042,9 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11745
12042
|
let agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
|
|
11746
12043
|
agentText = agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
|
|
11747
12044
|
await RevertManager.startTransaction(chatId, agentText);
|
|
12045
|
+
if (systemSettings?.advanceRollback) {
|
|
12046
|
+
await AdvanceRevertManager.takeInitialSnapshot(chatId);
|
|
12047
|
+
}
|
|
11748
12048
|
TERMINATION_SIGNAL = false;
|
|
11749
12049
|
let connectionPollInterval = null;
|
|
11750
12050
|
try {
|
|
@@ -11969,11 +12269,12 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11969
12269
|
"log",
|
|
11970
12270
|
".nyc_output",
|
|
11971
12271
|
".sonar",
|
|
11972
|
-
".ruff_cache"
|
|
12272
|
+
".ruff_cache",
|
|
12273
|
+
".VSCodeCounter"
|
|
11973
12274
|
];
|
|
11974
12275
|
const safeReaddirWithTypes = (dir) => {
|
|
11975
12276
|
try {
|
|
11976
|
-
return
|
|
12277
|
+
return fs22.readdirSync(dir, { withFileTypes: true });
|
|
11977
12278
|
} catch (e) {
|
|
11978
12279
|
return [];
|
|
11979
12280
|
}
|
|
@@ -11986,16 +12287,16 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11986
12287
|
if (COLLAPSED_DIRS_GLOBAL.includes(entry.name)) continue;
|
|
11987
12288
|
if (entry.isDirectory()) {
|
|
11988
12289
|
currentCount.value++;
|
|
11989
|
-
countFolders(
|
|
12290
|
+
countFolders(path21.join(dir, entry.name), currentCount, depth + 1);
|
|
11990
12291
|
}
|
|
11991
12292
|
}
|
|
11992
12293
|
return currentCount.value;
|
|
11993
12294
|
};
|
|
11994
12295
|
const getDirTree = (dir, maxDepth, prefix = "", depth = 1) => {
|
|
11995
12296
|
const entries = safeReaddirWithTypes(dir);
|
|
11996
|
-
const sep =
|
|
12297
|
+
const sep = path21.sep;
|
|
11997
12298
|
if (entries.length > 100) {
|
|
11998
|
-
return `${prefix}\u2514\u2500\u2500 ${
|
|
12299
|
+
return `${prefix}\u2514\u2500\u2500 ${path21.basename(dir)}${sep} ...100+ files...
|
|
11999
12300
|
`;
|
|
12000
12301
|
}
|
|
12001
12302
|
let result = "";
|
|
@@ -12013,7 +12314,7 @@ Provide a consolidated summary of the entire session.`;
|
|
|
12013
12314
|
];
|
|
12014
12315
|
finalItems.forEach((item, index) => {
|
|
12015
12316
|
const isLast = index === finalItems.length - 1;
|
|
12016
|
-
const filePath =
|
|
12317
|
+
const filePath = path21.join(dir, item.name);
|
|
12017
12318
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
12018
12319
|
const childPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
12019
12320
|
if (item.isCollapsed) {
|
|
@@ -12099,10 +12400,10 @@ ${currentSummary}
|
|
|
12099
12400
|
if (isBridgeConnected()) {
|
|
12100
12401
|
ideBlock = "[IDE CONTEXT]\n";
|
|
12101
12402
|
if (ideCtx.file_focused !== "none") {
|
|
12102
|
-
const relFocused =
|
|
12403
|
+
const relFocused = path21.relative(process.cwd(), ideCtx.file_focused);
|
|
12103
12404
|
const relOpened = (ideCtx.opened_editors || []).map((p) => {
|
|
12104
|
-
const rel =
|
|
12105
|
-
return rel.startsWith("..") ? `[External] ${
|
|
12405
|
+
const rel = path21.relative(process.cwd(), p);
|
|
12406
|
+
return rel.startsWith("..") ? `[External] ${path21.basename(p)}` : rel;
|
|
12106
12407
|
});
|
|
12107
12408
|
ideBlock += `Focused File: ${relFocused}
|
|
12108
12409
|
Cursor Line: ${ideCtx.cursor_line}
|
|
@@ -12144,7 +12445,7 @@ Cursor Line: ${ideCtx.cursor_line}
|
|
|
12144
12445
|
}
|
|
12145
12446
|
const getSumForLimit = (limit, activeFiles2) => {
|
|
12146
12447
|
return activeFiles2.reduce((sum, f) => {
|
|
12147
|
-
const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused ||
|
|
12448
|
+
const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused || path21.resolve(process.cwd(), f.path) === path21.resolve(ideCtx.file_focused));
|
|
12148
12449
|
const fileLimit = isFocused ? Math.ceil(limit * 1.2) : limit;
|
|
12149
12450
|
return sum + Math.min(f.edits.length, fileLimit);
|
|
12150
12451
|
}, 0);
|
|
@@ -12178,7 +12479,7 @@ Cursor Line: ${ideCtx.cursor_line}
|
|
|
12178
12479
|
}
|
|
12179
12480
|
}
|
|
12180
12481
|
for (const file of activeFiles) {
|
|
12181
|
-
const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused ||
|
|
12482
|
+
const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused || path21.resolve(process.cwd(), file.path) === path21.resolve(ideCtx.file_focused));
|
|
12182
12483
|
const fileLimit = isFocused ? Math.ceil(chosenLimit * 1.2) : chosenLimit;
|
|
12183
12484
|
if (file.edits.length > fileLimit) {
|
|
12184
12485
|
file.edits = file.edits.slice(-fileLimit);
|
|
@@ -12262,9 +12563,9 @@ ${ideCtx.warnings}
|
|
|
12262
12563
|
endLine = matchRange[2] ? parseInt(matchRange[2], 10) : startLine;
|
|
12263
12564
|
filePath = tagClean.slice(0, matchRange.index);
|
|
12264
12565
|
}
|
|
12265
|
-
const absPath =
|
|
12266
|
-
if (
|
|
12267
|
-
const stats =
|
|
12566
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
12567
|
+
if (fs22.existsSync(absPath)) {
|
|
12568
|
+
const stats = fs22.statSync(absPath);
|
|
12268
12569
|
if (stats.isFile()) {
|
|
12269
12570
|
const pathLower = filePath.toLowerCase();
|
|
12270
12571
|
const isPdf = pathLower.endsWith(".pdf");
|
|
@@ -12273,7 +12574,7 @@ ${ideCtx.warnings}
|
|
|
12273
12574
|
const isMultimodalFile = isImage || isPdf || isOfficeFile;
|
|
12274
12575
|
const isSupported = aiProvider === "Google" || MULTIMODAL_MODELS.includes(modelName);
|
|
12275
12576
|
if (isMultimodalFile && !isSupported) {
|
|
12276
|
-
const label = `\u2718 Unsupported Modality: ${
|
|
12577
|
+
const label = `\u2718 Unsupported Modality: ${path21.basename(filePath)}`;
|
|
12277
12578
|
let terminalWidth = 115;
|
|
12278
12579
|
if (process.stdout.isTTY) {
|
|
12279
12580
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -12326,7 +12627,7 @@ ${boxMid}
|
|
|
12326
12627
|
} else {
|
|
12327
12628
|
let totalLines = "...";
|
|
12328
12629
|
try {
|
|
12329
|
-
const content =
|
|
12630
|
+
const content = fs22.readFileSync(absPath, "utf8");
|
|
12330
12631
|
totalLines = content.split("\n").length;
|
|
12331
12632
|
} catch (e) {
|
|
12332
12633
|
}
|
|
@@ -12386,6 +12687,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
|
|
|
12386
12687
|
}
|
|
12387
12688
|
});
|
|
12388
12689
|
for (let loop = 0; loop <= MAX_LOOPS; loop++) {
|
|
12690
|
+
const currentTurnTools = [];
|
|
12389
12691
|
wasToolCalledInLastLoop = false;
|
|
12390
12692
|
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > contextTruncationCount) {
|
|
12391
12693
|
modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
|
|
@@ -12970,7 +13272,7 @@ ${ideErr} [/ERROR]`;
|
|
|
12970
13272
|
if (keyword) {
|
|
12971
13273
|
detail = keyword.replace(/["']/g, "");
|
|
12972
13274
|
} else if (filePath) {
|
|
12973
|
-
detail =
|
|
13275
|
+
detail = path21.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
|
|
12974
13276
|
} else if (title && (potentialTool === "invoke" || potentialTool === "invoke_sync")) {
|
|
12975
13277
|
detail = title.replace(/["']/g, "").substring(0, 30);
|
|
12976
13278
|
} else if (id && potentialTool === "get_progress") {
|
|
@@ -12999,7 +13301,7 @@ ${ideErr} [/ERROR]`;
|
|
|
12999
13301
|
if (potentialTool === "invoke" || potentialTool === "invoke_sync" || potentialTool === "get_progress") {
|
|
13000
13302
|
detail = val.substring(0, 30);
|
|
13001
13303
|
} else {
|
|
13002
|
-
detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val :
|
|
13304
|
+
detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val : path21.basename(val.replace(/\\/g, "/"));
|
|
13003
13305
|
}
|
|
13004
13306
|
}
|
|
13005
13307
|
}
|
|
@@ -13199,9 +13501,9 @@ ${ideErr} [/ERROR]`;
|
|
|
13199
13501
|
let totalLines = "...";
|
|
13200
13502
|
let actualEndLine = eLine;
|
|
13201
13503
|
try {
|
|
13202
|
-
const absPath =
|
|
13203
|
-
if (
|
|
13204
|
-
const content =
|
|
13504
|
+
const absPath = path21.resolve(process.cwd(), targetPath2);
|
|
13505
|
+
if (fs22.existsSync(absPath)) {
|
|
13506
|
+
const content = fs22.readFileSync(absPath, "utf8");
|
|
13205
13507
|
const lines = content.split("\n").length;
|
|
13206
13508
|
totalLines = lines;
|
|
13207
13509
|
actualEndLine = Math.min(eLine, lines);
|
|
@@ -13221,8 +13523,8 @@ ${ideErr} [/ERROR]`;
|
|
|
13221
13523
|
}
|
|
13222
13524
|
} else if (normToolName === "list_files" || normToolName === "read_folder") {
|
|
13223
13525
|
const action = normToolName === "list_files" ? "List" : "Browsed";
|
|
13224
|
-
const
|
|
13225
|
-
label = `\u2714 ${action}: ${
|
|
13526
|
+
const path23 = parseArgs(toolCall.args).path;
|
|
13527
|
+
label = `\u2714 ${action}: ${path23 === "." ? "./" : path23}`;
|
|
13226
13528
|
} else if (normToolName === "write_file" || normToolName === "update_file") {
|
|
13227
13529
|
const action = normToolName === "write_file" ? "Created" : "Edited";
|
|
13228
13530
|
label = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
|
|
@@ -13251,7 +13553,9 @@ ${ideErr} [/ERROR]`;
|
|
|
13251
13553
|
} else if (normToolName === "cancel") {
|
|
13252
13554
|
const detail2 = getToolDetail(normToolName, toolCall.args);
|
|
13253
13555
|
label = `\u{1F6C7} Cancelled${detail2 ? `: ${detail2}` : ""}`;
|
|
13254
|
-
} else if (normToolName === "
|
|
13556
|
+
} else if (normToolName === "EmergencyRollback") {
|
|
13557
|
+
label = `\u2714 Rollback`;
|
|
13558
|
+
} else if (normToolName === "await" || normToolName === "Await") {
|
|
13255
13559
|
const { time } = parseArgs(toolCall.args);
|
|
13256
13560
|
let sec = parseFloat(time) || 0;
|
|
13257
13561
|
if (sec < 10) sec = 10;
|
|
@@ -13305,7 +13609,7 @@ ${ideErr} [/ERROR]`;
|
|
|
13305
13609
|
const { command } = parseArgs(toolCall.args);
|
|
13306
13610
|
if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
|
|
13307
13611
|
const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
|
|
13308
|
-
const currentDrive =
|
|
13612
|
+
const currentDrive = path21.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
13309
13613
|
const splitCommands = (cmdString) => {
|
|
13310
13614
|
const commands = [];
|
|
13311
13615
|
let current = "";
|
|
@@ -13434,8 +13738,8 @@ ${ideErr} [/ERROR]`;
|
|
|
13434
13738
|
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
13435
13739
|
if (targetPath) {
|
|
13436
13740
|
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
13437
|
-
const absoluteTarget =
|
|
13438
|
-
const absoluteCwd =
|
|
13741
|
+
const absoluteTarget = path21.resolve(targetPath);
|
|
13742
|
+
const absoluteCwd = path21.resolve(process.cwd());
|
|
13439
13743
|
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
13440
13744
|
const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace.`;
|
|
13441
13745
|
if (normToolName === "write_file" || normToolName === "update_file") {
|
|
@@ -13624,18 +13928,18 @@ ${boxMid}`) };
|
|
|
13624
13928
|
const toolArgs = parseArgs(toolCall.args);
|
|
13625
13929
|
const { path: filePath } = toolArgs;
|
|
13626
13930
|
if (filePath) {
|
|
13627
|
-
const absPath =
|
|
13628
|
-
const
|
|
13629
|
-
const normAbsPath =
|
|
13931
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13932
|
+
const normalize2 = (p) => p ? p.toLowerCase().replace(/\\/g, "/").replace(/^[a-z]:/, (m) => m.toUpperCase()) : "";
|
|
13933
|
+
const normAbsPath = normalize2(absPath);
|
|
13630
13934
|
let originalContent = "";
|
|
13631
13935
|
let hasOriginal = false;
|
|
13632
13936
|
const currentIDE = await getIDEContext();
|
|
13633
|
-
const normFocused =
|
|
13937
|
+
const normFocused = normalize2(currentIDE?.file_focused);
|
|
13634
13938
|
if (currentIDE && normFocused === normAbsPath && currentIDE.full_content) {
|
|
13635
13939
|
originalContent = currentIDE.full_content;
|
|
13636
13940
|
hasOriginal = true;
|
|
13637
|
-
} else if (
|
|
13638
|
-
originalContent =
|
|
13941
|
+
} else if (fs22.existsSync(absPath)) {
|
|
13942
|
+
originalContent = fs22.readFileSync(absPath, "utf8");
|
|
13639
13943
|
hasOriginal = true;
|
|
13640
13944
|
}
|
|
13641
13945
|
originalContentForReporting = originalContent;
|
|
@@ -13662,9 +13966,9 @@ ${boxMid}`) };
|
|
|
13662
13966
|
const successes = patchResults.filter((r) => r.success);
|
|
13663
13967
|
const failures = patchResults.filter((r) => !r.success);
|
|
13664
13968
|
if (successes.length === 0) {
|
|
13665
|
-
const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${
|
|
13969
|
+
const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${path21.basename(absPath)}].
|
|
13666
13970
|
${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
|
|
13667
|
-
const errorLabel = `\u2714 Edited: ${
|
|
13971
|
+
const errorLabel = `\u2714 Edited: ${path21.basename(absPath)}`.toUpperCase();
|
|
13668
13972
|
let terminalWidth = 115;
|
|
13669
13973
|
if (process.stdout.isTTY) {
|
|
13670
13974
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -13682,19 +13986,19 @@ ${boxMid}}`) };
|
|
|
13682
13986
|
continue;
|
|
13683
13987
|
}
|
|
13684
13988
|
}
|
|
13685
|
-
yield { type: "status", content: `Opening Diff in IDE: ${
|
|
13989
|
+
yield { type: "status", content: `Opening Diff in IDE: ${path21.basename(absPath)}...` };
|
|
13686
13990
|
showDiffInIDE(absPath, originalContent, modifiedContent);
|
|
13687
13991
|
diffOpened = true;
|
|
13688
13992
|
await new Promise((r) => setTimeout(r, 50));
|
|
13689
13993
|
} else if (normToolName === "write_file") {
|
|
13690
13994
|
const rawContent = toolArgs.content || toolArgs.newContent || "";
|
|
13691
13995
|
const modifiedContent = rawContent.endsWith("\n") ? rawContent : rawContent + "\n";
|
|
13692
|
-
if (!
|
|
13996
|
+
if (!fs22.existsSync(absPath)) {
|
|
13693
13997
|
isNewFileCreated = true;
|
|
13694
|
-
|
|
13695
|
-
|
|
13998
|
+
fs22.mkdirSync(path21.dirname(absPath), { recursive: true });
|
|
13999
|
+
fs22.writeFileSync(absPath, "", "utf8");
|
|
13696
14000
|
}
|
|
13697
|
-
yield { type: "status", content: `Opening New File Diff in IDE: ${
|
|
14001
|
+
yield { type: "status", content: `Opening New File Diff in IDE: ${path21.basename(absPath)}...` };
|
|
13698
14002
|
showDiffInIDE(absPath, "", modifiedContent);
|
|
13699
14003
|
diffOpened = true;
|
|
13700
14004
|
await new Promise((r) => setTimeout(r, 50));
|
|
@@ -13730,11 +14034,11 @@ ${boxMid}}`) };
|
|
|
13730
14034
|
if (normToolName === "write_file" || normToolName === "update_file") {
|
|
13731
14035
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13732
14036
|
if (filePath) {
|
|
13733
|
-
const absPath =
|
|
14037
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13734
14038
|
closeDiffInIDE(absPath, approval);
|
|
13735
|
-
if (approval === "deny" && isNewFileCreated &&
|
|
14039
|
+
if (approval === "deny" && isNewFileCreated && fs22.existsSync(absPath)) {
|
|
13736
14040
|
try {
|
|
13737
|
-
|
|
14041
|
+
fs22.unlinkSync(absPath);
|
|
13738
14042
|
} catch (e) {
|
|
13739
14043
|
}
|
|
13740
14044
|
}
|
|
@@ -13746,13 +14050,13 @@ ${boxMid}}`) };
|
|
|
13746
14050
|
}
|
|
13747
14051
|
if (approval === "allow" && diffOpened && isBridgeConnected()) {
|
|
13748
14052
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13749
|
-
const absPath =
|
|
14053
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13750
14054
|
const finalIDE = await getIDEContext();
|
|
13751
14055
|
let finalContent = "";
|
|
13752
14056
|
if (finalIDE && finalIDE.file_focused === absPath && finalIDE.full_content) {
|
|
13753
14057
|
finalContent = finalIDE.full_content;
|
|
13754
|
-
} else if (
|
|
13755
|
-
finalContent =
|
|
14058
|
+
} else if (fs22.existsSync(absPath)) {
|
|
14059
|
+
finalContent = fs22.readFileSync(absPath, "utf8");
|
|
13756
14060
|
}
|
|
13757
14061
|
const verifiedLines = finalContent.split(/\r?\n/);
|
|
13758
14062
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -13915,7 +14219,7 @@ ${boxBottom}`}`) };
|
|
|
13915
14219
|
try {
|
|
13916
14220
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13917
14221
|
if (filePath) {
|
|
13918
|
-
const absPath =
|
|
14222
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13919
14223
|
const currentIDE = await getIDEContext();
|
|
13920
14224
|
if (currentIDE && currentIDE.file_focused === absPath && currentIDE.full_content) {
|
|
13921
14225
|
execToolContext.forcedContent = currentIDE.full_content;
|
|
@@ -13924,12 +14228,13 @@ ${boxBottom}`}`) };
|
|
|
13924
14228
|
} catch (e) {
|
|
13925
14229
|
}
|
|
13926
14230
|
}
|
|
14231
|
+
currentTurnTools.push(normToolName);
|
|
13927
14232
|
let result = await dispatchTool(normToolName, toolCall.args, execToolContext);
|
|
13928
14233
|
yield { type: "spinner", content: true };
|
|
13929
14234
|
if ((normToolName === "write_file" || normToolName === "update_file") && result.startsWith("SUCCESS")) {
|
|
13930
14235
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13931
14236
|
if (filePath) {
|
|
13932
|
-
const absPath =
|
|
14237
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13933
14238
|
openFileInEditor(absPath);
|
|
13934
14239
|
}
|
|
13935
14240
|
}
|
|
@@ -14173,9 +14478,9 @@ ${colorMainWords(output)}` };
|
|
|
14173
14478
|
})() : String(err);
|
|
14174
14479
|
;
|
|
14175
14480
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
14176
|
-
const agentErrDir =
|
|
14177
|
-
if (!
|
|
14178
|
-
|
|
14481
|
+
const agentErrDir = path21.join(LOGS_DIR, "agent");
|
|
14482
|
+
if (!fs22.existsSync(agentErrDir)) fs22.mkdirSync(agentErrDir, { recursive: true });
|
|
14483
|
+
fs22.appendFileSync(path21.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
14179
14484
|
|
|
14180
14485
|
----------------------------------------------------------------------
|
|
14181
14486
|
|
|
@@ -14222,7 +14527,7 @@ ${recoveryText}`
|
|
|
14222
14527
|
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
14223
14528
|
} else {
|
|
14224
14529
|
throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
|
|
14225
|
-
Error Log can be found in ${
|
|
14530
|
+
Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
|
|
14226
14531
|
}
|
|
14227
14532
|
} else {
|
|
14228
14533
|
if (retryCount <= MAX_RETRIES) {
|
|
@@ -14240,7 +14545,7 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14240
14545
|
yield { type: "status", content: `Trying to reach ${modelName}...` };
|
|
14241
14546
|
} else {
|
|
14242
14547
|
throw new Error(`Model ${modelName} cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
14243
|
-
Error Log can be found in ${
|
|
14548
|
+
Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
|
|
14244
14549
|
}
|
|
14245
14550
|
}
|
|
14246
14551
|
}
|
|
@@ -14313,6 +14618,9 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14313
14618
|
isStutteringLoop = false;
|
|
14314
14619
|
isGeneralLoop = false;
|
|
14315
14620
|
}
|
|
14621
|
+
if (systemSettings?.advanceRollback) {
|
|
14622
|
+
await AdvanceRevertManager.recordTurnDelta(chatId, loop + 1, currentTurnTools);
|
|
14623
|
+
}
|
|
14316
14624
|
wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
|
|
14317
14625
|
}
|
|
14318
14626
|
modifiedHistory.forEach((msg) => {
|
|
@@ -14343,10 +14651,10 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14343
14651
|
}
|
|
14344
14652
|
})() : String(err);
|
|
14345
14653
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
14346
|
-
const agentErrDir =
|
|
14654
|
+
const agentErrDir = path21.join(LOGS_DIR, "agent");
|
|
14347
14655
|
yield { type: "text", content: `\u274C CRITICAL ERROR: ${errLog}` };
|
|
14348
|
-
if (!
|
|
14349
|
-
|
|
14656
|
+
if (!fs22.existsSync(agentErrDir)) fs22.mkdirSync(agentErrDir, { recursive: true });
|
|
14657
|
+
fs22.appendFileSync(path21.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${errLog}
|
|
14350
14658
|
|
|
14351
14659
|
----------------------------------------------------------------------
|
|
14352
14660
|
|
|
@@ -14361,6 +14669,9 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14361
14669
|
connectionPollInterval = null;
|
|
14362
14670
|
}
|
|
14363
14671
|
await RevertManager.commitTransaction();
|
|
14672
|
+
if (systemSettings?.advanceRollback) {
|
|
14673
|
+
await AdvanceRevertManager.cleanup(chatId);
|
|
14674
|
+
}
|
|
14364
14675
|
}
|
|
14365
14676
|
yield { type: "status", content: null };
|
|
14366
14677
|
};
|
|
@@ -14387,6 +14698,7 @@ TOOL POLICY:
|
|
|
14387
14698
|
- FileMap >>> ReadFile to understand file efficiently
|
|
14388
14699
|
- Want spefific STRING across project/file? SearchKeyword >> Guessing/ReadFile
|
|
14389
14700
|
- HUGE FILES? SearchKeyword >> FileMap/Full Read
|
|
14701
|
+
- NO Terminal Access
|
|
14390
14702
|
-- PROVIDED TOOLS --
|
|
14391
14703
|
${Object.values(SUBAGENT_TOOL_DEFINITIONS).join("\n")}
|
|
14392
14704
|
|
|
@@ -14468,11 +14780,11 @@ ${cleanResponse}
|
|
|
14468
14780
|
} else if (normalizedToolName === "list_files" || normalizedToolName === "read_folder" || normalizedToolName === "readfolder") {
|
|
14469
14781
|
label = `\u2714 \x1B[95mBrowsed Folder\x1B[0m`;
|
|
14470
14782
|
} else if (normalizedToolName === "write_file" || normalizedToolName === "writefile") {
|
|
14471
|
-
const
|
|
14472
|
-
label = `\u2714 \x1B[95mFile Created\x1B[0m: ${
|
|
14783
|
+
const path23 = parseArgs(toolCall.args).path || "...";
|
|
14784
|
+
label = `\u2714 \x1B[95mFile Created\x1B[0m: ${path23}`;
|
|
14473
14785
|
} else if (normalizedToolName === "update_file" || normalizedToolName === "updatefile" || normalizedToolName === "patchfile" || normalizedToolName === "patch_file" || normalizedToolName === "patchfile" || normalizedToolName === "updatefile") {
|
|
14474
|
-
const
|
|
14475
|
-
label = `\u2714 \x1B[95mFile Edited\x1B[0m: ${
|
|
14786
|
+
const path23 = parseArgs(toolCall.args).path || "...";
|
|
14787
|
+
label = `\u2714 \x1B[95mFile Edited\x1B[0m: ${path23}`;
|
|
14476
14788
|
} else if (normalizedToolName === "file_map" || normalizedToolName === "filemap") {
|
|
14477
14789
|
label = `\u2714 \x1B[95mIndexed\x1B[0m`;
|
|
14478
14790
|
} else if (normalizedToolName === "await") {
|
|
@@ -15338,7 +15650,7 @@ var init_RevertModal = __esm({
|
|
|
15338
15650
|
import puppeteer4 from "puppeteer";
|
|
15339
15651
|
import { exec } from "child_process";
|
|
15340
15652
|
import { promisify } from "util";
|
|
15341
|
-
import
|
|
15653
|
+
import fs23 from "fs";
|
|
15342
15654
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
15343
15655
|
var init_setup = __esm({
|
|
15344
15656
|
"src/utils/setup.js"() {
|
|
@@ -15347,11 +15659,11 @@ var init_setup = __esm({
|
|
|
15347
15659
|
checkPuppeteerReady = () => {
|
|
15348
15660
|
try {
|
|
15349
15661
|
const pptrConfig = getPuppeteerConfig();
|
|
15350
|
-
if (pptrConfig.executablePath &&
|
|
15662
|
+
if (pptrConfig.executablePath && fs23.existsSync(pptrConfig.executablePath)) {
|
|
15351
15663
|
return true;
|
|
15352
15664
|
}
|
|
15353
15665
|
const exePath = puppeteer4.executablePath();
|
|
15354
|
-
const exists = exePath &&
|
|
15666
|
+
const exists = exePath && fs23.existsSync(exePath);
|
|
15355
15667
|
if (exists) return true;
|
|
15356
15668
|
} catch (e) {
|
|
15357
15669
|
return false;
|
|
@@ -15384,8 +15696,8 @@ __export(app_exports, {
|
|
|
15384
15696
|
import os5 from "os";
|
|
15385
15697
|
import React15, { useState as useState14, useEffect as useEffect11, useRef as useRef4, useMemo as useMemo2 } from "react";
|
|
15386
15698
|
import { Box as Box14, Text as Text15, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
|
|
15387
|
-
import
|
|
15388
|
-
import
|
|
15699
|
+
import fs24 from "fs-extra";
|
|
15700
|
+
import path22 from "path";
|
|
15389
15701
|
import { exec as exec2 } from "child_process";
|
|
15390
15702
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15391
15703
|
import TextInput4 from "ink-text-input";
|
|
@@ -15630,10 +15942,10 @@ function App({ args = [] }) {
|
|
|
15630
15942
|
const kbPath = getKeybindingsPath(ideName);
|
|
15631
15943
|
if (!kbPath) return;
|
|
15632
15944
|
try {
|
|
15633
|
-
await
|
|
15945
|
+
await fs24.ensureDir(path22.dirname(kbPath));
|
|
15634
15946
|
let bindings = [];
|
|
15635
|
-
if (
|
|
15636
|
-
const content =
|
|
15947
|
+
if (fs24.existsSync(kbPath)) {
|
|
15948
|
+
const content = fs24.readFileSync(kbPath, "utf8").trim();
|
|
15637
15949
|
if (content) {
|
|
15638
15950
|
try {
|
|
15639
15951
|
bindings = parseJsonc(content);
|
|
@@ -15653,7 +15965,7 @@ function App({ args = [] }) {
|
|
|
15653
15965
|
},
|
|
15654
15966
|
"when": "terminalFocus"
|
|
15655
15967
|
});
|
|
15656
|
-
|
|
15968
|
+
fs24.writeFileSync(kbPath, JSON.stringify(bindings, null, 4), "utf8");
|
|
15657
15969
|
cachedShortcut = "Shift + Enter";
|
|
15658
15970
|
setMessages((prev) => {
|
|
15659
15971
|
setCompletedIndex(prev.length + 1);
|
|
@@ -16329,7 +16641,7 @@ function App({ args = [] }) {
|
|
|
16329
16641
|
useEffect11(() => {
|
|
16330
16642
|
async function init() {
|
|
16331
16643
|
try {
|
|
16332
|
-
const pkg = JSON.parse(
|
|
16644
|
+
const pkg = JSON.parse(fs24.readFileSync(path22.join(process.cwd(), "package.json"), "utf8"));
|
|
16333
16645
|
initBridge(versionFluxflow || pkg.version || "2.0.0");
|
|
16334
16646
|
} catch (e) {
|
|
16335
16647
|
initBridge("2.0.0");
|
|
@@ -16452,7 +16764,7 @@ function App({ args = [] }) {
|
|
|
16452
16764
|
if (!parsedArgs.playground) {
|
|
16453
16765
|
deleteChat(PLAYGROUND_CHAT_ID).catch(() => {
|
|
16454
16766
|
});
|
|
16455
|
-
|
|
16767
|
+
fs24.remove(path22.join(DATA_DIR, "playground")).catch(() => {
|
|
16456
16768
|
});
|
|
16457
16769
|
}
|
|
16458
16770
|
performVersionCheck(false, freshSettings);
|
|
@@ -16486,9 +16798,9 @@ function App({ args = [] }) {
|
|
|
16486
16798
|
}
|
|
16487
16799
|
}
|
|
16488
16800
|
if (parsedArgs.playground) {
|
|
16489
|
-
const playgroundDir =
|
|
16801
|
+
const playgroundDir = path22.join(DATA_DIR, "playground");
|
|
16490
16802
|
try {
|
|
16491
|
-
|
|
16803
|
+
fs24.ensureDirSync(playgroundDir);
|
|
16492
16804
|
process.chdir(playgroundDir);
|
|
16493
16805
|
} catch (e) {
|
|
16494
16806
|
}
|
|
@@ -16529,8 +16841,8 @@ function App({ args = [] }) {
|
|
|
16529
16841
|
if (kbPath) {
|
|
16530
16842
|
try {
|
|
16531
16843
|
let bindings = [];
|
|
16532
|
-
if (
|
|
16533
|
-
const content =
|
|
16844
|
+
if (fs24.existsSync(kbPath)) {
|
|
16845
|
+
const content = fs24.readFileSync(kbPath, "utf8").trim();
|
|
16534
16846
|
if (content) {
|
|
16535
16847
|
bindings = parseJsonc(content);
|
|
16536
16848
|
}
|
|
@@ -17063,22 +17375,22 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17063
17375
|
});
|
|
17064
17376
|
break;
|
|
17065
17377
|
}
|
|
17066
|
-
const src =
|
|
17067
|
-
const dest =
|
|
17378
|
+
const src = path22.join(DATA_DIR, "playground");
|
|
17379
|
+
const dest = path22.join(parsedArgs.originalCwd, "playground-export");
|
|
17068
17380
|
const moveFiles = async () => {
|
|
17069
17381
|
try {
|
|
17070
17382
|
setMessages((prev) => {
|
|
17071
17383
|
setCompletedIndex(prev.length + 1);
|
|
17072
17384
|
return [...prev, { id: Date.now(), role: "system", text: `[PLAYGROUND] Exporting playground content to ${dest}`, isMeta: true }];
|
|
17073
17385
|
});
|
|
17074
|
-
await
|
|
17386
|
+
await fs24.ensureDir(dest);
|
|
17075
17387
|
const excludeDirs = ["node_modules", ".git", ".venv", "venv", "env", ".next", "dist", "build", ".cache"];
|
|
17076
|
-
await
|
|
17388
|
+
await fs24.copy(src, dest, {
|
|
17077
17389
|
overwrite: true,
|
|
17078
17390
|
filter: (srcPath) => {
|
|
17079
|
-
const relative =
|
|
17391
|
+
const relative = path22.relative(src, srcPath);
|
|
17080
17392
|
if (!relative) return true;
|
|
17081
|
-
const parts2 = relative.split(
|
|
17393
|
+
const parts2 = relative.split(path22.sep);
|
|
17082
17394
|
return !parts2.some((part) => excludeDirs.includes(part));
|
|
17083
17395
|
}
|
|
17084
17396
|
});
|
|
@@ -17138,7 +17450,7 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17138
17450
|
}
|
|
17139
17451
|
}
|
|
17140
17452
|
setTimeout(() => {
|
|
17141
|
-
|
|
17453
|
+
fs24.emptyDir(path22.join(DATA_DIR, "playground")).catch((err) => {
|
|
17142
17454
|
setMessages((prev) => {
|
|
17143
17455
|
const newMsgs = [...prev, {
|
|
17144
17456
|
id: "playground-" + Date.now(),
|
|
@@ -17435,7 +17747,7 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17435
17747
|
}
|
|
17436
17748
|
case "/export": {
|
|
17437
17749
|
const exportFile = `export-fluxflow-${chatId}.txt`;
|
|
17438
|
-
const exportPath =
|
|
17750
|
+
const exportPath = path22.join(process.cwd(), exportFile);
|
|
17439
17751
|
const exportLines = [];
|
|
17440
17752
|
let insideAgentBlock = false;
|
|
17441
17753
|
for (let i = 0; i < messages.length; i++) {
|
|
@@ -17487,7 +17799,7 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17487
17799
|
}
|
|
17488
17800
|
const fileContent = exportLines.join("\n");
|
|
17489
17801
|
try {
|
|
17490
|
-
|
|
17802
|
+
fs24.writeFileSync(exportPath, fileContent, "utf8");
|
|
17491
17803
|
setMessages((prev) => {
|
|
17492
17804
|
setCompletedIndex(prev.length + 1);
|
|
17493
17805
|
return [...prev, {
|
|
@@ -17534,12 +17846,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
17534
17846
|
setCompletedIndex(prev.length + 1);
|
|
17535
17847
|
return [...prev, { id: Date.now(), role: "system", text: "[NUCLEAR] Initiating reset...", isMeta: true }];
|
|
17536
17848
|
});
|
|
17537
|
-
if (
|
|
17538
|
-
if (
|
|
17539
|
-
if (
|
|
17849
|
+
if (fs24.existsSync(LOGS_DIR)) fs24.removeSync(LOGS_DIR);
|
|
17850
|
+
if (fs24.existsSync(SECRET_DIR)) fs24.removeSync(SECRET_DIR);
|
|
17851
|
+
if (fs24.existsSync(SETTINGS_FILE)) fs24.removeSync(SETTINGS_FILE);
|
|
17540
17852
|
try {
|
|
17541
|
-
const items =
|
|
17542
|
-
if (items.length === 0)
|
|
17853
|
+
const items = fs24.readdirSync(FLUXFLOW_DIR);
|
|
17854
|
+
if (items.length === 0) fs24.removeSync(FLUXFLOW_DIR);
|
|
17543
17855
|
} catch (e) {
|
|
17544
17856
|
}
|
|
17545
17857
|
setTimeout(() => {
|
|
@@ -17661,15 +17973,15 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
17661
17973
|
# SKILLS & WORKFLOWS
|
|
17662
17974
|
- [Define custom step-by-step recipes for this project here]
|
|
17663
17975
|
`;
|
|
17664
|
-
const filePath =
|
|
17665
|
-
if (
|
|
17976
|
+
const filePath = path22.join(process.cwd(), "FluxFlow.md");
|
|
17977
|
+
if (fs24.pathExistsSync(filePath)) {
|
|
17666
17978
|
setMessages((prev) => {
|
|
17667
17979
|
setCompletedIndex(prev.length + 1);
|
|
17668
17980
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
17669
17981
|
});
|
|
17670
17982
|
} else {
|
|
17671
17983
|
try {
|
|
17672
|
-
|
|
17984
|
+
fs24.writeFileSync(filePath, template);
|
|
17673
17985
|
setMessages((prev) => {
|
|
17674
17986
|
setCompletedIndex(prev.length + 1);
|
|
17675
17987
|
return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "[SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
|
|
@@ -19065,6 +19377,23 @@ Selection: ${val}`,
|
|
|
19065
19377
|
}
|
|
19066
19378
|
}
|
|
19067
19379
|
)));
|
|
19380
|
+
case "advanceRollbackDanger":
|
|
19381
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, paddingTop: 0, width: "100%" }, /* @__PURE__ */ React15.createElement(Text15, { color: "white", bold: true }, "\u26A0 Emergency Rollback Notice"), /* @__PURE__ */ React15.createElement(Text15, { marginTop: 1 }, "When enabled, full repo snapshots exist only during active AI turns."), /* @__PURE__ */ React15.createElement(Text15, { marginTop: 1 }, "If catastrophic changes occur during a turn, avoid abruptly stopping the agent unless absolutely necessary (external damages out of codebase)."), /* @__PURE__ */ React15.createElement(Text15, null, "The agent may be able to automatically restore the repo to a safe state."), /* @__PURE__ */ React15.createElement(Text15, { marginTop: 1 }, "Once the turn ends, emergency snapshots are deleted and standard /revert takes over which may not retain full repo content."), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(
|
|
19382
|
+
CommandMenu,
|
|
19383
|
+
{
|
|
19384
|
+
title: "Confirm",
|
|
19385
|
+
items: [
|
|
19386
|
+
{ label: "I understand and wish to enable", value: "on" },
|
|
19387
|
+
{ label: "Keep Off", value: "off" }
|
|
19388
|
+
],
|
|
19389
|
+
onSelect: (item) => {
|
|
19390
|
+
if (item.value === "on") {
|
|
19391
|
+
setSystemSettings((s) => ({ ...s, advanceRollback: true }));
|
|
19392
|
+
}
|
|
19393
|
+
setActiveView("settings");
|
|
19394
|
+
}
|
|
19395
|
+
}
|
|
19396
|
+
)));
|
|
19068
19397
|
case "externalDanger":
|
|
19069
19398
|
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React15.createElement(Text15, { color: "white", bold: true, underline: true }, "SECURITY WARNING: EXTERNAL WORKSPACE ACCESS"), /* @__PURE__ */ React15.createElement(Text15, { marginTop: 1 }, "Turning this ON allows the agent to execute tools (Read/Write/Exec) outside of the current active workspace directory."), /* @__PURE__ */ React15.createElement(Text15, { marginTop: 1, color: "white" }, "RISKS INVOLVED:"), /* @__PURE__ */ React15.createElement(Text15, null, "\u2022 Access to sensitive system files (SSH keys, Browser data, etc.)"), /* @__PURE__ */ React15.createElement(Text15, null, "\u2022 Potential for accidental or malicious deletion of OS-critical files."), /* @__PURE__ */ React15.createElement(Text15, null, "\u2022 Unauthorized script execution across your entire file system."), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(
|
|
19070
19399
|
CommandMenu,
|
|
@@ -19712,11 +20041,11 @@ var init_app = __esm({
|
|
|
19712
20041
|
if (process.platform === "win32") {
|
|
19713
20042
|
const appData = process.env.APPDATA;
|
|
19714
20043
|
if (!appData) return null;
|
|
19715
|
-
return
|
|
20044
|
+
return path22.join(appData, dirName, "User", "keybindings.json");
|
|
19716
20045
|
} else if (process.platform === "darwin") {
|
|
19717
|
-
return
|
|
20046
|
+
return path22.join(home, "Library", "Application Support", dirName, "User", "keybindings.json");
|
|
19718
20047
|
} else {
|
|
19719
|
-
return
|
|
20048
|
+
return path22.join(home, ".config", dirName, "User", "keybindings.json");
|
|
19720
20049
|
}
|
|
19721
20050
|
};
|
|
19722
20051
|
parseJsonc = (content) => {
|
|
@@ -19762,8 +20091,8 @@ var init_app = __esm({
|
|
|
19762
20091
|
DOCS_URL = "https://fluxflow-cli.onrender.com/";
|
|
19763
20092
|
linesAdded = 0;
|
|
19764
20093
|
linesRemoved = 0;
|
|
19765
|
-
packageJsonPath =
|
|
19766
|
-
packageJson = JSON.parse(
|
|
20094
|
+
packageJsonPath = path22.join(path22.dirname(fileURLToPath2(import.meta.url)), "../package.json");
|
|
20095
|
+
packageJson = JSON.parse(fs24.readFileSync(packageJsonPath, "utf8"));
|
|
19767
20096
|
versionFluxflow = packageJson.version;
|
|
19768
20097
|
updatedOn = packageJson.date || "2026-05-20";
|
|
19769
20098
|
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", padding: 0, width: "100%" }, /* @__PURE__ */ React15.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text15, { color: "white", bold: true, underline: true }, data.startsWith("/btw") ? "QUESTION" : "STEERING HINT", " RESOLUTION")), /* @__PURE__ */ React15.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text15, null, "The agent already finished the task before your ", data.startsWith("/btw") ? "question" : "hint", " was consumed.")), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React15.createElement(Text15, { italic: true, color: "gray" }, '"', data.replace("/btw", "").trim(), '"')), /* @__PURE__ */ React15.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text15, { color: "grey" }, "How would you like to proceed?")), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 0 }, /* @__PURE__ */ React15.createElement(
|
|
@@ -19859,19 +20188,19 @@ var init_app = __esm({
|
|
|
19859
20188
|
const fileList = [];
|
|
19860
20189
|
const scan = (currentDir) => {
|
|
19861
20190
|
try {
|
|
19862
|
-
const files =
|
|
20191
|
+
const files = fs24.readdirSync(currentDir);
|
|
19863
20192
|
for (const file of files) {
|
|
19864
20193
|
if (["node_modules", ".git", ".gemini", "dist", "build", ".next", ".cache", "out"].includes(file)) {
|
|
19865
20194
|
continue;
|
|
19866
20195
|
}
|
|
19867
|
-
const filePath =
|
|
19868
|
-
const stat =
|
|
20196
|
+
const filePath = path22.join(currentDir, file);
|
|
20197
|
+
const stat = fs24.statSync(filePath);
|
|
19869
20198
|
if (stat.isDirectory()) {
|
|
19870
20199
|
scan(filePath);
|
|
19871
20200
|
} else {
|
|
19872
20201
|
fileList.push({
|
|
19873
20202
|
name: file,
|
|
19874
|
-
relativePath:
|
|
20203
|
+
relativePath: path22.relative(process.cwd(), filePath)
|
|
19875
20204
|
});
|
|
19876
20205
|
}
|
|
19877
20206
|
}
|
|
@@ -19994,11 +20323,11 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
19994
20323
|
const isVersion = args.includes("--version") || args.includes("-v");
|
|
19995
20324
|
const isUpdate = args[0] === "--update";
|
|
19996
20325
|
if (isVersion || isHelp || isHelpCommands || isUpdate) {
|
|
19997
|
-
const
|
|
19998
|
-
const
|
|
20326
|
+
const fs25 = await import("fs");
|
|
20327
|
+
const path23 = await import("path");
|
|
19999
20328
|
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
20000
|
-
const packageJsonPath2 =
|
|
20001
|
-
const packageJson2 = JSON.parse(
|
|
20329
|
+
const packageJsonPath2 = path23.join(path23.dirname(fileURLToPath4(import.meta.url)), "../package.json");
|
|
20330
|
+
const packageJson2 = JSON.parse(fs25.readFileSync(packageJsonPath2, "utf8"));
|
|
20002
20331
|
const versionFluxflow2 = packageJson2.version;
|
|
20003
20332
|
if (isVersion) {
|
|
20004
20333
|
console.log(`v${versionFluxflow2}`);
|