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.
Files changed (2) hide show
  1. package/dist/fluxflow.js +498 -139
  2. 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 path20 from "path";
10280
- import fs21 from "fs";
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 ? path20.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
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 = path20.join(LOGS_DIR, "janitor");
11147
- if (!fs21.existsSync(janitorErrDir)) fs21.mkdirSync(janitorErrDir, { recursive: true });
11148
- fs21.appendFileSync(path20.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${errLog}
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 = path20.join(LOGS_DIR, "janitor");
11158
- fs21.appendFileSync(path20.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
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 = path20.join(LOGS_DIR, "janitor");
11639
- if (!fs21.existsSync(janitorLogDir)) fs21.mkdirSync(janitorLogDir, { recursive: true });
11640
- fs21.appendFileSync(
11641
- path20.join(janitorLogDir, "error.log"),
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 = path20.join(SECRET_DIR, "chat-summaries.json");
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 = path20.join(SECRET_DIR, "chat-summaries.json");
11724
- if (fs21.existsSync(summariesFile)) {
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 = path20.join(SECRET_DIR, "chat-summaries.json");
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 fs21.readdirSync(dir, { withFileTypes: true });
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(path20.join(dir, entry.name), currentCount, depth + 1);
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 = path20.sep;
12325
+ const sep = path21.sep;
11997
12326
  if (entries.length > 100) {
11998
- return `${prefix}\u2514\u2500\u2500 ${path20.basename(dir)}${sep} ...100+ files...
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 = path20.join(dir, item.name);
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 = path20.relative(process.cwd(), ideCtx.file_focused);
12431
+ const relFocused = path21.relative(process.cwd(), ideCtx.file_focused);
12103
12432
  const relOpened = (ideCtx.opened_editors || []).map((p) => {
12104
- const rel = path20.relative(process.cwd(), p);
12105
- return rel.startsWith("..") ? `[External] ${path20.basename(p)}` : rel;
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 || path20.resolve(process.cwd(), f.path) === path20.resolve(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 || path20.resolve(process.cwd(), file.path) === path20.resolve(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 = path20.resolve(process.cwd(), filePath);
12266
- if (fs21.existsSync(absPath)) {
12267
- const stats = fs21.statSync(absPath);
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: ${path20.basename(filePath)}`;
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 = fs21.readFileSync(absPath, "utf8");
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 = path20.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
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 : path20.basename(val.replace(/\\/g, "/"));
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 = path20.resolve(process.cwd(), targetPath2);
13203
- if (fs21.existsSync(absPath)) {
13204
- const content = fs21.readFileSync(absPath, "utf8");
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 path22 = parseArgs(toolCall.args).path;
13225
- label = `\u2714 ${action}: ${path22 === "." ? "./" : path22}`;
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 === "await") {
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 = path20.resolve(process.cwd()).substring(0, 3).toLowerCase();
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 = path20.resolve(targetPath);
13438
- const absoluteCwd = path20.resolve(process.cwd());
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 = path20.resolve(process.cwd(), filePath);
13628
- const normalize = (p) => p ? p.toLowerCase().replace(/\\/g, "/").replace(/^[a-z]:/, (m) => m.toUpperCase()) : "";
13629
- const normAbsPath = normalize(absPath);
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 = normalize(currentIDE?.file_focused);
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 (fs21.existsSync(absPath)) {
13638
- originalContent = fs21.readFileSync(absPath, "utf8");
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 [${path20.basename(absPath)}].
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: ${path20.basename(absPath)}`.toUpperCase();
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: ${path20.basename(absPath)}...` };
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 (!fs21.existsSync(absPath)) {
14025
+ if (!fs22.existsSync(absPath)) {
13693
14026
  isNewFileCreated = true;
13694
- fs21.mkdirSync(path20.dirname(absPath), { recursive: true });
13695
- fs21.writeFileSync(absPath, "", "utf8");
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: ${path20.basename(absPath)}...` };
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 = path20.resolve(process.cwd(), filePath);
14066
+ const absPath = path21.resolve(process.cwd(), filePath);
13734
14067
  closeDiffInIDE(absPath, approval);
13735
- if (approval === "deny" && isNewFileCreated && fs21.existsSync(absPath)) {
14068
+ if (approval === "deny" && isNewFileCreated && fs22.existsSync(absPath)) {
13736
14069
  try {
13737
- fs21.unlinkSync(absPath);
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 = path20.resolve(process.cwd(), filePath);
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 (fs21.existsSync(absPath)) {
13755
- finalContent = fs21.readFileSync(absPath, "utf8");
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 = path20.resolve(process.cwd(), filePath);
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 = path20.resolve(process.cwd(), filePath);
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 = path20.join(LOGS_DIR, "agent");
14177
- if (!fs21.existsSync(agentErrDir)) fs21.mkdirSync(agentErrDir, { recursive: true });
14178
- fs21.appendFileSync(path20.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
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 ${path20.join(LOGS_DIR, "agent", "error.log")}`);
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 ${path20.join(LOGS_DIR, "agent", "error.log")}`);
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 = path20.join(LOGS_DIR, "agent");
14683
+ const agentErrDir = path21.join(LOGS_DIR, "agent");
14347
14684
  yield { type: "text", content: `\u274C CRITICAL ERROR: ${errLog}` };
14348
- if (!fs21.existsSync(agentErrDir)) fs21.mkdirSync(agentErrDir, { recursive: true });
14349
- fs21.appendFileSync(path20.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${errLog}
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 path22 = parseArgs(toolCall.args).path || "...";
14472
- label = `\u2714 \x1B[95mFile Created\x1B[0m: ${path22}`;
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 path22 = parseArgs(toolCall.args).path || "...";
14475
- label = `\u2714 \x1B[95mFile Edited\x1B[0m: ${path22}`;
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 fs22 from "fs";
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 && fs22.existsSync(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 && fs22.existsSync(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 fs23 from "fs-extra";
15388
- import path21 from "path";
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 fs23.ensureDir(path21.dirname(kbPath));
15974
+ await fs24.ensureDir(path22.dirname(kbPath));
15634
15975
  let bindings = [];
15635
- if (fs23.existsSync(kbPath)) {
15636
- const content = fs23.readFileSync(kbPath, "utf8").trim();
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
- fs23.writeFileSync(kbPath, JSON.stringify(bindings, null, 4), "utf8");
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(fs23.readFileSync(path21.join(process.cwd(), "package.json"), "utf8"));
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
- fs23.remove(path21.join(DATA_DIR, "playground")).catch(() => {
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 = path21.join(DATA_DIR, "playground");
16830
+ const playgroundDir = path22.join(DATA_DIR, "playground");
16490
16831
  try {
16491
- fs23.ensureDirSync(playgroundDir);
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 (fs23.existsSync(kbPath)) {
16533
- const content = fs23.readFileSync(kbPath, "utf8").trim();
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 = path21.join(DATA_DIR, "playground");
17067
- const dest = path21.join(parsedArgs.originalCwd, "playground-export");
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 fs23.ensureDir(dest);
17415
+ await fs24.ensureDir(dest);
17075
17416
  const excludeDirs = ["node_modules", ".git", ".venv", "venv", "env", ".next", "dist", "build", ".cache"];
17076
- await fs23.copy(src, dest, {
17417
+ await fs24.copy(src, dest, {
17077
17418
  overwrite: true,
17078
17419
  filter: (srcPath) => {
17079
- const relative = path21.relative(src, srcPath);
17420
+ const relative = path22.relative(src, srcPath);
17080
17421
  if (!relative) return true;
17081
- const parts2 = relative.split(path21.sep);
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
- fs23.emptyDir(path21.join(DATA_DIR, "playground")).catch((err) => {
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 = path21.join(process.cwd(), exportFile);
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
- fs23.writeFileSync(exportPath, fileContent, "utf8");
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 (fs23.existsSync(LOGS_DIR)) fs23.removeSync(LOGS_DIR);
17538
- if (fs23.existsSync(SECRET_DIR)) fs23.removeSync(SECRET_DIR);
17539
- if (fs23.existsSync(SETTINGS_FILE)) fs23.removeSync(SETTINGS_FILE);
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 = fs23.readdirSync(FLUXFLOW_DIR);
17542
- if (items.length === 0) fs23.removeSync(FLUXFLOW_DIR);
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 = path21.join(process.cwd(), "FluxFlow.md");
17665
- if (fs23.pathExistsSync(filePath)) {
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
- fs23.writeFileSync(filePath, template);
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
- await new Promise((resolve) => setTimeout(resolve, 150));
18167
- setMessages((prev) => {
18168
- const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
18169
- const newMsgs = [...updatedPrev, {
18170
- id: "feedback-" + Date.now() + "-" + Math.random().toString(36).substring(2, 9),
18171
- role: "system",
18172
- text: packet.content,
18173
- isVisualFeedback: true
18174
- }];
18175
- setCompletedIndex(newMsgs.length);
18176
- return newMsgs;
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 path21.join(appData, dirName, "User", "keybindings.json");
20074
+ return path22.join(appData, dirName, "User", "keybindings.json");
19716
20075
  } else if (process.platform === "darwin") {
19717
- return path21.join(home, "Library", "Application Support", dirName, "User", "keybindings.json");
20076
+ return path22.join(home, "Library", "Application Support", dirName, "User", "keybindings.json");
19718
20077
  } else {
19719
- return path21.join(home, ".config", dirName, "User", "keybindings.json");
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 = path21.join(path21.dirname(fileURLToPath2(import.meta.url)), "../package.json");
19766
- packageJson = JSON.parse(fs23.readFileSync(packageJsonPath, "utf8"));
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 = fs23.readdirSync(currentDir);
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 = path21.join(currentDir, file);
19868
- const stat = fs23.statSync(filePath);
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: path21.relative(process.cwd(), filePath)
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 fs24 = await import("fs");
19998
- const path22 = await import("path");
20356
+ const fs25 = await import("fs");
20357
+ const path23 = await import("path");
19999
20358
  const { fileURLToPath: fileURLToPath4 } = await import("url");
20000
- const packageJsonPath2 = path22.join(path22.dirname(fileURLToPath4(import.meta.url)), "../package.json");
20001
- const packageJson2 = JSON.parse(fs24.readFileSync(packageJsonPath2, "utf8"));
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}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.0.22",
3
+ "version": "3.1.1",
4
4
  "date": "2026-07-05",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [