fluxflow-cli 3.0.22 → 3.1.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/dist/fluxflow.js +498 -139
- 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,11 @@ ${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
|
+
Info: 'initial' = user prompted for THIS active task, revert 'id' should be a turn BEFORE the disaster tool ran eg. Disaster Tool: "turn_3", Revert ID: "turn_2" (do explicit reasoning if needed)
|
|
5196
|
+
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
|
|
5197
|
+
` : ""}
|
|
5190
5198
|
-- SUB AGENTS DEFINITIONS --
|
|
5191
5199
|
**PROACTIVE USE OF SUB AGENTS HIGHLY RECOMMENDED, PREFER USING FOR ALL TASK WHERE PLAUSIBLE & BENEFICIAL, EVEN WITHOUT EXPLICIT USER NUDGE**
|
|
5192
5200
|
|
|
@@ -5944,6 +5952,7 @@ function SettingsMenu({
|
|
|
5944
5952
|
{ label: "Auto Approve Commands", value: "autoApprove", status: truncateCSV(systemSettings.autoApproveCommands), section: "Sandbox" },
|
|
5945
5953
|
{ label: "Auto Disapprove Commands", value: "autoDisallow", status: truncateCSV(systemSettings.autoDisallowCommands), section: "Sandbox" },
|
|
5946
5954
|
{ label: "Auto Approve Git Commits", value: "autoApproveGit", status: systemSettings.autoApproveGit ? "ON" : "OFF", section: "Sandbox" },
|
|
5955
|
+
{ label: "Advanced Rollback [EXPERIMENTAL]", value: "advanceRollback", status: systemSettings.advanceRollback ? "ON" : "OFF", section: "Other" },
|
|
5947
5956
|
{ label: "Auto-Delete History", value: "autoDelete", status: systemSettings.autoDeleteHistory || "30d", section: "Other" },
|
|
5948
5957
|
{ label: "Save AppData Externally", value: "externalData", status: systemSettings.useExternalData ? "ON" : "OFF", section: "Other" }
|
|
5949
5958
|
];
|
|
@@ -6075,6 +6084,16 @@ function SettingsMenu({
|
|
|
6075
6084
|
setActiveView("apiTier");
|
|
6076
6085
|
} else if (item.value === "aiProvider") {
|
|
6077
6086
|
setActiveView("selectProvider");
|
|
6087
|
+
} else if (item.value === "advanceRollback") {
|
|
6088
|
+
if (!systemSettings.advanceRollback) {
|
|
6089
|
+
setActiveView("advanceRollbackDanger");
|
|
6090
|
+
} else {
|
|
6091
|
+
setSystemSettings((s) => {
|
|
6092
|
+
const newSysSettings = { ...s, advanceRollback: false };
|
|
6093
|
+
saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
|
|
6094
|
+
return newSysSettings;
|
|
6095
|
+
});
|
|
6096
|
+
}
|
|
6078
6097
|
} else if (item.value === "autoDelete") {
|
|
6079
6098
|
const options = ["1d", "7d", "30d"];
|
|
6080
6099
|
const currentIndex = options.indexOf(systemSettings.autoDeleteHistory || "30d");
|
|
@@ -6544,7 +6563,7 @@ ${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && !isGemini ? `
|
|
|
6544
6563
|
CRITICAL THINKING POLICY
|
|
6545
6564
|
- ALWAYS use <think> ... </think> before responding, even with simple queries/greetings
|
|
6546
6565
|
` : ""}` : `${thinkingConfig}`}
|
|
6547
|
-
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider)}
|
|
6566
|
+
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider, systemSettings?.advanceRollback)}
|
|
6548
6567
|
${projectContextBlock}
|
|
6549
6568
|
-- MEMORY RULES --
|
|
6550
6569
|
- Memory: ${isMemoryEnabled ? "Subtly Personalize. Auto Saves" : "OFF. Decline Remembering Memories"}
|
|
@@ -10044,6 +10063,308 @@ var init_await = __esm({
|
|
|
10044
10063
|
}
|
|
10045
10064
|
});
|
|
10046
10065
|
|
|
10066
|
+
// src/utils/advanceRevert.js
|
|
10067
|
+
import fs21 from "fs-extra";
|
|
10068
|
+
import path20 from "path";
|
|
10069
|
+
async function scanWorkspace(dir, baseDir = dir) {
|
|
10070
|
+
const manifest = {};
|
|
10071
|
+
const entries = await fs21.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
10072
|
+
for (const entry of entries) {
|
|
10073
|
+
if (JUNK_DIRECTORIES.includes(entry.name)) continue;
|
|
10074
|
+
const fullPath = path20.join(dir, entry.name);
|
|
10075
|
+
const relPath = path20.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
10076
|
+
if (entry.isDirectory()) {
|
|
10077
|
+
const sub = await scanWorkspace(fullPath, baseDir);
|
|
10078
|
+
Object.assign(manifest, sub);
|
|
10079
|
+
} else {
|
|
10080
|
+
const stats = await fs21.stat(fullPath).catch(() => null);
|
|
10081
|
+
if (stats) {
|
|
10082
|
+
manifest[relPath] = {
|
|
10083
|
+
size: stats.size,
|
|
10084
|
+
mtime: stats.mtimeMs
|
|
10085
|
+
};
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
}
|
|
10089
|
+
return manifest;
|
|
10090
|
+
}
|
|
10091
|
+
async function copyWorkspaceFiles(destDir, manifest) {
|
|
10092
|
+
await fs21.ensureDir(destDir);
|
|
10093
|
+
for (const relPath of Object.keys(manifest)) {
|
|
10094
|
+
const srcPath = path20.join(process.cwd(), relPath);
|
|
10095
|
+
const destPath = path20.join(destDir, relPath);
|
|
10096
|
+
await fs21.ensureDir(path20.dirname(destPath));
|
|
10097
|
+
await fs21.copyFile(srcPath, destPath).catch(() => {
|
|
10098
|
+
});
|
|
10099
|
+
}
|
|
10100
|
+
}
|
|
10101
|
+
async function restoreSnapshotDir(srcDir, destDir) {
|
|
10102
|
+
if (!await fs21.pathExists(srcDir)) return;
|
|
10103
|
+
const entries = await fs21.readdir(srcDir, { withFileTypes: true }).catch(() => []);
|
|
10104
|
+
for (const entry of entries) {
|
|
10105
|
+
const srcPath = path20.join(srcDir, entry.name);
|
|
10106
|
+
const destPath = path20.join(destDir, entry.name);
|
|
10107
|
+
if (entry.isDirectory()) {
|
|
10108
|
+
await restoreSnapshotDir(srcPath, destPath);
|
|
10109
|
+
} else {
|
|
10110
|
+
if (await fs21.pathExists(destPath)) {
|
|
10111
|
+
await fs21.chmod(destPath, 438).catch(() => {
|
|
10112
|
+
});
|
|
10113
|
+
}
|
|
10114
|
+
await fs21.ensureDir(path20.dirname(destPath));
|
|
10115
|
+
await fs21.copyFile(srcPath, destPath).catch(() => {
|
|
10116
|
+
});
|
|
10117
|
+
await fs21.chmod(destPath, 438).catch(() => {
|
|
10118
|
+
});
|
|
10119
|
+
}
|
|
10120
|
+
}
|
|
10121
|
+
}
|
|
10122
|
+
var JUNK_DIRECTORIES, AdvanceRevertManager;
|
|
10123
|
+
var init_advanceRevert = __esm({
|
|
10124
|
+
"src/utils/advanceRevert.js"() {
|
|
10125
|
+
init_paths();
|
|
10126
|
+
init_crypto();
|
|
10127
|
+
JUNK_DIRECTORIES = [
|
|
10128
|
+
"node_modules",
|
|
10129
|
+
"dist",
|
|
10130
|
+
"bin",
|
|
10131
|
+
"logs",
|
|
10132
|
+
".git",
|
|
10133
|
+
".fluxflow",
|
|
10134
|
+
"secret",
|
|
10135
|
+
".gemini",
|
|
10136
|
+
".agents",
|
|
10137
|
+
"tmp",
|
|
10138
|
+
"temp",
|
|
10139
|
+
"build",
|
|
10140
|
+
"out",
|
|
10141
|
+
"snapshots"
|
|
10142
|
+
];
|
|
10143
|
+
AdvanceRevertManager = {
|
|
10144
|
+
async takeInitialSnapshot(chatId) {
|
|
10145
|
+
try {
|
|
10146
|
+
const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
|
|
10147
|
+
await fs21.remove(snapshotsDir).catch(() => {
|
|
10148
|
+
});
|
|
10149
|
+
await fs21.ensureDir(snapshotsDir);
|
|
10150
|
+
const manifest = await scanWorkspace(process.cwd());
|
|
10151
|
+
await copyWorkspaceFiles(path20.join(snapshotsDir, "initial"), manifest);
|
|
10152
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10153
|
+
ledger[chatId] = {
|
|
10154
|
+
initialManifest: manifest,
|
|
10155
|
+
currentManifest: manifest,
|
|
10156
|
+
checkpoints: [
|
|
10157
|
+
{
|
|
10158
|
+
id: "initial",
|
|
10159
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10160
|
+
newFiles: [],
|
|
10161
|
+
modifiedFiles: [],
|
|
10162
|
+
deletedFiles: [],
|
|
10163
|
+
toolsUsed: []
|
|
10164
|
+
}
|
|
10165
|
+
]
|
|
10166
|
+
};
|
|
10167
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10168
|
+
} catch (err) {
|
|
10169
|
+
}
|
|
10170
|
+
},
|
|
10171
|
+
async recordTurnDelta(chatId, turnNumber, toolsUsed = []) {
|
|
10172
|
+
try {
|
|
10173
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10174
|
+
const session = ledger[chatId];
|
|
10175
|
+
if (!session) return;
|
|
10176
|
+
const previousManifest = session.currentManifest || session.initialManifest;
|
|
10177
|
+
const currentManifest = await scanWorkspace(process.cwd());
|
|
10178
|
+
const newFiles = [];
|
|
10179
|
+
const modifiedFiles = [];
|
|
10180
|
+
const deletedFiles = [];
|
|
10181
|
+
for (const [relPath, info] of Object.entries(currentManifest)) {
|
|
10182
|
+
const prev = previousManifest[relPath];
|
|
10183
|
+
if (!prev) {
|
|
10184
|
+
newFiles.push(relPath);
|
|
10185
|
+
} else if (prev.size !== info.size || prev.mtime !== info.mtime) {
|
|
10186
|
+
modifiedFiles.push(relPath);
|
|
10187
|
+
}
|
|
10188
|
+
}
|
|
10189
|
+
for (const relPath of Object.keys(previousManifest)) {
|
|
10190
|
+
if (!currentManifest[relPath]) {
|
|
10191
|
+
deletedFiles.push(relPath);
|
|
10192
|
+
}
|
|
10193
|
+
}
|
|
10194
|
+
const changedFiles = [...newFiles, ...modifiedFiles];
|
|
10195
|
+
if (changedFiles.length > 0 || deletedFiles.length > 0) {
|
|
10196
|
+
const deltaManifest = {};
|
|
10197
|
+
for (const file of changedFiles) {
|
|
10198
|
+
deltaManifest[file] = currentManifest[file];
|
|
10199
|
+
}
|
|
10200
|
+
const turnDir = path20.join(DATA_DIR, "snapshots", chatId, `turn_${turnNumber}`);
|
|
10201
|
+
await copyWorkspaceFiles(turnDir, deltaManifest);
|
|
10202
|
+
}
|
|
10203
|
+
session.checkpoints.push({
|
|
10204
|
+
id: `turn_${turnNumber}`,
|
|
10205
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10206
|
+
newFiles,
|
|
10207
|
+
modifiedFiles,
|
|
10208
|
+
deletedFiles,
|
|
10209
|
+
toolsUsed
|
|
10210
|
+
});
|
|
10211
|
+
session.currentManifest = currentManifest;
|
|
10212
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10213
|
+
} catch (err) {
|
|
10214
|
+
}
|
|
10215
|
+
},
|
|
10216
|
+
async getCheckpoints(chatId) {
|
|
10217
|
+
try {
|
|
10218
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10219
|
+
const session = ledger[chatId];
|
|
10220
|
+
if (!session) return [];
|
|
10221
|
+
return session.checkpoints || [];
|
|
10222
|
+
} catch (err) {
|
|
10223
|
+
return [];
|
|
10224
|
+
}
|
|
10225
|
+
},
|
|
10226
|
+
async rollbackToCheckpoint(chatId, checkpointId) {
|
|
10227
|
+
try {
|
|
10228
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10229
|
+
const session = ledger[chatId];
|
|
10230
|
+
if (!session) throw new Error("No session active for Advance Rollback.");
|
|
10231
|
+
const checkpoints = session.checkpoints || [];
|
|
10232
|
+
const targetIdx = checkpoints.findIndex((c) => c.id === checkpointId);
|
|
10233
|
+
if (targetIdx === -1) throw new Error(`Checkpoint [${checkpointId}] not found.`);
|
|
10234
|
+
const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
|
|
10235
|
+
const currentFiles = await scanWorkspace(process.cwd());
|
|
10236
|
+
for (const relPath of Object.keys(currentFiles)) {
|
|
10237
|
+
const fullPath = path20.join(process.cwd(), relPath);
|
|
10238
|
+
await fs21.chmod(fullPath, 438).catch(() => {
|
|
10239
|
+
});
|
|
10240
|
+
await fs21.remove(fullPath).catch(() => {
|
|
10241
|
+
});
|
|
10242
|
+
}
|
|
10243
|
+
const initialDir = path20.join(snapshotsDir, "initial");
|
|
10244
|
+
await restoreSnapshotDir(initialDir, process.cwd());
|
|
10245
|
+
for (let i = 1; i <= targetIdx; i++) {
|
|
10246
|
+
const cp = checkpoints[i];
|
|
10247
|
+
const turnDir = path20.join(snapshotsDir, cp.id);
|
|
10248
|
+
await restoreSnapshotDir(turnDir, process.cwd());
|
|
10249
|
+
if (cp.deletedFiles && cp.deletedFiles.length > 0) {
|
|
10250
|
+
for (const delFile of cp.deletedFiles) {
|
|
10251
|
+
const fullPath = path20.join(process.cwd(), delFile);
|
|
10252
|
+
await fs21.chmod(fullPath, 438).catch(() => {
|
|
10253
|
+
});
|
|
10254
|
+
await fs21.remove(fullPath).catch(() => {
|
|
10255
|
+
});
|
|
10256
|
+
}
|
|
10257
|
+
}
|
|
10258
|
+
}
|
|
10259
|
+
session.checkpoints = checkpoints.slice(0, targetIdx + 1);
|
|
10260
|
+
session.currentManifest = await scanWorkspace(process.cwd());
|
|
10261
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10262
|
+
return true;
|
|
10263
|
+
} catch (err) {
|
|
10264
|
+
throw new Error(`Rollback failed: ${err.message}`);
|
|
10265
|
+
}
|
|
10266
|
+
},
|
|
10267
|
+
async cleanup(chatId) {
|
|
10268
|
+
try {
|
|
10269
|
+
const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
|
|
10270
|
+
await fs21.remove(snapshotsDir).catch(() => {
|
|
10271
|
+
});
|
|
10272
|
+
const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
|
|
10273
|
+
if (ledger[chatId]) {
|
|
10274
|
+
delete ledger[chatId];
|
|
10275
|
+
writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
|
|
10276
|
+
}
|
|
10277
|
+
} catch (err) {
|
|
10278
|
+
}
|
|
10279
|
+
}
|
|
10280
|
+
};
|
|
10281
|
+
}
|
|
10282
|
+
});
|
|
10283
|
+
|
|
10284
|
+
// src/tools/emergency_rollback.js
|
|
10285
|
+
var emergency_rollback;
|
|
10286
|
+
var init_emergency_rollback = __esm({
|
|
10287
|
+
"src/tools/emergency_rollback.js"() {
|
|
10288
|
+
init_arg_parser();
|
|
10289
|
+
init_advanceRevert();
|
|
10290
|
+
emergency_rollback = async (args, context = {}) => {
|
|
10291
|
+
const parsed = parseArgs(args);
|
|
10292
|
+
const method = parsed.method;
|
|
10293
|
+
const id = parsed.id;
|
|
10294
|
+
const chatId = context.chatId;
|
|
10295
|
+
const systemSettings = context.systemSettings;
|
|
10296
|
+
if (!systemSettings?.advanceRollback) {
|
|
10297
|
+
return "ERROR: Advance Rollback feature is currently disabled in settings under Security. Tell user to enable it.";
|
|
10298
|
+
}
|
|
10299
|
+
if (!chatId) {
|
|
10300
|
+
return "ERROR: No active chat transaction found for rollback.";
|
|
10301
|
+
}
|
|
10302
|
+
if (method === "getCheckpoint") {
|
|
10303
|
+
const checkpoints = await AdvanceRevertManager.getCheckpoints(chatId);
|
|
10304
|
+
if (checkpoints.length === 0) {
|
|
10305
|
+
return "No checkpoints available.";
|
|
10306
|
+
}
|
|
10307
|
+
const FRIENDLY_TOOL_NAMES = {
|
|
10308
|
+
"write_file": "WriteFile",
|
|
10309
|
+
"update_file": "PatchFile",
|
|
10310
|
+
"view_file": "ReadFile",
|
|
10311
|
+
"read_folder": "ReadFolder",
|
|
10312
|
+
"exec_command": "Run",
|
|
10313
|
+
"web_search": "WebSearch",
|
|
10314
|
+
"web_scrape": "WebScrape",
|
|
10315
|
+
"search_keyword": "SearchKeyword",
|
|
10316
|
+
"write_pdf": "WritePDF",
|
|
10317
|
+
"write_docx": "WriteDoc",
|
|
10318
|
+
"generate_image": "GenerateImage",
|
|
10319
|
+
"file_map": "FileMap",
|
|
10320
|
+
"todo": "Todo",
|
|
10321
|
+
"await": "Await",
|
|
10322
|
+
"ask": "Ask",
|
|
10323
|
+
"ask_user": "Ask",
|
|
10324
|
+
"invoke": "Invoke",
|
|
10325
|
+
"invokesync": "InvokeSync",
|
|
10326
|
+
"getprogress": "GetProgress",
|
|
10327
|
+
"cancel": "Cancel",
|
|
10328
|
+
"emergency_rollback": "EmergencyRollback",
|
|
10329
|
+
"emergencyrollback": "EmergencyRollback"
|
|
10330
|
+
};
|
|
10331
|
+
const getFriendlyName = (name) => {
|
|
10332
|
+
return FRIENDLY_TOOL_NAMES[name] || FRIENDLY_TOOL_NAMES[name.toLowerCase()] || name;
|
|
10333
|
+
};
|
|
10334
|
+
let output = "Available checkpoints for rollback:\n\n";
|
|
10335
|
+
for (const cp of checkpoints) {
|
|
10336
|
+
if (cp.id === "initial") {
|
|
10337
|
+
output += `--- Initial State (id: initial) ---
|
|
10338
|
+
Tools Used: User Prompted for task
|
|
10339
|
+
|
|
10340
|
+
`;
|
|
10341
|
+
} else {
|
|
10342
|
+
const turnNum = cp.id.replace("turn_", "");
|
|
10343
|
+
const toolsStr = cp.toolsUsed && cp.toolsUsed.length > 0 ? cp.toolsUsed.map(getFriendlyName).join(", ") : "None";
|
|
10344
|
+
output += `--- Turn ${turnNum} (id: ${cp.id}) ---
|
|
10345
|
+
Tools Used: ${toolsStr}
|
|
10346
|
+
|
|
10347
|
+
`;
|
|
10348
|
+
}
|
|
10349
|
+
}
|
|
10350
|
+
return output.trim();
|
|
10351
|
+
} else if (method === "forceRevert") {
|
|
10352
|
+
if (!id) {
|
|
10353
|
+
return "ERROR: Missing required parameter 'id' for forceRevert.";
|
|
10354
|
+
}
|
|
10355
|
+
try {
|
|
10356
|
+
await AdvanceRevertManager.rollbackToCheckpoint(chatId, id);
|
|
10357
|
+
return `SUCCESS: Repository rolled back to checkpoint [${id}].`;
|
|
10358
|
+
} catch (err) {
|
|
10359
|
+
return `ERROR: ${err.message}`;
|
|
10360
|
+
}
|
|
10361
|
+
} else {
|
|
10362
|
+
return `ERROR: Invalid method "${method}". Use "getCheckpoint" or "forceRevert".`;
|
|
10363
|
+
}
|
|
10364
|
+
};
|
|
10365
|
+
}
|
|
10366
|
+
});
|
|
10367
|
+
|
|
10047
10368
|
// src/utils/tools.js
|
|
10048
10369
|
var TOOL_MAP, dispatchTool;
|
|
10049
10370
|
var init_tools = __esm({
|
|
@@ -10071,6 +10392,7 @@ var init_tools = __esm({
|
|
|
10071
10392
|
init_getProgress();
|
|
10072
10393
|
init_cancel();
|
|
10073
10394
|
init_await();
|
|
10395
|
+
init_emergency_rollback();
|
|
10074
10396
|
TOOL_MAP = {
|
|
10075
10397
|
web_search,
|
|
10076
10398
|
web_scrape,
|
|
@@ -10126,7 +10448,9 @@ var init_tools = __esm({
|
|
|
10126
10448
|
GetProgress: getProgress,
|
|
10127
10449
|
Cancel: cancel,
|
|
10128
10450
|
await: awaitTool,
|
|
10129
|
-
Await: awaitTool
|
|
10451
|
+
Await: awaitTool,
|
|
10452
|
+
EmergencyRollback: emergency_rollback,
|
|
10453
|
+
emergency_rollback
|
|
10130
10454
|
};
|
|
10131
10455
|
dispatchTool = async (toolName, args, context = {}) => {
|
|
10132
10456
|
const mode = context.mode ? context.mode.toLowerCase() : "flux";
|
|
@@ -10276,8 +10600,8 @@ __export(ai_exports, {
|
|
|
10276
10600
|
signalTermination: () => signalTermination
|
|
10277
10601
|
});
|
|
10278
10602
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
10279
|
-
import
|
|
10280
|
-
import
|
|
10603
|
+
import path21, { normalize } from "path";
|
|
10604
|
+
import fs22 from "fs";
|
|
10281
10605
|
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
10606
|
var init_ai = __esm({
|
|
10283
10607
|
async "src/utils/ai.js"() {
|
|
@@ -10294,12 +10618,13 @@ var init_ai = __esm({
|
|
|
10294
10618
|
init_subagent_state();
|
|
10295
10619
|
init_paths();
|
|
10296
10620
|
init_revert();
|
|
10621
|
+
init_advanceRevert();
|
|
10297
10622
|
init_editor();
|
|
10298
10623
|
client = null;
|
|
10299
10624
|
globalSettings = {};
|
|
10300
10625
|
colorMainWords = (label) => {
|
|
10301
10626
|
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) => {
|
|
10627
|
+
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 Checked|Emergency 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
10628
|
return `${ansiBefore || ""}${icon}${ansiAfter || ""} \x1B[95m${word}\x1B[0m`;
|
|
10304
10629
|
});
|
|
10305
10630
|
};
|
|
@@ -10902,7 +11227,7 @@ var init_ai = __esm({
|
|
|
10902
11227
|
return pArgs.id || pArgs.taskId;
|
|
10903
11228
|
}
|
|
10904
11229
|
const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
|
|
10905
|
-
return filePath ?
|
|
11230
|
+
return filePath ? path21.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
|
|
10906
11231
|
} catch (e) {
|
|
10907
11232
|
return null;
|
|
10908
11233
|
}
|
|
@@ -11143,9 +11468,9 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
11143
11468
|
}
|
|
11144
11469
|
})() : String(err);
|
|
11145
11470
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
11146
|
-
const janitorErrDir =
|
|
11147
|
-
if (!
|
|
11148
|
-
|
|
11471
|
+
const janitorErrDir = path21.join(LOGS_DIR, "janitor");
|
|
11472
|
+
if (!fs22.existsSync(janitorErrDir)) fs22.mkdirSync(janitorErrDir, { recursive: true });
|
|
11473
|
+
fs22.appendFileSync(path21.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${errLog}
|
|
11149
11474
|
|
|
11150
11475
|
`);
|
|
11151
11476
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -11154,8 +11479,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
11154
11479
|
}
|
|
11155
11480
|
}
|
|
11156
11481
|
if (attempts) {
|
|
11157
|
-
const janitorErrDir =
|
|
11158
|
-
|
|
11482
|
+
const janitorErrDir = path21.join(LOGS_DIR, "janitor");
|
|
11483
|
+
fs22.appendFileSync(path21.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
11159
11484
|
|
|
11160
11485
|
`);
|
|
11161
11486
|
if (attempts >= MAX_JANITOR_RETRIES) {
|
|
@@ -11635,10 +11960,10 @@ ${newMemoryListStr}
|
|
|
11635
11960
|
}
|
|
11636
11961
|
})() : String(err);
|
|
11637
11962
|
;
|
|
11638
|
-
const janitorLogDir =
|
|
11639
|
-
if (!
|
|
11640
|
-
|
|
11641
|
-
|
|
11963
|
+
const janitorLogDir = path21.join(LOGS_DIR, "janitor");
|
|
11964
|
+
if (!fs22.existsSync(janitorLogDir)) fs22.mkdirSync(janitorLogDir, { recursive: true });
|
|
11965
|
+
fs22.appendFileSync(
|
|
11966
|
+
path21.join(janitorLogDir, "error.log"),
|
|
11642
11967
|
`[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${errLog}
|
|
11643
11968
|
`
|
|
11644
11969
|
);
|
|
@@ -11646,7 +11971,7 @@ ${newMemoryListStr}
|
|
|
11646
11971
|
};
|
|
11647
11972
|
compressHistory = async (settings, history, isAuto = false) => {
|
|
11648
11973
|
const { chatId, aiProvider = "Google" } = settings;
|
|
11649
|
-
const summariesFile =
|
|
11974
|
+
const summariesFile = path21.join(SECRET_DIR, "chat-summaries.json");
|
|
11650
11975
|
const flattenContext = (hist) => {
|
|
11651
11976
|
return hist.filter(
|
|
11652
11977
|
(m) => (m.role === "user" || m.role === "agent" || m.role === "system") && m.role !== "think" && !m.isVisualFeedback && !m.isMeta && !String(m.id).startsWith("welcome")
|
|
@@ -11720,8 +12045,8 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11720
12045
|
};
|
|
11721
12046
|
deleteChatSummary = (chatId) => {
|
|
11722
12047
|
try {
|
|
11723
|
-
const summariesFile =
|
|
11724
|
-
if (
|
|
12048
|
+
const summariesFile = path21.join(SECRET_DIR, "chat-summaries.json");
|
|
12049
|
+
if (fs22.existsSync(summariesFile)) {
|
|
11725
12050
|
const summaries = readEncryptedJson(summariesFile, {});
|
|
11726
12051
|
if (summaries[chatId]) {
|
|
11727
12052
|
delete summaries[chatId];
|
|
@@ -11737,7 +12062,7 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11737
12062
|
if (!client && aiProvider === "Google") throw new Error("AI not initialized");
|
|
11738
12063
|
const isMemoryEnabled = systemSettings?.memory !== false;
|
|
11739
12064
|
const originalText = history[history.length - 1].text;
|
|
11740
|
-
const summariesFile =
|
|
12065
|
+
const summariesFile = path21.join(SECRET_DIR, "chat-summaries.json");
|
|
11741
12066
|
let wasCompressedInStream = false;
|
|
11742
12067
|
const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
|
|
11743
12068
|
const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
|
|
@@ -11745,6 +12070,9 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11745
12070
|
let agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
|
|
11746
12071
|
agentText = agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
|
|
11747
12072
|
await RevertManager.startTransaction(chatId, agentText);
|
|
12073
|
+
if (systemSettings?.advanceRollback) {
|
|
12074
|
+
await AdvanceRevertManager.takeInitialSnapshot(chatId);
|
|
12075
|
+
}
|
|
11748
12076
|
TERMINATION_SIGNAL = false;
|
|
11749
12077
|
let connectionPollInterval = null;
|
|
11750
12078
|
try {
|
|
@@ -11969,11 +12297,12 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11969
12297
|
"log",
|
|
11970
12298
|
".nyc_output",
|
|
11971
12299
|
".sonar",
|
|
11972
|
-
".ruff_cache"
|
|
12300
|
+
".ruff_cache",
|
|
12301
|
+
".VSCodeCounter"
|
|
11973
12302
|
];
|
|
11974
12303
|
const safeReaddirWithTypes = (dir) => {
|
|
11975
12304
|
try {
|
|
11976
|
-
return
|
|
12305
|
+
return fs22.readdirSync(dir, { withFileTypes: true });
|
|
11977
12306
|
} catch (e) {
|
|
11978
12307
|
return [];
|
|
11979
12308
|
}
|
|
@@ -11986,16 +12315,16 @@ Provide a consolidated summary of the entire session.`;
|
|
|
11986
12315
|
if (COLLAPSED_DIRS_GLOBAL.includes(entry.name)) continue;
|
|
11987
12316
|
if (entry.isDirectory()) {
|
|
11988
12317
|
currentCount.value++;
|
|
11989
|
-
countFolders(
|
|
12318
|
+
countFolders(path21.join(dir, entry.name), currentCount, depth + 1);
|
|
11990
12319
|
}
|
|
11991
12320
|
}
|
|
11992
12321
|
return currentCount.value;
|
|
11993
12322
|
};
|
|
11994
12323
|
const getDirTree = (dir, maxDepth, prefix = "", depth = 1) => {
|
|
11995
12324
|
const entries = safeReaddirWithTypes(dir);
|
|
11996
|
-
const sep =
|
|
12325
|
+
const sep = path21.sep;
|
|
11997
12326
|
if (entries.length > 100) {
|
|
11998
|
-
return `${prefix}\u2514\u2500\u2500 ${
|
|
12327
|
+
return `${prefix}\u2514\u2500\u2500 ${path21.basename(dir)}${sep} ...100+ files...
|
|
11999
12328
|
`;
|
|
12000
12329
|
}
|
|
12001
12330
|
let result = "";
|
|
@@ -12013,7 +12342,7 @@ Provide a consolidated summary of the entire session.`;
|
|
|
12013
12342
|
];
|
|
12014
12343
|
finalItems.forEach((item, index) => {
|
|
12015
12344
|
const isLast = index === finalItems.length - 1;
|
|
12016
|
-
const filePath =
|
|
12345
|
+
const filePath = path21.join(dir, item.name);
|
|
12017
12346
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
12018
12347
|
const childPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
12019
12348
|
if (item.isCollapsed) {
|
|
@@ -12099,10 +12428,10 @@ ${currentSummary}
|
|
|
12099
12428
|
if (isBridgeConnected()) {
|
|
12100
12429
|
ideBlock = "[IDE CONTEXT]\n";
|
|
12101
12430
|
if (ideCtx.file_focused !== "none") {
|
|
12102
|
-
const relFocused =
|
|
12431
|
+
const relFocused = path21.relative(process.cwd(), ideCtx.file_focused);
|
|
12103
12432
|
const relOpened = (ideCtx.opened_editors || []).map((p) => {
|
|
12104
|
-
const rel =
|
|
12105
|
-
return rel.startsWith("..") ? `[External] ${
|
|
12433
|
+
const rel = path21.relative(process.cwd(), p);
|
|
12434
|
+
return rel.startsWith("..") ? `[External] ${path21.basename(p)}` : rel;
|
|
12106
12435
|
});
|
|
12107
12436
|
ideBlock += `Focused File: ${relFocused}
|
|
12108
12437
|
Cursor Line: ${ideCtx.cursor_line}
|
|
@@ -12144,7 +12473,7 @@ Cursor Line: ${ideCtx.cursor_line}
|
|
|
12144
12473
|
}
|
|
12145
12474
|
const getSumForLimit = (limit, activeFiles2) => {
|
|
12146
12475
|
return activeFiles2.reduce((sum, f) => {
|
|
12147
|
-
const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused ||
|
|
12476
|
+
const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused || path21.resolve(process.cwd(), f.path) === path21.resolve(ideCtx.file_focused));
|
|
12148
12477
|
const fileLimit = isFocused ? Math.ceil(limit * 1.2) : limit;
|
|
12149
12478
|
return sum + Math.min(f.edits.length, fileLimit);
|
|
12150
12479
|
}, 0);
|
|
@@ -12178,7 +12507,7 @@ Cursor Line: ${ideCtx.cursor_line}
|
|
|
12178
12507
|
}
|
|
12179
12508
|
}
|
|
12180
12509
|
for (const file of activeFiles) {
|
|
12181
|
-
const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused ||
|
|
12510
|
+
const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused || path21.resolve(process.cwd(), file.path) === path21.resolve(ideCtx.file_focused));
|
|
12182
12511
|
const fileLimit = isFocused ? Math.ceil(chosenLimit * 1.2) : chosenLimit;
|
|
12183
12512
|
if (file.edits.length > fileLimit) {
|
|
12184
12513
|
file.edits = file.edits.slice(-fileLimit);
|
|
@@ -12262,9 +12591,9 @@ ${ideCtx.warnings}
|
|
|
12262
12591
|
endLine = matchRange[2] ? parseInt(matchRange[2], 10) : startLine;
|
|
12263
12592
|
filePath = tagClean.slice(0, matchRange.index);
|
|
12264
12593
|
}
|
|
12265
|
-
const absPath =
|
|
12266
|
-
if (
|
|
12267
|
-
const stats =
|
|
12594
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
12595
|
+
if (fs22.existsSync(absPath)) {
|
|
12596
|
+
const stats = fs22.statSync(absPath);
|
|
12268
12597
|
if (stats.isFile()) {
|
|
12269
12598
|
const pathLower = filePath.toLowerCase();
|
|
12270
12599
|
const isPdf = pathLower.endsWith(".pdf");
|
|
@@ -12273,7 +12602,7 @@ ${ideCtx.warnings}
|
|
|
12273
12602
|
const isMultimodalFile = isImage || isPdf || isOfficeFile;
|
|
12274
12603
|
const isSupported = aiProvider === "Google" || MULTIMODAL_MODELS.includes(modelName);
|
|
12275
12604
|
if (isMultimodalFile && !isSupported) {
|
|
12276
|
-
const label = `\u2718 Unsupported Modality: ${
|
|
12605
|
+
const label = `\u2718 Unsupported Modality: ${path21.basename(filePath)}`;
|
|
12277
12606
|
let terminalWidth = 115;
|
|
12278
12607
|
if (process.stdout.isTTY) {
|
|
12279
12608
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -12326,7 +12655,7 @@ ${boxMid}
|
|
|
12326
12655
|
} else {
|
|
12327
12656
|
let totalLines = "...";
|
|
12328
12657
|
try {
|
|
12329
|
-
const content =
|
|
12658
|
+
const content = fs22.readFileSync(absPath, "utf8");
|
|
12330
12659
|
totalLines = content.split("\n").length;
|
|
12331
12660
|
} catch (e) {
|
|
12332
12661
|
}
|
|
@@ -12386,6 +12715,7 @@ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" &&
|
|
|
12386
12715
|
}
|
|
12387
12716
|
});
|
|
12388
12717
|
for (let loop = 0; loop <= MAX_LOOPS; loop++) {
|
|
12718
|
+
const currentTurnTools = [];
|
|
12389
12719
|
wasToolCalledInLastLoop = false;
|
|
12390
12720
|
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > contextTruncationCount) {
|
|
12391
12721
|
modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
|
|
@@ -12970,7 +13300,7 @@ ${ideErr} [/ERROR]`;
|
|
|
12970
13300
|
if (keyword) {
|
|
12971
13301
|
detail = keyword.replace(/["']/g, "");
|
|
12972
13302
|
} else if (filePath) {
|
|
12973
|
-
detail =
|
|
13303
|
+
detail = path21.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
|
|
12974
13304
|
} else if (title && (potentialTool === "invoke" || potentialTool === "invoke_sync")) {
|
|
12975
13305
|
detail = title.replace(/["']/g, "").substring(0, 30);
|
|
12976
13306
|
} else if (id && potentialTool === "get_progress") {
|
|
@@ -12999,7 +13329,7 @@ ${ideErr} [/ERROR]`;
|
|
|
12999
13329
|
if (potentialTool === "invoke" || potentialTool === "invoke_sync" || potentialTool === "get_progress") {
|
|
13000
13330
|
detail = val.substring(0, 30);
|
|
13001
13331
|
} else {
|
|
13002
|
-
detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val :
|
|
13332
|
+
detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val : path21.basename(val.replace(/\\/g, "/"));
|
|
13003
13333
|
}
|
|
13004
13334
|
}
|
|
13005
13335
|
}
|
|
@@ -13199,9 +13529,9 @@ ${ideErr} [/ERROR]`;
|
|
|
13199
13529
|
let totalLines = "...";
|
|
13200
13530
|
let actualEndLine = eLine;
|
|
13201
13531
|
try {
|
|
13202
|
-
const absPath =
|
|
13203
|
-
if (
|
|
13204
|
-
const content =
|
|
13532
|
+
const absPath = path21.resolve(process.cwd(), targetPath2);
|
|
13533
|
+
if (fs22.existsSync(absPath)) {
|
|
13534
|
+
const content = fs22.readFileSync(absPath, "utf8");
|
|
13205
13535
|
const lines = content.split("\n").length;
|
|
13206
13536
|
totalLines = lines;
|
|
13207
13537
|
actualEndLine = Math.min(eLine, lines);
|
|
@@ -13221,8 +13551,8 @@ ${ideErr} [/ERROR]`;
|
|
|
13221
13551
|
}
|
|
13222
13552
|
} else if (normToolName === "list_files" || normToolName === "read_folder") {
|
|
13223
13553
|
const action = normToolName === "list_files" ? "List" : "Browsed";
|
|
13224
|
-
const
|
|
13225
|
-
label = `\u2714 ${action}: ${
|
|
13554
|
+
const path23 = parseArgs(toolCall.args).path;
|
|
13555
|
+
label = `\u2714 ${action}: ${path23 === "." ? "./" : path23}`;
|
|
13226
13556
|
} else if (normToolName === "write_file" || normToolName === "update_file") {
|
|
13227
13557
|
const action = normToolName === "write_file" ? "Created" : "Edited";
|
|
13228
13558
|
label = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
|
|
@@ -13251,7 +13581,10 @@ ${ideErr} [/ERROR]`;
|
|
|
13251
13581
|
} else if (normToolName === "cancel") {
|
|
13252
13582
|
const detail2 = getToolDetail(normToolName, toolCall.args);
|
|
13253
13583
|
label = `\u{1F6C7} Cancelled${detail2 ? `: ${detail2}` : ""}`;
|
|
13254
|
-
} else if (normToolName === "
|
|
13584
|
+
} else if (normToolName === "EmergencyRollback") {
|
|
13585
|
+
const { method } = parseArgs(toolCall.args);
|
|
13586
|
+
label = `\u2714 ${method === "forceRevert" ? "Emergency Rollback!" : "Rollback Checked"}`;
|
|
13587
|
+
} else if (normToolName === "await" || normToolName === "Await") {
|
|
13255
13588
|
const { time } = parseArgs(toolCall.args);
|
|
13256
13589
|
let sec = parseFloat(time) || 0;
|
|
13257
13590
|
if (sec < 10) sec = 10;
|
|
@@ -13305,7 +13638,7 @@ ${ideErr} [/ERROR]`;
|
|
|
13305
13638
|
const { command } = parseArgs(toolCall.args);
|
|
13306
13639
|
if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
|
|
13307
13640
|
const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
|
|
13308
|
-
const currentDrive =
|
|
13641
|
+
const currentDrive = path21.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
13309
13642
|
const splitCommands = (cmdString) => {
|
|
13310
13643
|
const commands = [];
|
|
13311
13644
|
let current = "";
|
|
@@ -13434,8 +13767,8 @@ ${ideErr} [/ERROR]`;
|
|
|
13434
13767
|
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
13435
13768
|
if (targetPath) {
|
|
13436
13769
|
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
13437
|
-
const absoluteTarget =
|
|
13438
|
-
const absoluteCwd =
|
|
13770
|
+
const absoluteTarget = path21.resolve(targetPath);
|
|
13771
|
+
const absoluteCwd = path21.resolve(process.cwd());
|
|
13439
13772
|
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
13440
13773
|
const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace.`;
|
|
13441
13774
|
if (normToolName === "write_file" || normToolName === "update_file") {
|
|
@@ -13624,18 +13957,18 @@ ${boxMid}`) };
|
|
|
13624
13957
|
const toolArgs = parseArgs(toolCall.args);
|
|
13625
13958
|
const { path: filePath } = toolArgs;
|
|
13626
13959
|
if (filePath) {
|
|
13627
|
-
const absPath =
|
|
13628
|
-
const
|
|
13629
|
-
const normAbsPath =
|
|
13960
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13961
|
+
const normalize2 = (p) => p ? p.toLowerCase().replace(/\\/g, "/").replace(/^[a-z]:/, (m) => m.toUpperCase()) : "";
|
|
13962
|
+
const normAbsPath = normalize2(absPath);
|
|
13630
13963
|
let originalContent = "";
|
|
13631
13964
|
let hasOriginal = false;
|
|
13632
13965
|
const currentIDE = await getIDEContext();
|
|
13633
|
-
const normFocused =
|
|
13966
|
+
const normFocused = normalize2(currentIDE?.file_focused);
|
|
13634
13967
|
if (currentIDE && normFocused === normAbsPath && currentIDE.full_content) {
|
|
13635
13968
|
originalContent = currentIDE.full_content;
|
|
13636
13969
|
hasOriginal = true;
|
|
13637
|
-
} else if (
|
|
13638
|
-
originalContent =
|
|
13970
|
+
} else if (fs22.existsSync(absPath)) {
|
|
13971
|
+
originalContent = fs22.readFileSync(absPath, "utf8");
|
|
13639
13972
|
hasOriginal = true;
|
|
13640
13973
|
}
|
|
13641
13974
|
originalContentForReporting = originalContent;
|
|
@@ -13662,9 +13995,9 @@ ${boxMid}`) };
|
|
|
13662
13995
|
const successes = patchResults.filter((r) => r.success);
|
|
13663
13996
|
const failures = patchResults.filter((r) => !r.success);
|
|
13664
13997
|
if (successes.length === 0) {
|
|
13665
|
-
const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${
|
|
13998
|
+
const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${path21.basename(absPath)}].
|
|
13666
13999
|
${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
|
|
13667
|
-
const errorLabel = `\u2714 Edited: ${
|
|
14000
|
+
const errorLabel = `\u2714 Edited: ${path21.basename(absPath)}`.toUpperCase();
|
|
13668
14001
|
let terminalWidth = 115;
|
|
13669
14002
|
if (process.stdout.isTTY) {
|
|
13670
14003
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -13682,19 +14015,19 @@ ${boxMid}}`) };
|
|
|
13682
14015
|
continue;
|
|
13683
14016
|
}
|
|
13684
14017
|
}
|
|
13685
|
-
yield { type: "status", content: `Opening Diff in IDE: ${
|
|
14018
|
+
yield { type: "status", content: `Opening Diff in IDE: ${path21.basename(absPath)}...` };
|
|
13686
14019
|
showDiffInIDE(absPath, originalContent, modifiedContent);
|
|
13687
14020
|
diffOpened = true;
|
|
13688
14021
|
await new Promise((r) => setTimeout(r, 50));
|
|
13689
14022
|
} else if (normToolName === "write_file") {
|
|
13690
14023
|
const rawContent = toolArgs.content || toolArgs.newContent || "";
|
|
13691
14024
|
const modifiedContent = rawContent.endsWith("\n") ? rawContent : rawContent + "\n";
|
|
13692
|
-
if (!
|
|
14025
|
+
if (!fs22.existsSync(absPath)) {
|
|
13693
14026
|
isNewFileCreated = true;
|
|
13694
|
-
|
|
13695
|
-
|
|
14027
|
+
fs22.mkdirSync(path21.dirname(absPath), { recursive: true });
|
|
14028
|
+
fs22.writeFileSync(absPath, "", "utf8");
|
|
13696
14029
|
}
|
|
13697
|
-
yield { type: "status", content: `Opening New File Diff in IDE: ${
|
|
14030
|
+
yield { type: "status", content: `Opening New File Diff in IDE: ${path21.basename(absPath)}...` };
|
|
13698
14031
|
showDiffInIDE(absPath, "", modifiedContent);
|
|
13699
14032
|
diffOpened = true;
|
|
13700
14033
|
await new Promise((r) => setTimeout(r, 50));
|
|
@@ -13730,11 +14063,11 @@ ${boxMid}}`) };
|
|
|
13730
14063
|
if (normToolName === "write_file" || normToolName === "update_file") {
|
|
13731
14064
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13732
14065
|
if (filePath) {
|
|
13733
|
-
const absPath =
|
|
14066
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13734
14067
|
closeDiffInIDE(absPath, approval);
|
|
13735
|
-
if (approval === "deny" && isNewFileCreated &&
|
|
14068
|
+
if (approval === "deny" && isNewFileCreated && fs22.existsSync(absPath)) {
|
|
13736
14069
|
try {
|
|
13737
|
-
|
|
14070
|
+
fs22.unlinkSync(absPath);
|
|
13738
14071
|
} catch (e) {
|
|
13739
14072
|
}
|
|
13740
14073
|
}
|
|
@@ -13746,13 +14079,13 @@ ${boxMid}}`) };
|
|
|
13746
14079
|
}
|
|
13747
14080
|
if (approval === "allow" && diffOpened && isBridgeConnected()) {
|
|
13748
14081
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13749
|
-
const absPath =
|
|
14082
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13750
14083
|
const finalIDE = await getIDEContext();
|
|
13751
14084
|
let finalContent = "";
|
|
13752
14085
|
if (finalIDE && finalIDE.file_focused === absPath && finalIDE.full_content) {
|
|
13753
14086
|
finalContent = finalIDE.full_content;
|
|
13754
|
-
} else if (
|
|
13755
|
-
finalContent =
|
|
14087
|
+
} else if (fs22.existsSync(absPath)) {
|
|
14088
|
+
finalContent = fs22.readFileSync(absPath, "utf8");
|
|
13756
14089
|
}
|
|
13757
14090
|
const verifiedLines = finalContent.split(/\r?\n/);
|
|
13758
14091
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -13915,7 +14248,7 @@ ${boxBottom}`}`) };
|
|
|
13915
14248
|
try {
|
|
13916
14249
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13917
14250
|
if (filePath) {
|
|
13918
|
-
const absPath =
|
|
14251
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13919
14252
|
const currentIDE = await getIDEContext();
|
|
13920
14253
|
if (currentIDE && currentIDE.file_focused === absPath && currentIDE.full_content) {
|
|
13921
14254
|
execToolContext.forcedContent = currentIDE.full_content;
|
|
@@ -13924,12 +14257,13 @@ ${boxBottom}`}`) };
|
|
|
13924
14257
|
} catch (e) {
|
|
13925
14258
|
}
|
|
13926
14259
|
}
|
|
14260
|
+
currentTurnTools.push(normToolName);
|
|
13927
14261
|
let result = await dispatchTool(normToolName, toolCall.args, execToolContext);
|
|
13928
14262
|
yield { type: "spinner", content: true };
|
|
13929
14263
|
if ((normToolName === "write_file" || normToolName === "update_file") && result.startsWith("SUCCESS")) {
|
|
13930
14264
|
const { path: filePath } = parseArgs(toolCall.args);
|
|
13931
14265
|
if (filePath) {
|
|
13932
|
-
const absPath =
|
|
14266
|
+
const absPath = path21.resolve(process.cwd(), filePath);
|
|
13933
14267
|
openFileInEditor(absPath);
|
|
13934
14268
|
}
|
|
13935
14269
|
}
|
|
@@ -14173,9 +14507,9 @@ ${colorMainWords(output)}` };
|
|
|
14173
14507
|
})() : String(err);
|
|
14174
14508
|
;
|
|
14175
14509
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
14176
|
-
const agentErrDir =
|
|
14177
|
-
if (!
|
|
14178
|
-
|
|
14510
|
+
const agentErrDir = path21.join(LOGS_DIR, "agent");
|
|
14511
|
+
if (!fs22.existsSync(agentErrDir)) fs22.mkdirSync(agentErrDir, { recursive: true });
|
|
14512
|
+
fs22.appendFileSync(path21.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
14179
14513
|
|
|
14180
14514
|
----------------------------------------------------------------------
|
|
14181
14515
|
|
|
@@ -14222,7 +14556,7 @@ ${recoveryText}`
|
|
|
14222
14556
|
yield { type: "status", content: `Error Occured. Recovering Stream...` };
|
|
14223
14557
|
} else {
|
|
14224
14558
|
throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
|
|
14225
|
-
Error Log can be found in ${
|
|
14559
|
+
Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
|
|
14226
14560
|
}
|
|
14227
14561
|
} else {
|
|
14228
14562
|
if (retryCount <= MAX_RETRIES) {
|
|
@@ -14240,7 +14574,7 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14240
14574
|
yield { type: "status", content: `Trying to reach ${modelName}...` };
|
|
14241
14575
|
} else {
|
|
14242
14576
|
throw new Error(`Model ${modelName} cannot be reached. (Failed ${MAX_RETRIES} times)
|
|
14243
|
-
Error Log can be found in ${
|
|
14577
|
+
Error Log can be found in ${path21.join(LOGS_DIR, "agent", "error.log")}`);
|
|
14244
14578
|
}
|
|
14245
14579
|
}
|
|
14246
14580
|
}
|
|
@@ -14313,6 +14647,9 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14313
14647
|
isStutteringLoop = false;
|
|
14314
14648
|
isGeneralLoop = false;
|
|
14315
14649
|
}
|
|
14650
|
+
if (systemSettings?.advanceRollback) {
|
|
14651
|
+
await AdvanceRevertManager.recordTurnDelta(chatId, loop + 1, currentTurnTools);
|
|
14652
|
+
}
|
|
14316
14653
|
wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
|
|
14317
14654
|
}
|
|
14318
14655
|
modifiedHistory.forEach((msg) => {
|
|
@@ -14343,10 +14680,10 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14343
14680
|
}
|
|
14344
14681
|
})() : String(err);
|
|
14345
14682
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
14346
|
-
const agentErrDir =
|
|
14683
|
+
const agentErrDir = path21.join(LOGS_DIR, "agent");
|
|
14347
14684
|
yield { type: "text", content: `\u274C CRITICAL ERROR: ${errLog}` };
|
|
14348
|
-
if (!
|
|
14349
|
-
|
|
14685
|
+
if (!fs22.existsSync(agentErrDir)) fs22.mkdirSync(agentErrDir, { recursive: true });
|
|
14686
|
+
fs22.appendFileSync(path21.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${errLog}
|
|
14350
14687
|
|
|
14351
14688
|
----------------------------------------------------------------------
|
|
14352
14689
|
|
|
@@ -14361,6 +14698,9 @@ Error Log can be found in ${path20.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
14361
14698
|
connectionPollInterval = null;
|
|
14362
14699
|
}
|
|
14363
14700
|
await RevertManager.commitTransaction();
|
|
14701
|
+
if (systemSettings?.advanceRollback) {
|
|
14702
|
+
await AdvanceRevertManager.cleanup(chatId);
|
|
14703
|
+
}
|
|
14364
14704
|
}
|
|
14365
14705
|
yield { type: "status", content: null };
|
|
14366
14706
|
};
|
|
@@ -14387,6 +14727,7 @@ TOOL POLICY:
|
|
|
14387
14727
|
- FileMap >>> ReadFile to understand file efficiently
|
|
14388
14728
|
- Want spefific STRING across project/file? SearchKeyword >> Guessing/ReadFile
|
|
14389
14729
|
- HUGE FILES? SearchKeyword >> FileMap/Full Read
|
|
14730
|
+
- NO Terminal Access
|
|
14390
14731
|
-- PROVIDED TOOLS --
|
|
14391
14732
|
${Object.values(SUBAGENT_TOOL_DEFINITIONS).join("\n")}
|
|
14392
14733
|
|
|
@@ -14468,11 +14809,11 @@ ${cleanResponse}
|
|
|
14468
14809
|
} else if (normalizedToolName === "list_files" || normalizedToolName === "read_folder" || normalizedToolName === "readfolder") {
|
|
14469
14810
|
label = `\u2714 \x1B[95mBrowsed Folder\x1B[0m`;
|
|
14470
14811
|
} else if (normalizedToolName === "write_file" || normalizedToolName === "writefile") {
|
|
14471
|
-
const
|
|
14472
|
-
label = `\u2714 \x1B[95mFile Created\x1B[0m: ${
|
|
14812
|
+
const path23 = parseArgs(toolCall.args).path || "...";
|
|
14813
|
+
label = `\u2714 \x1B[95mFile Created\x1B[0m: ${path23}`;
|
|
14473
14814
|
} 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: ${
|
|
14815
|
+
const path23 = parseArgs(toolCall.args).path || "...";
|
|
14816
|
+
label = `\u2714 \x1B[95mFile Edited\x1B[0m: ${path23}`;
|
|
14476
14817
|
} else if (normalizedToolName === "file_map" || normalizedToolName === "filemap") {
|
|
14477
14818
|
label = `\u2714 \x1B[95mIndexed\x1B[0m`;
|
|
14478
14819
|
} else if (normalizedToolName === "await") {
|
|
@@ -15338,7 +15679,7 @@ var init_RevertModal = __esm({
|
|
|
15338
15679
|
import puppeteer4 from "puppeteer";
|
|
15339
15680
|
import { exec } from "child_process";
|
|
15340
15681
|
import { promisify } from "util";
|
|
15341
|
-
import
|
|
15682
|
+
import fs23 from "fs";
|
|
15342
15683
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
15343
15684
|
var init_setup = __esm({
|
|
15344
15685
|
"src/utils/setup.js"() {
|
|
@@ -15347,11 +15688,11 @@ var init_setup = __esm({
|
|
|
15347
15688
|
checkPuppeteerReady = () => {
|
|
15348
15689
|
try {
|
|
15349
15690
|
const pptrConfig = getPuppeteerConfig();
|
|
15350
|
-
if (pptrConfig.executablePath &&
|
|
15691
|
+
if (pptrConfig.executablePath && fs23.existsSync(pptrConfig.executablePath)) {
|
|
15351
15692
|
return true;
|
|
15352
15693
|
}
|
|
15353
15694
|
const exePath = puppeteer4.executablePath();
|
|
15354
|
-
const exists = exePath &&
|
|
15695
|
+
const exists = exePath && fs23.existsSync(exePath);
|
|
15355
15696
|
if (exists) return true;
|
|
15356
15697
|
} catch (e) {
|
|
15357
15698
|
return false;
|
|
@@ -15384,8 +15725,8 @@ __export(app_exports, {
|
|
|
15384
15725
|
import os5 from "os";
|
|
15385
15726
|
import React15, { useState as useState14, useEffect as useEffect11, useRef as useRef4, useMemo as useMemo2 } from "react";
|
|
15386
15727
|
import { Box as Box14, Text as Text15, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
|
|
15387
|
-
import
|
|
15388
|
-
import
|
|
15728
|
+
import fs24 from "fs-extra";
|
|
15729
|
+
import path22 from "path";
|
|
15389
15730
|
import { exec as exec2 } from "child_process";
|
|
15390
15731
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15391
15732
|
import TextInput4 from "ink-text-input";
|
|
@@ -15630,10 +15971,10 @@ function App({ args = [] }) {
|
|
|
15630
15971
|
const kbPath = getKeybindingsPath(ideName);
|
|
15631
15972
|
if (!kbPath) return;
|
|
15632
15973
|
try {
|
|
15633
|
-
await
|
|
15974
|
+
await fs24.ensureDir(path22.dirname(kbPath));
|
|
15634
15975
|
let bindings = [];
|
|
15635
|
-
if (
|
|
15636
|
-
const content =
|
|
15976
|
+
if (fs24.existsSync(kbPath)) {
|
|
15977
|
+
const content = fs24.readFileSync(kbPath, "utf8").trim();
|
|
15637
15978
|
if (content) {
|
|
15638
15979
|
try {
|
|
15639
15980
|
bindings = parseJsonc(content);
|
|
@@ -15653,7 +15994,7 @@ function App({ args = [] }) {
|
|
|
15653
15994
|
},
|
|
15654
15995
|
"when": "terminalFocus"
|
|
15655
15996
|
});
|
|
15656
|
-
|
|
15997
|
+
fs24.writeFileSync(kbPath, JSON.stringify(bindings, null, 4), "utf8");
|
|
15657
15998
|
cachedShortcut = "Shift + Enter";
|
|
15658
15999
|
setMessages((prev) => {
|
|
15659
16000
|
setCompletedIndex(prev.length + 1);
|
|
@@ -16329,7 +16670,7 @@ function App({ args = [] }) {
|
|
|
16329
16670
|
useEffect11(() => {
|
|
16330
16671
|
async function init() {
|
|
16331
16672
|
try {
|
|
16332
|
-
const pkg = JSON.parse(
|
|
16673
|
+
const pkg = JSON.parse(fs24.readFileSync(path22.join(process.cwd(), "package.json"), "utf8"));
|
|
16333
16674
|
initBridge(versionFluxflow || pkg.version || "2.0.0");
|
|
16334
16675
|
} catch (e) {
|
|
16335
16676
|
initBridge("2.0.0");
|
|
@@ -16452,7 +16793,7 @@ function App({ args = [] }) {
|
|
|
16452
16793
|
if (!parsedArgs.playground) {
|
|
16453
16794
|
deleteChat(PLAYGROUND_CHAT_ID).catch(() => {
|
|
16454
16795
|
});
|
|
16455
|
-
|
|
16796
|
+
fs24.remove(path22.join(DATA_DIR, "playground")).catch(() => {
|
|
16456
16797
|
});
|
|
16457
16798
|
}
|
|
16458
16799
|
performVersionCheck(false, freshSettings);
|
|
@@ -16486,9 +16827,9 @@ function App({ args = [] }) {
|
|
|
16486
16827
|
}
|
|
16487
16828
|
}
|
|
16488
16829
|
if (parsedArgs.playground) {
|
|
16489
|
-
const playgroundDir =
|
|
16830
|
+
const playgroundDir = path22.join(DATA_DIR, "playground");
|
|
16490
16831
|
try {
|
|
16491
|
-
|
|
16832
|
+
fs24.ensureDirSync(playgroundDir);
|
|
16492
16833
|
process.chdir(playgroundDir);
|
|
16493
16834
|
} catch (e) {
|
|
16494
16835
|
}
|
|
@@ -16529,8 +16870,8 @@ function App({ args = [] }) {
|
|
|
16529
16870
|
if (kbPath) {
|
|
16530
16871
|
try {
|
|
16531
16872
|
let bindings = [];
|
|
16532
|
-
if (
|
|
16533
|
-
const content =
|
|
16873
|
+
if (fs24.existsSync(kbPath)) {
|
|
16874
|
+
const content = fs24.readFileSync(kbPath, "utf8").trim();
|
|
16534
16875
|
if (content) {
|
|
16535
16876
|
bindings = parseJsonc(content);
|
|
16536
16877
|
}
|
|
@@ -17063,22 +17404,22 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17063
17404
|
});
|
|
17064
17405
|
break;
|
|
17065
17406
|
}
|
|
17066
|
-
const src =
|
|
17067
|
-
const dest =
|
|
17407
|
+
const src = path22.join(DATA_DIR, "playground");
|
|
17408
|
+
const dest = path22.join(parsedArgs.originalCwd, "playground-export");
|
|
17068
17409
|
const moveFiles = async () => {
|
|
17069
17410
|
try {
|
|
17070
17411
|
setMessages((prev) => {
|
|
17071
17412
|
setCompletedIndex(prev.length + 1);
|
|
17072
17413
|
return [...prev, { id: Date.now(), role: "system", text: `[PLAYGROUND] Exporting playground content to ${dest}`, isMeta: true }];
|
|
17073
17414
|
});
|
|
17074
|
-
await
|
|
17415
|
+
await fs24.ensureDir(dest);
|
|
17075
17416
|
const excludeDirs = ["node_modules", ".git", ".venv", "venv", "env", ".next", "dist", "build", ".cache"];
|
|
17076
|
-
await
|
|
17417
|
+
await fs24.copy(src, dest, {
|
|
17077
17418
|
overwrite: true,
|
|
17078
17419
|
filter: (srcPath) => {
|
|
17079
|
-
const relative =
|
|
17420
|
+
const relative = path22.relative(src, srcPath);
|
|
17080
17421
|
if (!relative) return true;
|
|
17081
|
-
const parts2 = relative.split(
|
|
17422
|
+
const parts2 = relative.split(path22.sep);
|
|
17082
17423
|
return !parts2.some((part) => excludeDirs.includes(part));
|
|
17083
17424
|
}
|
|
17084
17425
|
});
|
|
@@ -17138,7 +17479,7 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17138
17479
|
}
|
|
17139
17480
|
}
|
|
17140
17481
|
setTimeout(() => {
|
|
17141
|
-
|
|
17482
|
+
fs24.emptyDir(path22.join(DATA_DIR, "playground")).catch((err) => {
|
|
17142
17483
|
setMessages((prev) => {
|
|
17143
17484
|
const newMsgs = [...prev, {
|
|
17144
17485
|
id: "playground-" + Date.now(),
|
|
@@ -17435,7 +17776,7 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17435
17776
|
}
|
|
17436
17777
|
case "/export": {
|
|
17437
17778
|
const exportFile = `export-fluxflow-${chatId}.txt`;
|
|
17438
|
-
const exportPath =
|
|
17779
|
+
const exportPath = path22.join(process.cwd(), exportFile);
|
|
17439
17780
|
const exportLines = [];
|
|
17440
17781
|
let insideAgentBlock = false;
|
|
17441
17782
|
for (let i = 0; i < messages.length; i++) {
|
|
@@ -17487,7 +17828,7 @@ ${cleanText}`, color: "magenta" }];
|
|
|
17487
17828
|
}
|
|
17488
17829
|
const fileContent = exportLines.join("\n");
|
|
17489
17830
|
try {
|
|
17490
|
-
|
|
17831
|
+
fs24.writeFileSync(exportPath, fileContent, "utf8");
|
|
17491
17832
|
setMessages((prev) => {
|
|
17492
17833
|
setCompletedIndex(prev.length + 1);
|
|
17493
17834
|
return [...prev, {
|
|
@@ -17534,12 +17875,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
17534
17875
|
setCompletedIndex(prev.length + 1);
|
|
17535
17876
|
return [...prev, { id: Date.now(), role: "system", text: "[NUCLEAR] Initiating reset...", isMeta: true }];
|
|
17536
17877
|
});
|
|
17537
|
-
if (
|
|
17538
|
-
if (
|
|
17539
|
-
if (
|
|
17878
|
+
if (fs24.existsSync(LOGS_DIR)) fs24.removeSync(LOGS_DIR);
|
|
17879
|
+
if (fs24.existsSync(SECRET_DIR)) fs24.removeSync(SECRET_DIR);
|
|
17880
|
+
if (fs24.existsSync(SETTINGS_FILE)) fs24.removeSync(SETTINGS_FILE);
|
|
17540
17881
|
try {
|
|
17541
|
-
const items =
|
|
17542
|
-
if (items.length === 0)
|
|
17882
|
+
const items = fs24.readdirSync(FLUXFLOW_DIR);
|
|
17883
|
+
if (items.length === 0) fs24.removeSync(FLUXFLOW_DIR);
|
|
17543
17884
|
} catch (e) {
|
|
17544
17885
|
}
|
|
17545
17886
|
setTimeout(() => {
|
|
@@ -17661,15 +18002,15 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
17661
18002
|
# SKILLS & WORKFLOWS
|
|
17662
18003
|
- [Define custom step-by-step recipes for this project here]
|
|
17663
18004
|
`;
|
|
17664
|
-
const filePath =
|
|
17665
|
-
if (
|
|
18005
|
+
const filePath = path22.join(process.cwd(), "FluxFlow.md");
|
|
18006
|
+
if (fs24.pathExistsSync(filePath)) {
|
|
17666
18007
|
setMessages((prev) => {
|
|
17667
18008
|
setCompletedIndex(prev.length + 1);
|
|
17668
18009
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
17669
18010
|
});
|
|
17670
18011
|
} else {
|
|
17671
18012
|
try {
|
|
17672
|
-
|
|
18013
|
+
fs24.writeFileSync(filePath, template);
|
|
17673
18014
|
setMessages((prev) => {
|
|
17674
18015
|
setCompletedIndex(prev.length + 1);
|
|
17675
18016
|
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 }];
|
|
@@ -18163,18 +18504,19 @@ Selection: ${val}`,
|
|
|
18163
18504
|
continue;
|
|
18164
18505
|
}
|
|
18165
18506
|
if (packet.type === "visual_feedback") {
|
|
18166
|
-
|
|
18167
|
-
|
|
18168
|
-
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18175
|
-
|
|
18176
|
-
|
|
18177
|
-
|
|
18507
|
+
setTimeout(async () => {
|
|
18508
|
+
setMessages((prev) => {
|
|
18509
|
+
const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
|
|
18510
|
+
const newMsgs = [...updatedPrev, {
|
|
18511
|
+
id: "feedback-" + Date.now() + "-" + Math.random().toString(36).substring(2, 9),
|
|
18512
|
+
role: "system",
|
|
18513
|
+
text: packet.content,
|
|
18514
|
+
isVisualFeedback: true
|
|
18515
|
+
}];
|
|
18516
|
+
setCompletedIndex(newMsgs.length);
|
|
18517
|
+
return newMsgs;
|
|
18518
|
+
});
|
|
18519
|
+
}, 300);
|
|
18178
18520
|
continue;
|
|
18179
18521
|
}
|
|
18180
18522
|
if (packet.type === "exec_start") {
|
|
@@ -19065,6 +19407,23 @@ Selection: ${val}`,
|
|
|
19065
19407
|
}
|
|
19066
19408
|
}
|
|
19067
19409
|
)));
|
|
19410
|
+
case "advanceRollbackDanger":
|
|
19411
|
+
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(
|
|
19412
|
+
CommandMenu,
|
|
19413
|
+
{
|
|
19414
|
+
title: "Confirm",
|
|
19415
|
+
items: [
|
|
19416
|
+
{ label: "I understand and wish to enable", value: "on" },
|
|
19417
|
+
{ label: "Keep Off", value: "off" }
|
|
19418
|
+
],
|
|
19419
|
+
onSelect: (item) => {
|
|
19420
|
+
if (item.value === "on") {
|
|
19421
|
+
setSystemSettings((s) => ({ ...s, advanceRollback: true }));
|
|
19422
|
+
}
|
|
19423
|
+
setActiveView("settings");
|
|
19424
|
+
}
|
|
19425
|
+
}
|
|
19426
|
+
)));
|
|
19068
19427
|
case "externalDanger":
|
|
19069
19428
|
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
19429
|
CommandMenu,
|
|
@@ -19712,11 +20071,11 @@ var init_app = __esm({
|
|
|
19712
20071
|
if (process.platform === "win32") {
|
|
19713
20072
|
const appData = process.env.APPDATA;
|
|
19714
20073
|
if (!appData) return null;
|
|
19715
|
-
return
|
|
20074
|
+
return path22.join(appData, dirName, "User", "keybindings.json");
|
|
19716
20075
|
} else if (process.platform === "darwin") {
|
|
19717
|
-
return
|
|
20076
|
+
return path22.join(home, "Library", "Application Support", dirName, "User", "keybindings.json");
|
|
19718
20077
|
} else {
|
|
19719
|
-
return
|
|
20078
|
+
return path22.join(home, ".config", dirName, "User", "keybindings.json");
|
|
19720
20079
|
}
|
|
19721
20080
|
};
|
|
19722
20081
|
parseJsonc = (content) => {
|
|
@@ -19762,8 +20121,8 @@ var init_app = __esm({
|
|
|
19762
20121
|
DOCS_URL = "https://fluxflow-cli.onrender.com/";
|
|
19763
20122
|
linesAdded = 0;
|
|
19764
20123
|
linesRemoved = 0;
|
|
19765
|
-
packageJsonPath =
|
|
19766
|
-
packageJson = JSON.parse(
|
|
20124
|
+
packageJsonPath = path22.join(path22.dirname(fileURLToPath2(import.meta.url)), "../package.json");
|
|
20125
|
+
packageJson = JSON.parse(fs24.readFileSync(packageJsonPath, "utf8"));
|
|
19767
20126
|
versionFluxflow = packageJson.version;
|
|
19768
20127
|
updatedOn = packageJson.date || "2026-05-20";
|
|
19769
20128
|
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 +20218,19 @@ var init_app = __esm({
|
|
|
19859
20218
|
const fileList = [];
|
|
19860
20219
|
const scan = (currentDir) => {
|
|
19861
20220
|
try {
|
|
19862
|
-
const files =
|
|
20221
|
+
const files = fs24.readdirSync(currentDir);
|
|
19863
20222
|
for (const file of files) {
|
|
19864
20223
|
if (["node_modules", ".git", ".gemini", "dist", "build", ".next", ".cache", "out"].includes(file)) {
|
|
19865
20224
|
continue;
|
|
19866
20225
|
}
|
|
19867
|
-
const filePath =
|
|
19868
|
-
const stat =
|
|
20226
|
+
const filePath = path22.join(currentDir, file);
|
|
20227
|
+
const stat = fs24.statSync(filePath);
|
|
19869
20228
|
if (stat.isDirectory()) {
|
|
19870
20229
|
scan(filePath);
|
|
19871
20230
|
} else {
|
|
19872
20231
|
fileList.push({
|
|
19873
20232
|
name: file,
|
|
19874
|
-
relativePath:
|
|
20233
|
+
relativePath: path22.relative(process.cwd(), filePath)
|
|
19875
20234
|
});
|
|
19876
20235
|
}
|
|
19877
20236
|
}
|
|
@@ -19994,11 +20353,11 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
19994
20353
|
const isVersion = args.includes("--version") || args.includes("-v");
|
|
19995
20354
|
const isUpdate = args[0] === "--update";
|
|
19996
20355
|
if (isVersion || isHelp || isHelpCommands || isUpdate) {
|
|
19997
|
-
const
|
|
19998
|
-
const
|
|
20356
|
+
const fs25 = await import("fs");
|
|
20357
|
+
const path23 = await import("path");
|
|
19999
20358
|
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
20000
|
-
const packageJsonPath2 =
|
|
20001
|
-
const packageJson2 = JSON.parse(
|
|
20359
|
+
const packageJsonPath2 = path23.join(path23.dirname(fileURLToPath4(import.meta.url)), "../package.json");
|
|
20360
|
+
const packageJson2 = JSON.parse(fs25.readFileSync(packageJsonPath2, "utf8"));
|
|
20002
20361
|
const versionFluxflow2 = packageJson2.version;
|
|
20003
20362
|
if (isVersion) {
|
|
20004
20363
|
console.log(`v${versionFluxflow2}`);
|