fluxflow-cli 2.11.0 → 2.11.2

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 +199 -20
  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" },
@@ -2935,7 +2936,7 @@ function SettingsMenu({
2935
2936
  case "other":
2936
2937
  return [
2937
2938
  { label: "Current Provider", value: "aiProvider", status: aiProvider },
2938
- { label: "API Tier", value: "apiTier", status: apiTier === "Free" ? "Provider Limits" : "Custom Budget" },
2939
+ { label: "Budgets", value: "apiTier", status: apiTier === "Free" ? "Provider Limits" : "Custom Budget" },
2939
2940
  { label: "Download Language Parsers", value: "parserDownload", status: "ACTION" }
2940
2941
  ];
2941
2942
  default:
@@ -3145,8 +3146,7 @@ function SettingsMenu({
3145
3146
  Text6,
3146
3147
  {
3147
3148
  color: isSelected ? "white" : "grey",
3148
- bold: isSelected,
3149
- underline: isParserDownload
3149
+ bold: isSelected
3150
3150
  },
3151
3151
  isSelected ? "\u276F " : " ",
3152
3152
  item.label
@@ -4394,11 +4394,31 @@ var init_usage = __esm({
4394
4394
  const tier = settings.apiTier || "Free";
4395
4395
  const quotas = settings.quotas || {};
4396
4396
  if (tier === "Free") {
4397
- if (key === "agent" || key === "background") {
4398
- const daily = await getDailyUsage();
4399
- return daily.agent + daily.background < 999999;
4397
+ if (key === "agent") {
4398
+ const reqLimit = quotas.agentLimit || 99999999;
4399
+ const tokenLimit = quotas.tokenLimit || 99999999999999;
4400
+ const monthlyTokenLimit = quotas.monthlyTokenLimit || 99999999999999;
4401
+ const dailyUsage = await getDailyUsage();
4402
+ if (dailyUsage.agent + dailyUsage.background >= 999999) return false;
4403
+ const dailyOk = dailyUsage.agent < reqLimit && (dailyUsage.tokens || 0) < tokenLimit;
4404
+ if (!dailyOk) return false;
4405
+ let monthlyUsage;
4406
+ if (quotas.resetMode === "Custom") {
4407
+ monthlyUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
4408
+ } else {
4409
+ monthlyUsage = await getMonthlyUsage();
4410
+ }
4411
+ return (monthlyUsage.tokens || 0) < monthlyTokenLimit;
4412
+ }
4413
+ if (key === "background") {
4414
+ const dailyUsage = await getDailyUsage();
4415
+ if (dailyUsage.agent + dailyUsage.background >= 999999) return false;
4416
+ return dailyUsage.background < (quotas.backgroundLimit || 999999);
4417
+ }
4418
+ if (key === "search") {
4419
+ const dailyUsage = await getDailyUsage();
4420
+ return dailyUsage.search < (quotas.searchLimit || 100);
4400
4421
  }
4401
- if (key === "search") return true;
4402
4422
  }
4403
4423
  if (tier === "Paid" || tier === "Custom") {
4404
4424
  if (key === "agent") {
@@ -10268,8 +10288,10 @@ var init_ResumeModal = __esm({
10268
10288
 
10269
10289
  // src/components/MemoryModal.jsx
10270
10290
  import React10, { useState as useState7, useEffect as useEffect5 } from "react";
10271
- import { Box as Box10, Text as Text10, useInput as useInput5 } from "ink";
10291
+ import { Box as Box10, Text as Text10, useInput as useInput5, useStdout } from "ink";
10272
10292
  function MemoryModal({ onClose }) {
10293
+ const { stdout } = useStdout();
10294
+ const columns = stdout?.columns || 80;
10273
10295
  const [memories, setMemories] = useState7([]);
10274
10296
  const [selectedIndex, setSelectedIndex] = useState7(0);
10275
10297
  const [isMemoryOn, setIsMemoryOn] = useState7(true);
@@ -10301,9 +10323,42 @@ function MemoryModal({ onClose }) {
10301
10323
  }
10302
10324
  }
10303
10325
  });
10304
- const cleanDisplay = (text) => {
10326
+ const formatMemory = (text, idx, isSelected) => {
10305
10327
  if (!text) return "";
10306
- return text.replace(/\[Saved on: .*?\]/g, "").replace(/\\+'/g, "'").trim();
10328
+ const clean = text.replace(/\[Saved on: .*?\]/g, "").replace(/\\+'/g, "'").trim();
10329
+ const prefix = `${isSelected ? "\u276F " : " "}${idx + 1}. `;
10330
+ const prefixLen = prefix.length;
10331
+ const rightPadding = isSelected ? 22 : 2;
10332
+ const parts = clean.split("\n");
10333
+ return parts.map((part, partIdx) => {
10334
+ const isFirstPart = partIdx === 0;
10335
+ const firstLineMax = Math.max(10, columns - 4 - (isFirstPart ? prefixLen : 3) - rightPadding);
10336
+ const subLineMax = Math.max(10, columns - 4 - 3 - rightPadding);
10337
+ const words = part.split(/(\s+)/);
10338
+ const lines = [];
10339
+ let currentLine = "";
10340
+ words.forEach((word) => {
10341
+ if (word.length === 0) return;
10342
+ const currentLimit = lines.length === 0 ? firstLineMax : subLineMax;
10343
+ if (currentLine.length + word.length > currentLimit) {
10344
+ if (currentLine.trim().length > 0) {
10345
+ lines.push(currentLine.trimEnd());
10346
+ currentLine = word;
10347
+ } else {
10348
+ lines.push(word.substring(0, currentLimit));
10349
+ currentLine = word.substring(currentLimit);
10350
+ }
10351
+ } else {
10352
+ currentLine += word;
10353
+ }
10354
+ });
10355
+ if (currentLine.trimEnd().length > 0) {
10356
+ lines.push(currentLine.trimEnd());
10357
+ }
10358
+ if (lines.length === 0) return "";
10359
+ const wrapped = lines.join("\n ");
10360
+ return isFirstPart ? wrapped : " " + wrapped;
10361
+ }).join("\n");
10307
10362
  };
10308
10363
  const totalCapacity = 4 * 1024 * 2;
10309
10364
  const currentLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
@@ -10327,8 +10382,8 @@ function MemoryModal({ onClose }) {
10327
10382
  backgroundColor: isSelected ? "#2a2a2a" : void 0,
10328
10383
  width: "100%"
10329
10384
  },
10330
- /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: isSelected ? "white" : "grey", bold: isSelected }, isSelected ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory))),
10331
- isSelected && /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0 }, /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true }, "[ "), " ", /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true, italic: true }, mem.score), /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true }, " ]"), /* @__PURE__ */ React10.createElement(Text10, { color: "grey", bold: true }, "[X] WIPE "))
10385
+ /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: isSelected ? "white" : "grey", bold: isSelected }, isSelected ? "\u276F " : " ", idx + 1, ". ", formatMemory(mem.memory, idx, isSelected))),
10386
+ isSelected && /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0 }, /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true }, " [", /* @__PURE__ */ React10.createElement(Text10, { italic: true }, mem.score), "] "), /* @__PURE__ */ React10.createElement(Text10, { color: "grey", bold: true }, "[X] WIPE "))
10332
10387
  );
