fluxflow-cli 2.10.3 → 2.11.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 +520 -59
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -1898,6 +1898,7 @@ var init_ChatLayout = __esm({
1898
1898
  { cmd: "/chats", desc: "List all chat sessions" },
1899
1899
  { cmd: "/btw", desc: "Send raw inquiry mid-turn" },
1900
1900
  { cmd: "/image", desc: "Generate images" },
1901
+ { cmd: "/budget", desc: "Set or View budget limits" },
1901
1902
  { cmd: "/mode", desc: "Toggle Flux/Flow modes" },
1902
1903
  { cmd: "/thinking", desc: "Set AI reasoning depth" },
1903
1904
  { cmd: "/model", desc: "Switch AI model" },
@@ -1993,7 +1994,7 @@ var init_StatusBar = __esm({
1993
1994
  },
1994
1995
  /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Box4, { marginRight: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, modeIcon, " ", mode.toUpperCase())), /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React4.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, thinkingLevel.toUpperCase())), /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React4.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "MEM: "), /* @__PURE__ */ React4.createElement(Text4, { color: "white", bold: true }, isMemoryEnabled ? "ON" : "OFF"))),
1995
1996
  /* @__PURE__ */ React4.createElement(Box4, { flexGrow: 1, justifyContent: "center", paddingX: 2 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white", italic: true }, " ", truncatePath(process.cwd(), 35))),
1996
- /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React4.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, " ", formatTokens(tokensTotal), " ", /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, (tokens / maxLimit * 100).toFixed(0), "%"))), /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React4.createElement(Box4, { marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", italic: true }, " ", chatId), (apiTier === "Custom" || apiTier === "Paid") && /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, " | ", /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "PAID"))))
1997
+ /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React4.createElement(Box4, { marginX: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, " ", formatTokens(tokensTotal), " ", /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, (tokens / maxLimit * 100).toFixed(0), "%"))), /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "\u2503 "), /* @__PURE__ */ React4.createElement(Box4, { marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", italic: true }, " ", chatId), (apiTier === "Custom" || apiTier === "Paid") && /* @__PURE__ */ React4.createElement(Text4, { color: "white" }, " | ", /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "CUSTOM"))))
1997
1998
  );
1998
1999
  });
1999
2000
  StatusBar_default = StatusBar;
