fluxflow-cli 1.11.2 → 1.11.3

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 +117 -25
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -173,7 +173,7 @@ var init_ChatLayout = __esm({
173
173
  };
174
174
  cleanSignals = (text) => {
175
175
  if (!text) return text;
176
- let result = text;
176
+ let result = text.replace(/<\/think>(\r?\n){2}/gi, "</think>").replace(/(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi, "");
177
177
  const trigger = "tool:functions.";
178
178
  while (true) {
179
179
  const lowerResult = result.toLowerCase();
@@ -1368,11 +1368,25 @@ var init_history = __esm({
1368
1368
  // src/utils/usage.js
1369
1369
  import fs6 from "fs-extra";
1370
1370
  import path5 from "path";
1371
- var cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
1371
+ import os3 from "os";
1372
+ var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
1372
1373
  var init_usage = __esm({
1373
1374
  "src/utils/usage.js"() {
1374
1375
  init_paths();
1375
1376
  init_crypto();
1377
+ getLocalBackupPath = () => {
1378
+ if (process.platform === "win32") {
1379
+ const localAppData = process.env.LOCALAPPDATA || path5.join(os3.homedir(), "AppData", "Local");
1380
+ return path5.join(localAppData, "FxFl", "backups", "backup.json");
1381
+ }
1382
+ if (process.platform === "darwin") {
1383
+ return path5.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
1384
+ }
1385
+ const xdgDataHome = process.env.XDG_DATA_HOME || path5.join(os3.homedir(), ".local", "share");
1386
+ return path5.join(xdgDataHome, "fxfl", "backups", "backup.json");
1387
+ };
1388
+ BACKUP_FILE = getLocalBackupPath();
1389
+ generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
1376
1390
  cachedUsage = null;
1377
1391
  writeTimeout = null;
1378
1392
  lastWriteTime = 0;
@@ -1390,28 +1404,67 @@ var init_usage = __esm({
1390
1404
  };
1391
1405
  loadUsageFromFile = async () => {
1392
1406
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1407
+ let primaryData = null;
1408
+ let backupData = null;
1393
1409
  try {
1394
1410
  if (await fs6.exists(USAGE_FILE)) {
1395
1411
  const rawContent = (await fs6.readFile(USAGE_FILE, "utf8")).trim();
1396
- let data;
1397
1412
  if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
1398
- data = JSON.parse(rawContent);
1413
+ primaryData = JSON.parse(rawContent);
1399
1414
  } else {
1400
- data = JSON.parse(decryptAes(rawContent));
1415
+ primaryData = JSON.parse(decryptAes(rawContent));
1401
1416
  }
1402
- if (data && data.date === today && data.stats) {
1403
- const mergedStats = { ...defaultStats, ...data.stats };
1404
- if (!Array.isArray(mergedStats.imageCalls)) {
1405
- mergedStats.imageCalls = [];
1406
- }
1407
- return {
1408
- ...data,
1409
- stats: mergedStats
1410
- };
1417
+ }
1418
+ } catch (err) {
1419
+ }
1420
+ try {
1421
+ if (await fs6.exists(BACKUP_FILE)) {
1422
+ const rawContent = (await fs6.readFile(BACKUP_FILE, "utf8")).trim();
1423
+ if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
1424
+ backupData = JSON.parse(rawContent);
1425
+ } else {
1426
+ backupData = JSON.parse(decryptAes(rawContent));
1411
1427
  }
1412
1428
  }
1413
1429
  } catch (err) {
1414
1430
  }
1431
+ let resolvedData = null;
1432
+ if (primaryData && backupData) {
1433
+ if (primaryData.saveId !== backupData.saveId) {
1434
+ resolvedData = primaryData;
1435
+ try {
1436
+ await fs6.ensureDir(path5.dirname(BACKUP_FILE));
1437
+ await fs6.copy(USAGE_FILE, BACKUP_FILE);
1438
+ } catch (e) {
1439
+ }
1440
+ } else {
1441
+ resolvedData = primaryData;
1442
+ }
1443
+ } else if (primaryData && !backupData) {
1444
+ resolvedData = primaryData;
1445
+ try {
1446
+ await fs6.ensureDir(path5.dirname(BACKUP_FILE));
1447
+ await fs6.copy(USAGE_FILE, BACKUP_FILE);
1448
+ } catch (e) {
1449
+ }
1450
+ } else if (!primaryData && backupData) {
1451
+ resolvedData = backupData;
1452
+ try {
1453
+ await fs6.ensureDir(path5.dirname(USAGE_FILE));
1454
+ await fs6.copy(BACKUP_FILE, USAGE_FILE);
1455
+ } catch (e) {
1456
+ }
1457
+ }
1458
+ if (resolvedData && resolvedData.date === today && resolvedData.stats) {
1459
+ const mergedStats = { ...defaultStats, ...resolvedData.stats };
1460
+ if (!Array.isArray(mergedStats.imageCalls)) {
1461
+ mergedStats.imageCalls = [];
1462
+ }
1463
+ return {
1464
+ ...resolvedData,
1465
+ stats: mergedStats
1466
+ };
1467
+ }
1415
1468
  return { date: today, stats: { ...defaultStats } };
1416
1469
  };
1417
1470
  flushUsage = async () => {
@@ -1449,6 +1502,7 @@ var init_usage = __esm({
1449
1502
  }
1450
1503
  }
1451
1504
  }
1505
+ cachedUsage.saveId = generateSaveId();
1452
1506
  const tempFile = USAGE_FILE + ".tmp";
1453
1507
  const encryptedStr = encryptAes(JSON.stringify(cachedUsage, null, 2));
1454
1508
  await fs6.writeFile(tempFile, encryptedStr, "utf8");
@@ -1456,6 +1510,11 @@ var init_usage = __esm({
1456
1510
  await fs6.fsync(fd);
1457
1511
  await fs6.close(fd);
1458
1512
  await fs6.rename(tempFile, USAGE_FILE);
1513
+ try {
1514
+ await fs6.ensureDir(path5.dirname(BACKUP_FILE));
1515
+ await fs6.copy(USAGE_FILE, BACKUP_FILE);
1516
+ } catch (backupErr) {
1517
+ }
1459
1518
  isDirty = false;
1460
1519
  lastWriteTime = Date.now();
1461
1520
  } catch (e) {
@@ -2790,6 +2849,26 @@ var init_write_pdf = __esm({
2790
2849
  ]
2791
2850
  });
2792
2851
  const page = await browser.newPage();
2852
+ let resolvedContent = content;
2853
+ const imgRegex = /<img[^>]+src=["']([^"']+)["']/gi;
2854
+ let match;
2855
+ while ((match = imgRegex.exec(content)) !== null) {
2856
+ const originalSrc = match[1];
2857
+ if (!originalSrc || originalSrc.startsWith("http://") || originalSrc.startsWith("https://") || originalSrc.startsWith("data:")) {
2858
+ continue;
2859
+ }
2860
+ try {
2861
+ const imgPath = path11.resolve(process.cwd(), originalSrc);
2862
+ if (await fs12.pathExists(imgPath)) {
2863
+ const ext = path11.extname(imgPath).toLowerCase().replace(".", "") || "png";
2864
+ const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
2865
+ const base64 = await fs12.readFile(imgPath, "base64");
2866
+ const dataUri = `data:image/${mime};base64,${base64}`;
2867
+ resolvedContent = resolvedContent.split(originalSrc).join(dataUri);
2868
+ }
2869
+ } catch (e) {
2870
+ }
2871
+ }
2793
2872
  const styledContent = `
2794
2873
  <style>
2795
2874
  @page {
@@ -2819,7 +2898,7 @@ var init_write_pdf = __esm({
2819
2898
  }
2820
2899
  </style>
2821
2900
  <div class="watermark">Generated by FluxFlow CLI (AI)</div>
2822
- ${content}
2901
+ ${resolvedContent}
2823
2902
  `;
2824
2903
  await page.setContent(styledContent, { waitUntil: "networkidle0", timeout: 18e4 });
2825
2904
  const pdfBytes = await page.pdf({
@@ -3795,6 +3874,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
3795
3874
  let lastToolSniffed = null;
3796
3875
  let lastToolDetail = null;
3797
3876
  let lastToolEventTime = null;
3877
+ let lastToolFinishedAt = 0;
3798
3878
  let toolResults = [];
3799
3879
  let toolCallPointer = 0;
3800
3880
  let isThinkingLoop = false;
@@ -4223,6 +4303,12 @@ ${boxBottom}` };
4223
4303
  }
4224
4304
  }
4225
4305
  }
4306
+ if (lastToolFinishedAt > 0) {
4307
+ const timeSinceLastTool = Date.now() - lastToolFinishedAt;
4308
+ if (timeSinceLastTool < 1e3) {
4309
+ await new Promise((resolve) => setTimeout(resolve, 1e3 - timeSinceLastTool));
4310
+ }
4311
+ }
4226
4312
  const effectiveStart = lastToolEventTime || Date.now();
4227
4313
  yield { type: "spinner", content: false };
4228
4314
  let result = await dispatchTool(normToolName, toolCall.args, {
@@ -4236,6 +4322,7 @@ ${boxBottom}` };
4236
4322
  process.stdout.write(`\x1B]0;Working...\x07`);
4237
4323
  }
4238
4324
  const toolEnd = Date.now();
4325
+ lastToolFinishedAt = toolEnd;
4239
4326
  yield { type: "tool_time", content: toolEnd - effectiveStart };
4240
4327
  lastToolEventTime = toolEnd;
4241
4328
  let binaryPart = null;
@@ -4693,7 +4780,7 @@ var app_exports = {};
4693
4780
  __export(app_exports, {
4694
4781
  default: () => App
4695
4782
  });
4696
- import os3 from "os";
4783
+ import os4 from "os";
4697
4784
  import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
4698
4785
  import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
4699
4786
  import Spinner2 from "ink-spinner";
@@ -4868,7 +4955,7 @@ function App() {
4868
4955
  const [messages, setMessages] = useState7(() => {
4869
4956
  const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
4870
4957
  const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
4871
- const isHomeDir = process.cwd() === os3.homedir();
4958
+ const isHomeDir = process.cwd() === os4.homedir();
4872
4959
  const isSystemDir = (() => {
4873
4960
  const cwd = process.cwd().toLowerCase();
4874
4961
  if (process.platform === "win32") {
@@ -4896,7 +4983,7 @@ function App() {
4896
4983
  id: "home-warning",
4897
4984
  role: "system",
4898
4985
  text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
4899
- subText: `You are currently in ${os3.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
4986
+ subText: `You are currently in ${os4.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
4900
4987
  isHomeWarning: true,
4901
4988
  isMeta: true
4902
4989
  });
@@ -5305,7 +5392,8 @@ ${hintText}`, color: "magenta" }];
5305
5392
  const resumedMsgs = [...target.messages];
5306
5393
  const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
5307
5394
  if (!hasLogo) {
5308
- resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...\n" });
5395
+ resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: "\u{1F30A}\u26A1 Resuming Flux Flow Session...", isMeta: true });
5396
+ resumedMsgs.unshift({ id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true });
5309
5397
  }
5310
5398
  setMessages(resumedMsgs);
5311
5399
  setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${targetId}]`, isMeta: true }]);
@@ -5321,8 +5409,11 @@ ${hintText}`, color: "magenta" }];
5321
5409
  break;
5322
5410
  }
5323
5411
  case "/clear": {
5324
- setMessages([{ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome back to Flux Flow! Context cleared.\n", isMeta: true }]);
5325
- setCompletedIndex(1);
5412
+ setMessages([
5413
+ { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true },
5414
+ { id: "welcome-" + Date.now(), role: "system", text: "\u{1F30A}\u26A1 Welcome back to Flux Flow! Context cleared.", isMeta: true }
5415
+ ]);
5416
+ setCompletedIndex(2);
5326
5417
  setChatId(generateChatId());
5327
5418
  setSessionStats({ tokens: 0 });
5328
5419
  setIsExpanded(false);
@@ -5481,21 +5572,22 @@ ${hintText}`, color: "magenta" }];
5481
5572
  let formattedLevel;
5482
5573
  if (parts[1]) {
5483
5574
  let val = parts[1].toLowerCase();
5575
+ const isBypass = parts.includes("--bypass");
5484
5576
  formattedLevel = val.charAt(0).toUpperCase() + val.slice(1);
5485
5577
  if (val === "xhigh") {
5486
5578
  formattedLevel = "xHigh";
5487
5579
  }
5488
- if (mode === "Flow" && (formattedLevel === "Medium" || formattedLevel === "High" || formattedLevel === "xHigh")) {
5580
+ if (!isBypass && mode === "Flow" && (formattedLevel === "Medium" || formattedLevel === "High" || formattedLevel === "xHigh")) {
5489
5581
  setMessages((prev) => {
5490
5582
  setCompletedIndex(prev.length + 1);
5491
5583
  return [...prev, { id: Date.now(), role: "system", text: `\u274C [RESTRICTED] "${formattedLevel}" is restricted in Flow mode. Switch to Flux to enable Higher Thinking Levels.`, isMeta: true }];
5492
5584
  });
5493
5585
  } else {
5494
5586
  setThinkingLevel(formattedLevel);
5495
- const s2 = emojiSpace(2);
5587
+ const s2 = emojiSpace(1);
5496
5588
  setMessages((prev) => {
5497
5589
  setCompletedIndex(prev.length + 1);
5498
- return [...prev, { id: Date.now(), role: "system", text: `\u{1F527}${s2}[SYSTEM] Thinking level set to ${formattedLevel}`, isMeta: true }];
5590
+ return [...prev, { id: Date.now(), role: "system", text: `\u{1F527} [SYSTEM] Thinking level set to ${formattedLevel}${isBypass ? ` (Bypass Activated \u{1F575}\uFE0F${s2})` : ""}`, isMeta: true }];
5499
5591
  });
5500
5592
  }
5501
5593
  } else {
@@ -6678,7 +6770,7 @@ var init_app = __esm({
6678
6770
  packageJsonPath = path16.join(path16.dirname(fileURLToPath(import.meta.url)), "../package.json");
6679
6771
  packageJson = JSON.parse(fs18.readFileSync(packageJsonPath, "utf8"));
6680
6772
  versionFluxflow = packageJson.version;
6681
- updatedOn = "2026-05-17";
6773
+ updatedOn = "2026-05-20";
6682
6774
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 0 }, /* @__PURE__ */ React10.createElement(
6683
6775
  CommandMenu,
6684
6776
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.11.2",
3
+ "version": "1.11.3",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",