10333
10388
  })), /* @__PURE__ */ React10.createElement(
10334
10389
  Box10,
@@ -10994,7 +11049,7 @@ __export(app_exports, {
10994
11049
  });
10995
11050
  import os4 from "os";
10996
11051
  import React14, { useState as useState11, useEffect as useEffect8, useRef as useRef3, useMemo as useMemo2 } from "react";
10997
- import { Box as Box14, Text as Text14, useInput as useInput8, useStdout } from "ink";
11052
+ import { Box as Box14, Text as Text14, useInput as useInput8, useStdout as useStdout2 } from "ink";
10998
11053
  import fs22 from "fs-extra";
10999
11054
  import path20 from "path";
11000
11055
  import { exec as exec2 } from "child_process";
@@ -11005,7 +11060,7 @@ import gradient2 from "gradient-string";
11005
11060
  function App({ args = [] }) {
11006
11061
  const [confirmExit, setConfirmExit] = useState11(false);
11007
11062
  const [exitCountdown, setExitCountdown] = useState11(10);
11008
- const { stdout } = useStdout();
11063
+ const { stdout } = useStdout2();
11009
11064
  const [input, setInput] = useState11("");
11010
11065
  const [inputKey, setInputKey] = useState11(0);
11011
11066
  const [isExpanded, setIsExpanded] = useState11(false);
@@ -12292,6 +12347,14 @@ function App({ args = [] }) {
12292
12347
  { cmd: "init", desc: "Create FluxFlow.md template" }
12293
12348
  ]
12294
12349
  },
12350
+ {
12351
+ cmd: "/budget",
12352
+ desc: "Set or View budget limits",
12353
+ subs: [
12354
+ { cmd: "Set", desc: "Configure budgets (Daily/Monthly limits)" },
12355
+ { cmd: "View", desc: "View current usage budget bars" }
12356
+ ]
12357
+ },
12295
12358
  {
12296
12359
  cmd: "/update",
12297
12360
  desc: "Check/Install updates",
@@ -12823,6 +12886,50 @@ ${list || "No saved chats found."}`, isMeta: true }];
12823
12886
  });
12824
12887
  break;
12825
12888
  }
12889
+ case "/budget": {
12890
+ const sub = parts[1]?.toLowerCase();
12891
+ if (sub === "set") {
12892
+ setInputConfig({
12893
+ label: "Enter Agent daily budget (requests made):",
12894
+ key: "quotas",
12895
+ subKey: "agentLimit",
12896
+ value: getPrefilledValue(quotas.agentLimit),
12897
+ returnView: "chat",
12898
+ next: (newQuotas) => ({
12899
+ label: "Enter Agent daily budget (tokens used):",
12900
+ key: "quotas",
12901
+ subKey: "tokenLimit",
12902
+ value: getPrefilledValue(newQuotas.tokenLimit),
12903
+ returnView: "chat",
12904
+ next: (q2) => ({
12905
+ label: "Enter Agent monthly budget (tokens used):",
12906
+ key: "quotas",
12907
+ subKey: "monthlyTokenLimit",
12908
+ value: getPrefilledValue(q2.monthlyTokenLimit),
12909
+ returnView: "budgetResetMode"
12910
+ })
12911
+ })
12912
+ });
12913
+ setActiveView("input");
12914
+ } else if (sub === "view") {
12915
+ const run = async () => {
12916
+ const usage = await getDailyUsage();
12917
+ const mUsage = await getMonthlyUsage();
12918
+ const cUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
12919
+ setDailyUsage(usage);
12920
+ setMonthlyUsage(mUsage);
12921
+ setCustomPeriodUsage(cUsage);
12922
+ setActiveView("budgetView");
12923
+ };
12924
+ run();
12925
+ } else {
12926
+ setMessages((prev) => {
12927
+ setCompletedIndex(prev.length + 1);
12928
+ return [...prev, { id: Date.now(), role: "system", text: `Usage: /budget <Set|View>`, isMeta: true }];
12929
+ });
12930
+ }
12931
+ break;
12932
+ }
12826
12933
  case "/fluxflow": {
12827
12934
  const args2 = parts.slice(1);
12828
12935
  if (args2[0] === "init") {
@@ -13569,7 +13676,10 @@ Selection: ${val}`,
13569
13676
  } else if (percent > 80) {
13570
13677
  barColor = "red";
13571
13678
  }
13572
- 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, "% (", current, "/", limit >= 99999999 ? "\u221E" : limit, ")"));
13679
+ const isTokens = label.toLowerCase().includes("token");
13680
+ const displayLimit = shouldClearValue(limit) ? "\u221E" : isTokens ? formatTokens(limit) : limit;
13681
+ const displayCurrent = isTokens ? formatTokens(current) : current;
13682
+ 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, ")"));
13573
13683
  };