@@ -2009,6 +2010,7 @@ function CommandMenu({ title, subtitle, items, onSelect }) {
2009
2010
  Box5,
2010
2011
  {
2011
2012
  flexDirection: "column",
2013
+ borderStyle: "round",
2012
2014
  borderColor: "white",
2013
2015
  padding: 0,
2014
2016
  marginTop: 0,
@@ -2934,7 +2936,7 @@ function SettingsMenu({
2934
2936
  case "other":
2935
2937
  return [
2936
2938
  { label: "Current Provider", value: "aiProvider", status: aiProvider },
2937
- { label: "API Tier", value: "apiTier", status: apiTier },
2939
+ { label: "Budgets", value: "apiTier", status: apiTier === "Free" ? "Provider Limits" : "Custom Budget" },
2938
2940
  { label: "Download Language Parsers", value: "parserDownload", status: "ACTION" }
2939
2941
  ];
2940
2942
  default:
@@ -3951,7 +3953,7 @@ var init_history = __esm({
3951
3953
  import fs8 from "fs-extra";
3952
3954
  import path7 from "path";
3953
3955
  import os3 from "os";
3954
- var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, addToUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
3956
+ var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, addToUsage, getCustomPeriodUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
3955
3957
  var init_usage = __esm({
3956
3958
  "src/utils/usage.js"() {
3957
3959
  init_paths();
@@ -4325,20 +4327,124 @@ var init_usage = __esm({
4325
4327
  }
4326
4328
  queueFlush();
4327
4329
  };
4330
+ getCustomPeriodUsage = async (resetDay = 1) => {
4331
+ const today = /* @__PURE__ */ new Date();
4332
+ const todayStr = today.toISOString().split("T")[0];
4333
+ if (!cachedUsage) {
4334
+ cachedUsage = await loadUsageFromFile();
4335
+ }
4336
+ if (cachedUsage.date !== todayStr) {
4337
+ await getDailyUsage();
4338
+ }
4339
+ let startYear = today.getFullYear();
4340
+ let startMonth = today.getMonth();
4341
+ const todayDay = today.getDate();
4342
+ if (todayDay < resetDay) {
4343
+ startMonth -= 1;
4344
+ if (startMonth < 0) {
4345
+ startMonth = 11;
4346
+ startYear -= 1;
4347
+ }
4348
+ }
4349
+ const startDate = new Date(startYear, startMonth, resetDay);
4350
+ const startDateStr = startDate.toISOString().split("T")[0];
4351
+ const history = cachedUsage.history || {};
4352
+ const todayStats = cachedUsage.stats || { ...defaultStats };
4353
+ const summed = { ...defaultStats };
4354
+ summed.imageCalls = [];
4355
+ summed.models = {};
4356
+ const addStats = (target, source) => {
4357
+ for (const key in target) {
4358
+ if (key === "imageCalls") {
4359
+ target.imageCalls = [...target.imageCalls || [], ...source.imageCalls || []];
4360
+ } else if (key === "models") {
4361
+ const srcModels = source.models || {};
4362
+ for (const provider in srcModels) {
4363
+ if (!target.models[provider]) {
4364
+ target.models[provider] = {};
4365
+ }
4366
+ for (const model in srcModels[provider]) {
4367
+ if (!target.models[provider][model]) {
4368
+ target.models[provider][model] = {
4369
+ tokens: 0,
4370
+ cachedTokens: 0,
4371
+ candidateTokens: 0
4372
+ };
4373
+ }
4374
+ const tM = target.models[provider][model];
4375
+ const sM = srcModels[provider][model];
4376
+ tM.tokens += sM.tokens || 0;
4377
+ tM.cachedTokens += sM.cachedTokens || 0;
4378
+ tM.candidateTokens += sM.candidateTokens || 0;
4379
+ }
4380
+ }
4381
+ } else if (typeof target[key] === "number") {
4382
+ target[key] += source[key] || 0;
4383
+ }
4384
+ }
4385
+ };
4386
+ addStats(summed, todayStats);
4387
+ for (const dateKey in history) {
4388
+ if (dateKey >= startDateStr && dateKey < todayStr) {
4389
+ addStats(summed, history[dateKey]);
4390
+ }
4391
+ }
4392
+ return summed;
4393
+ };
4328
4394
  checkQuota = async (key, settings) => {
4329
- const usage = await getDailyUsage();
4330
4395
  const tier = settings.apiTier || "Free";
4331
4396
  const quotas = settings.quotas || {};
4332
4397
  if (tier === "Free") {
4333
- if (key === "agent" || key === "background") {
4334
- return usage.agent + usage.background < 999999;
4398
+ if (key === "agent") {
4399
+ const reqLimit = quotas.agentLimit || 99999999;
4400
+ const tokenLimit = quotas.tokenLimit || 99999999999999;
4401
+ const monthlyTokenLimit = quotas.monthlyTokenLimit || 99999999999999;
4402
+ const dailyUsage = await getDailyUsage();
4403
+ if (dailyUsage.agent + dailyUsage.background >= 999999) return false;
4404
+ const dailyOk = dailyUsage.agent < reqLimit && (dailyUsage.tokens || 0) < tokenLimit;
4405
+ if (!dailyOk) return false;
4406
+ let monthlyUsage;
4407
+ if (quotas.resetMode === "Custom") {
4408
+ monthlyUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
4409
+ } else {
4410
+ monthlyUsage = await getMonthlyUsage();
4411
+ }
4412
+ return (monthlyUsage.tokens || 0) < monthlyTokenLimit;
4413
+ }
4414
+ if (key === "background") {
4415
+ const dailyUsage = await getDailyUsage();
4416
+ if (dailyUsage.agent + dailyUsage.background >= 999999) return false;
4417
+ return dailyUsage.background < (quotas.backgroundLimit || 999999);
4418
+ }
4419
+ if (key === "search") {
4420
+ const dailyUsage = await getDailyUsage();
4421
+ return dailyUsage.search < (quotas.searchLimit || 100);
4335
4422
  }
4336
- if (key === "search") return true;
4337
4423
  }
4338
4424
  if (tier === "Paid" || tier === "Custom") {
4339
- if (key === "agent") return usage.agent < (quotas.agentLimit || 999999);
4340
- if (key === "background") return usage.background < (quotas.backgroundLimit || 999999);
4341
- if (key === "search") return usage.search < (quotas.searchLimit || 100);
4425
+ if (key === "agent") {
4426
+ const reqLimit = quotas.agentLimit || 99999999;
4427
+ const tokenLimit = quotas.tokenLimit || 99999999999999;
4428
+ const monthlyTokenLimit = quotas.monthlyTokenLimit || 99999999999999;
4429
+ const dailyUsage = await getDailyUsage();
4430
+ const dailyOk = dailyUsage.agent < reqLimit && (dailyUsage.tokens || 0) < tokenLimit;
4431
+ if (!dailyOk) return false;
4432
+ let monthlyUsage;
4433
+ if (quotas.resetMode === "Custom") {
4434
+ monthlyUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
4435
+ } else {
4436
+ monthlyUsage = await getMonthlyUsage();
4437
+ }
4438
+ return (monthlyUsage.tokens || 0) < monthlyTokenLimit;
4439
+ }
4440
+ if (key === "background") {
4441
+ const dailyUsage = await getDailyUsage();
4442
+ return dailyUsage.background < (quotas.backgroundLimit || 999999);
4443
+ }
4444
+ if (key === "search") {
4445
+ const dailyUsage = await getDailyUsage();
4446
+ return dailyUsage.search < (quotas.searchLimit || 100);
4447
+ }
4342
4448
  }
4343
4449
  return true;
4344
4450
  };
@@ -7153,16 +7259,23 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
7153
7259
  }
7154
7260
  }
7155
7261
  break;
7156
- } catch (janitorErr) {
7262
+ } catch (err) {
7157
7263
  attempts++;
7158
7264
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
7159
7265
  if (process.stdout.isTTY) {
7160
7266
  process.stdout.write(`\x1B]0;Finalizing Error\x07`);
7161
7267
  }
7268
+ const errLog = err instanceof Error ? (() => {
7269
+ try {
7270
+ return JSON.parse(JSON.parse(err.message).error.message).error.message;
7271
+ } catch {
7272
+ return String(err);
7273
+ }
7274
+ })() : String(err);
7162
7275
  await new Promise((resolve) => setTimeout(resolve, 1e3));
7163
7276
  const janitorErrDir = path19.join(LOGS_DIR, "janitor");
7164
7277
  if (!fs20.existsSync(janitorErrDir)) fs20.mkdirSync(janitorErrDir, { recursive: true });
7165
- fs20.appendFileSync(path19.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
7278
+ fs20.appendFileSync(path19.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${errLog}
7166
7279
 
7167
7280
  `);
7168
7281
  if (attempts > MAX_JANITOR_RETRIES) break;
@@ -7174,7 +7287,6 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
7174
7287
  const janitorErrDir = path19.join(LOGS_DIR, "janitor");
7175
7288
  fs20.appendFileSync(path19.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
7176
7289
 
7177
-
7178
7290
  `);
7179
7291
  if (attempts >= MAX_JANITOR_RETRIES) {
7180
7292
  if (process.stdout.isTTY) {
@@ -7531,11 +7643,19 @@ ${newMemoryListStr}
7531
7643
  }
7532
7644
  }
7533
7645
  } catch (err) {
7646
+ const errLog = err instanceof Error ? (() => {
7647
+ try {
7648
+ return JSON.parse(JSON.parse(err.message).error.message).error.message;
7649
+ } catch {
7650
+ return String(err);
7651
+ }
7652
+ })() : String(err);
7653
+ ;
7534
7654
  const janitorLogDir = path19.join(LOGS_DIR, "janitor");
7535
7655
  if (!fs20.existsSync(janitorLogDir)) fs20.mkdirSync(janitorLogDir, { recursive: true });
7536
7656
  fs20.appendFileSync(
7537
7657
  path19.join(janitorLogDir, "error.log"),
7538
- `[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${err.message}
7658
+ `[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${errLog}
7539
7659
  `
7540
7660
  );
7541
7661
  }
@@ -8020,19 +8140,106 @@ Cursor Line: ${ideCtx.cursor_line}
8020
8140
  `;
8021
8141
  if (ideCtx.manual_edits) {
8022
8142
  let edits = ideCtx.manual_edits;
8023
- const CHAR_LIMIT = 4 * 512;
8024
- const LINE_LIMIT = 50;
8025
8143
  const lines = edits.split("\n");
8026
- if (lines.length > LINE_LIMIT) {
8027
- edits = lines.slice(0, LINE_LIMIT).join("\n") + `
8028
- ... (${lines.length - LINE_LIMIT} more lines truncated)`;
8144
+ const files = [];
8145
+ let currentFile = null;
8146
+ for (const line of lines) {
8147
+ if (!line.trim()) continue;
8148
+ if (line.startsWith(" Line ")) {
8149
+ if (currentFile) {
8150
+ currentFile.edits.push(line);
8151
+ }
8152
+ } else {
8153
+ const filePath = line.endsWith(":") ? line.slice(0, -1) : line;
8154
+ currentFile = { path: filePath, edits: [] };
8155
+ files.push(currentFile);
8156
+ }
8157
+ }
8158
+ for (const file of files) {
8159
+ if (file.edits.length > 80) {
8160
+ file.edits = file.edits.slice(-80);
8161
+ }
8162
+ file.originalEditsCount = file.edits.length;
8163
+ }
8164
+ const getSumForLimit = (limit, activeFiles2) => {
8165
+ return activeFiles2.reduce((sum, f) => {
8166
+ const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused || path19.resolve(process.cwd(), f.path) === path19.resolve(ideCtx.file_focused));
8167
+ const fileLimit = isFocused ? Math.ceil(limit * 1.2) : limit;
8168
+ return sum + Math.min(f.edits.length, fileLimit);
8169
+ }, 0);
8170
+ };
8171
+ let chosenLimit = 80;
8172
+ if (getSumForLimit(80, files) > 300) {
8173
+ let found = false;
8174
+ for (let L = 80; L >= 10; L--) {
8175
+ if (getSumForLimit(L, files) <= 300) {
8176
+ chosenLimit = L;
8177
+ found = true;
8178
+ break;
8179
+ }
8180
+ }
8181
+ if (!found) {
8182
+ chosenLimit = 10;
8183
+ }
8184
+ }
8185
+ let activeFiles = [...files];
8186
+ if (chosenLimit === 10 && getSumForLimit(10, activeFiles) > 500) {
8187
+ while (activeFiles.length > 0 && getSumForLimit(10, activeFiles) > 500) {
8188
+ let minIndex = 0;
8189
+ let minVal = activeFiles[0].originalEditsCount;
8190
+ for (let i = 1; i < activeFiles.length; i++) {
8191
+ if (activeFiles[i].originalEditsCount < minVal) {
8192
+ minVal = activeFiles[i].originalEditsCount;
8193
+ minIndex = i;
8194
+ }
8195
+ }
8196
+ activeFiles.splice(minIndex, 1);
8197
+ }
8198
+ }
8199
+ for (const file of activeFiles) {
8200
+ const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused || path19.resolve(process.cwd(), file.path) === path19.resolve(ideCtx.file_focused));
8201
+ const fileLimit = isFocused ? Math.ceil(chosenLimit * 1.2) : chosenLimit;
8202
+ if (file.edits.length > fileLimit) {
8203
+ file.edits = file.edits.slice(-fileLimit);
8204
+ }
8205
+ }
8206
+ for (const file of activeFiles) {
8207
+ let fileString = `${file.path}:
8208
+ ${file.edits.join("\n")}`;
8209
+ while (file.edits.length > 0 && fileString.length > 4 * 768) {
8210
+ file.edits.shift();
8211
+ fileString = `${file.path}:
8212
+ ${file.edits.join("\n")}`;
8213
+ }
8214
+ if (fileString.length > 4 * 768) {
8215
+ file.stringRepresentation = "... " + fileString.slice(-(4 * 768 - 4));
8216
+ } else {
8217
+ file.stringRepresentation = fileString;
8218
+ }
8219
+ }
8220
+ let finalEdits = activeFiles.map((f) => f.stringRepresentation).join("\n");
8221
+ while (activeFiles.length > 0 && finalEdits.length > 4 * 2048) {
8222
+ if (activeFiles[0].edits.length > 0) {
8223
+ activeFiles[0].edits.shift();
8224
+ } else {
8225
+ activeFiles.shift();
8226
+ }
8227
+ for (const file of activeFiles) {
8228
+ let fileString = `${file.path}:
8229
+ ${file.edits.join("\n")}`;
8230
+ if (fileString.length > 4 * 768) {
8231
+ file.stringRepresentation = "... " + fileString.slice(-(4 * 768 - 4));
8232
+ } else {
8233
+ file.stringRepresentation = fileString;
8234
+ }
8235
+ }
8236
+ finalEdits = activeFiles.map((f) => f.stringRepresentation).join("\n");
8029
8237
  }
8030
- if (edits.length > CHAR_LIMIT) {
8031
- edits = edits.substring(0, CHAR_LIMIT) + `
8032
- ... (Character limit reached, truncated)`;
8238
+ if (finalEdits.length > 4 * 2048) {
8239
+ finalEdits = "... " + finalEdits.slice(-(4 * 2048 - 4));
8033
8240
  }
8034
8241
  ideBlock += `Recent Manual Edits:
8035
- ${edits}
8242
+ ${finalEdits}
8036
8243
  `;
8037
8244
  }
8038
8245
  if (relOpened.length > 0) ideBlock += `All Opened Editors: ${relOpened.join(", ")}`;
@@ -9471,7 +9678,7 @@ ${boxBottom}` };
9471
9678
  denyMsg = "Permission Denied: Prohibited Command in User Policy";
9472
9679
  }
9473
9680
  if (normToolName === "write_file" || normToolName === "update_file") {
9474
- const action = normToolName === "write_file" ? "WRITE DENIED" : "UPDATE DENIED";
9681
+ const action = normToolName === "write_file" ? "Write Cancelled" : "Edit Denied";
9475
9682
  const deniedLabel = `\u{1F4BE} ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
9476
9683
  let terminalWidth = 115;
9477
9684
  if (process.stdout.isTTY) {
@@ -9617,7 +9824,7 @@ ${boxBottom}` };
9617
9824
  uiTitle = "\u{1F4E5} Added Plan";
9618
9825
  listItems = normalizeList(tasks).map((item) => `\u25CB ${item}`);
9619
9826
  } else if (method === "get") {
9620
- uiTitle = markDone ? "\u{1F4CC} Updated Plan" : "\u{1F4DD} Reviewed Plan";
9827
+ uiTitle = markDone ? "\u{1F504} Updated Plan" : "\u{1F4DD} Reviewed Plan";
9621
9828
  const content = (result || "").split("\n").slice(1).join("\n");
9622
9829
  listItems = content.split("\n").filter((line) => line.trim().startsWith("- [")).map((line) => {
9623
9830
  const trimmed = line.trim();
@@ -9786,8 +9993,14 @@ ${boxBottom}` };
9786
9993
  isDedupeActive = false;
9787
9994
  dedupeBuffer = "";
9788
9995
  }
9789
- const errMsg = err.status || err.error && err.error.message || String(err);
9790
- const errLog = String(err);
9996
+ const errLog = err instanceof Error ? (() => {
9997
+ try {
9998
+ return JSON.parse(JSON.parse(err.message).error.message).error.message;
9999
+ } catch {
10000
+ return String(err);
10001
+ }
10002
+ })() : String(err);
10003
+ ;
9791
10004
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
9792
10005
  const agentErrDir = path19.join(LOGS_DIR, "agent");
9793
10006
  if (!fs20.existsSync(agentErrDir)) fs20.mkdirSync(agentErrDir, { recursive: true });
@@ -9802,6 +10015,8 @@ ${boxBottom}` };
9802
10015
  if (retryCount < MAX_RETRIES - 3) {
9803
10016
  throw err;
9804
10017
  }
10018
+ yield { type: "text", content: errLog };
10019
+ yield { type: "status", content: "Error Occured" };
9805
10020
  }
9806
10021
  if (turnText.trim().length > 0 || inStreamRetryCount > 1) {
9807
10022
  if (inStreamRetryCount <= MAX_RETRIES) {
@@ -9948,11 +10163,18 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9948
10163
  }
9949
10164
  });
9950
10165
  } catch (err) {
9951
- const errorMsg = err instanceof Error ? err.message : String(err);
10166
+ const errLog = err instanceof Error ? (() => {
10167
+ try {
10168
+ return JSON.parse(JSON.parse(err.message).error.message).error.message;
10169
+ } catch {
10170
+ return String(err);
10171
+ }
10172
+ })() : String(err);
9952
10173
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
9953
10174
  const agentErrDir = path19.join(LOGS_DIR, "agent");
10175
+ yield { type: "text", content: `\u274C CRITICAL ERROR: ${errLog}` };
9954
10176
  if (!fs20.existsSync(agentErrDir)) fs20.mkdirSync(agentErrDir, { recursive: true });
9955
- fs20.appendFileSync(path19.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${err instanceof Error ? err.stack : err}
10177
+ fs20.appendFileSync(path19.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${errLog}
9956
10178
 
9957
10179
  ----------------------------------------------------------------------
9958
10180
 
@@ -9960,7 +10182,7 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
9960
10182
  if (typeof flushGoogleBuffer === "function") {
9961
10183
  yield* flushGoogleBuffer();
9962
10184
  }
9963
- yield { type: "tool_result", content: `ERROR: [INTERNAL CRITICAL] ${errorMsg}` };
10185
+ yield { type: "tool_result", content: `ERROR: [INTERNAL CRITICAL] ${errLog}` };
9964
10186
  } finally {
9965
10187
  if (connectionPollInterval) {
9966
10188
  clearInterval(connectionPollInterval);
@@ -10799,6 +11021,7 @@ import path20 from "path";
10799
11021
  import { exec as exec2 } from "child_process";
10800
11022
  import { fileURLToPath } from "url";
10801
11023
  import TextInput4 from "ink-text-input";
11024
+ import SelectInput2 from "ink-select-input";
10802
11025
  import gradient2 from "gradient-string";
10803
11026
  function App({ args = [] }) {
10804
11027
  const [confirmExit, setConfirmExit] = useState11(false);
@@ -11065,7 +11288,7 @@ function App({ args = [] }) {
11065
11288
  };
11066
11289
  const [activeView, setActiveView] = useState11("chat");
11067
11290
  const [apiTier, setApiTier] = useState11("Free");
11068
- const [quotas, setQuotas] = useState11({ agentLimit: 999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
11291
+ const [quotas, setQuotas] = useState11({ limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
11069
11292
  const [inputConfig, setInputConfig] = useState11(null);
11070
11293
  const [systemSettings, setSystemSettings] = useState11({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
11071
11294
  const [profileData, setProfileData] = useState11({ name: null, nickname: null, instructions: null });
@@ -11087,6 +11310,7 @@ function App({ args = [] }) {
11087
11310
  const [sessionImageCredits, setSessionImageCredits] = useState11(0);
11088
11311
  const [dailyUsage, setDailyUsage] = useState11(null);
11089
11312
  const [monthlyUsage, setMonthlyUsage] = useState11(null);
11313
+ const [customPeriodUsage, setCustomPeriodUsage] = useState11(null);
11090
11314
  const [statsMode, setStatsMode] = useState11("daily");
11091
11315
  const [chatId, setChatId] = useState11(generateChatId());
11092
11316
  useEffect8(() => {
@@ -11097,6 +11321,19 @@ function App({ args = [] }) {
11097
11321
  });
11098
11322
  }
11099
11323
  }, [sessionTotalTokens, chatId, sessionStats.tokens]);
11324
+ useEffect8(() => {
11325
+ if (activeView === "apiTier") {
11326
+ const load = async () => {
11327
+ const d = await getDailyUsage();
11328
+ setDailyUsage(d);
11329
+ const m = await getMonthlyUsage();
11330
+ setMonthlyUsage(m);
11331
+ const c = await getCustomPeriodUsage(quotas.resetDay || 1);
11332
+ setCustomPeriodUsage(c);
11333
+ };
11334
+ load();
11335
+ }
11336
+ }, [activeView, quotas.resetDay]);
11100
11337
  const [activeCommand, setActiveCommand] = useState11(null);
11101
11338
  const [execOutput, setExecOutput] = useState11("");
11102
11339
  const [isTerminalFocused, setIsTerminalFocused] = useState11(false);
@@ -11608,7 +11845,7 @@ function App({ args = [] }) {
11608
11845
  }
11609
11846
  setShowFullThinking(saved.showFullThinking);
11610
11847
  setApiTier(saved.apiTier || "Free");
11611
- setQuotas(saved.quotas || { agentLimit: 999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
11848
+ setQuotas(saved.quotas || { limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
11612
11849
  const freshSettings = {
11613
11850
  memory: true,
11614
11851
  compression: 0,
@@ -12076,6 +12313,14 @@ function App({ args = [] }) {
12076
12313
  { cmd: "init", desc: "Create FluxFlow.md template" }
12077
12314
  ]
12078
12315
  },
12316
+ {
12317
+ cmd: "/budget",
12318
+ desc: "Set or View budget limits",
12319
+ subs: [
12320
+ { cmd: "Set", desc: "Configure budgets (Daily/Monthly limits)" },
12321
+ { cmd: "View", desc: "View current usage budget bars" }
12322
+ ]
12323
+ },
12079
12324
  {
12080
12325
  cmd: "/update",
12081
12326
  desc: "Check/Install updates",
@@ -12607,6 +12852,50 @@ ${list || "No saved chats found."}`, isMeta: true }];
12607
12852
  });
12608
12853
  break;
12609
12854
  }
12855
+ case "/budget": {
12856
+ const sub = parts[1]?.toLowerCase();
12857
+ if (sub === "set") {
12858
+ setInputConfig({
12859
+ label: "Enter Agent daily budget (requests made):",
12860
+ key: "quotas",
12861
+ subKey: "agentLimit",
12862
+ value: getPrefilledValue(quotas.agentLimit),
12863
+ returnView: "chat",
12864
+ next: (newQuotas) => ({
12865
+ label: "Enter Agent daily budget (tokens used):",
12866
+ key: "quotas",
12867
+ subKey: "tokenLimit",
12868
+ value: getPrefilledValue(newQuotas.tokenLimit),
12869
+ returnView: "chat",
12870
+ next: (q2) => ({
12871
+ label: "Enter Agent monthly budget (tokens used):",
12872
+ key: "quotas",
12873
+ subKey: "monthlyTokenLimit",
12874
+ value: getPrefilledValue(q2.monthlyTokenLimit),
12875
+ returnView: "budgetResetMode"
12876
+ })
12877
+ })
12878
+ });
12879
+ setActiveView("input");
12880
+ } else if (sub === "view") {
12881
+ const run = async () => {
12882
+ const usage = await getDailyUsage();
12883
+ const mUsage = await getMonthlyUsage();
12884
+ const cUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
12885
+ setDailyUsage(usage);
12886
+ setMonthlyUsage(mUsage);
12887
+ setCustomPeriodUsage(cUsage);
12888
+ setActiveView("budgetView");
12889
+ };
12890
+ run();
12891
+ } else {
12892
+ setMessages((prev) => {
12893
+ setCompletedIndex(prev.length + 1);
12894
+ return [...prev, { id: Date.now(), role: "system", text: `Usage: /budget <Set|View>`, isMeta: true }];
12895
+ });
12896
+ }
12897
+ break;
12898
+ }
12610
12899
  case "/fluxflow": {
12611
12900
  const args2 = parts.slice(1);
12612
12901
  if (args2[0] === "init") {
@@ -13329,6 +13618,35 @@ Selection: ${val}`,
13329
13618
  useEffect8(() => {
13330
13619
  setSelectedIndex(0);
13331
13620
  }, [suggestions]);
13621
+ const CustomMenuItem = ({ label, isSelected }) => {
13622
+ const isCancel = label === "Cancel" || label === "Back" || label.toLowerCase().includes("exit") || label.toLowerCase().includes("back");
13623
+ return /* @__PURE__ */ React14.createElement(
13624
+ Box14,
13625
+ {
13626
+ marginTop: isCancel ? 1 : 0,
13627
+ backgroundColor: isSelected ? "#2a2a2a" : void 0,
13628
+ paddingX: 1,
13629
+ width: "100%"
13630
+ },
13631
+ /* @__PURE__ */ React14.createElement(Text14, { color: isSelected ? "white" : "gray", bold: isSelected }, isSelected ? "\u276F " : " ", label)
13632
+ );
13633
+ };
13634
+ const renderProgressBar = (label, current, limit) => {
13635
+ const percent = limit > 0 ? Math.min(100, Math.round(current / limit * 100)) : 0;
13636
+ const barWidth = 15;
13637
+ const filledCount = Math.round(percent / 100 * barWidth);
13638
+ const barStr = "\u2588".repeat(filledCount) + "\u2591".repeat(Math.max(0, barWidth - filledCount));
13639
+ let barColor = "gray";
13640
+ if (percent >= 40 && percent <= 80) {
13641
+ barColor = "yellow";
13642
+ } else if (percent > 80) {
13643
+ barColor = "red";
13644
+ }
13645
+ const isTokens = label.toLowerCase().includes("token");
13646
+ const displayLimit = shouldClearValue(limit) ? "\u221E" : isTokens ? formatTokens(limit) : limit;
13647
+ const displayCurrent = isTokens ? formatTokens(current) : current;
13648
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "row", paddingLeft: 4, key: label }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, label, ": ")), /* @__PURE__ */ React14.createElement(Text14, { color: barColor }, barStr), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, " ", percent, "% (", displayCurrent, "/", displayLimit, ")"));
13649
+ };
13332
13650
  const renderActiveView = () => {
13333
13651
  switch (activeView) {
13334
13652
  case "settings":
@@ -13353,9 +13671,9 @@ Selection: ${val}`,
13353
13671
  title: "SELECT AI PROVIDER",
13354
13672
  items: [
13355
13673
  { label: "Google (Free/Paid)", value: "Google" },
13674
+ { label: "Nvidia (Free/Paid)", value: "NVIDIA" },
13356
13675
  { label: "DeepSeek (Paid)", value: "DeepSeek" },
13357
13676
  { label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" },
13358
- { label: "NVIDIA (Free/Paid)", value: "NVIDIA" },
13359
13677
  { label: "Back", value: "settings" }
13360
13678
  ],
13361
13679
  onSelect: async (item) => {
@@ -13383,7 +13701,7 @@ Selection: ${val}`,
13383
13701
  ...prev,
13384
13702
  {
13385
13703
  role: "system",
13386
- text: `\u2705 Switched to ${selectedProvider}! Key loaded from Vault. Model set to ${defaultModel}.`,
13704
+ text: `[SYSTEM] Switched to ${selectedProvider}! Key loaded from Cache. Model set to ${defaultModel}.`,
13387
13705
  isMeta: true
13388
13706
  }
13389
13707
  ]);
@@ -13402,14 +13720,31 @@ Selection: ${val}`,
13402
13720
  onClose: () => setActiveView("settings")
13403
13721
  }
13404
13722
  );
13405
- case "apiTier":
13406
- return /* @__PURE__ */ React14.createElement(
13407
- CommandMenu,
13723
+ case "apiTier": {
13724
+ const reqCurrent = dailyUsage?.agent || 0;
13725
+ const reqLimit = quotas.agentLimit || 99999999;
13726
+ const tokenCurrent = dailyUsage?.tokens || 0;
13727
+ const tokenLimit = quotas.tokenLimit || 99999999999999;
13728
+ const monthlyCurrent = quotas.resetMode === "Custom" ? customPeriodUsage?.tokens || 0 : monthlyUsage?.tokens || 0;
13729
+ const monthlyLimit = quotas.monthlyTokenLimit || 99999999999999;
13730
+ let resetInfo = "";
13731
+ if (quotas.resetMode === "Custom") {
13732
+ const today = /* @__PURE__ */ new Date();
13733
+ const resetDay = quotas.resetDay || 1;
13734
+ let resetMonth = today.getMonth();
13735
+ if (today.getDate() >= resetDay) {
13736
+ resetMonth += 1;
13737
+ }
13738
+ const resetDate = new Date(today.getFullYear(), resetMonth, resetDay);
13739
+ const monthName = resetDate.toLocaleString("default", { month: "short" });
13740
+ resetInfo = `Resets on: ${resetDay}-${monthName}`;
13741
+ }
13742
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "white", padding: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, "SELECT YOUR CURRENT API TIER BASED ON YOUR PROVIDER. (Provider: ", aiProvider, ")")), /* @__PURE__ */ React14.createElement(
13743
+ SelectInput2,
13408
13744
  {
13409
- title: /* @__PURE__ */ React14.createElement(Text14, null, "SELECT YOUR CURRENT API TIER BASED ON ", /* @__PURE__ */ React14.createElement(Text14, { color: "cyan", underline: true, bold: true }, "\x1B]8;;https://aistudio.google.com/projects\x07AI STUDIO\x1B]8;;\x07"), ". (CURRENT: ", apiTier.toUpperCase(), ")"),
13410
13745
  items: [
13411
- { label: "Free Tier (Gemini API Free Tier)", value: "Free" },
13412
- { label: `Paid Tier (API with Billing Account)`, value: "Paid" },
13746
+ { label: "Provider Limits", value: "Free" },
13747
+ { label: `Set Budgets (API with Billing Account) ${apiTier === "Paid" ? "\u25CF" : ""}`, value: "Paid" },
13413
13748
  { label: "Back", value: "settings" }
13414
13749
  ],
13415
13750
  onSelect: (item) => {
@@ -13424,17 +13759,129 @@ Selection: ${val}`,
13424
13759
  label: "Enter Agent daily budget (requests made):",
13425
13760
  key: "quotas",
13426
13761
  subKey: "agentLimit",
13427
- value: String(quotas.agentLimit)
13762
+ value: getPrefilledValue(quotas.agentLimit),
13763
+ returnView: "settings",
13764
+ next: (newQuotas) => ({
13765
+ label: "Enter Agent daily budget (tokens used):",
13766
+ key: "quotas",
13767
+ subKey: "tokenLimit",
13768
+ value: getPrefilledValue(newQuotas.tokenLimit),
13769
+ returnView: "settings",
13770
+ next: (q2) => ({
13771
+ label: "Enter Agent monthly budget (tokens used):",
13772
+ key: "quotas",
13773
+ subKey: "monthlyTokenLimit",
13774
+ value: getPrefilledValue(q2.monthlyTokenLimit),
13775
+ returnView: "resetMode"
13776
+ })
13777
+ })
13428
13778
  });
13429
13779
  setActiveView("input");
13430
13780
  } else {
13431
- saveSettings({ apiTier: newTier, quotas });
13781
+ const newQuotas = { ...quotas, agentLimit: 99999999, tokenLimit: 99999999999999, monthlyTokenLimit: 99999999999999 };
13782
+ setQuotas(newQuotas);
13783
+ saveSettings({ apiTier: newTier, quotas: newQuotas });
13432
13784
  setActiveView("settings");
13433
13785
  }
13434
13786
  },
13435
- onClose: () => setActiveView("settings")
13787
+ itemComponent: CustomMenuItem,
13788
+ indicatorComponent: () => null
13789
+ }
13790
+ ), apiTier === "Paid" && /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, "USAGE BUDGET STATUS")), renderProgressBar("Daily Requests", reqCurrent, reqLimit, "cyan"), renderProgressBar("Daily Tokens", tokenCurrent, tokenLimit, "green"), renderProgressBar("Monthly Tokens", monthlyCurrent, monthlyLimit, "yellow"), resetInfo ? /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "Monthly Reset : "), /* @__PURE__ */ React14.createElement(Text14, { color: "magenta", bold: true }, resetInfo)) : /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "Monthly Reset : "), /* @__PURE__ */ React14.createElement(Text14, { color: "blue", bold: true }, "Rolling 30-Day Window"))), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", italic: true }, "(Arrows to select \u2022 Enter to confirm)")));
13791
+ }
13792
+ case "resetMode":
13793
+ return /* @__PURE__ */ React14.createElement(
13794
+ CommandMenu,
13795
+ {
13796
+ title: "SELECT MONTHLY RESET MODE",
13797
+ items: [
13798
+ { label: "Default (Rolling 30-Day Window)", value: "Rolling" },
13799
+ { label: "Custom (Set reset day of month)", value: "Custom" },
13800
+ { label: "Back", value: "apiTier" }
13801
+ ],
13802
+ onSelect: (item) => {
13803
+ if (item.value === "apiTier" || item.value === "Back") {
13804
+ setActiveView("apiTier");
13805
+ return;
13806
+ }
13807
+ const selectedMode = item.value;
13808
+ const updatedQuotas = { ...quotas, resetMode: selectedMode };
13809
+ setQuotas(updatedQuotas);
13810
+ if (selectedMode === "Custom") {
13811
+ setInputConfig({
13812
+ label: "Enter monthly reset day (1-30):",
13813
+ key: "quotas",
13814
+ subKey: "resetDay",
13815
+ value: String(quotas.resetDay || 1),
13816
+ returnView: "settings"
13817
+ });
13818
+ setActiveView("input");
13819
+ } else {
13820
+ saveSettings({ apiTier, quotas: updatedQuotas });
13821
+ setActiveView("settings");
13822
+ }
13823
+ },
13824
+ onClose: () => setActiveView("apiTier")
13436
13825
  }
13437
13826
  );
13827
+ case "budgetResetMode":
13828
+ return /* @__PURE__ */ React14.createElement(
13829
+ CommandMenu,
13830
+ {
13831
+ title: "SELECT MONTHLY RESET MODE",
13832
+ items: [
13833
+ { label: "Default (Rolling 30-Day Window)", value: "Rolling" },
13834
+ { label: "Custom (Set reset day of month)", value: "Custom" },
13835
+ { label: "Back", value: "chat" }
13836
+ ],
13837
+ onSelect: (item) => {
13838
+ if (item.value === "chat" || item.value === "Back") {
13839
+ setActiveView("chat");
13840
+ return;
13841
+ }
13842
+ const selectedMode = item.value;
13843
+ const updatedQuotas = { ...quotas, resetMode: selectedMode };
13844
+ setQuotas(updatedQuotas);
13845
+ if (selectedMode === "Custom") {
13846
+ setInputConfig({
13847
+ label: "Enter monthly reset day (1-30):",
13848
+ key: "quotas",
13849
+ subKey: "resetDay",
13850
+ value: String(quotas.resetDay || 1),
13851
+ returnView: "chat"
13852
+ });
13853
+ setActiveView("input");
13854
+ } else {
13855
+ saveSettings({ apiTier, quotas: updatedQuotas });
13856
+ setActiveView("chat");
13857
+ }
13858
+ },
13859
+ onClose: () => setActiveView("chat")
13860
+ }
13861
+ );
13862
+ case "budgetView": {
13863
+ const reqCurrent = dailyUsage?.agent || 0;
13864
+ const reqLimit = quotas.agentLimit || 99999999;
13865
+ const tokenCurrent = dailyUsage?.tokens || 0;
13866
+ const tokenLimit = quotas.tokenLimit || 99999999999999;
13867
+ const monthlyCurrent = quotas.resetMode === "Custom" ? customPeriodUsage?.tokens || 0 : monthlyUsage?.tokens || 0;
13868
+ const monthlyLimit = quotas.monthlyTokenLimit || 99999999999999;
13869
+ const isFreeTier = apiTier !== "Paid";
13870
+ const limitsNotSet = isFreeTier && (shouldClearValue(reqLimit) || shouldClearValue(tokenLimit) || shouldClearValue(monthlyLimit));
13871
+ let resetInfo = "";
13872
+ if (quotas.resetMode === "Custom") {
13873
+ const today = /* @__PURE__ */ new Date();
13874
+ const resetDay = quotas.resetDay || 1;
13875
+ let resetMonth = today.getMonth();
13876
+ if (today.getDate() >= resetDay) {
13877
+ resetMonth += 1;
13878
+ }
13879
+ const resetDate = new Date(today.getFullYear(), resetMonth, resetDay);
13880
+ const monthName = resetDate.toLocaleString("default", { month: "short" });
13881
+ resetInfo = `Resets on: ${resetDay}-${monthName}`;
13882
+ }
13883
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "white", padding: 1, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "BUDGET LIMIT STATUS", isFreeTier ? " (Isn't it fun to see numbers go BRRRR)" : ""), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "[ ESC to Close ]")), limitsNotSet ? /* @__PURE__ */ React14.createElement(Box14, { padding: 1, justifyContent: "center", alignItems: "center", width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { color: "yellow", bold: true }, "LIMITS NOT SET")) : /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, width: "100%" }, renderProgressBar("Daily Requests", reqCurrent, reqLimit, "cyan"), renderProgressBar("Daily Tokens", tokenCurrent, tokenLimit, "green"), renderProgressBar("Monthly Tokens", monthlyCurrent, monthlyLimit, "yellow"), resetInfo ? /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "Monthly Reset : "), /* @__PURE__ */ React14.createElement(Text14, { color: "magenta", bold: true }, resetInfo)) : /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "Monthly Reset : "), /* @__PURE__ */ React14.createElement(Text14, { color: "blue", bold: true }, "Rolling 30-Day Window"))));
13884
+ }
13438
13885
  case "input":
13439
13886
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "white", padding: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, "DATA CONFIGURATION")), inputConfig?.note && /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", italic: true }, inputConfig.note)), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, inputConfig?.label, " "), /* @__PURE__ */ React14.createElement(
13440
13887
  TextInput4,
@@ -13446,7 +13893,10 @@ Selection: ${val}`,
13446
13893
  let newQuotas = { ...quotas };
13447
13894
  let newSettings = {};
13448
13895
  if (key === "quotas") {
13449
- const parsedValue = subKey.toLowerCase().includes("limit") ? parseInt(val) || 0 : val;
13896
+ let parsedValue = subKey.toLowerCase().includes("limit") || subKey === "resetDay" ? parseInt(val) || 0 : val;
13897
+ if (subKey === "resetDay") {
13898
+ parsedValue = Math.max(1, Math.min(30, parsedValue));
13899
+ }
13450
13900
  newQuotas[subKey] = parsedValue;
13451
13901
  setQuotas(newQuotas);
13452
13902
  newSettings.quotas = newQuotas;
@@ -13518,17 +13968,17 @@ Selection: ${val}`,
13518
13968
  )), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", dimColor: true, italic: true }, "(Press Enter to confirm selection)")));
13519
13969
  case "stats": {
13520
13970
  const u = statsMode === "monthly" ? monthlyUsage : dailyUsage;
13521
- const trackerTitle = statsMode === "monthly" ? "LAST 30 DAYS USAGE TRACKER" : "DAILY USAGE TRACKER";
13522
- const timeLabel = statsMode === "monthly" ? "Wall Time (30d):" : "Wall Time Today:";
13523
- const tokensLabel = statsMode === "monthly" ? "Tokens Used (30d):" : "Tokens Used Today:";
13524
- const imagesLabel = statsMode === "monthly" ? "Images Made (30d):" : "Images Made Today:";
13525
- const imageCreditsLabel = statsMode === "monthly" ? "Image Credits (30d):" : "Image Credits Today:";
13526
- const codeChangesLabel = statsMode === "monthly" ? "Code Changes (30d):" : "Code Changes Today:";
13527
- const toolCallsLabel = statsMode === "monthly" ? "Tool Calls (30d):" : "Tool Calls Today:";
13971
+ const trackerTitle = statsMode === "monthly" ? "LAST 30 DAYS USAGE" : "TODAY's USAGE";
13972
+ const timeLabel = statsMode === "monthly" ? "Wall Time:" : "Wall Time:";
13973
+ const tokensLabel = statsMode === "monthly" ? "Tokens Used:" : "Tokens Used:";
13974
+ const imagesLabel = statsMode === "monthly" ? "Images Made:" : "Images Made:";
13975
+ const imageCreditsLabel = statsMode === "monthly" ? "Image Credits:" : "Image Credits:";
13976
+ const codeChangesLabel = statsMode === "monthly" ? "Code Changes:" : "Code Changes:";
13977
+ const toolCallsLabel = statsMode === "monthly" ? "Tool Calls:" : "Tool Calls:";
13528
13978
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 3, paddingY: 1, paddingBottom: 0, width: Math.min(125, (stdout?.columns || 100) - 2) }, statsMode === "modelBreakdown" ? /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "30-DAY MODEL TOKEN BREAKDOWN"), !monthlyUsage?.models || Object.keys(monthlyUsage.models).length === 0 ? /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey", italic: true }, "No model token usage recorded in the last 30 days.")) : Object.entries(monthlyUsage.models).map(([provider, models]) => {
13529
13979
  const providerTotalTokens = Object.values(models).reduce((sum, m) => sum + (m.tokens || 0), 0);
13530
- return /* @__PURE__ */ React14.createElement(Box14, { key: provider, flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "cyan", bold: true }, provider, ":")), /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, formatTokens(providerTotalTokens))), Object.entries(models).map(([modelName, stats]) => /* @__PURE__ */ React14.createElement(Box14, { key: modelName, flexDirection: "column", marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 21 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "\xBB ", modelName, ":")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(stats.tokens || 0))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 17 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens((stats.tokens || 0) - (stats.candidateTokens || 0)))), (stats.cachedTokens || 0) > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 5 }, /* @__PURE__ */ React14.createElement(Box14, { width: 16 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(stats.cachedTokens))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 17 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(stats.candidateTokens || 0))))));
13531
- })) : /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Session Duration:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionAgentCalls)), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB API Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Tool Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionBackgroundCalls)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Active Context:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionStats.tokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 21 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionImageCount)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Code Changes (Sess):")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "+", linesAdded), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "-", linesRemoved))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tool Calls (Sess):")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( "), /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "\u2713 ", sessionToolSuccess), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "yellow" }, "\u2298 ", sessionToolDenied), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "\u2715 ", sessionToolFailure), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " )"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, trackerTitle), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, timeLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatDuration(u?.duration || 0))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, u?.agent || 0)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, u?.background || 0)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, tokensLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(u?.tokens || 0))), (u?.tokens || 0) > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens((u?.tokens || 0) - (u?.candidateTokens || 0)))), (u?.cachedTokens || 0) > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 21 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(u.cachedTokens))), (u?.candidateTokens || 0) > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(u.candidateTokens)))), (u?.imageCalls?.length || 0) > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, imagesLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, u.imageCalls.length)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, imageCreditsLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, Number(((u.imageCalls.reduce((sum, c) => sum + c.cost, 0) || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, codeChangesLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "+", u?.linesAdded || 0), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "-", u?.linesRemoved || 0))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, toolCallsLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, (u?.toolSuccess || 0) + (u?.toolFailure || 0) + (u?.toolDenied || 0), " ( "), /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "\u2713 ", u?.toolSuccess || 0), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "yellow" }, "\u2298 ", u?.toolDenied || 0), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "\u2715 ", u?.toolFailure || 0), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " )")))), /* @__PURE__ */ React14.createElement(Text14, { dimColor: true, marginTop: 1, italic: true }, "(Press TAB to toggle Daily/Monthly views, SPACE for Model Breakdown, ESC to return)"));
13980
+ return /* @__PURE__ */ React14.createElement(Box14, { key: provider, flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 40 }, /* @__PURE__ */ React14.createElement(Text14, { color: "cyan", bold: true }, provider, ":")), /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, formatTokens(providerTotalTokens))), Object.entries(models).map(([modelName, stats]) => /* @__PURE__ */ React14.createElement(Box14, { key: modelName, flexDirection: "column", marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 36 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "\xBB ", modelName, ":")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(stats.tokens || 0))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 32 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens((stats.tokens || 0) - (stats.candidateTokens || 0)))), (stats.cachedTokens || 0) > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 5 }, /* @__PURE__ */ React14.createElement(Box14, { width: 31 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(stats.cachedTokens))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 32 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(stats.candidateTokens || 0))))));
13981
+ })) : /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Session Duration:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Model Requests:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionAgentCalls)), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB API Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Tool Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Memory Agent:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionBackgroundCalls)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Active Context:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionStats.tokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 21 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionImageCount)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Code Changes (Sess):")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "+", linesAdded), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "-", linesRemoved))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tool Calls (Sess):")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( "), /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "\u2713 ", sessionToolSuccess), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "yellow" }, "\u2298 ", sessionToolDenied), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "\u2715 ", sessionToolFailure), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " )"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, trackerTitle), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, timeLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatDuration(u?.duration || 0))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Model Requests:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, u?.agent || 0)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Memory Agent:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, u?.background || 0)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, tokensLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(u?.tokens || 0))), (u?.tokens || 0) > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens((u?.tokens || 0) - (u?.candidateTokens || 0)))), (u?.cachedTokens || 0) > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 21 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(u.cachedTokens))), (u?.candidateTokens || 0) > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 23 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(u.candidateTokens)))), (u?.imageCalls?.length || 0) > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, imagesLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, u.imageCalls.length)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, imageCreditsLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, Number(((u.imageCalls.reduce((sum, c) => sum + c.cost, 0) || 0) * 1e3).toFixed(0)), " credits"))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, codeChangesLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "+", u?.linesAdded || 0), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "-", u?.linesRemoved || 0))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 25 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, toolCallsLabel)), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, (u?.toolSuccess || 0) + (u?.toolFailure || 0) + (u?.toolDenied || 0), " ( "), /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "\u2713 ", u?.toolSuccess || 0), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "yellow" }, "\u2298 ", u?.toolDenied || 0), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " "), /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "\u2715 ", u?.toolFailure || 0), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, " )")))), /* @__PURE__ */ React14.createElement(Text14, { dimColor: true, marginTop: 1, italic: true }, "(Press TAB to toggle Daily/Monthly views, SPACE for Model Breakdown, ESC to return)"));
13532
13982
  }
13533
13983
  case "autoExecDanger":
13534
13984
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "SECURITY WARNING: YOLO MODE"), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "Turning this ON allows the agent to execute terminal commands automatically without requiring your approval for each step."), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1, color: "white" }, "RISKS INVOLVED:"), /* @__PURE__ */ React14.createElement(Text14, null, "\u2022 The agent may execute destructive commands (rm -rf, etc.) by mistake unless specified in sandbox rules."), /* @__PURE__ */ React14.createElement(Text14, null, "\u2022 Unintended system changes if the agent hallucinates a path or command."), /* @__PURE__ */ React14.createElement(Text14, null, "\u2022 Reduced control over the agent's step-by-step decision making."), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
@@ -13984,16 +14434,16 @@ Selection: ${val}`,
13984
14434
  {
13985
14435
  items: [
13986
14436
  { label: "Google (Free/Paid)", value: "Google" },
14437
+ { label: "Nvidia (Free/Paid)", value: "NVIDIA" },
13987
14438
  { label: "DeepSeek (Paid)", value: "DeepSeek" },
13988
- { label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" },
13989
- { label: "NVIDIA (Free/Paid)", value: "NVIDIA" }
14439
+ { label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" }
13990
14440
  ],
13991
14441
  onSelect: (item) => {
13992
14442
  setAiProvider(item.value);
13993
14443
  setSetupStep(1);
13994
14444
  }
13995
14445
  }
13996
- ))) : /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, "Please enter your ", aiProvider, " API Key to initialize the agent (If billing is enabled set Tier to paid in /settings \u2192 other \u2192 API Tier)."), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, " ", ">", " "), /* @__PURE__ */ React14.createElement(
14446
+ ))) : /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, "Please enter your ", aiProvider, " API Key to initialize the agent (If billing is enabled set budgets in /settings \u2192 Others \u2192 Budgets to avoid runaway spending)."), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, " ", ">", " "), /* @__PURE__ */ React14.createElement(
13997
14447
  TextInput4,
13998
14448
  {
13999
14449
  value: tempKey,
@@ -14087,7 +14537,7 @@ Selection: ${val}`,
14087
14537
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "grey", width: Math.min(100, (stdout?.columns || 100) - 2), marginTop: 0, marginBottom: 0 }, /* @__PURE__ */ React14.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { bold: true }, gradient2(["blue", "purple"])("Agent powering down. Goodbye!"))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, chatId)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionToolSuccess + sessionToolFailure + sessionToolDenied, " ( ", /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "\u2713 ", sessionToolSuccess), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "yellow" }, "\u2298 ", sessionToolDenied), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "\u2715 ", sessionToolFailure), " )")), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, successRate, "%")), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Code Changes:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green" }, "+", linesAdded), " ", /* @__PURE__ */ React14.createElement(Text14, { color: "red" }, "-", linesRemoved))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Input Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React14.createElement(Box14, { width: 16 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Cached:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Output Tokens:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Images Made:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, sessionImageCount)), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Image Credits:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits")))), /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React14.createElement(Box14, null, /* @__PURE__ */ React14.createElement(Box14, { width: 20 }, /* @__PURE__ */ React14.createElement(Text14, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB API Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React14.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React14.createElement(Box14, { width: 18 }, /* @__PURE__ */ React14.createElement(Text14, { color: "grey" }, "\xBB Tool Time:")), /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
14088
14538
  })())));
14089
14539
  }
14090
- var getIDEName, getIDEDirName, getKeybindingsPath, parseJsonc, hasShiftEnterBinding, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles, cachedShortcut;
14540
+ var shouldClearValue, getPrefilledValue, getIDEName, getIDEDirName, getKeybindingsPath, parseJsonc, hasShiftEnterBinding, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles, cachedShortcut;
14091
14541
  var init_app = __esm({
14092
14542
  async "src/app.jsx"() {
14093
14543
  init_MultilineInput();
@@ -14118,6 +14568,16 @@ var init_app = __esm({
14118
14568
  init_setup();
14119
14569
  init_text();
14120
14570
  init_editor();
14571
+ shouldClearValue = (val) => {
14572
+ const s = String(val);
14573
+ return s.startsWith("999") && s.endsWith("9");
14574
+ };
14575
+ getPrefilledValue = (val) => {
14576
+ if (val === void 0 || val === null || val === 0 || shouldClearValue(val)) {
14577
+ return "";
14578
+ }
14579
+ return String(val);
14580
+ };
14121
14581
  getIDEName = () => {
14122
14582
  const termProgram = (process.env.TERM_PROGRAM || "").toLowerCase();
14123
14583
  if (process.env.WT_SESSION) return "Windows Terminal";
@@ -14398,6 +14858,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
14398
14858
  /chats List all chat sessions
14399
14859
  /btw <question> Send raw inquiry to the agent mid-turn
14400
14860
  /image setup key <default|custom> Configure image API key strategy
14861
+ /budget Set or View budget limits
14401
14862
  /image setup quality <low...premium> Configure default image generation quality
14402
14863
  /image stats Show image quota stats
14403
14864
  /mode <flux|flow> Toggle Flux/Flow modes
@@ -14461,7 +14922,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
14461
14922
  const React16 = (await import("react")).default;
14462
14923
  const { useState: useState12 } = React16;
14463
14924
  const { render: render2, Box: Box15, Text: Text15 } = await import("ink");
14464
- const SelectInput2 = (await import("ink-select-input")).default;
14925
+ const SelectInput3 = (await import("ink-select-input")).default;
14465
14926
  const TextInput5 = (await import("ink-text-input")).default;
14466
14927
  return new Promise((resolve) => {
14467
14928
  const items = [
@@ -14499,7 +14960,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
14499
14960
  )), /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, { color: "gray", dimColor: true, italic: true }, " (Press Enter to confirm)")));
14500
14961
  }
14501
14962
  return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React16.createElement(Box15, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text15, { color: "magenta", bold: true }, "\u{1F4E6} Select a package manager for the update:")), /* @__PURE__ */ React16.createElement(
14502
- SelectInput2,
14963
+ SelectInput3,
14503
14964
  {
14504
14965
  items,
14505
14966
  onSelect: handleSelect,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.10.3",
4
- "date": "2026-06-21",
3
+ "version": "2.11.1",
4
+ "date": "2026-06-22",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",