fluxflow-cli 1.7.16 → 1.7.18

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 +104 -73
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/utils/text.js
13
- var wrapText;
13
+ var wrapText, formatTokens;
14
14
  var init_text = __esm({
15
15
  "src/utils/text.js"() {
16
16
  wrapText = (text, width) => {
@@ -44,6 +44,16 @@ var init_text = __esm({
44
44
  });
45
45
  return finalLines.join("\n");
46
46
  };
47
+ formatTokens = (tokens) => {
48
+ if (!tokens && tokens !== 0) return "0.0k";
49
+ const num = typeof tokens === "string" ? parseFloat(tokens) : tokens;
50
+ if (num >= 1e6) {
51
+ return `${(num / 1e6).toFixed(2)}m`;
52
+ } else if (num >= 1e3) {
53
+ return `${(num / 1e3).toFixed(2)}k`;
54
+ }
55
+ return num.toString();
56
+ };
47
57
  }
48
58
  });
49
59
 
@@ -445,6 +455,7 @@ import { Box as Box3, Text as Text3 } from "ink";
445
455
  var StatusBar, StatusBar_default;
446
456
  var init_StatusBar = __esm({
447
457
  "src/components/StatusBar.jsx"() {
458
+ init_text();
448
459
  StatusBar = React3.memo(({ mode, thinkingLevel, tokens = "0.0k", tokensTotal = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true }) => {
449
460
  const modeColor = mode === "Flux" ? "yellow" : "cyan";
450
461
  const modeIcon = mode === "Flux" ? "\u26A1" : "\u{1F30A}";
@@ -461,7 +472,7 @@ var init_StatusBar = __esm({
461
472
  },
462
473
  /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: modeColor, bold: true }, modeIcon, " ", mode.toUpperCase()), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "magenta" }, "\u{1F9E0} ", thinkingLevel)),
463
474
  /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1, justifyContent: "center", paddingX: 2 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, "\u{1F4C1} "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue", dimColor: true, italic: true }, process.cwd())),
464
- /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, "MEM: "), /* @__PURE__ */ React3.createElement(Text3, { color: memStatus === "ON" ? "green" : "red" }, memStatus), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, tokensTotal > 1e3 ? `${(tokensTotal / 1e3).toFixed(1)}k` : tokensTotal, " (", Math.round(tokens / 254e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, chatId, " "))
475
+ /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, "MEM: "), /* @__PURE__ */ React3.createElement(Text3, { color: memStatus === "ON" ? "green" : "red" }, memStatus), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, formatTokens(tokensTotal), " (", Math.round(tokens / 254e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, chatId, " "))
465
476
  );
466
477
  });
467
478
  StatusBar_default = StatusBar;
@@ -714,9 +725,9 @@ tool:functions.tool_name(arguments)
714
725
  2. Web Scrape: tool:functions.web_scrape(url="<url>"). provides detail from a URL.