13574
13684
  const renderActiveView = () => {
13575
13685
  switch (activeView) {
@@ -13683,19 +13793,19 @@ Selection: ${val}`,
13683
13793
  label: "Enter Agent daily budget (requests made):",
13684
13794
  key: "quotas",
13685
13795
  subKey: "agentLimit",
13686
- value: quotas.agentLimit >= 99999999 ? "" : String(quotas.agentLimit),
13796
+ value: getPrefilledValue(quotas.agentLimit),
13687
13797
  returnView: "settings",
13688
13798
  next: (newQuotas) => ({
13689
13799
  label: "Enter Agent daily budget (tokens used):",
13690
13800
  key: "quotas",
13691
13801
  subKey: "tokenLimit",
13692
- value: newQuotas.tokenLimit >= 99999999999999 || newQuotas.tokenLimit === 0 ? "" : String(newQuotas.tokenLimit),
13802
+ value: getPrefilledValue(newQuotas.tokenLimit),
13693
13803
  returnView: "settings",
13694
13804
  next: (q2) => ({
13695
13805
  label: "Enter Agent monthly budget (tokens used):",
13696
13806
  key: "quotas",
13697
13807
  subKey: "monthlyTokenLimit",
13698
- value: q2.monthlyTokenLimit >= 99999999999999 || q2.monthlyTokenLimit === 0 ? "" : String(q2.monthlyTokenLimit),
13808
+ value: getPrefilledValue(q2.monthlyTokenLimit),
13699
13809
  returnView: "resetMode"
13700
13810
  })
13701
13811
  })
@@ -13748,6 +13858,64 @@ Selection: ${val}`,
13748
13858
  onClose: () => setActiveView("apiTier")
13749
13859
  }
13750
13860
  );
13861
+ case "budgetResetMode":
13862
+ return /* @__PURE__ */ React14.createElement(
13863
+ CommandMenu,
13864
+ {
13865
+ title: "SELECT MONTHLY RESET MODE",
13866
+ items: [
13867
+ { label: "Default (Rolling 30-Day Window)", value: "Rolling" },
13868
+ { label: "Custom (Set reset day of month)", value: "Custom" },
13869
+ { label: "Back", value: "chat" }
13870
+ ],
13871
+ onSelect: (item) => {
13872
+ if (item.value === "chat" || item.value === "Back") {
13873
+ setActiveView("chat");
13874
+ return;
13875
+ }
13876
+ const selectedMode = item.value;
13877
+ const updatedQuotas = { ...quotas, resetMode: selectedMode };
13878
+ setQuotas(updatedQuotas);
13879
+ if (selectedMode === "Custom") {
13880
+ setInputConfig({
13881
+ label: "Enter monthly reset day (1-30):",
13882
+ key: "quotas",
13883
+ subKey: "resetDay",
13884
+ value: String(quotas.resetDay || 1),
13885
+ returnView: "chat"
13886
+ });
13887
+ setActiveView("input");
13888
+ } else {
13889
+ saveSettings({ apiTier, quotas: updatedQuotas });
13890
+ setActiveView("chat");
13891
+ }
13892
+ },
13893
+ onClose: () => setActiveView("chat")
13894
+ }
13895
+ );
13896
+ case "budgetView": {
13897
+ const reqCurrent = dailyUsage?.agent || 0;
13898
+ const reqLimit = quotas.agentLimit || 99999999;
13899
+ const tokenCurrent = dailyUsage?.tokens || 0;
13900
+ const tokenLimit = quotas.tokenLimit || 99999999999999;
13901
+ const monthlyCurrent = quotas.resetMode === "Custom" ? customPeriodUsage?.tokens || 0 : monthlyUsage?.tokens || 0;
13902
+ const monthlyLimit = quotas.monthlyTokenLimit || 99999999999999;
13903
+ const isFreeTier = apiTier !== "Paid";
13904
+ const limitsNotSet = isFreeTier && (shouldClearValue(reqLimit) || shouldClearValue(tokenLimit) || shouldClearValue(monthlyLimit));
13905
+ let resetInfo = "";
13906
+ if (quotas.resetMode === "Custom") {
13907
+ const today = /* @__PURE__ */ new Date();
13908
+ const resetDay = quotas.resetDay || 1;
13909
+ let resetMonth = today.getMonth();
13910
+ if (today.getDate() >= resetDay) {
13911
+ resetMonth += 1;
13912
+ }
13913
+ const resetDate = new Date(today.getFullYear(), resetMonth, resetDay);
13914
+ const monthName = resetDate.toLocaleString("default", { month: "short" });
13915
+ resetInfo = `Resets on: ${resetDay}-${monthName}`;
13916
+ }
13917
+ 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"))));
13918
+ }
13751
13919
  case "input":
13752
13920
  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(
13753
13921
  TextInput4,
@@ -14309,7 +14477,7 @@ Selection: ${val}`,
14309
14477
  setSetupStep(1);
14310
14478
  }
14311
14479
  }
14312
- ))) : /* @__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(
14480
+ ))) : /* @__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(
14313
14481
  TextInput4,
14314
14482
  {
14315
14483
  value: tempKey,
@@ -14403,7 +14571,7 @@ Selection: ${val}`,
14403
14571
  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, "%)"))));
14404
14572
  })())));
14405
14573
  }
14406
- 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;
14574
+ 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;
14407
14575
  var init_app = __esm({
14408
14576
  async "src/app.jsx"() {
14409
14577
  init_MultilineInput();
@@ -14434,6 +14602,16 @@ var init_app = __esm({
14434
14602
  init_setup();
14435
14603
  init_text();
14436
14604
  init_editor();
14605
+ shouldClearValue = (val) => {
14606
+ const s = String(val);
14607
+ return s.startsWith("999") && s.endsWith("9");
14608
+ };
14609
+ getPrefilledValue = (val) => {
14610
+ if (val === void 0 || val === null || val === 0 || shouldClearValue(val)) {
14611
+ return "";
14612
+ }
14613
+ return String(val);
14614
+ };
14437
14615
  getIDEName = () => {
14438
14616
  const termProgram = (process.env.TERM_PROGRAM || "").toLowerCase();
14439
14617
  if (process.env.WT_SESSION) return "Windows Terminal";
@@ -14714,6 +14892,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
14714
14892
  /chats List all chat sessions
14715
14893
  /btw <question> Send raw inquiry to the agent mid-turn
14716
14894
  /image setup key <default|custom> Configure image API key strategy
14895
+ /budget Set or View budget limits
14717
14896
  /image setup quality <low...premium> Configure default image generation quality
14718
14897
  /image stats Show image quota stats
14719
14898
  /mode <flux|flow> Toggle Flux/Flow modes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.11.0",
4
- "date": "2026-06-22",
3
+ "version": "2.11.2",
4
+ "date": "2026-06-23",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",