fluxflow-cli 3.16.0 → 3.16.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 +145 -106
  2. package/package.json +3 -2
package/dist/fluxflow.js CHANGED
@@ -52,13 +52,14 @@ __export(paths_exports, {
52
52
  SETTINGS_FILE: () => SETTINGS_FILE,
53
53
  TEMP_MEM_CHAT_FILE: () => TEMP_MEM_CHAT_FILE,
54
54
  TEMP_MEM_FILE: () => TEMP_MEM_FILE,
55
- USAGE_FILE: () => USAGE_FILE
55
+ USAGE_FILE: () => USAGE_FILE,
56
+ USAGE_FILE_OLD: () => USAGE_FILE_OLD
56
57
  });
57
58
  import os from "os";
58
59
  import path from "path";
59
60
  import fs from "fs";
60
61
  import crypto from "crypto";
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;
62
+ var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, HISTORY_DIR, USAGE_FILE_OLD, 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;
62
63
  var init_paths = __esm({
63
64
  "src/utils/paths.js"() {
64
65
  FLUXFLOW_DIR = path.join(os.homedir(), ".fluxflow");
@@ -96,7 +97,8 @@ var init_paths = __esm({
96
97
  SECRET_DIR = path.join(DATA_DIR, "secret");
97
98
  HISTORY_FILE = path.join(SECRET_DIR, "history.json");
98
99
  HISTORY_DIR = path.join(SECRET_DIR, "history");
99
- USAGE_FILE = path.join(FLUXFLOW_DIR, "usage.json");
100
+ USAGE_FILE_OLD = path.join(FLUXFLOW_DIR, "usage.json");
101
+ USAGE_FILE = path.join(SECRET_DIR, "usage.json");
100
102
  MEMORIES_FILE = path.join(SECRET_DIR, "memories.json");
101
103
  TEMP_MEM_FILE = path.join(SECRET_DIR, "memory-temp.json");
102
104
  TEMP_MEM_CHAT_FILE = path.join(SECRET_DIR, "temp-memory-chat.json");
@@ -9187,24 +9189,11 @@ var init_history = __esm({
9187
9189
  // src/utils/usage.js
9188
9190
  import fs10 from "fs-extra";
9189
9191
  import path9 from "path";
9190
- import os3 from "os";
9191
- var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, runtimeSession, addToUsage, getCustomPeriodUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
9192
+ var generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, runtimeSession, addToUsage, getCustomPeriodUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
9192
9193
  var init_usage = __esm({
9193
9194
  "src/utils/usage.js"() {
9194
9195
  init_paths();
9195
9196
  init_crypto();
9196
- getLocalBackupPath = () => {
9197
- if (process.platform === "win32") {
9198
- const localAppData = process.env.LOCALAPPDATA || path9.join(os3.homedir(), "AppData", "Local");
9199
- return path9.join(localAppData, "FxFl", "backups", "backup.json");
9200
- }
9201
- if (process.platform === "darwin") {
9202
- return path9.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
9203
- }
9204
- const xdgDataHome = process.env.XDG_DATA_HOME || path9.join(os3.homedir(), ".local", "share");
9205
- return path9.join(xdgDataHome, "fxfl", "backups", "backup.json");
9206
- };
9207
- BACKUP_FILE = getLocalBackupPath();
9208
9197
  generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
9209
9198
  cachedUsage = null;
9210
9199
  writeTimeout = null;
@@ -9239,10 +9228,16 @@ var init_usage = __esm({
9239
9228
  return purged;
9240
9229
  };
9241
9230
  loadUsageFromFile = async () => {
9242
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9231
+ const today2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9232
+ try {
9233
+ if (!await fs10.exists(USAGE_FILE) && await fs10.exists(USAGE_FILE_OLD)) {
9234
+ await fs10.ensureDir(path9.dirname(USAGE_FILE));
9235
+ await fs10.move(USAGE_FILE_OLD, USAGE_FILE);
9236
+ }
9237
+ } catch (err) {
9238
+ }
9243
9239
  const tempFile = USAGE_FILE + ".tmp";
9244
9240
  let primaryData = null;
9245
- let backupData = null;
9246
9241
  try {
9247
9242
  if (await fs10.exists(tempFile)) {
9248
9243
  const rawContent = (await fs10.readFile(tempFile, "utf8")).trim();
@@ -9284,44 +9279,7 @@ var init_usage = __esm({
9284
9279
  } catch (err) {
9285
9280
  }
9286
9281
  }
9287
- try {
9288
- if (await fs10.exists(BACKUP_FILE)) {
9289
- const rawContent = (await fs10.readFile(BACKUP_FILE, "utf8")).trim();
9290
- if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
9291
- backupData = JSON.parse(rawContent);
9292
- } else {
9293
- backupData = JSON.parse(decryptAes(rawContent));
9294
- }
9295
- }
9296
- } catch (err) {
9297
- }
9298
- let resolvedData = null;
9299
- if (primaryData && backupData) {
9300
- if (primaryData.saveId !== backupData.saveId) {
9301
- resolvedData = primaryData;
9302
- try {
9303
- await fs10.ensureDir(path9.dirname(BACKUP_FILE));
9304
- await fs10.copy(USAGE_FILE, BACKUP_FILE);
9305
- } catch (e) {
9306
- }
9307
- } else {
9308
- resolvedData = primaryData;
9309
- }
9310
- } else if (primaryData && !backupData) {
9311
- resolvedData = primaryData;
9312
- try {
9313
- await fs10.ensureDir(path9.dirname(BACKUP_FILE));
9314
- await fs10.copy(USAGE_FILE, BACKUP_FILE);
9315
- } catch (e) {
9316
- }
9317
- } else if (!primaryData && backupData) {
9318
- resolvedData = backupData;
9319
- try {
9320
- await fs10.ensureDir(path9.dirname(USAGE_FILE));
9321
- await fs10.copy(BACKUP_FILE, USAGE_FILE);
9322
- } catch (e) {
9323
- }
9324
- }
9282
+ let resolvedData = primaryData;
9325
9283
  if (resolvedData) {
9326
9284
  const stats = resolvedData.stats || { ...defaultStats };
9327
9285
  const mergedStats = { ...defaultStats, ...stats };
@@ -9329,28 +9287,32 @@ var init_usage = __esm({
9329
9287
  mergedStats.imageCalls = [];
9330
9288
  }
9331
9289
  const history = resolvedData.history || {};
9332
- if (resolvedData.date === today) {
9290
+ const purgedHistory = purgeOldHistory(history, today2);
9291
+ if (Object.keys(history).length !== Object.keys(purgedHistory).length) {
9292
+ isDirty = true;
9293
+ }
9294
+ if (resolvedData.date === today2) {
9333
9295
  return {
9334
9296
  ...resolvedData,
9335
9297
  stats: mergedStats,
9336
- history
9298
+ history: purgedHistory
9337
9299
  };
9338
9300
  } else {
9339
9301
  const oldDate = resolvedData.date;
9340
9302
  const oldStats = mergedStats;
9341
- const updatedHistory = { ...history };
9303
+ const updatedHistory = { ...purgedHistory };
9342
9304
  if (oldDate) {
9343
9305
  updatedHistory[oldDate] = oldStats;
9344
9306
  }
9345
9307
  return {
9346
- date: today,
9308
+ date: today2,
9347
9309
  stats: { ...defaultStats },
9348
- history: purgeOldHistory(updatedHistory, today)
9310
+ history: purgeOldHistory(updatedHistory, today2)
9349
9311
  };
9350
9312
  }
9351
9313
  }
9352
9314
  return {
9353
- date: today,
9315
+ date: today2,
9354
9316
  stats: { ...defaultStats },
9355
9317
  history: {}
9356
9318
  };
@@ -9433,7 +9395,10 @@ var init_usage = __esm({
9433
9395
  mergedHistory[dateKey] = diskData.history[dateKey];
9434
9396
  }
9435
9397
  }
9436
- cachedUsage.history = mergedHistory;
9398
+ cachedUsage.history = purgeOldHistory(mergedHistory, cachedUsage.date || today);
9399
+ } else if (cachedUsage && cachedUsage.history) {
9400
+ const today2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9401
+ cachedUsage.history = purgeOldHistory(cachedUsage.history, today2);
9437
9402
  }
9438
9403
  cachedUsage.saveId = generateSaveId();
9439
9404
  const tempFile = USAGE_FILE + ".tmp";
@@ -9443,11 +9408,6 @@ var init_usage = __esm({
9443
9408
  await fs10.fsync(fd);
9444
9409
  await fs10.close(fd);
9445
9410
  await fs10.rename(tempFile, USAGE_FILE);
9446
- try {
9447
- await fs10.ensureDir(path9.dirname(BACKUP_FILE));
9448
- await fs10.copy(USAGE_FILE, BACKUP_FILE);
9449
- } catch (backupErr) {
9450
- }
9451
9411
  isDirty = false;
9452
9412
  lastWriteTime = Date.now();
9453
9413
  } catch (e) {
@@ -9466,6 +9426,9 @@ var init_usage = __esm({
9466
9426
  };
9467
9427
  initUsage = async () => {
9468
9428
  cachedUsage = await loadUsageFromFile();
9429
+ if (isDirty) {
9430
+ queueFlush();
9431
+ }
9469
9432
  };
9470
9433
  forceFlushUsage = async () => {
9471
9434
  if (writeTimeout) {
@@ -9475,10 +9438,10 @@ var init_usage = __esm({
9475
9438
  await flushUsage();
9476
9439
  };
9477
9440
  getDailyUsage = async () => {
9478
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9441
+ const today2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9479
9442
  if (!cachedUsage) {
9480
9443
  cachedUsage = await loadUsageFromFile();
9481
- } else if (cachedUsage.date !== today) {
9444
+ } else if (cachedUsage.date !== today2) {
9482
9445
  const oldDate = cachedUsage.date;
9483
9446
  const oldStats = cachedUsage.stats;
9484
9447
  const history = cachedUsage.history || {};
@@ -9486,9 +9449,9 @@ var init_usage = __esm({
9486
9449
  history[oldDate] = oldStats;
9487
9450
  }
9488
9451
  cachedUsage = {
9489
- date: today,
9452
+ date: today2,
9490
9453
  stats: { ...defaultStats },
9491
- history: purgeOldHistory(history, today)
9454
+ history: purgeOldHistory(history, today2)
9492
9455
  };
9493
9456
  isDirty = true;
9494
9457
  await flushUsage();
@@ -9499,15 +9462,15 @@ var init_usage = __esm({
9499
9462
  return cachedUsage.stats;
9500
9463
  };
9501
9464
  getMonthlyUsage = async () => {
9502
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9465
+ const today2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9503
9466
  if (!cachedUsage) {
9504
9467
  cachedUsage = await loadUsageFromFile();
9505
9468
  }
9506
- if (cachedUsage.date !== today) {
9469
+ if (cachedUsage.date !== today2) {
9507
9470
  await getDailyUsage();
9508
9471
  }
9509
9472
  const history = cachedUsage.history || {};
9510
- const purgedHistory = purgeOldHistory(history, today);
9473
+ const purgedHistory = purgeOldHistory(history, today2);
9511
9474
  cachedUsage.history = purgedHistory;
9512
9475
  const todayStats = cachedUsage.stats || { ...defaultStats };
9513
9476
  const summed = { ...defaultStats };
@@ -9604,17 +9567,17 @@ var init_usage = __esm({
9604
9567
  queueFlush();
9605
9568
  };
9606
9569
  getCustomPeriodUsage = async (resetDay = 1) => {
9607
- const today = /* @__PURE__ */ new Date();
9608
- const todayStr = today.toISOString().split("T")[0];
9570
+ const today2 = /* @__PURE__ */ new Date();
9571
+ const todayStr = today2.toISOString().split("T")[0];
9609
9572
  if (!cachedUsage) {
9610
9573
  cachedUsage = await loadUsageFromFile();
9611
9574
  }
9612
9575
  if (cachedUsage.date !== todayStr) {
9613
9576
  await getDailyUsage();
9614
9577
  }
9615
- let startYear = today.getFullYear();
9616
- let startMonth = today.getMonth();
9617
- const todayDay = today.getDate();
9578
+ let startYear = today2.getFullYear();
9579
+ let startMonth = today2.getMonth();
9580
+ const todayDay = today2.getDate();
9618
9581
  if (todayDay < resetDay) {
9619
9582
  startMonth -= 1;
9620
9583
  if (startMonth < 0) {
@@ -9928,14 +9891,14 @@ var init_usage = __esm({
9928
9891
  });
9929
9892
 
9930
9893
  // src/utils/puppeteer_helper.js
9931
- import os4 from "os";
9894
+ import os3 from "os";
9932
9895
  import path10 from "path";
9933
9896
  import fs11 from "fs";
9934
9897
  import { createRequire } from "module";
9935
9898
  import { fileURLToPath as fileURLToPath2 } from "url";
9936
9899
  function getPuppeteerConfig() {
9937
- const platform = os4.platform();
9938
- const arch = os4.arch();
9900
+ const platform = os3.platform();
9901
+ const arch = os3.arch();
9939
9902
  let pptrPlatform = "";
9940
9903
  let execName = "";
9941
9904
  let subDir = "";
@@ -10272,6 +10235,7 @@ ${finalResults}`;
10272
10235
  import puppeteer2 from "puppeteer";
10273
10236
  import fs13 from "fs";
10274
10237
  import path12 from "path";
10238
+ import TurndownService from "turndown";
10275
10239
  var web_scrape;
10276
10240
  var init_web_scrape = __esm({
10277
10241
  "src/tools/web_scrape.js"() {
@@ -10329,15 +10293,20 @@ var init_web_scrape = __esm({
10329
10293
  el.removeAttribute(attrName);
10330
10294
  }
10331
10295
  }
10332
- if ((el.tagName === "SPAN" || el.tagName === "DIV" || el.tagName === "SECTION") && el.attributes.length === 0) {
10333
- if (el.tagName === "SPAN" || el.tagName === "DIV" && el.childNodes.length === 1 && el.childNodes[0].nodeType === Node.TEXT_NODE) {
10296
+ });
10297
+ while (document.querySelector("div, span")) {
10298
+ document.querySelectorAll("div, span").forEach((el) => {
10299
+ if (el.parentNode) {
10334
10300
  el.replaceWith(...el.childNodes);
10335
10301
  }
10336
- }
10302
+ });
10303
+ }
10304
+ document.querySelectorAll("br").forEach((br) => {
10305
+ br.replaceWith(document.createTextNode("\n\n"));
10337
10306
  });
10338
10307
  const pruneEmpty = () => {
10339
10308
  let found = false;
10340
- document.querySelectorAll("*:not(br)").forEach((el) => {
10309
+ document.querySelectorAll("*").forEach((el) => {
10341
10310
  if (el.childNodes.length === 0 && !el.innerText.trim()) {
10342
10311
  el.remove();
10343
10312
  found = true;
@@ -10349,11 +10318,17 @@ var init_web_scrape = __esm({
10349
10318
  return document.body.innerHTML;
10350
10319
  });
10351
10320
  if (!htmlContent) throw new Error("EMPTY_RENDER_RESULT");
10352
- const cleanedHtml = htmlContent.replace(/\s+/g, " ").replace(/>\s+</g, "><").trim().substring(0, 5e4);
10321
+ const cleanedHtml = htmlContent.replace(/<br\s*\/?>/gi, "\n\n").replace(/[ \t]+/g, " ").replace(/>[ \t]+</g, "><").replace(/\n\s+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
10322
+ const turndownService = new TurndownService({
10323
+ headingStyle: "atx",
10324
+ codeBlockStyle: "fenced"
10325
+ });
10326
+ const rawMarkdown = turndownService.turndown(cleanedHtml).replace(/\.\s*\n/g, "\n").replace(/ +/g, " ").replace(/\t/g, " ").replace(/\n\s+/g, "\n").replace(/\n{3,}/g, "\n\n");
10327
+ const markdown = rawMarkdown.substring(0, 5e4);
10353
10328
  await browser.close();
10354
- return `CLEANED HTML FROM [${url}]:
10329
+ return `Markdown parsed from [${url}]:
10355
10330
 
10356
- ${cleanedHtml}${htmlContent.length > 5e4 ? "\n\n[TRUNCATED AT 50K CHARS]" : ""}`;
10331
+ ${markdown}${rawMarkdown.length > 5e4 ? "\n\n[TRUNCATED AT 50K CHARS]" : ""}`;
10357
10332
  } catch (err) {
10358
10333
  lastError = err;
10359
10334
  if (browser) await browser.close();
@@ -10553,7 +10528,7 @@ var init_view_file = __esm({
10553
10528
  const end = Math.min(totalLines, finalEnd);
10554
10529
  const resultLines = lines.slice(start, end);
10555
10530
  const header = `File: [${targetPath}] (Showing lines ${start + 1}-${end} of ${totalLines}).`;
10556
- const code = resultLines.map((line, i) => `${String(start + i + 1).padStart(4)}: ${line}`).join("\n");
10531
+ const code = resultLines.map((line, i) => `${String(start + i + 1).padStart(4)}: ${line.trimEnd()}`).join("\n");
10557
10532
  return `${header}
10558
10533
 
10559
10534
  ${code}`;
@@ -19503,7 +19478,7 @@ var app_exports = {};
19503
19478
  __export(app_exports, {
19504
19479
  default: () => App
19505
19480
  });
19506
- import os5 from "os";
19481
+ import os4 from "os";
19507
19482
  import React16, { useState as useState15, useEffect as useEffect12, useRef as useRef4, useMemo as useMemo2 } from "react";
19508
19483
  import { Box as Box14, Text as Text16, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
19509
19484
  import fs30 from "fs-extra";
@@ -19531,6 +19506,7 @@ function App({ args = [] }) {
19531
19506
  const [showBridgePromo, setShowBridgePromo] = useState15(false);
19532
19507
  const [promoSelectedIndex, setPromoSelectedIndex] = useState15(0);
19533
19508
  const suggestionOffsetRef = useRef4(0);
19509
+ const maxScrollRef = useRef4(0);
19534
19510
  const persistedModelRef = useRef4(null);
19535
19511
  const activeStreamingMsgRef = useRef4(null);
19536
19512
  const [renderTick, setRenderTick] = useState15(0);
@@ -20018,6 +19994,7 @@ function App({ args = [] }) {
20018
19994
  const [monthlyUsage, setMonthlyUsage] = useState15(null);
20019
19995
  const [customPeriodUsage, setCustomPeriodUsage] = useState15(null);
20020
19996
  const [statsMode, setStatsMode] = useState15("daily");
19997
+ const [statsScrollOffset, setStatsScrollOffset] = useState15(0);
20021
19998
  const PLAYGROUND_CHAT_ID = "flow-playground";
20022
19999
  const [chatId, setChatId] = useState15(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
20023
20000
  useEffect12(() => {
@@ -20192,7 +20169,7 @@ function App({ args = [] }) {
20192
20169
  useEffect12(() => setEscPressCount(0), [input]);
20193
20170
  const [messages, rawSetMessages] = useState15(() => {
20194
20171
  const logoMsg = { id: "logo-" + Date.now(), role: "system", isLogo: true, isMeta: true };
20195
- const isHomeDir = process.cwd() === os5.homedir();
20172
+ const isHomeDir = process.cwd() === os4.homedir();
20196
20173
  const isSystemDir = (() => {
20197
20174
  const cwd = process.cwd().toLowerCase();
20198
20175
  if (process.platform === "win32") {
@@ -20219,7 +20196,7 @@ function App({ args = [] }) {
20219
20196
  id: "home-warning",
20220
20197
  role: "system",
20221
20198
  text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
20222
- subText: `You are currently in ${os5.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please open FluxFlow in project folder.`,
20199
+ subText: `You are currently in ${os4.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please open FluxFlow in project folder.`,
20223
20200
  isHomeWarning: true
20224
20201
  });
20225
20202
  }
@@ -20398,10 +20375,20 @@ function App({ args = [] }) {
20398
20375
  if (prev === "modelBreakdown") return "daily";
20399
20376
  return prev === "daily" ? "monthly" : "daily";
20400
20377
  });
20378
+ setStatsScrollOffset(0);
20401
20379
  return;
20402
20380
  }
20403
20381
  if (key.space || inputText === " ") {
20404
20382
  setStatsMode((prev) => prev === "modelBreakdown" ? "daily" : "modelBreakdown");
20383
+ setStatsScrollOffset(0);
20384
+ return;
20385
+ }
20386
+ if (key.upArrow) {
20387
+ setStatsScrollOffset((prev) => Math.max(0, prev - 1));
20388
+ return;
20389
+ }
20390
+ if (key.downArrow) {
20391
+ setStatsScrollOffset((prev) => Math.min(maxScrollRef.current, prev + 1));
20405
20392
  return;
20406
20393
  }
20407
20394
  }
@@ -23196,13 +23183,13 @@ Selection: ${val}`,
23196
23183
  const limitsNotSet = !usingProviderBudgets && (shouldClearValue(reqLimit) || shouldClearValue(tokenLimit) || shouldClearValue(monthlyLimit));
23197
23184
  let resetInfo = "";
23198
23185
  if (quotas.resetMode === "Custom") {
23199
- const today = /* @__PURE__ */ new Date();
23186
+ const today2 = /* @__PURE__ */ new Date();
23200
23187
  const resetDay = quotas.resetDay || 1;
23201
- let resetMonth = today.getMonth();
23202
- if (today.getDate() >= resetDay) {
23188
+ let resetMonth = today2.getMonth();
23189
+ if (today2.getDate() >= resetDay) {
23203
23190
  resetMonth += 1;
23204
23191
  }
23205
- const resetDate = new Date(today.getFullYear(), resetMonth, resetDay);
23192
+ const resetDate = new Date(today2.getFullYear(), resetMonth, resetDay);
23206
23193
  const monthName = resetDate.toLocaleString("default", { month: "short" });
23207
23194
  resetInfo = `${monthName}-${resetDay}`;
23208
23195
  }
@@ -23334,10 +23321,62 @@ Selection: ${val}`,
23334
23321
  const imageCreditsLabel = statsMode === "monthly" ? "Image Credits:" : "Image Credits:";
23335
23322
  const codeChangesLabel = statsMode === "monthly" ? "Code Changes:" : "Code Changes:";
23336
23323
  const toolCallsLabel = statsMode === "monthly" ? "Tool Calls:" : "Tool Calls:";
23337
- return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, paddingX: 3, paddingY: 1, paddingBottom: 0, width: Math.min(125, (stdout?.columns || 100) - 2) }, statsMode === "modelBreakdown" ? /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "30-DAY MODEL TOKEN BREAKDOWN"), !monthlyUsage?.models || Object.keys(monthlyUsage.models).length === 0 ? /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, italic: true }, "No model token usage recorded in the last 30 days.")) : Object.entries(monthlyUsage.models).map(([provider, models]) => {
23338
- const providerTotalTokens = Object.values(models).reduce((sum, m) => sum + (m.tokens || 0), 0);
23339
- return /* @__PURE__ */ React16.createElement(Box14, { key: provider, flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 40 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.primary, bold: true }, provider, ":")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, formatTokens(providerTotalTokens))), Object.entries(models).map(([modelName, stats]) => /* @__PURE__ */ React16.createElement(Box14, { key: modelName, flexDirection: "column", marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 36 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "\xBB ", modelName, ":")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(stats.tokens || 0))), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 32 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Input Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens((stats.tokens || 0) - (stats.candidateTokens || 0)))), (stats.cachedTokens || 0) > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 5 }, /* @__PURE__ */ React16.createElement(Box14, { width: 31 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Cached:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(stats.cachedTokens))), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 32 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Output Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(stats.candidateTokens || 0))))));
23340
- })) : /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Session Duration:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Model Requests:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionAgentCalls)), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB API Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Tool Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Memory Agent:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionBackgroundCalls)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Tokens Consumed:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Active Context:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionStats.tokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Input Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 21 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Cached:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Output Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Images Made:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionImageCount)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Image Credits:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Code Changes (Sess):")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "+", runtimeSession.linesAdded), " ", /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "-", runtimeSession.linesRemoved))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Tool Calls (Sess):")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, runtimeSession.toolSuccess + runtimeSession.toolFailure + runtimeSession.toolDenied, " ( "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "\u2714 ", runtimeSession.toolSuccess), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.warning || "yellow" }, "\u{1F6C7} ", runtimeSession.toolDenied), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "\u2718 ", runtimeSession.toolFailure), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " )"))), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, trackerTitle), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, timeLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatDuration(u?.duration || 0))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Model Requests:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, u?.agent || 0)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Memory Agent:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, u?.background || 0)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, tokensLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(u?.tokens || 0))), (u?.tokens || 0) > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Input Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens((u?.tokens || 0) - (u?.candidateTokens || 0)))), (u?.cachedTokens || 0) > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 21 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Cached:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(u.cachedTokens))), (u?.candidateTokens || 0) > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Output Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(u.candidateTokens)))), (u?.imageCalls?.length || 0) > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, imagesLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, u.imageCalls.length)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, imageCreditsLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, Number(((u.imageCalls.reduce((sum, c) => sum + c.cost, 0) || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, codeChangesLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "+", u?.linesAdded || 0), " ", /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "-", u?.linesRemoved || 0))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, toolCallsLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, (u?.toolSuccess || 0) + (u?.toolFailure || 0) + (u?.toolDenied || 0), " ( "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "\u2714 ", u?.toolSuccess || 0), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.warning || "yellow" }, "\u{1F6C7} ", u?.toolDenied || 0), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "\u2718 ", u?.toolFailure || 0), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " )")))), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, dimColor: true, marginTop: 1, italic: true }, "(Press TAB to toggle Daily/Monthly views, SPACE for Model Breakdown, ESC to return)"));
23324
+ const maxRows = Math.max(4, (stdout?.rows || terminalSize?.rows || 24) - 15);
23325
+ const renderLeaderRow = (key, leftText, rightText, leftColor, rightColor, indent = 0, isBold = false) => {
23326
+ const cols = stdout?.columns || terminalSize?.columns || 80;
23327
+ const boxWidth = Math.min(125, cols - 2);
23328
+ const lineWidth = Math.max(20, boxWidth - 6);
23329
+ const maxLeftLen = Math.max(5, lineWidth - indent - rightText.length - 5);
23330
+ let cleanLeftText = leftText;
23331
+ if (cleanLeftText.length > maxLeftLen) {
23332
+ cleanLeftText = cleanLeftText.substring(0, maxLeftLen - 1) + "\u2026";
23333
+ }
23334
+ const dotsCount = Math.max(2, lineWidth - indent - cleanLeftText.length - rightText.length - 2);
23335
+ const dotsStr = " " + ".".repeat(dotsCount) + " ";
23336
+ const indentStr = " ".repeat(indent);
23337
+ return /* @__PURE__ */ React16.createElement(Box14, { key, width: lineWidth }, /* @__PURE__ */ React16.createElement(Text16, { wrap: "truncate" }, /* @__PURE__ */ React16.createElement(Text16, null, indentStr), /* @__PURE__ */ React16.createElement(Text16, { color: leftColor, bold: isBold }, cleanLeftText), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, dimColor: true }, dotsStr), /* @__PURE__ */ React16.createElement(Text16, { color: rightColor, bold: isBold }, rightText)));
23338
+ };
23339
+ const breakdownRows = [];
23340
+ if (!monthlyUsage?.models || Object.keys(monthlyUsage.models).length === 0) {
23341
+ breakdownRows.push(
23342
+ /* @__PURE__ */ React16.createElement(Box14, { key: "empty", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, italic: true }, "No model token usage recorded in the last 30 days."))
23343
+ );
23344
+ } else {
23345
+ Object.entries(monthlyUsage.models).forEach(([provider, models], pIdx) => {
23346
+ const providerTotalTokens = Object.values(models).reduce((sum, m) => sum + (m.tokens || 0), 0);
23347
+ if (pIdx > 0) {
23348
+ breakdownRows.push(/* @__PURE__ */ React16.createElement(Box14, { key: `space-prov-${provider}` }, /* @__PURE__ */ React16.createElement(Text16, null, " ")));
23349
+ }
23350
+ breakdownRows.push(
23351
+ renderLeaderRow(`prov-${provider}`, `${provider}:`, formatTokens(providerTotalTokens), colors.primary, colors.text, 0, true)
23352
+ );
23353
+ Object.entries(models).forEach(([modelName, stats], mIdx) => {
23354
+ if (mIdx > 0) {
23355
+ breakdownRows.push(/* @__PURE__ */ React16.createElement(Box14, { key: `space-mod-${provider}-${modelName}` }, /* @__PURE__ */ React16.createElement(Text16, null, " ")));
23356
+ }
23357
+ breakdownRows.push(
23358
+ renderLeaderRow(`mod-${provider}-${modelName}`, `\xBB ${modelName}:`, formatTokens(stats.tokens || 0), colors.secondary, colors.text, 2, true)
23359
+ );
23360
+ breakdownRows.push(
23361
+ renderLeaderRow(`in-${provider}-${modelName}`, "\xBB Input Tokens:", formatTokens((stats.tokens || 0) - (stats.candidateTokens || 0)), colors.textMuted, colors.text, 5, false)
23362
+ );
23363
+ if ((stats.cachedTokens || 0) > 0) {
23364
+ breakdownRows.push(
23365
+ renderLeaderRow(`cache-${provider}-${modelName}`, "\xBB Cached:", formatTokens(stats.cachedTokens), colors.textMuted, colors.text, 7, false)
23366
+ );
23367
+ }
23368
+ breakdownRows.push(
23369
+ renderLeaderRow(`out-${provider}-${modelName}`, "\xBB Output Tokens:", formatTokens(stats.candidateTokens || 0), colors.textMuted, colors.text, 5, false)
23370
+ );
23371
+ });
23372
+ });
23373
+ }
23374
+ const totalRows = breakdownRows.length;
23375
+ const maxScroll = Math.max(0, totalRows - maxRows);
23376
+ maxScrollRef.current = maxScroll;
23377
+ const effectiveScroll = Math.min(statsScrollOffset, maxScroll);
23378
+ const visibleRows = breakdownRows.slice(effectiveScroll, effectiveScroll + maxRows);
23379
+ return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, paddingX: 3, paddingY: 1, paddingBottom: 0, width: Math.min(125, (stdout?.columns || 100) - 2) }, statsMode === "modelBreakdown" ? /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Box14, { justifyContent: "space-between" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "30-DAY MODEL TOKEN BREAKDOWN"), totalRows > maxRows && /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, dimColor: true }, "[", effectiveScroll + 1, "-", Math.min(totalRows, effectiveScroll + maxRows), " of ", totalRows, "] \u25B2\u25BC")), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", height: maxRows, marginTop: 1 }, visibleRows)) : /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Session Duration:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Model Requests:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionAgentCalls)), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB API Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Tool Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Memory Agent:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionBackgroundCalls)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Tokens Consumed:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Active Context:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionStats.tokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Input Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 21 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Cached:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Output Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Images Made:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionImageCount)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Image Credits:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Code Changes (Sess):")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "+", runtimeSession.linesAdded), " ", /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "-", runtimeSession.linesRemoved))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Tool Calls (Sess):")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, runtimeSession.toolSuccess + runtimeSession.toolFailure + runtimeSession.toolDenied, " ( "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "\u2714 ", runtimeSession.toolSuccess), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.warning || "yellow" }, "\u{1F6C7} ", runtimeSession.toolDenied), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "\u2718 ", runtimeSession.toolFailure), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " )"))), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, trackerTitle), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, timeLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatDuration(u?.duration || 0))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Model Requests:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, u?.agent || 0)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Memory Agent:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, u?.background || 0)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, tokensLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(u?.tokens || 0))), (u?.tokens || 0) > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Input Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens((u?.tokens || 0) - (u?.candidateTokens || 0)))), (u?.cachedTokens || 0) > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 21 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Cached:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(u.cachedTokens))), (u?.candidateTokens || 0) > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 23 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Output Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(u.candidateTokens)))), (u?.imageCalls?.length || 0) > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, imagesLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, u.imageCalls.length)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, imageCreditsLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, Number(((u.imageCalls.reduce((sum, c) => sum + c.cost, 0) || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, codeChangesLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "+", u?.linesAdded || 0), " ", /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "-", u?.linesRemoved || 0))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 25 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, toolCallsLabel)), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, (u?.toolSuccess || 0) + (u?.toolFailure || 0) + (u?.toolDenied || 0), " ( "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green" }, "\u2714 ", u?.toolSuccess || 0), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.warning || "yellow" }, "\u{1F6C7} ", u?.toolDenied || 0), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.danger || "red" }, "\u2718 ", u?.toolFailure || 0), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " )")))), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, dimColor: true, italic: true }, "\n", "(Press TAB to toggle Daily/Monthly views, SPACE for Model Breakdown, ESC to return)"));
23341
23380
  }
23342
23381
  case "dynamicDirDanger":
23343
23382
  return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.warning || "yellow", bold: true, underline: true }, "DYNAMIC DIRECTORY AWARENESS"), /* @__PURE__ */ React16.createElement(Text16, { marginTop: 1, color: colors.text }, "Enabling this keeps the agent aware of filesystem state in real time, but may reduce prompt cache efficiency."), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, "\n", "RECOMMENDED SCENARIOS TO TURN ON:"), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\u2022 Repo is small."), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\u2022 The task benefits from real-time filesystem awareness."), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\u2022 Files are often created, renamed, or deleted."), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\u2022 You know exactly what you're signing up for."), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\u2022 You don't have conflicting decisions regarding token bills."), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\u2022 You want to see your wallet crying at 3am."), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(
@@ -24142,7 +24181,7 @@ var init_app = __esm({
24142
24181
  };
24143
24182
  getKeybindingsPath = (ideName) => {
24144
24183
  const dirName = getIDEDirName(ideName);
24145
- const home = os5.homedir();
24184
+ const home = os4.homedir();
24146
24185
  if (process.platform === "win32") {
24147
24186
  const appData = process.env.APPDATA;
24148
24187
  if (!appData) return null;
@@ -24401,10 +24440,10 @@ var init_app = __esm({
24401
24440
  // src/cli.jsx
24402
24441
  import { spawn as spawn3 } from "child_process";
24403
24442
  import { fileURLToPath as fileURLToPath4 } from "url";
24404
- import os6 from "os";
24443
+ import os5 from "os";
24405
24444
  import dotenv2 from "dotenv";
24406
24445
  dotenv2.config({ quiet: true });
24407
- var totalSystemRamBytes = os6.totalmem();
24446
+ var totalSystemRamBytes = os5.totalmem();
24408
24447
  var totalSystemRamMB = totalSystemRamBytes / (1024 * 1024);
24409
24448
  var SAFETY_MARGIN = 0.5;
24410
24449
  var calculatedLimit = Math.floor(totalSystemRamMB * SAFETY_MARGIN);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "3.16.0",
3
+ "version": "3.16.1",
4
4
  "date": "2026-08-01",
5
5
  "description": "A High-Fidelity Agentic CLI with Sub-Agents for the Flux Era.",
6
6
  "keywords": [
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "scripts": {
43
43
  "start": "tsx ./src/cli.jsx",
44
- "build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:@google/genai --external:zod --external:nanoid --external:puppeteer --external:pdf-lib --external:node-pty --external:html-to-docx --external:typescript --external:ws --external:web-tree-sitter --external:diff --external:dotenv --external:fast-glob"
44
+ "build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:@google/genai --external:zod --external:nanoid --external:puppeteer --external:pdf-lib --external:node-pty --external:html-to-docx --external:typescript --external:ws --external:web-tree-sitter --external:diff --external:dotenv --external:fast-glob --external:turndown"
45
45
  },
46
46
  "dependencies": {
47
47
  "@google/genai": "^1.52.0",
@@ -62,6 +62,7 @@
62
62
  "pdf-lib": "^1.17.1",
63
63
  "puppeteer": "24.43.1",
64
64
  "react": "^19.2.5",
65
+ "turndown": "^7.2.4",
65
66
  "web-tree-sitter": "^0.25.10",
66
67
  "ws": "^8.21.0",
67
68
  "zod": "^4.3.6"