715
726
  ${mode === "Flux" ? `
716
727
  - DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
717
- 1. View File: tool:functions.view_file(path="relative/path", start_line=number, end_line=number). Reads file content. Auto-truncates at 500 lines unless start_line and end_line are provided. YOU CAN ALSO USE THIS TOOL TO SEE IMAGES AND DOCUMENTS IN A FOLDER. IF USER ASK HOW TO SHARE A IMAGE TELL THEM TO PASTE THE IMAGE IN THE CURRENT FOLDER.
728
+ 1. View File: tool:functions.view_file(path="relative/path", start_line=number, end_line=number). Reads file content. Auto-truncates at 500 lines unless start_line and end_line are provided. YOU CAN ALSO USE THIS TOOL TO SEE IMAGES AND DOCUMENTS IN A FOLDER. IF USER ASK HOW TO SHARE A IMAGE TELL THEM TO PASTE THE IMAGE IN THE CURRENT FOLDER. IF USER GIVES A IMAGE/DOCUMENT, YOU MUST SEE IT FIRST BEFORE DOING ANYTHING.
718
729
  2. List Files: tool:functions.list_files(path="relative/path"). Lists content of a directory.
719
- 3. Read Folder: tool:functions.read_folder(path="relative/path"). Detailed stats of a directory.
730
+ 3. Read Folder: tool:functions.read_folder(path="relative/path"). Detailed stats of a directory. Prefer this one over list_files.
720
731
  4. Write File: tool:functions.write_file(path="path", content="content"). Creates/Overwrites. NO CODE BLOCKS. RETURNS: Disk verification + original content (if overwritten) for 100% reversibility. Escape your double quotes '"' using backslash.
721
732
  5. Update File: tool:functions.update_file(path="relative/path", content_to_replace="old", content_to_add="new"). Surgical patching. RETURNS: High-fidelity visual diff and old code block. You MUST verify that the change specifically matches your intent using the returned diff. PREFFER UPDATE FILE OVER WRITE FILE if file already exists for better reversal tracking (if a file has 500+ lines, try to stick with update_file over full-rewrite). DONT WRAP UPDATE FILE CALL CONTENT IN MARKDOWN CODE BLOCKS.
722
733
  6. Write PDF: tool:functions.write_pdf(path="path", content="<html/css content>", orientation="portrait/landscape"). Generates a professional PDF document. Orientation are optional. A4 size page will be used, so any multi-page PDFs calculate your alightment and page breaks to not mess up A4 page layout. DO NOT ADD FOOTER MANUALLY, the system will handle it automatically. USE CSS TO VISUALLY BEAUTIFY THE DOCUMENT, USE full 100vh & 100vw for page area. ENSURE THE CONTENT IS NEVER BROKEN IN BETWEEN PAGES, USE PAGE BREAKS PROACTIVELY FOR A A4 PAGE LAYOUT. Keep generous margins for better redability.
@@ -728,9 +739,9 @@ ${mode === "Flux" ? `
728
739
  - Supported Styles: background-color, color, font-family, font-size (use 'pt'), font-style (italic), font-weight (bold), margin, text-align, text-shadow.
729
740
  9. Execution: tool:functions.exec_command(command="terminal command"). Runs a shell command. Use ask tool to confirm before executing any destructive or irreversible operations.
730
741
 
731
- AFTER GETTING THE TOOL RESULT, YOU MUST VERIFY THAT ITS A SUCCESS, IF IT GIVES A ERROR, TELL THE USER AND TRY TO FIX IF YOU CAN. DO NOT HALLUCINATE SUCCESS IF TOOL RETURNS ERROR.
732
-
733
- **CRITICAL POLICY: WHEN WRITING/UPDATING FILES, ALWAYS USE ACTUAL NEW LINE CONTROL CHARACTER (LF) FOR LINE BREAKS.**`.trim() : `
742
+ AFTER GETTING THE TOOL RESULT, YOU MUST VERIFY THAT ITS A SUCCESS, IF IT GIVES A ERROR, TELL THE USER AND TRY TO FIX IF YOU CAN. DO NOT HALLUCINATE SUCCESS IF TOOL RETURNS ERROR.
743
+ NEVER GUESS A CODE, IF UNSURE READ THE FILE FIRST BEFORE EDITING IT.
744
+ **CRITICAL POLICY: WHEN WRITING/UPDATING FILES, ALWAYS USE ACTUAL NEW LINE CONTROL CHARACTER (LF) FOR LINE BREAKS.**`.trim() : `
734
745
  - DEV & FILE TOOLS ARE NOT AVAILABLE IN FLOW MODE. If you need to access files, tell the user to switch to FLUX MODE (manually by user).`.trim()}
735
746
  -----------------
736
747
 
@@ -778,10 +789,10 @@ var thinking_prompts_default;
778
789
  var init_thinking_prompts = __esm({
779
790
  "src/data/thinking_prompts.json"() {
780
791
  thinking_prompts_default = {
781
- Max: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: MAX\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nRULES OF THINKING: -HEADING COUNT SHOULD BE 12 - 20. SELF-MONOLOGUE SHOULD BE DETAILED AND THROROUGH. MONOLOGUES SHOULD BE **8 - 12** SENTENCES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- CONSIDER ABOUT EDGE CASES BEFORE COMMITING.\n- SHOULD PLAN ARCHITECHTURALLY.\n- SHOULD PLAN LOGICALLY.\n\n-- END THINKING INSTRUCTIONS --",
782
- High: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: HIGH\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nnRULES OF THINKING: -HEADING COUNT SHOULD BE 8 - 12. SELF-MONOLOGUE SHOULD BE DETAILED AND THROROUGH. MONOLOGUES SHOULD BE **6 - 8** SENTENCES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- CONSIDER ABOUT EDGE CASES BEFORE COMMITING.\n\n-- END THINKING INSTRUCTIONS --",
783
- Medium: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: MEDIUM\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nnRULES OF THINKING: -HEADING COUNT SHOULD BE 2 - 4. SELF-MONOLOGUE SHOULD BE SHORT YET THROROUGH. MONOLOGUES SHOULD BE **4 - 6** SENTENCES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- LITTLE TO NO THINKING IS PREFFERED IF QUERY IS CONVERSATIONAL AND SIMPLE.\n\n-- END THINKING INSTRUCTIONS --",
784
- Minimal: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: LOW\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nnRULES OF THINKING: -HEADING COUNT SHOULD BE 0 - 2. SELF-MONOLOGUE SHOULD BE SHORT AND CONCISE. MONOLOGUES SHOULD BE **1 - 2** SENTENCES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- NO THINKING IS PREFFERED IF QUERY IS CONVERSATIONAL AND SIMPLE.\n\n-- END THINKING INSTRUCTIONS --"
792
+ Max: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: MAX\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nRULES OF THINKING: -HEADING COUNT SHOULD BE 8 - 16. SELF-MONOLOGUE SHOULD BE DETAILED AND THROROUGH. MONOLOGUES **MUST** BE **8 - 10** LINES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- CONSIDER ABOUT EDGE CASES BEFORE COMMITING.\n- SHOULD PLAN ARCHITECHTURALLY.\n- SHOULD PLAN LOGICALLY.\n\n-- END THINKING INSTRUCTIONS --",
793
+ High: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: HIGH\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nnRULES OF THINKING: -HEADING COUNT SHOULD BE 4 - 8. SELF-MONOLOGUE SHOULD BE DETAILED AND THROROUGH. MONOLOGUES **MUST** BE **4 - 8** LINES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- CONSIDER ABOUT EDGE CASES BEFORE COMMITING.\n\n-- END THINKING INSTRUCTIONS --",
794
+ Medium: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: MEDIUM\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nnRULES OF THINKING: -HEADING COUNT SHOULD BE 2 - 4. SELF-MONOLOGUE SHOULD BE SHORT YET THROROUGH. MONOLOGUES **MUST** BE **2 - 4** LINES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- LITTLE TO NO THINKING IS PREFFERED IF QUERY IS CONVERSATIONAL AND SIMPLE.\n\n-- END THINKING INSTRUCTIONS --",
795
+ Minimal: "-- START THINKING INSTRUCTIONS --\nEFFORT_LEVEL: LOW\nThink Step by Step in Chain-of-Thought. Provide the thinking in <think>...</think> block, length given. Thinking should be structured in this format:\n\n<think>\n\\n\\n\n**Heading**\n\\n\\n\nSELF-MONOLOGUE\n\\n\\n\n**Heading**\n\\n\\n\nSelf MONOLOGUE\ncontinue.\n\\n\\n\n</think>\n\nnRULES OF THINKING: -HEADING COUNT SHOULD BE 0 - 2. SELF-MONOLOGUE SHOULD BE SHORT AND CONCISE. MONOLOGUES **MUST** BE **1 - 2** LINES EACH REGARDLESS OF QUERY COMPLEXITY.\n- YOU MUST **NOT** EXCREED YOUR ALLOTED THINKING BUDGET UNDER **ANY** CIRCUMSTANCES.\n- IF THE QUERY IS SIMPLE, YOU CAN KEEP HEADING COUNT LESS THAN MIN COUNT.\n- NO THINKING IS PREFFERED IF QUERY IS CONVERSATIONAL AND SIMPLE.\n\n-- END THINKING INSTRUCTIONS --"
785
796
  };
786
797
  }
787
798
  });
@@ -1015,29 +1026,21 @@ var init_history = __esm({
1015
1026
  // src/utils/usage.js
1016
1027
  import fs5 from "fs-extra";
1017
1028
  import path5 from "path";
1018
- var getDailyUsage, incrementUsage, addToUsage, checkQuota;
1029
+ var cachedUsage, writeTimeout, lastWriteTime, isDirty, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota;
1019
1030
  var init_usage = __esm({
1020
1031
  "src/utils/usage.js"() {
1021
1032
  init_paths();
1022
- getDailyUsage = async () => {
1033
+ cachedUsage = null;
1034
+ writeTimeout = null;
1035
+ lastWriteTime = 0;
1036
+ isDirty = false;
1037
+ loadUsageFromFile = async () => {
1023
1038
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1024
1039
  try {
1025
1040
  if (await fs5.exists(USAGE_FILE)) {
1026
1041
  const data = await fs5.readJson(USAGE_FILE);
1027
1042
  if (data && data.date === today && data.stats) {
1028
- const s = data.stats;
1029
- const normalized = {
1030
- agent: s.agent || 0,
1031
- background: s.background || 0,
1032
- search: s.search || 0,
1033
- toolSuccess: s.toolSuccess || 0,
1034
- toolFailure: s.toolFailure || 0,
1035
- duration: s.duration || 0,
1036
- tokens: s.tokens || 0
1037
- };
1038
- return normalized;
1039
- } else if (data && data.date !== today) {
1040
- } else {
1043
+ return data;
1041
1044
  }
1042
1045
  }
1043
1046
  } catch (err) {
@@ -1051,52 +1054,77 @@ var init_usage = __esm({
1051
1054
  duration: 0,
1052
1055
  tokens: 0
1053
1056
  };
1057
+ return { date: today, stats: defaultStats };
1058
+ };
1059
+ flushUsage = async () => {
1060
+ if (!isDirty || !cachedUsage) return;
1054
1061
  try {
1055
1062
  await fs5.ensureDir(path5.dirname(USAGE_FILE));
1056
1063
  const tempFile = USAGE_FILE + ".tmp";
1057
- await fs5.writeJson(tempFile, { date: today, stats: defaultStats }, { spaces: 2 });
1064
+ await fs5.writeJson(tempFile, cachedUsage, { spaces: 2 });
1058
1065
  const fd = await fs5.open(tempFile, "r+");
1059
1066
  await fs5.fsync(fd);
1060
1067
  await fs5.close(fd);
1061
1068
  await fs5.rename(tempFile, USAGE_FILE);
1069
+ isDirty = false;
1070
+ lastWriteTime = Date.now();
1062
1071
  } catch (e) {
1063
1072
  }
1064
- return defaultStats;
1065
1073
  };
1066
- incrementUsage = async (key) => {
1074
+ queueFlush = () => {
1075
+ isDirty = true;
1076
+ if (writeTimeout) return;
1077
+ const now = Date.now();
1078
+ const delay = Math.max(0, 1500 - (now - lastWriteTime));
1079
+ writeTimeout = setTimeout(async () => {
1080
+ await flushUsage();
1081
+ writeTimeout = null;
1082
+ }, delay);
1083
+ };
1084
+ initUsage = async () => {
1085
+ cachedUsage = await loadUsageFromFile();
1086
+ };
1087
+ forceFlushUsage = async () => {
1088
+ if (writeTimeout) {
1089
+ clearTimeout(writeTimeout);
1090
+ writeTimeout = null;
1091
+ }
1092
+ await flushUsage();
1093
+ };
1094
+ getDailyUsage = async () => {
1067
1095
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1096
+ if (!cachedUsage) {
1097
+ cachedUsage = await loadUsageFromFile();
1098
+ } else if (cachedUsage.date !== today) {
1099
+ cachedUsage = {
1100
+ date: today,
1101
+ stats: {
1102
+ agent: 0,
1103
+ background: 0,
1104
+ search: 0,
1105
+ toolSuccess: 0,
1106
+ toolFailure: 0,
1107
+ duration: 0,
1108
+ tokens: 0
1109
+ }
1110
+ };
1111
+ isDirty = true;
1112
+ await flushUsage();
1113
+ }
1114
+ return cachedUsage.stats;
1115
+ };
1116
+ incrementUsage = async (key) => {
1068
1117
  const stats = await getDailyUsage();
1069
- const data = { date: today, stats };
1070
- if (data.stats[key] !== void 0) {
1071
- data.stats[key]++;
1072
- try {
1073
- await fs5.ensureDir(path5.dirname(USAGE_FILE));
1074
- const tempFile = USAGE_FILE + ".tmp";
1075
- await fs5.writeJson(tempFile, data, { spaces: 2 });
1076
- const fd = await fs5.open(tempFile, "r+");
1077
- await fs5.fsync(fd);
1078
- await fs5.close(fd);
1079
- await fs5.rename(tempFile, USAGE_FILE);
1080
- } catch (e) {
1081
- }
1118
+ if (stats[key] !== void 0) {
1119
+ stats[key]++;
1120
+ queueFlush();
1082
1121
  }
1083
1122
  };
1084
1123
  addToUsage = async (key, amount) => {
1085
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1086
1124
  const stats = await getDailyUsage();
1087
- const data = { date: today, stats };
1088
- if (data.stats[key] !== void 0) {
1089
- data.stats[key] += Math.floor(amount);
1090
- try {
1091
- await fs5.ensureDir(path5.dirname(USAGE_FILE));
1092
- const tempFile = USAGE_FILE + ".tmp";
1093
- await fs5.writeJson(tempFile, data, { spaces: 2 });
1094
- const fd = await fs5.open(tempFile, "r+");
1095
- await fs5.fsync(fd);
1096
- await fs5.close(fd);
1097
- await fs5.rename(tempFile, USAGE_FILE);
1098
- } catch (e) {
1099
- }
1125
+ if (stats[key] !== void 0) {
1126
+ stats[key] += Math.floor(amount);
1127
+ queueFlush();
1100
1128
  }
1101
1129
  };
1102
1130
  checkQuota = async (key, settings) => {
@@ -1112,8 +1140,7 @@ var init_usage = __esm({
1112
1140
  if (tier === "Paid" || tier === "Custom") {
1113
1141
  if (key === "agent") return usage.agent < (quotas.agentLimit || 1500);
1114
1142
  if (key === "background") return usage.background < (quotas.backgroundLimit || 1500);
1115
- if (key === "search") return true;
1116
- return true;
1143
+ if (key === "search") return usage.search < (quotas.searchLimit || 100);
1117
1144
  }
1118
1145
  return true;
1119
1146
  };
@@ -1290,7 +1317,7 @@ Snippet: ${snippet}`;
1290
1317
  const finalResults = results.join("\n\n");
1291
1318
  const toolLogDir = path6.join(LOGS_DIR, "tools");
1292
1319
  if (!fs6.existsSync(toolLogDir)) fs6.mkdirSync(toolLogDir, { recursive: true });
1293
- fs6.appendFileSync(path6.join(toolLogDir, "search-results.log"), `SEARCH ${(/* @__PURE__ */ new Date()).toISOString()} - Query: [${query}]. Count: ${results.length}.
1320
+ fs6.appendFileSync(path6.join(toolLogDir, "search-results.log"), `SEARCH ${(/* @__PURE__ */ new Date()).toLocaleString()} - Query: [${query}]. Count: ${results.length}.
1294
1321
  Content:
1295
1322
  ${finalResults}
1296
1323
 
@@ -1388,7 +1415,7 @@ var init_web_scrape = __esm({
1388
1415
  const cleanedHtml = htmlContent.replace(/\s+/g, " ").replace(/>\s+</g, "><").trim().substring(0, 3e4);
1389
1416
  const toolLogDir = path7.join(LOGS_DIR, "tools");
1390
1417
  if (!fs7.existsSync(toolLogDir)) fs7.mkdirSync(toolLogDir, { recursive: true });
1391
- fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toISOString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
1418
+ fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toLocaleString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
1392
1419
  Content:
1393
1420
  ${cleanedHtml}${htmlContent.length > 3e4 ? "\n\n[TRUNCATED AT 30K CHARS]" : ""}
1394
1421
 
@@ -1436,7 +1463,7 @@ var init_memory = __esm({
1436
1463
  if (!content) return "ERROR: Missing 'content' for temp memory.";
1437
1464
  const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
1438
1465
  if (!tempStorage[chatId]) tempStorage[chatId] = [];
1439
- const MAX_CHARS = 5e3 * 4;
1466
+ const MAX_CHARS = 2500 * 4;
1440
1467
  let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
1441
1468
  while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
1442
1469
  const removed = tempStorage[chatId].shift();
@@ -1450,7 +1477,7 @@ var init_memory = __esm({
1450
1477
  const memories = readEncryptedJson(MEMORIES_FILE, []);
1451
1478
  if (method === "add") {
1452
1479
  if (!content) return "ERROR: Missing 'content' for memory addition.";
1453
- const MAX_CHARS = 3e3 * 4;
1480
+ const MAX_CHARS = 2e3 * 4;
1454
1481
  let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
1455
1482
  while (memories.length > 0 && currentTotalLength + content.length > MAX_CHARS) {
1456
1483
  const removed = memories.shift();
@@ -2436,6 +2463,7 @@ USER_PROMPT: ${agentText}`.trim();
2436
2463
  }
2437
2464
  if (TERMINATION_SIGNAL) {
2438
2465
  yield { type: "status", content: "Termination Signal Received." };
2466
+ await new Promise((resolve) => setTimeout(resolve, 1500));
2439
2467
  break;
2440
2468
  }
2441
2469
  if (steeringCallback) {
@@ -2473,10 +2501,10 @@ USER_PROMPT: ${agentText}`.trim();
2473
2501
  let targetModel = modelName;
2474
2502
  if (retryCount === 5) {
2475
2503
  targetModel = "gemini-3-flash-preview";
2476
- yield { type: "model_update", content: "Trying with fallback model (v3)" };
2504
+ yield { type: "model_update", content: "Trying with fallback model" };
2477
2505
  } else if (retryCount >= 6) {
2478
2506
  targetModel = "gemini-3.1-flash-lite-preview";
2479
- yield { type: "model_update", content: "Trying with fallback model (v3.1)" };
2507
+ yield { type: "model_update", content: "Trying with fallback model lite" };
2480
2508
  } else if (retryCount > 0) {
2481
2509
  yield { type: "model_update", content: null };
2482
2510
  }
@@ -2495,7 +2523,7 @@ USER_PROMPT: ${agentText}`.trim();
2495
2523
  yield { type: "status", content: "Working..." };
2496
2524
  } catch (err) {
2497
2525
  const errMsg = err.status || err.error && err.error.message || String(err);
2498
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
2526
+ const date = (/* @__PURE__ */ new Date()).toLocaleString();
2499
2527
  const agentErrDir = path16.join(LOGS_DIR, "agent");
2500
2528
  if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
2501
2529
  fs16.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errMsg}
@@ -2715,7 +2743,7 @@ ${boxBottom}
2715
2743
  const hasFinish = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(turnText.toLowerCase());
2716
2744
  const shouldContinue = toolCallPointer > 0;
2717
2745
  yield { type: "status", content: "Working..." };
2718
- const cleanedTurnText = turnText.replace(/<think>[\s\S]*?<\/think>/g, "").replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
2746
+ const cleanedTurnText = turnText.replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
2719
2747
  let isActuallyFinished = hasFinish && !shouldContinue;
2720
2748
  if (isActuallyFinished) {
2721
2749
  yield { type: "status", content: "Finalizing..." };
@@ -2752,7 +2780,7 @@ ${boxBottom}
2752
2780
  const parts = janitorResult.candidates?.[0]?.content?.parts;
2753
2781
  if (parts && parts[1]?.text) {
2754
2782
  finalSynthesis = parts[1].text;
2755
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
2783
+ const date = (/* @__PURE__ */ new Date()).toLocaleString();
2756
2784
  const janitorLogDir = path16.join(LOGS_DIR, "janitor");
2757
2785
  if (!fs16.existsSync(janitorLogDir)) {
2758
2786
  fs16.mkdirSync(janitorLogDir, { recursive: true });
@@ -2771,7 +2799,7 @@ ${boxBottom}
2771
2799
  for (const janitorToolCall of janitorToolCalls) {
2772
2800
  const toolContext = { chatId, sessionId: chatId, history };
2773
2801
  const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
2774
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
2802
+ const date = (/* @__PURE__ */ new Date()).toLocaleString();
2775
2803
  const janitorLogDir = path16.join(LOGS_DIR, "janitor");
2776
2804
  fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
2777
2805
  `);
@@ -2780,7 +2808,7 @@ ${boxBottom}
2780
2808
  }
2781
2809
  }
2782
2810
  } catch (janitorErr) {
2783
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
2811
+ const date = (/* @__PURE__ */ new Date()).toLocaleString();
2784
2812
  const janitorErrDir = path16.join(LOGS_DIR, "janitor");
2785
2813
  if (!fs16.existsSync(janitorErrDir)) {
2786
2814
  fs16.mkdirSync(janitorErrDir, { recursive: true });
@@ -3370,6 +3398,7 @@ Check what's new using \`/changelog\` command.`,
3370
3398
  cleanupOldHistory(saved.systemSettings.autoDeleteHistory);
3371
3399
  }
3372
3400
  performVersionCheck(false, freshSettings);
3401
+ await initUsage();
3373
3402
  setIsInitializing(false);
3374
3403
  }
3375
3404
  init();
@@ -3408,6 +3437,7 @@ Check what's new using \`/changelog\` command.`,
3408
3437
  await addToUsage("duration", deltaSecs);
3409
3438
  lastSavedTimeRef.current += deltaSecs * 1e3;
3410
3439
  }
3440
+ await forceFlushUsage();
3411
3441
  };
3412
3442
  flush();
3413
3443
  const timer = setTimeout(() => {
@@ -4301,7 +4331,7 @@ Selection: ${val}`,
4301
4331
  }
4302
4332
  )), /* @__PURE__ */ React10.createElement(Text10, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
4303
4333
  case "stats":
4304
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, width: 100 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Session Duration:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionAgentCalls)), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 23 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 23 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionBackgroundCalls)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, (sessionTotalTokens / 1e3).toFixed(2), "k")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls (Sess):")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionToolSuccess + sessionToolFailure, " ( "), /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u2713 ", sessionToolSuccess), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " "), /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", sessionToolFailure), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " )"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "DAILY USAGE TRACKER"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Wall Time Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatDuration(dailyUsage?.duration || 0))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, dailyUsage?.agent || 0)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, dailyUsage?.background || 0)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Used Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, ((dailyUsage?.tokens || 0) / 1e3).toFixed(2), "k")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, (dailyUsage?.toolSuccess || 0) + (dailyUsage?.toolFailure || 0), " ( "), /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u2713 ", dailyUsage?.toolSuccess || 0), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " "), /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", dailyUsage?.toolFailure || 0), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " )"))), /* @__PURE__ */ React10.createElement(Text10, { dimColor: true, marginTop: 1, italic: true }, "(Press ESC to return to chat)"));
4334
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, width: 100 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Session Duration:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionAgentCalls)), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 23 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 23 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionBackgroundCalls)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatTokens(sessionTotalTokens))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls (Sess):")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionToolSuccess + sessionToolFailure, " ( "), /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u2713 ", sessionToolSuccess), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " "), /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", sessionToolFailure), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " )"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "DAILY USAGE TRACKER"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Wall Time Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatDuration(dailyUsage?.duration || 0))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, dailyUsage?.agent || 0)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, dailyUsage?.background || 0)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Used Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatTokens(dailyUsage?.tokens || 0))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, (dailyUsage?.toolSuccess || 0) + (dailyUsage?.toolFailure || 0), " ( "), /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u2713 ", dailyUsage?.toolSuccess || 0), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " "), /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", dailyUsage?.toolFailure || 0), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " )"))), /* @__PURE__ */ React10.createElement(Text10, { dimColor: true, marginTop: 1, italic: true }, "(Press ESC to return to chat)"));
4305
4335
  case "autoExecDanger":
4306
4336
  return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: AUTO-EXEC MODE"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "Turning this ON allows the agent to execute terminal commands automatically without requiring your approval for each step."), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React10.createElement(Text10, null, "\u2022 The agent may execute destructive commands (rm -rf, etc.) by mistake."), /* @__PURE__ */ React10.createElement(Text10, null, "\u2022 Unintended system changes if the agent hallucinates a path or command."), /* @__PURE__ */ React10.createElement(Text10, null, "\u2022 Reduced control over the agent's step-by-step decision making."), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
4307
4337
  CommandMenu,
@@ -4649,7 +4679,7 @@ Selection: ${val}`,
4649
4679
  const agentActiveMs = sessionApiTime + sessionToolTime;
4650
4680
  const apiPercent = agentActiveMs > 0 ? (sessionApiTime / agentActiveMs * 100).toFixed(1) : "0.0";
4651
4681
  const toolPercent = agentActiveMs > 0 ? (sessionToolTime / agentActiveMs * 100).toFixed(1) : "0.0";
4652
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "red", width: 100, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan", bold: true }, "Agent powering down. ", /* @__PURE__ */ React10.createElement(Text10, { color: "magenta" }, "Goodbye!"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, chatId)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, totalTools, " ( ", /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u2713 ", sessionToolSuccess), " ", /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", sessionToolFailure), " )")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, successRate, "%")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, (sessionTotalTokens / 1e3).toFixed(2), "k"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 18 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 18 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
4682
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "red", width: 100, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan", bold: true }, "Agent powering down. ", /* @__PURE__ */ React10.createElement(Text10, { color: "magenta" }, "Goodbye!"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, chatId)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, totalTools, " ( ", /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u2713 ", sessionToolSuccess), " ", /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", sessionToolFailure), " )")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, successRate, "%")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatTokens(sessionTotalTokens)))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 18 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 18 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
4653
4683
  })(), suggestions.length > 0 && (() => {
4654
4684
  const windowSize = 5;
4655
4685
  const startIdx = Math.max(0, Math.min(selectedIndex - 2, suggestions.length - windowSize));
@@ -4700,10 +4730,11 @@ var init_app = __esm({
4700
4730
  init_terminal();
4701
4731
  init_exec_command();
4702
4732
  init_setup();
4733
+ init_text();
4703
4734
  SESSION_START_TIME = Date.now();
4704
4735
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
4705
- versionFluxflow = "1.7.16";
4706
- updatedOn = "2026-05-05";
4736
+ versionFluxflow = "1.7.18";
4737
+ updatedOn = "2026-05-06";
4707
4738
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent already finished the task before your hint was consumed."), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
4708
4739
  CommandMenu,
4709
4740
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.7.16",
3
+ "version": "1.7.18",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",