fluxflow-cli 3.1.7 → 3.1.8

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 +66 -12
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -10096,24 +10096,35 @@ async function copyWorkspaceFiles(destDir, manifest) {
10096
10096
  });
10097
10097
  }
10098
10098
  }
10099
- async function restoreSnapshotDir(srcDir, destDir) {
10099
+ async function restoreSnapshotDir(srcDir, destDir, stats = null, baseDir = null) {
10100
10100
  if (!await fs21.pathExists(srcDir)) return;
10101
+ if (!baseDir) baseDir = srcDir;
10101
10102
  const entries = await fs21.readdir(srcDir, { withFileTypes: true }).catch(() => []);
10102
10103
  for (const entry of entries) {
10103
10104
  const srcPath = path20.join(srcDir, entry.name);
10104
10105
  const destPath = path20.join(destDir, entry.name);
10105
10106
  if (entry.isDirectory()) {
10106
- await restoreSnapshotDir(srcPath, destPath);
10107
+ await restoreSnapshotDir(srcPath, destPath, stats, baseDir);
10107
10108
  } else {
10108
- if (await fs21.pathExists(destPath)) {
10109
+ const relPath = path20.relative(baseDir, srcPath).replace(/\\/g, "/");
10110
+ const existed = await fs21.pathExists(destPath);
10111
+ if (existed) {
10109
10112
  await fs21.chmod(destPath, 438).catch(() => {
10110
10113
  });
10111
10114
  }
10112
10115
  await fs21.ensureDir(path20.dirname(destPath));
10113
- await fs21.copyFile(srcPath, destPath).catch(() => {
10114
- });
10116
+ const ok = await fs21.copyFile(srcPath, destPath).then(() => true).catch(() => false);
10115
10117
  await fs21.chmod(destPath, 438).catch(() => {
10116
10118
  });
10119
+ if (stats) {
10120
+ if (!ok) {
10121
+ stats.failed.push(relPath);
10122
+ } else if (existed) {
10123
+ stats.replaced++;
10124
+ } else {
10125
+ stats.restored++;
10126
+ }
10127
+ }
10117
10128
  }
10118
10129
  }
10119
10130
  }
@@ -10230,6 +10241,7 @@ var init_advanceRevert = __esm({
10230
10241
  const targetIdx = checkpoints.findIndex((c) => c.id === checkpointId);
10231
10242
  if (targetIdx === -1) throw new Error(`Checkpoint [${checkpointId}] not found.`);
10232
10243
  const snapshotsDir = path20.join(DATA_DIR, "snapshots", chatId);
10244
+ const stats = { restored: 0, replaced: 0, failed: [] };
10233
10245
  const currentFiles = await scanWorkspace(process.cwd());
10234
10246
  for (const relPath of Object.keys(currentFiles)) {
10235
10247
  const fullPath = path20.join(process.cwd(), relPath);
@@ -10239,11 +10251,11 @@ var init_advanceRevert = __esm({
10239
10251
  });
10240
10252
  }
10241
10253
  const initialDir = path20.join(snapshotsDir, "initial");
10242
- await restoreSnapshotDir(initialDir, process.cwd());
10254
+ await restoreSnapshotDir(initialDir, process.cwd(), stats, initialDir);
10243
10255
  for (let i = 1; i <= targetIdx; i++) {
10244
10256
  const cp = checkpoints[i];
10245
10257
  const turnDir = path20.join(snapshotsDir, cp.id);
10246
- await restoreSnapshotDir(turnDir, process.cwd());
10258
+ await restoreSnapshotDir(turnDir, process.cwd(), stats, turnDir);
10247
10259
  if (cp.deletedFiles && cp.deletedFiles.length > 0) {
10248
10260
  for (const delFile of cp.deletedFiles) {
10249
10261
  const fullPath = path20.join(process.cwd(), delFile);
@@ -10257,7 +10269,7 @@ var init_advanceRevert = __esm({
10257
10269
  session.checkpoints = checkpoints.slice(0, targetIdx + 1);
10258
10270
  session.currentManifest = await scanWorkspace(process.cwd());
10259
10271
  writeEncryptedJson(LEDGER_ADVANCE_FILE, ledger);
10260
- return true;
10272
+ return { checkpointId, stats };
10261
10273
  } catch (err) {
10262
10274
  throw new Error(`Rollback failed: ${err.message}`);
10263
10275
  }
@@ -10351,8 +10363,28 @@ Tools Used: ${toolsStr}
10351
10363
  return "ERROR: Missing required parameter 'id' for forceRevert.";
10352
10364
  }
10353
10365
  try {
10354
- await AdvanceRevertManager.rollbackToCheckpoint(chatId, id);
10355
- return `SUCCESS: Repository rolled back to checkpoint [${id}].`;
10366
+ const result = await AdvanceRevertManager.rollbackToCheckpoint(chatId, id);
10367
+ const { checkpointId, stats } = result;
10368
+ const totalFiles = stats.restored + stats.replaced + stats.failed.length;
10369
+ let output = `SUCCESS: Repository rolled back to checkpoint [${checkpointId}].
10370
+
10371
+ `;
10372
+ output += `Stats:
10373
+ `;
10374
+ output += ` Restored : ${stats.restored} file${stats.restored !== 1 ? "s" : ""} (new to workspace)
10375
+ `;
10376
+ output += ` Replaced : ${stats.replaced} file${stats.replaced !== 1 ? "s" : ""} (overwritten)
10377
+ `;
10378
+ output += ` Failed : ${stats.failed.length} file${stats.failed.length !== 1 ? "s" : ""}`;
10379
+ if (stats.failed.length > 0) {
10380
+ output += `
10381
+ ${stats.failed.join("\n ")}`;
10382
+ }
10383
+ output += `
10384
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500-
10385
+ `;
10386
+ output += ` Total : ${totalFiles} file${totalFiles !== 1 ? "s" : ""} processed`;
10387
+ return output;
10356
10388
  } catch (err) {
10357
10389
  return `ERROR: ${err.message}`;
10358
10390
  }
@@ -10622,7 +10654,7 @@ var init_ai = __esm({
10622
10654
  globalSettings = {};
10623
10655
  colorMainWords = (label) => {
10624
10656
  if (!label) return label;
10625
- 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) => {
10657
+ 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 Point Checked|Emergency Rollback Failed|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) => {
10626
10658
  return `${ansiBefore || ""}${icon}${ansiAfter || ""} \x1B[95m${word}\x1B[0m`;
10627
10659
  });
10628
10660
  };
@@ -13680,7 +13712,7 @@ ${ideErr} [/ERROR]`;
13680
13712
  label = `\u{1F6C7} Cancelled${detail2 ? `: ${detail2}` : ""}`;
13681
13713
  } else if (normToolName === "EmergencyRollback") {
13682
13714
  const { method } = parseArgs(toolCall.args);
13683
- label = `\u2714 ${method === "forceRevert" ? "Emergency Rollback" : "Rollback Checked"}`;
13715
+ label = method === "forceRevert" ? "" : "\u2714 Rollback Point Checked";
13684
13716
  } else if (normToolName === "await" || normToolName === "Await") {
13685
13717
  const { time } = parseArgs(toolCall.args);
13686
13718
  let sec = parseFloat(time) || 0;
@@ -14397,6 +14429,28 @@ ${boxBottom}`}`) };
14397
14429
  ${boxMid}
14398
14430
  `) };
14399
14431
  }
14432
+ if (normToolName === "EmergencyRollback") {
14433
+ const { method } = parseArgs(toolCall.args);
14434
+ if (method === "forceRevert") {
14435
+ let totalFiles = 0;
14436
+ if (result) {
14437
+ const m = result.match(/Total\s*:\s*(\d+)/i);
14438
+ if (m) totalFiles = parseInt(m[1]);
14439
+ }
14440
+ const isErr = result && result.startsWith("ERROR:");
14441
+ const postLabel = isErr ? `\u2718 Emergency Rollback Failed` : `\u2714 Emergency Rollback \u2192 ${totalFiles} file${totalFiles === 1 ? "" : "s"} processed`;
14442
+ let terminalWidth = 115;
14443
+ if (process.stdout.isTTY) {
14444
+ terminalWidth = process.stdout.columns - 5 || 120;
14445
+ }
14446
+ const boxWidth = Math.min(postLabel.length + 4, terminalWidth);
14447
+ const boxMid = `${postLabel.padEnd(boxWidth - 2).substring(0, boxWidth - 2)}`;
14448
+ const boxBottom = ` ${" ".repeat(boxWidth)} `;
14449
+ yield { type: "visual_feedback", content: colorMainWords(`${boxBottom}
14450
+ ${boxMid}
14451
+ `) };
14452
+ }
14453
+ }
14400
14454
  if (normToolName === "todo") {
14401
14455
  const { method, tasks, markDone } = parseArgs(toolCall.args);
14402
14456
  let uiTitle = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.1.7",
3
+ "version": "3.1.8",
4
4
  "date": "2026-07-06",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [