fluxflow-cli 3.13.3 → 3.13.4

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 +791 -561
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -110,9 +110,321 @@ var init_paths = __esm({
110
110
  }
111
111
  });
112
112
 
113
- // src/utils/crypto.js
114
- import fs2 from "fs";
113
+ // src/utils/export.js
114
+ var export_exports = {};
115
+ __export(export_exports, {
116
+ exportCurrentChat: () => exportCurrentChat,
117
+ exportErrorLogs: () => exportErrorLogs,
118
+ handleExport: () => handleExport,
119
+ parseAgentText: () => parseAgentText,
120
+ parseLogEntries: () => parseLogEntries
121
+ });
122
+ import fs2 from "fs-extra";
115
123
  import path2 from "path";
124
+ var parseAgentText, exportCurrentChat, parseLogEntries, exportErrorLogs, handleExport;
125
+ var init_export = __esm({
126
+ "src/utils/export.js"() {
127
+ init_paths();
128
+ parseAgentText = (text) => {
129
+ if (!text) return [];
130
+ const blocks = [];
131
+ const toolRegex = /\[tool:(.*?)\((.*?)\)\]/g;
132
+ let lastIndex = 0;
133
+ let match;
134
+ while ((match = toolRegex.exec(text)) !== null) {
135
+ if (match.index > lastIndex) {
136
+ const content = text.slice(lastIndex, match.index);
137
+ if (content.trim()) {
138
+ blocks.push({ type: "output", content });
139
+ }
140
+ }
141
+ blocks.push({
142
+ type: "tool",
143
+ toolName: match[1],
144
+ args: match[2]
145
+ });
146
+ lastIndex = toolRegex.lastIndex;
147
+ }
148
+ if (lastIndex < text.length) {
149
+ const content = text.slice(lastIndex);
150
+ if (content.trim()) {
151
+ blocks.push({ type: "output", content });
152
+ }
153
+ }
154
+ return blocks;
155
+ };
156
+ exportCurrentChat = async (chatId, messages, targetDir = process.cwd()) => {
157
+ const exportFile = `export-fluxflow-${chatId}.txt`;
158
+ const exportPath = path2.join(targetDir, exportFile);
159
+ const exportLines = [];
160
+ let insideAgentBlock = false;
161
+ for (let i = 0; i < messages.length; i++) {
162
+ const msg = messages[i];
163
+ if (!msg) continue;
164
+ if (msg.role === "system" || msg.isMeta || msg.isLogo || String(msg.id).startsWith("welcome")) {
165
+ continue;
166
+ }
167
+ if (msg.role === "user") {
168
+ let cleanUserText = msg.text || "";
169
+ cleanUserText = cleanUserText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
170
+ if (exportLines.length > 0) {
171
+ exportLines.push("");
172
+ }
173
+ exportLines.push("[USER]");
174
+ exportLines.push(cleanUserText);
175
+ insideAgentBlock = false;
176
+ } else if (msg.role === "think") {
177
+ if (!insideAgentBlock) {
178
+ exportLines.push("");
179
+ exportLines.push("[AGENT]");
180
+ insideAgentBlock = true;
181
+ }
182
+ const cleanThinkText = (msg.text || "").replace(/\[\[\s*turn\s*:\s*(continue|finish)\s*\]\]/gi, "").replace(/\[\[END\]\]/gi, "").replace(/\[\[TOOL RESULTS\]\]/gi, "").replace(/\[TOOL RESULTS\]/gi, "").replace(/\[TOOL RESULT\]/gi, "").trim();
183
+ if (cleanThinkText) {
184
+ exportLines.push("[thoughts]");
185
+ exportLines.push(cleanThinkText);
186
+ }
187
+ } else if (msg.role === "agent") {
188
+ if (!insideAgentBlock) {
189
+ exportLines.push("");
190
+ exportLines.push("[AGENT]");
191
+ insideAgentBlock = true;
192
+ }
193
+ const blocks = parseAgentText(msg.text || "");
194
+ for (const block of blocks) {
195
+ if (block.type === "output") {
196
+ const cleanContent = block.content.replace(/\[\[\s*turn\s*:\s*(continue|finish)\s*\]\]/gi, "").replace(/\[\[END\]\]/gi, "").replace(/\[\[TOOL RESULTS\]\]/gi, "").replace(/\[TOOL RESULTS\]/gi, "").replace(/\[TOOL RESULT\]/gi, "").trim();
197
+ if (cleanContent) {
198
+ exportLines.push("[output]");
199
+ exportLines.push(cleanContent);
200
+ }
201
+ } else if (block.type === "tool") {
202
+ exportLines.push("[tool]");
203
+ exportLines.push(`${block.toolName} ${block.args}`);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ const fileContent = exportLines.join("\n");
209
+ await fs2.writeFile(exportPath, fileContent, "utf8");
210
+ return { exportFile, exportPath, totalLines: exportLines.length };
211
+ };
212
+ parseLogEntries = (content, defaultSource = "FluxFlow", fileMtime = null) => {
213
+ if (!content || !content.trim()) return [];
214
+ const lines = content.split("\n");
215
+ const rawBlocks = [];
216
+ let currentLines = [];
217
+ const headerRegex = /^\s*(?:CRITICAL\s+ERROR|ERROR|DEBUG|SEARCH|PUPPETEER|WARN|WARNING|INFO)\b/i;
218
+ const separatorRegex = /^\s*-{3,}\s*$/;
219
+ let hasExplicitHeaders = false;
220
+ for (const line of lines) {
221
+ if (headerRegex.test(line)) {
222
+ hasExplicitHeaders = true;
223
+ break;
224
+ }
225
+ }
226
+ if (!hasExplicitHeaders) {
227
+ const cleanMsg = content.trim();
228
+ if (!cleanMsg) return [];
229
+ const dateStr = fileMtime ? new Date(fileMtime).toLocaleString() : "Unknown Time";
230
+ const source = /\bjanitor\b/i.test(cleanMsg) ? "Memory" : defaultSource;
231
+ return [{
232
+ timestamp: dateStr,
233
+ level: "ERROR",
234
+ source,
235
+ message: cleanMsg
236
+ }];
237
+ }
238
+ for (const line of lines) {
239
+ if (separatorRegex.test(line)) {
240
+ if (currentLines.length > 0) {
241
+ rawBlocks.push(currentLines.join("\n").trim());
242
+ currentLines = [];
243
+ }
244
+ } else if (headerRegex.test(line)) {
245
+ if (currentLines.length > 0) {
246
+ rawBlocks.push(currentLines.join("\n").trim());
247
+ currentLines = [];
248
+ }
249
+ currentLines.push(line);
250
+ } else {
251
+ if (currentLines.length > 0 || line.trim()) {
252
+ currentLines.push(line);
253
+ }
254
+ }
255
+ }
256
+ if (currentLines.length > 0) {
257
+ rawBlocks.push(currentLines.join("\n").trim());
258
+ }
259
+ const structuredEntries = [];
260
+ for (const block of rawBlocks) {
261
+ if (!block) continue;
262
+ const blockLines = block.split("\n").map((l) => l.trimEnd());
263
+ const firstLine = blockLines[0] || "";
264
+ const isError = /\bERROR\b/i.test(block);
265
+ if (!isError) continue;
266
+ const timeMatch = firstLine.match(/\[(.*?)\]/);
267
+ const timestamp = timeMatch ? timeMatch[1] : null;
268
+ let level = "ERROR";
269
+ if (/CRITICAL\s+ERROR/i.test(firstLine)) {
270
+ level = "CRITICAL ERROR";
271
+ }
272
+ let messageText = "";
273
+ if (timeMatch) {
274
+ const headerEnd = firstLine.indexOf("]:");
275
+ if (headerEnd !== -1) {
276
+ messageText = firstLine.substring(headerEnd + 2).trim();
277
+ } else {
278
+ messageText = firstLine.replace(headerRegex, "").replace(/\[.*?\]/, "").replace(/^:\s*/, "").trim();
279
+ }
280
+ } else {
281
+ messageText = firstLine.replace(headerRegex, "").replace(/^:\s*/, "").trim();
282
+ }
283
+ if (blockLines.length > 1) {
284
+ const rest = blockLines.slice(1).join("\n").trim();
285
+ if (rest) {
286
+ messageText = messageText ? `${messageText}
287
+ ${rest}` : rest;
288
+ }
289
+ }
290
+ if (messageText) {
291
+ const entrySource = /\bjanitor\b/i.test(block) ? "Memory" : defaultSource;
292
+ structuredEntries.push({
293
+ timestamp: timestamp || (fileMtime ? new Date(fileMtime).toLocaleString() : "Unknown Time"),
294
+ level,
295
+ source: entrySource,
296
+ message: messageText
297
+ });
298
+ }
299
+ }
300
+ return structuredEntries;
301
+ };
302
+ exportErrorLogs = async (targetDir = process.cwd()) => {
303
+ const exportFile = `fluxflow-error-${Date.now()}.txt`;
304
+ const exportPath = path2.join(targetDir, exportFile);
305
+ const collectLogFiles = async (dir) => {
306
+ if (!await fs2.pathExists(dir)) return [];
307
+ const items = await fs2.readdir(dir);
308
+ let files = [];
309
+ for (const item of items) {
310
+ const fullPath = path2.join(dir, item);
311
+ const stat = await fs2.stat(fullPath);
312
+ if (stat.isDirectory()) {
313
+ const subFiles = await collectLogFiles(fullPath);
314
+ files = files.concat(subFiles);
315
+ } else if (item.endsWith(".log") || item.endsWith(".txt")) {
316
+ files.push({ path: fullPath, mtime: stat.mtimeMs });
317
+ }
318
+ }
319
+ return files;
320
+ };
321
+ const logFiles = await collectLogFiles(LOGS_DIR);
322
+ let allEntries = [];
323
+ for (const fileObj of logFiles) {
324
+ try {
325
+ const content = await fs2.readFile(fileObj.path, "utf8");
326
+ if (content.trim()) {
327
+ const normPath = fileObj.path.replace(/\\/g, "/").toLowerCase();
328
+ let defaultSource = "FluxFlow";
329
+ if (normPath.includes("/janitor") || normPath.includes("janitor")) {
330
+ defaultSource = "Memory";
331
+ } else if (!normPath.includes("/agent") && !normPath.includes("agent")) {
332
+ defaultSource = "Other";
333
+ }
334
+ const parsed = parseLogEntries(content, defaultSource, fileObj.mtime);
335
+ allEntries = allEntries.concat(parsed);
336
+ }
337
+ } catch (e) {
338
+ }
339
+ }
340
+ const uniqueEntries = [];
341
+ const seenKeys = /* @__PURE__ */ new Set();
342
+ for (const entry of allEntries) {
343
+ const key = `${entry.source}::${entry.timestamp}::${entry.message.trim()}`;
344
+ if (!seenKeys.has(key)) {
345
+ seenKeys.add(key);
346
+ uniqueEntries.push(entry);
347
+ }
348
+ }
349
+ const fluxflowEntries = uniqueEntries.filter((e) => e.source === "FluxFlow");
350
+ const memoryEntries = uniqueEntries.filter((e) => e.source === "Memory");
351
+ const otherEntries = uniqueEntries.filter((e) => e.source !== "FluxFlow" && e.source !== "Memory");
352
+ const renderSection = (title, entries, categoryName) => {
353
+ const sectionHeader = [
354
+ "================================================================================",
355
+ `${title} (${entries.length})`,
356
+ "================================================================================"
357
+ ].join("\n");
358
+ if (entries.length === 0) {
359
+ return `${sectionHeader}
360
+ No ${categoryName} error entries found.`;
361
+ }
362
+ const blocks = entries.map((entry, idx) => {
363
+ const header = `[${categoryName} #${idx + 1}] ${entry.timestamp} (${entry.level})`;
364
+ const indentedMsg = entry.message.split("\n").map((line) => ` ${line}`).join("\n");
365
+ return `${header}
366
+ ${indentedMsg}`;
367
+ });
368
+ return `${sectionHeader}
369
+
370
+ ` + blocks.join("\n\n--------------------------------------------------------------------------------\n\n");
371
+ };
372
+ const exportHeader = [
373
+ "================================================================================",
374
+ "FLUXFLOW ERROR LOGS EXPORT",
375
+ `Exported At : ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
376
+ `Total Errors: ${uniqueEntries.length} (FluxFlow: ${fluxflowEntries.length} | Memory: ${memoryEntries.length}${otherEntries.length > 0 ? ` | Other: ${otherEntries.length}` : ""})`,
377
+ "================================================================================",
378
+ ""
379
+ ].join("\n");
380
+ const sections = [
381
+ renderSection("SECTION 1: FLUXFLOW ERRORS", fluxflowEntries, "FluxFlow"),
382
+ renderSection("SECTION 2: MEMORY ERRORS", memoryEntries, "Memory")
383
+ ];
384
+ if (otherEntries.length > 0) {
385
+ sections.push(renderSection("SECTION 3: OTHER SYSTEM ERRORS", otherEntries, "Other"));
386
+ }
387
+ const fileContent = exportHeader + sections.join("\n\n\n") + "\n";
388
+ await fs2.writeFile(exportPath, fileContent, "utf8");
389
+ return {
390
+ exportFile,
391
+ exportPath,
392
+ entryCount: uniqueEntries.length,
393
+ fluxflowCount: fluxflowEntries.length,
394
+ memoryCount: memoryEntries.length
395
+ };
396
+ };
397
+ handleExport = async (parts, { chatId, messages }) => {
398
+ const subCategory = (parts[1] || "chat").toLowerCase();
399
+ if (subCategory === "chat") {
400
+ const result = await exportCurrentChat(chatId, messages);
401
+ return {
402
+ success: true,
403
+ type: "chat",
404
+ message: `[EXPORT] Current chat exported to "${result.exportFile}"`
405
+ };
406
+ } else if (subCategory === "logs") {
407
+ const result = await exportErrorLogs();
408
+ return {
409
+ success: true,
410
+ type: "logs",
411
+ message: `[EXPORT LOGS] Exported ${result.entryCount} error log entries (FluxFlow: ${result.fluxflowCount}, Memory: ${result.memoryCount}) to "${result.exportFile}"`
412
+ };
413
+ } else {
414
+ return {
415
+ success: false,
416
+ message: `[EXPORT USAGE] Unknown subcommand "${subCategory}". Options:
417
+ \u2022 /export chat current
418
+ \u2022 /export logs error`
419
+ };
420
+ }
421
+ };
422
+ }
423
+ });
424
+
425
+ // src/utils/crypto.js
426
+ import fs3 from "fs";
427
+ import path3 from "path";
116
428
  import crypto2 from "crypto";
117
429
  var XOR_KEY, bypass, xorTransform, AES_ALGORITHM, AES_KEY, encryptAes, decryptAes, readEncryptedJson, writeEncryptedJson, readAesEncryptedJson, writeAesEncryptedJson;
118
430
  var init_crypto = __esm({
@@ -152,8 +464,8 @@ var init_crypto = __esm({
152
464
  };
153
465
  readEncryptedJson = (filePath, defaultValue = {}) => {
154
466
  try {
155
- if (!fs2.existsSync(filePath)) return defaultValue;
156
- const rawContent = fs2.readFileSync(filePath);
467
+ if (!fs3.existsSync(filePath)) return defaultValue;
468
+ const rawContent = fs3.readFileSync(filePath);
157
469
  const fileContent = rawContent.toString("utf8").trim();
158
470
  if (fileContent.startsWith("{") || fileContent.startsWith("[")) {
159
471
  return JSON.parse(fileContent);
@@ -169,19 +481,19 @@ var init_crypto = __esm({
169
481
  }
170
482
  throw new Error("Unsupported or corrupt encryption format");
171
483
  } catch (err) {
172
- console.error(`Vault Read Error [${path2.basename(filePath)}]:`, err.message);
484
+ console.error(`Vault Read Error [${path3.basename(filePath)}]:`, err.message);
173
485
  return defaultValue;
174
486
  }
175
487
  };
176
488
  writeEncryptedJson = (filePath, data) => {
177
489
  try {
178
- const dir = path2.dirname(filePath);
179
- if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
490
+ const dir = path3.dirname(filePath);
491
+ if (!fs3.existsSync(dir)) fs3.mkdirSync(dir, { recursive: true });
180
492
  const jsonData = JSON.stringify(data, null, 2);
181
493
  const encrypted = encryptAes(jsonData);
182
- fs2.writeFileSync(filePath, encrypted, "utf8");
494
+ fs3.writeFileSync(filePath, encrypted, "utf8");
183
495
  } catch (err) {
184
- console.error(`Vault Write Error [${path2.basename(filePath)}]:`, err.message);
496
+ console.error(`Vault Write Error [${path3.basename(filePath)}]:`, err.message);
185
497
  }
186
498
  };
187
499
  readAesEncryptedJson = readEncryptedJson;
@@ -190,36 +502,36 @@ var init_crypto = __esm({
190
502
  });
191
503
 
192
504
  // src/data/model_config.js
193
- import fs3 from "fs";
194
- import path3 from "path";
505
+ import fs4 from "fs";
506
+ import path4 from "path";
195
507
  import { fileURLToPath } from "url";
196
508
  var __filename, __dirname, packageConfigPath, pathsToCheck, userConfigPath, activeConfig, multimodalModelsSet, rebuildMultimodalSet, loadRemoteModelConfig, isModelMultimodal, getModels, getDefaultModel, getFallbackValue;
197
509
  var init_model_config = __esm({
198
510
  "src/data/model_config.js"() {
199
511
  init_paths();
200
512
  __filename = fileURLToPath(import.meta.url);
201
- __dirname = path3.dirname(__filename);
513
+ __dirname = path4.dirname(__filename);
202
514
  packageConfigPath = "";
203
515
  pathsToCheck = [
204
- path3.join(__dirname, "../../model_config.json"),
516
+ path4.join(__dirname, "../../model_config.json"),
205
517
  // Dev: src/data/model_config.js -> root
206
- path3.join(__dirname, "../model_config.json")
518
+ path4.join(__dirname, "../model_config.json")
207
519
  // Prod: dist/fluxflow.js -> root
208
520
  ];
209
521
  for (const p of pathsToCheck) {
210
522
  try {
211
- if (fs3.existsSync(p)) {
523
+ if (fs4.existsSync(p)) {
212
524
  packageConfigPath = p;
213
525
  break;
214
526
  }
215
527
  } catch (e) {
216
528
  }
217
529
  }
218
- userConfigPath = path3.join(FLUXFLOW_DIR, "model_config.json");
530
+ userConfigPath = path4.join(FLUXFLOW_DIR, "model_config.json");
219
531
  activeConfig = null;
220
- if (fs3.existsSync(userConfigPath)) {
532
+ if (fs4.existsSync(userConfigPath)) {
221
533
  try {
222
- const fileContent = fs3.readFileSync(userConfigPath, "utf-8");
534
+ const fileContent = fs4.readFileSync(userConfigPath, "utf-8");
223
535
  const parsed = JSON.parse(fileContent);
224
536
  if (parsed && parsed.providers && parsed.fallbacks && parsed.release) {
225
537
  activeConfig = parsed;
@@ -229,7 +541,7 @@ var init_model_config = __esm({
229
541
  }
230
542
  if (!activeConfig && packageConfigPath) {
231
543
  try {
232
- const fileContent = fs3.readFileSync(packageConfigPath, "utf-8");
544
+ const fileContent = fs4.readFileSync(packageConfigPath, "utf-8");
233
545
  const parsed = JSON.parse(fileContent);
234
546
  if (parsed && parsed.providers && parsed.fallbacks && parsed.release) {
235
547
  activeConfig = parsed;
@@ -285,10 +597,10 @@ var init_model_config = __esm({
285
597
  activeConfig = data;
286
598
  rebuildMultimodalSet();
287
599
  try {
288
- if (!fs3.existsSync(FLUXFLOW_DIR)) {
289
- fs3.mkdirSync(FLUXFLOW_DIR, { recursive: true });
600
+ if (!fs4.existsSync(FLUXFLOW_DIR)) {
601
+ fs4.mkdirSync(FLUXFLOW_DIR, { recursive: true });
290
602
  }
291
- fs3.writeFileSync(userConfigPath, JSON.stringify(data, null, 2), "utf-8");
603
+ fs4.writeFileSync(userConfigPath, JSON.stringify(data, null, 2), "utf-8");
292
604
  } catch (writeErr) {
293
605
  }
294
606
  return true;
@@ -337,14 +649,14 @@ __export(secrets_exports, {
337
649
  saveSearchKey: () => saveSearchKey,
338
650
  saveSecret: () => saveSecret
339
651
  });
340
- import fs4 from "fs-extra";
341
- import path4 from "path";
652
+ import fs5 from "fs-extra";
653
+ import path5 from "path";
342
654
  var SECRET_FILE, getAPIKey, getProviderAPIKey, saveProviderAPIKey, getSecret, saveSecret, getSearchSecrets, saveAPIKey, saveSearchKey, saveSearchId, removeSecret, removeAPIKey;
343
655
  var init_secrets = __esm({
344
656
  "src/utils/secrets.js"() {
345
657
  init_crypto();
346
658
  init_paths();
347
- SECRET_FILE = path4.join(SECRET_DIR, "secrets.json");
659
+ SECRET_FILE = path5.join(SECRET_DIR, "secrets.json");
348
660
  getAPIKey = async () => {
349
661
  try {
350
662
  const secrets = readEncryptedJson(SECRET_FILE, {});
@@ -388,7 +700,7 @@ var init_secrets = __esm({
388
700
  }
389
701
  };
390
702
  saveSecret = async (key, value) => {
391
- await fs4.ensureDir(SECRET_DIR);
703
+ await fs5.ensureDir(SECRET_DIR);
392
704
  let current = readEncryptedJson(SECRET_FILE, {});
393
705
  current[key] = value;
394
706
  writeEncryptedJson(SECRET_FILE, current);
@@ -425,8 +737,8 @@ __export(settings_exports, {
425
737
  loadSettings: () => loadSettings,
426
738
  saveSettings: () => saveSettings
427
739
  });
428
- import fs5 from "fs-extra";
429
- import path5 from "path";
740
+ import fs6 from "fs-extra";
741
+ import path6 from "path";
430
742
  var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
431
743
  var init_settings = __esm({
432
744
  "src/utils/settings.js"() {
@@ -483,7 +795,7 @@ var init_settings = __esm({
483
795
  loadSettings = async () => {
484
796
  let settingsObj = { ...DEFAULT_SETTINGS };
485
797
  try {
486
- if (await fs5.exists(SETTINGS_FILE)) {
798
+ if (await fs6.exists(SETTINGS_FILE)) {
487
799
  const saved = readAesEncryptedJson(SETTINGS_FILE);
488
800
  if (saved.imageSettings && saved.imageSettings.apiKey) {
489
801
  try {
@@ -535,12 +847,12 @@ var init_settings = __esm({
535
847
  const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
536
848
  const folders = ["logs", "secret"];
537
849
  for (const folder of folders) {
538
- const src = path5.join(FLUXFLOW_DIR2, folder);
539
- const dest = path5.join(newPath, folder);
850
+ const src = path6.join(FLUXFLOW_DIR2, folder);
851
+ const dest = path6.join(newPath, folder);
540
852
  try {
541
- if (await fs5.exists(src)) {
542
- await fs5.ensureDir(dest);
543
- await fs5.copy(src, dest, { overwrite: true });
853
+ if (await fs6.exists(src)) {
854
+ await fs6.ensureDir(dest);
855
+ await fs6.copy(src, dest, { overwrite: true });
544
856
  }
545
857
  } catch (err) {
546
858
  console.error(`Migration failed for ${folder}:`, err);
@@ -566,7 +878,7 @@ var init_settings = __esm({
566
878
  if (updated.imageSettings) {
567
879
  updated.imageSettings = { ...updated.imageSettings, apiKey: "" };
568
880
  }
569
- await fs5.ensureDir(path5.dirname(SETTINGS_FILE));
881
+ await fs6.ensureDir(path6.dirname(SETTINGS_FILE));
570
882
  writeAesEncryptedJson(SETTINGS_FILE, updated);
571
883
  return true;
572
884
  } catch (err) {
@@ -5665,7 +5977,14 @@ var init_ChatLayout = __esm({
5665
5977
  { cmd: "/resume", desc: "Load previous session" },
5666
5978
  { cmd: "/revert", desc: "Revert codebase to checkpoint" },
5667
5979
  { cmd: "/save", desc: "Force save current chat" },
5668
- { cmd: "/export", desc: "Export current chat in a .txt file" },
5980
+ {
5981
+ cmd: "/export",
5982
+ desc: "Export current chat or error logs",
5983
+ subs: [
5984
+ { cmd: "chat", desc: "Export current active chat" },
5985
+ { cmd: "logs", desc: "Export error logs" }
5986
+ ]
5987
+ },
5669
5988
  { cmd: "/chats", desc: "List all chat sessions" },
5670
5989
  { cmd: "/btw", desc: "Send raw inquiry mid-turn" },
5671
5990
  { cmd: "/image", desc: "Generate images" },
@@ -7750,7 +8069,7 @@ var init_thinking_prompts = __esm({
7750
8069
  });
7751
8070
 
7752
8071
  // src/utils/prompts.js
7753
- import fs6 from "fs";
8072
+ import fs7 from "fs";
7754
8073
  var cachedProjectContextBlock, cachedChatId, cachedUserMemories, getCachedUserMemories, getMemoryPrompt, getSystemInstruction, getJanitorInstruction;
7755
8074
  var init_prompts = __esm({
7756
8075
  async "src/utils/prompts.js"() {
@@ -7776,7 +8095,7 @@ var init_prompts = __esm({
7776
8095
  }
7777
8096
  } catch (e) {
7778
8097
  cachedUserMemories = "";
7779
- fs6.appendFileSync(`${LOGS_DIR}/memory/error.txt`, `${e.message}
8098
+ fs7.appendFileSync(`${LOGS_DIR}/memory/error.txt`, `${e.message}
7780
8099
  -------------------------------------------------
7781
8100
 
7782
8101
  `);
@@ -7863,7 +8182,7 @@ ${userMemories}
7863
8182
  { name: "architecture.md", desc: "System Structure" }
7864
8183
  ];
7865
8184
  if (isFirstPrompt || cachedProjectContextBlock === null) {
7866
- const foundFiles = projectContextFiles.filter((f) => fs6.existsSync(f.name));
8185
+ const foundFiles = projectContextFiles.filter((f) => fs7.existsSync(f.name));
7867
8186
  cachedProjectContextBlock = mode === "Flux" && foundFiles.length > 0 ? `
7868
8187
  -- PROJECT CONTEXT --
7869
8188
  ${foundFiles.map((f) => `- ${f.name}: ${f.desc}`).join("\n")}
@@ -7933,35 +8252,35 @@ ${userMemories}` : ""}`.trim();
7933
8252
  });
7934
8253
 
7935
8254
  // src/utils/revert.js
7936
- import fs7 from "fs-extra";
7937
- import path6 from "path";
8255
+ import fs8 from "fs-extra";
8256
+ import path7 from "path";
7938
8257
  async function performRestoration(change, tx) {
7939
8258
  try {
7940
8259
  if (change.type === "create") {
7941
- if (await fs7.pathExists(change.filePath)) {
7942
- await fs7.chmod(change.filePath, 438).catch(() => {
8260
+ if (await fs8.pathExists(change.filePath)) {
8261
+ await fs8.chmod(change.filePath, 438).catch(() => {
7943
8262
  });
7944
- await fs7.remove(change.filePath);
8263
+ await fs8.remove(change.filePath);
7945
8264
  }
7946
8265
  } else if (change.type === "update") {
7947
8266
  if (!change.backupFile) return;
7948
- const backupPath = path6.join(BACKUPS_DIR, tx.chatId, change.backupFile);
7949
- if (await fs7.pathExists(backupPath)) {
8267
+ const backupPath = path7.join(BACKUPS_DIR, tx.chatId, change.backupFile);
8268
+ if (await fs8.pathExists(backupPath)) {
7950
8269
  const backupContainer = readEncryptedJson(backupPath, null);
7951
8270
  if (!backupContainer || !backupContainer.data) {
7952
- throw new Error(`Backup container corrupt or empty for ${path6.basename(change.filePath)}`);
8271
+ throw new Error(`Backup container corrupt or empty for ${path7.basename(change.filePath)}`);
7953
8272
  }
7954
8273
  const decrypted = decryptAes(backupContainer.data);
7955
- if (await fs7.pathExists(change.filePath)) {
7956
- await fs7.chmod(change.filePath, 438).catch(() => {
8274
+ if (await fs8.pathExists(change.filePath)) {
8275
+ await fs8.chmod(change.filePath, 438).catch(() => {
7957
8276
  });
7958
8277
  }
7959
- await fs7.writeFile(change.filePath, decrypted, "utf8");
8278
+ await fs8.writeFile(change.filePath, decrypted, "utf8");
7960
8279
  } else {
7961
8280
  }
7962
8281
  }
7963
8282
  } catch (err) {
7964
- throw new Error(`Restoration failed for ${path6.basename(change.filePath)}: ${err.message}`);
8283
+ throw new Error(`Restoration failed for ${path7.basename(change.filePath)}: ${err.message}`);
7965
8284
  }
7966
8285
  }
7967
8286
  async function restoreWithRetry(change, tx, maxAttempts = 7) {
@@ -7986,7 +8305,7 @@ var init_revert = __esm({
7986
8305
  "src/utils/revert.js"() {
7987
8306
  init_paths();
7988
8307
  init_crypto();
7989
- fs7.ensureDirSync(BACKUPS_DIR);
8308
+ fs8.ensureDirSync(BACKUPS_DIR);
7990
8309
  currentTransaction = null;
7991
8310
  lastChatId = null;
7992
8311
  RevertManager = {
@@ -8011,16 +8330,16 @@ var init_revert = __esm({
8011
8330
  if (lastTx) {
8012
8331
  const alreadyBackedUp2 = lastTx.changes.some((c) => c.filePath === absolutePath);
8013
8332
  if (alreadyBackedUp2) return;
8014
- const fileExists2 = await fs7.pathExists(absolutePath);
8333
+ const fileExists2 = await fs8.pathExists(absolutePath);
8015
8334
  let type2 = fileExists2 || forcedContent ? "update" : "create";
8016
8335
  let backupFile2 = null;
8017
8336
  if (type2 === "update") {
8018
- const fileName = path6.basename(absolutePath);
8337
+ const fileName = path7.basename(absolutePath);
8019
8338
  backupFile2 = `${lastTx.id}_${fileName}.bak`;
8020
- const chatBackupDir = path6.join(BACKUPS_DIR, lastTx.chatId);
8021
- await fs7.ensureDir(chatBackupDir);
8022
- const backupPath = path6.join(chatBackupDir, backupFile2);
8023
- let content = forcedContent !== null ? forcedContent : await fs7.readFile(absolutePath, "utf8").catch(() => null);
8339
+ const chatBackupDir = path7.join(BACKUPS_DIR, lastTx.chatId);
8340
+ await fs8.ensureDir(chatBackupDir);
8341
+ const backupPath = path7.join(chatBackupDir, backupFile2);
8342
+ let content = forcedContent !== null ? forcedContent : await fs8.readFile(absolutePath, "utf8").catch(() => null);
8024
8343
  if (content !== null) {
8025
8344
  writeEncryptedJson(backupPath, { data: encryptAes(content) });
8026
8345
  } else {
@@ -8036,16 +8355,16 @@ var init_revert = __esm({
8036
8355
  }
8037
8356
  const alreadyBackedUp = currentTransaction.changes.some((c) => c.filePath === absolutePath);
8038
8357
  if (alreadyBackedUp) return;
8039
- const fileExists = await fs7.pathExists(absolutePath);
8358
+ const fileExists = await fs8.pathExists(absolutePath);
8040
8359
  let type = fileExists || forcedContent ? "update" : "create";
8041
8360
  let backupFile = null;
8042
8361
  if (type === "update") {
8043
- const fileName = path6.basename(absolutePath);
8362
+ const fileName = path7.basename(absolutePath);
8044
8363
  backupFile = `${currentTransaction.id}_${fileName}.bak`;
8045
- const chatBackupDir = path6.join(BACKUPS_DIR, currentTransaction.chatId);
8046
- await fs7.ensureDir(chatBackupDir);
8047
- const backupPath = path6.join(chatBackupDir, backupFile);
8048
- let content = forcedContent !== null ? forcedContent : await fs7.readFile(absolutePath, "utf8").catch(() => null);
8364
+ const chatBackupDir = path7.join(BACKUPS_DIR, currentTransaction.chatId);
8365
+ await fs8.ensureDir(chatBackupDir);
8366
+ const backupPath = path7.join(chatBackupDir, backupFile);
8367
+ let content = forcedContent !== null ? forcedContent : await fs8.readFile(absolutePath, "utf8").catch(() => null);
8049
8368
  if (content !== null) {
8050
8369
  writeEncryptedJson(backupPath, { data: encryptAes(content) });
8051
8370
  } else {
@@ -8068,14 +8387,14 @@ var init_revert = __esm({
8068
8387
  if (removed.changes) {
8069
8388
  for (const change of removed.changes) {
8070
8389
  if (change.backupFile) {
8071
- await fs7.remove(path6.join(BACKUPS_DIR, removed.chatId, change.backupFile)).catch(() => {
8390
+ await fs8.remove(path7.join(BACKUPS_DIR, removed.chatId, change.backupFile)).catch(() => {
8072
8391
  });
8073
8392
  }
8074
8393
  }
8075
8394
  }
8076
8395
  }
8077
8396
  writeEncryptedJson(LEDGER_FILE, ledger);
8078
- await fs7.remove(ACTIVE_TX_FILE).catch(() => {
8397
+ await fs8.remove(ACTIVE_TX_FILE).catch(() => {
8079
8398
  });
8080
8399
  } catch (err) {
8081
8400
  } finally {
@@ -8084,7 +8403,7 @@ var init_revert = __esm({
8084
8403
  },
8085
8404
  async recoverCrashedTransaction() {
8086
8405
  try {
8087
- if (await fs7.pathExists(ACTIVE_TX_FILE)) {
8406
+ if (await fs8.pathExists(ACTIVE_TX_FILE)) {
8088
8407
  const orphanedTx = readEncryptedJson(ACTIVE_TX_FILE, null);
8089
8408
  if (orphanedTx?.changes?.length > 0) {
8090
8409
  const ledger = readEncryptedJson(LEDGER_FILE, []);
@@ -8093,7 +8412,7 @@ var init_revert = __esm({
8093
8412
  writeEncryptedJson(LEDGER_FILE, ledger);
8094
8413
  }
8095
8414
  }
8096
- await fs7.remove(ACTIVE_TX_FILE).catch(() => {
8415
+ await fs8.remove(ACTIVE_TX_FILE).catch(() => {
8097
8416
  });
8098
8417
  }
8099
8418
  } catch (e) {
@@ -8113,8 +8432,8 @@ var init_revert = __esm({
8113
8432
  }
8114
8433
  for (const change of tx.changes) {
8115
8434
  if (change.backupFile) {
8116
- const backupPath = path6.join(BACKUPS_DIR, tx.chatId, change.backupFile);
8117
- await fs7.remove(backupPath).catch(() => {
8435
+ const backupPath = path7.join(BACKUPS_DIR, tx.chatId, change.backupFile);
8436
+ await fs8.remove(backupPath).catch(() => {
8118
8437
  });
8119
8438
  }
8120
8439
  }
@@ -8133,7 +8452,7 @@ var init_revert = __esm({
8133
8452
  },
8134
8453
  async deleteChatBackups(chatId) {
8135
8454
  try {
8136
- await fs7.remove(path6.join(BACKUPS_DIR, chatId));
8455
+ await fs8.remove(path7.join(BACKUPS_DIR, chatId));
8137
8456
  let ledger = readEncryptedJson(LEDGER_FILE, []);
8138
8457
  const clean = ledger.filter((t) => t.chatId !== chatId);
8139
8458
  if (ledger.length !== clean.length) writeEncryptedJson(LEDGER_FILE, clean);
@@ -8145,8 +8464,8 @@ var init_revert = __esm({
8145
8464
  });
8146
8465
 
8147
8466
  // src/utils/history.js
8148
- import fs8 from "fs-extra";
8149
- import path7 from "path";
8467
+ import fs9 from "fs-extra";
8468
+ import path8 from "path";
8150
8469
  import { nanoid } from "nanoid";
8151
8470
  var WRITE_LOCK, withLock, loadHistory, saveChat, saveChatTitle, deleteChat, generateChatId, cleanupOldHistory, parseCustomDate, cleanupLogFile, cleanupOldLogs, getTruncatedHistory, saveChatContext, loadChatContext;
8152
8471
  var init_history = __esm({
@@ -8170,9 +8489,9 @@ var init_history = __esm({
8170
8489
  return nextLock;
8171
8490
  };
8172
8491
  loadHistory = async () => {
8173
- await fs8.ensureDir(HISTORY_DIR);
8492
+ await fs9.ensureDir(HISTORY_DIR);
8174
8493
  let history = {};
8175
- if (await fs8.pathExists(HISTORY_FILE)) {
8494
+ if (await fs9.pathExists(HISTORY_FILE)) {
8176
8495
  try {
8177
8496
  history = readEncryptedJson(HISTORY_FILE, {});
8178
8497
  } catch (e) {
@@ -8180,10 +8499,10 @@ var init_history = __esm({
8180
8499
  }
8181
8500
  }
8182
8501
  for (const id in history) {
8183
- const chatFile = path7.join(HISTORY_DIR, `${id}.json`);
8502
+ const chatFile = path8.join(HISTORY_DIR, `${id}.json`);
8184
8503
  Object.defineProperty(history[id], "messages", {
8185
8504
  get: () => {
8186
- if (fs8.existsSync(chatFile)) {
8505
+ if (fs9.existsSync(chatFile)) {
8187
8506
  try {
8188
8507
  return readEncryptedJson(chatFile, []);
8189
8508
  } catch (e) {
@@ -8206,7 +8525,7 @@ var init_history = __esm({
8206
8525
  };
8207
8526
  saveChat = async (id, name, messages) => {
8208
8527
  return withLock(async () => {
8209
- await fs8.ensureDir(HISTORY_DIR);
8528
+ await fs9.ensureDir(HISTORY_DIR);
8210
8529
  const history = await loadHistory();
8211
8530
  const existingChat = history[id];
8212
8531
  let persistentMessages = (messages || []).filter(
@@ -8238,7 +8557,7 @@ var init_history = __esm({
8238
8557
  const firstUserMsg = userMessages[0];
8239
8558
  const latestUserMsg = userMessages[userMessages.length - 1];
8240
8559
  if (existingChat && existingChat.prompt) {
8241
- if (Math.random() < 0.8) {
8560
+ if (Math.random() < 0.95) {
8242
8561
  prompt = extractPrompt(latestUserMsg) || existingChat.prompt;
8243
8562
  } else {
8244
8563
  prompt = existingChat.prompt;
@@ -8247,7 +8566,7 @@ var init_history = __esm({
8247
8566
  prompt = extractPrompt(firstUserMsg);
8248
8567
  }
8249
8568
  const finalName = name || (existingChat ? existingChat.name : prompt || `Session ${id.slice(-6)}`);
8250
- const chatFile = path7.join(HISTORY_DIR, `${id}.json`);
8569
+ const chatFile = path8.join(HISTORY_DIR, `${id}.json`);
8251
8570
  writeEncryptedJson(chatFile, persistentMessages);
8252
8571
  history[id] = {
8253
8572
  name: finalName,
@@ -8298,7 +8617,7 @@ var init_history = __esm({
8298
8617
  };
8299
8618
  }
8300
8619
  writeEncryptedJson(HISTORY_FILE, indexHistory);
8301
- if (await fs8.pathExists(CONTEXT_FILE)) {
8620
+ if (await fs9.pathExists(CONTEXT_FILE)) {
8302
8621
  try {
8303
8622
  const contextData = readEncryptedJson(CONTEXT_FILE, []);
8304
8623
  if (Array.isArray(contextData)) {
@@ -8319,10 +8638,10 @@ var init_history = __esm({
8319
8638
  writeEncryptedJson(TEMP_MEM_CHAT_FILE, cache);
8320
8639
  }
8321
8640
  await RevertManager.deleteChatBackups(id);
8322
- const chatFile = path7.join(HISTORY_DIR, `${id}.json`);
8323
- if (await fs8.pathExists(chatFile)) {
8641
+ const chatFile = path8.join(HISTORY_DIR, `${id}.json`);
8642
+ if (await fs9.pathExists(chatFile)) {
8324
8643
  try {
8325
- await fs8.remove(chatFile);
8644
+ await fs9.remove(chatFile);
8326
8645
  } catch (e) {
8327
8646
  }
8328
8647
  }
@@ -8395,8 +8714,8 @@ var init_history = __esm({
8395
8714
  };
8396
8715
  cleanupLogFile = async (filePath) => {
8397
8716
  try {
8398
- if (!await fs8.pathExists(filePath)) return;
8399
- const content = await fs8.readFile(filePath, "utf8");
8717
+ if (!await fs9.pathExists(filePath)) return;
8718
+ const content = await fs9.readFile(filePath, "utf8");
8400
8719
  if (!content.trim()) return;
8401
8720
  const lines = content.split("\n");
8402
8721
  const entries = [];
@@ -8436,26 +8755,26 @@ var init_history = __esm({
8436
8755
  }
8437
8756
  const finalContent = keptEntries.join("\n").trim();
8438
8757
  if (finalContent) {
8439
- await fs8.writeFile(filePath, finalContent + "\n", "utf8");
8758
+ await fs9.writeFile(filePath, finalContent + "\n", "utf8");
8440
8759
  } else {
8441
- await fs8.writeFile(filePath, "", "utf8");
8760
+ await fs9.writeFile(filePath, "", "utf8");
8442
8761
  }
8443
8762
  } catch (e) {
8444
8763
  }
8445
8764
  };
8446
8765
  cleanupOldLogs = async (logsDir) => {
8447
8766
  try {
8448
- if (!await fs8.pathExists(logsDir)) return;
8767
+ if (!await fs9.pathExists(logsDir)) return;
8449
8768
  const cleanRecursive = async (dir) => {
8450
- const files = await fs8.readdir(dir);
8769
+ const files = await fs9.readdir(dir);
8451
8770
  for (const file of files) {
8452
- const fullPath = path7.join(dir, file);
8453
- const stat = await fs8.stat(fullPath);
8771
+ const fullPath = path8.join(dir, file);
8772
+ const stat = await fs9.stat(fullPath);
8454
8773
  if (stat.isDirectory()) {
8455
8774
  await cleanRecursive(fullPath);
8456
- const subFiles = await fs8.readdir(fullPath);
8775
+ const subFiles = await fs9.readdir(fullPath);
8457
8776
  if (subFiles.length === 0) {
8458
- await fs8.remove(fullPath);
8777
+ await fs9.remove(fullPath);
8459
8778
  }
8460
8779
  } else if (file.endsWith(".log")) {
8461
8780
  await cleanupLogFile(fullPath);
@@ -8490,7 +8809,7 @@ var init_history = __esm({
8490
8809
  };
8491
8810
  loadChatContext = async (chatId) => {
8492
8811
  try {
8493
- if (!await fs8.pathExists(CONTEXT_FILE)) return { total: 0, context: 0 };
8812
+ if (!await fs9.pathExists(CONTEXT_FILE)) return { total: 0, context: 0 };
8494
8813
  const contextData = readEncryptedJson(CONTEXT_FILE, []);
8495
8814
  if (!Array.isArray(contextData)) return { total: 0, context: 0 };
8496
8815
  const entry = contextData.find((item) => Object.keys(item)[0] === String(chatId));
@@ -8503,8 +8822,8 @@ var init_history = __esm({
8503
8822
  });
8504
8823
 
8505
8824
  // src/utils/usage.js
8506
- import fs9 from "fs-extra";
8507
- import path8 from "path";
8825
+ import fs10 from "fs-extra";
8826
+ import path9 from "path";
8508
8827
  import os3 from "os";
8509
8828
  var getLocalBackupPath, BACKUP_FILE, generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, runtimeSession, addToUsage, getCustomPeriodUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
8510
8829
  var init_usage = __esm({
@@ -8513,14 +8832,14 @@ var init_usage = __esm({
8513
8832
  init_crypto();
8514
8833
  getLocalBackupPath = () => {
8515
8834
  if (process.platform === "win32") {
8516
- const localAppData = process.env.LOCALAPPDATA || path8.join(os3.homedir(), "AppData", "Local");
8517
- return path8.join(localAppData, "FxFl", "backups", "backup.json");
8835
+ const localAppData = process.env.LOCALAPPDATA || path9.join(os3.homedir(), "AppData", "Local");
8836
+ return path9.join(localAppData, "FxFl", "backups", "backup.json");
8518
8837
  }
8519
8838
  if (process.platform === "darwin") {
8520
- return path8.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
8839
+ return path9.join(os3.homedir(), "Library", "Application Support", "FxFl", "backups", "backup.json");
8521
8840
  }
8522
- const xdgDataHome = process.env.XDG_DATA_HOME || path8.join(os3.homedir(), ".local", "share");
8523
- return path8.join(xdgDataHome, "fxfl", "backups", "backup.json");
8841
+ const xdgDataHome = process.env.XDG_DATA_HOME || path9.join(os3.homedir(), ".local", "share");
8842
+ return path9.join(xdgDataHome, "fxfl", "backups", "backup.json");
8524
8843
  };
8525
8844
  BACKUP_FILE = getLocalBackupPath();
8526
8845
  generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
@@ -8562,8 +8881,8 @@ var init_usage = __esm({
8562
8881
  let primaryData = null;
8563
8882
  let backupData = null;
8564
8883
  try {
8565
- if (await fs9.exists(tempFile)) {
8566
- const rawContent = (await fs9.readFile(tempFile, "utf8")).trim();
8884
+ if (await fs10.exists(tempFile)) {
8885
+ const rawContent = (await fs10.readFile(tempFile, "utf8")).trim();
8567
8886
  let parsed = null;
8568
8887
  if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
8569
8888
  parsed = JSON.parse(rawContent);
@@ -8573,26 +8892,26 @@ var init_usage = __esm({
8573
8892
  if (parsed && parsed.date && parsed.stats) {
8574
8893
  primaryData = parsed;
8575
8894
  try {
8576
- await fs9.rename(tempFile, USAGE_FILE);
8895
+ await fs10.rename(tempFile, USAGE_FILE);
8577
8896
  } catch (e) {
8578
8897
  }
8579
8898
  } else {
8580
8899
  try {
8581
- await fs9.remove(tempFile);
8900
+ await fs10.remove(tempFile);
8582
8901
  } catch (e) {
8583
8902
  }
8584
8903
  }
8585
8904
  }
8586
8905
  } catch (err) {
8587
8906
  try {
8588
- await fs9.remove(tempFile);
8907
+ await fs10.remove(tempFile);
8589
8908
  } catch (e) {
8590
8909
  }
8591
8910
  }
8592
8911
  if (!primaryData) {
8593
8912
  try {
8594
- if (await fs9.exists(USAGE_FILE)) {
8595
- const rawContent = (await fs9.readFile(USAGE_FILE, "utf8")).trim();
8913
+ if (await fs10.exists(USAGE_FILE)) {
8914
+ const rawContent = (await fs10.readFile(USAGE_FILE, "utf8")).trim();
8596
8915
  if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
8597
8916
  primaryData = JSON.parse(rawContent);
8598
8917
  } else {
@@ -8603,8 +8922,8 @@ var init_usage = __esm({
8603
8922
  }
8604
8923
  }
8605
8924
  try {
8606
- if (await fs9.exists(BACKUP_FILE)) {
8607
- const rawContent = (await fs9.readFile(BACKUP_FILE, "utf8")).trim();
8925
+ if (await fs10.exists(BACKUP_FILE)) {
8926
+ const rawContent = (await fs10.readFile(BACKUP_FILE, "utf8")).trim();
8608
8927
  if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
8609
8928
  backupData = JSON.parse(rawContent);
8610
8929
  } else {
@@ -8618,8 +8937,8 @@ var init_usage = __esm({
8618
8937
  if (primaryData.saveId !== backupData.saveId) {
8619
8938
  resolvedData = primaryData;
8620
8939
  try {
8621
- await fs9.ensureDir(path8.dirname(BACKUP_FILE));
8622
- await fs9.copy(USAGE_FILE, BACKUP_FILE);
8940
+ await fs10.ensureDir(path9.dirname(BACKUP_FILE));
8941
+ await fs10.copy(USAGE_FILE, BACKUP_FILE);
8623
8942
  } catch (e) {
8624
8943
  }
8625
8944
  } else {
@@ -8628,15 +8947,15 @@ var init_usage = __esm({
8628
8947
  } else if (primaryData && !backupData) {
8629
8948
  resolvedData = primaryData;
8630
8949
  try {
8631
- await fs9.ensureDir(path8.dirname(BACKUP_FILE));
8632
- await fs9.copy(USAGE_FILE, BACKUP_FILE);
8950
+ await fs10.ensureDir(path9.dirname(BACKUP_FILE));
8951
+ await fs10.copy(USAGE_FILE, BACKUP_FILE);
8633
8952
  } catch (e) {
8634
8953
  }
8635
8954
  } else if (!primaryData && backupData) {
8636
8955
  resolvedData = backupData;
8637
8956
  try {
8638
- await fs9.ensureDir(path8.dirname(USAGE_FILE));
8639
- await fs9.copy(BACKUP_FILE, USAGE_FILE);
8957
+ await fs10.ensureDir(path9.dirname(USAGE_FILE));
8958
+ await fs10.copy(BACKUP_FILE, USAGE_FILE);
8640
8959
  } catch (e) {
8641
8960
  }
8642
8961
  }
@@ -8676,11 +8995,11 @@ var init_usage = __esm({
8676
8995
  flushUsage = async () => {
8677
8996
  if (!isDirty || !cachedUsage) return;
8678
8997
  try {
8679
- await fs9.ensureDir(path8.dirname(USAGE_FILE));
8998
+ await fs10.ensureDir(path9.dirname(USAGE_FILE));
8680
8999
  let diskData = null;
8681
9000
  try {
8682
- if (await fs9.exists(USAGE_FILE)) {
8683
- const rawContent = (await fs9.readFile(USAGE_FILE, "utf8")).trim();
9001
+ if (await fs10.exists(USAGE_FILE)) {
9002
+ const rawContent = (await fs10.readFile(USAGE_FILE, "utf8")).trim();
8684
9003
  if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
8685
9004
  diskData = JSON.parse(rawContent);
8686
9005
  } else {
@@ -8756,14 +9075,14 @@ var init_usage = __esm({
8756
9075
  cachedUsage.saveId = generateSaveId();
8757
9076
  const tempFile = USAGE_FILE + ".tmp";
8758
9077
  const encryptedStr = encryptAes(JSON.stringify(cachedUsage, null, 2));
8759
- await fs9.writeFile(tempFile, encryptedStr, "utf8");
8760
- const fd = await fs9.open(tempFile, "r+");
8761
- await fs9.fsync(fd);
8762
- await fs9.close(fd);
8763
- await fs9.rename(tempFile, USAGE_FILE);
9078
+ await fs10.writeFile(tempFile, encryptedStr, "utf8");
9079
+ const fd = await fs10.open(tempFile, "r+");
9080
+ await fs10.fsync(fd);
9081
+ await fs10.close(fd);
9082
+ await fs10.rename(tempFile, USAGE_FILE);
8764
9083
  try {
8765
- await fs9.ensureDir(path8.dirname(BACKUP_FILE));
8766
- await fs9.copy(USAGE_FILE, BACKUP_FILE);
9084
+ await fs10.ensureDir(path9.dirname(BACKUP_FILE));
9085
+ await fs10.copy(USAGE_FILE, BACKUP_FILE);
8767
9086
  } catch (backupErr) {
8768
9087
  }
8769
9088
  isDirty = false;
@@ -9247,8 +9566,8 @@ var init_usage = __esm({
9247
9566
 
9248
9567
  // src/utils/puppeteer_helper.js
9249
9568
  import os4 from "os";
9250
- import path9 from "path";
9251
- import fs10 from "fs";
9569
+ import path10 from "path";
9570
+ import fs11 from "fs";
9252
9571
  import { createRequire } from "module";
9253
9572
  import { fileURLToPath as fileURLToPath2 } from "url";
9254
9573
  function getPuppeteerConfig() {
@@ -9273,11 +9592,11 @@ function getPuppeteerConfig() {
9273
9592
  } else {
9274
9593
  return {};
9275
9594
  }
9276
- let configPath = path9.resolve(__dirname2, "..", "..", ".puppeteerrc.cjs");
9277
- if (!fs10.existsSync(configPath)) {
9278
- configPath = path9.resolve(__dirname2, "..", ".puppeteerrc.cjs");
9595
+ let configPath = path10.resolve(__dirname2, "..", "..", ".puppeteerrc.cjs");
9596
+ if (!fs11.existsSync(configPath)) {
9597
+ configPath = path10.resolve(__dirname2, "..", ".puppeteerrc.cjs");
9279
9598
  }
9280
- if (!fs10.existsSync(configPath)) {
9599
+ if (!fs11.existsSync(configPath)) {
9281
9600
  return {};
9282
9601
  }
9283
9602
  try {
@@ -9287,14 +9606,14 @@ function getPuppeteerConfig() {
9287
9606
  if (cacheDir) {
9288
9607
  process.env.PUPPETEER_CACHE_DIR = cacheDir;
9289
9608
  if (version) {
9290
- const expectedPath = path9.join(
9609
+ const expectedPath = path10.join(
9291
9610
  cacheDir,
9292
9611
  "chrome",
9293
9612
  `${pptrPlatform}-${version}`,
9294
9613
  subDir,
9295
9614
  execName
9296
9615
  );
9297
- if (fs10.existsSync(expectedPath)) {
9616
+ if (fs11.existsSync(expectedPath)) {
9298
9617
  return {
9299
9618
  executablePath: expectedPath,
9300
9619
  cacheDirectory: cacheDir
@@ -9302,15 +9621,15 @@ function getPuppeteerConfig() {
9302
9621
  }
9303
9622
  }
9304
9623
  const findExecutable = (dir) => {
9305
- if (!fs10.existsSync(dir)) return null;
9624
+ if (!fs11.existsSync(dir)) return null;
9306
9625
  try {
9307
- const files = fs10.readdirSync(dir);
9626
+ const files = fs11.readdirSync(dir);
9308
9627
  const dirsToSearch = [];
9309
9628
  for (const file of files) {
9310
- const fullPath = path9.join(dir, file);
9629
+ const fullPath = path10.join(dir, file);
9311
9630
  let stat;
9312
9631
  try {
9313
- stat = fs10.statSync(fullPath);
9632
+ stat = fs11.statSync(fullPath);
9314
9633
  } catch (e) {
9315
9634
  continue;
9316
9635
  }
@@ -9356,14 +9675,14 @@ var require2, __dirname2;
9356
9675
  var init_puppeteer_helper = __esm({
9357
9676
  "src/utils/puppeteer_helper.js"() {
9358
9677
  require2 = createRequire(import.meta.url);
9359
- __dirname2 = path9.dirname(fileURLToPath2(import.meta.url));
9678
+ __dirname2 = path10.dirname(fileURLToPath2(import.meta.url));
9360
9679
  }
9361
9680
  });
9362
9681
 
9363
9682
  // src/tools/web_search.js
9364
9683
  import puppeteer from "puppeteer";
9365
- import fs11 from "fs";
9366
- import path10 from "path";
9684
+ import fs12 from "fs";
9685
+ import path11 from "path";
9367
9686
  var web_search;
9368
9687
  var init_web_search = __esm({
9369
9688
  "src/tools/web_search.js"() {
@@ -9512,7 +9831,7 @@ Sources:
9512
9831
  ${aiResult}`;
9513
9832
  } catch (err) {
9514
9833
  lastError = err;
9515
- fs11.writeFileSync(path10.join(LOGS_DIR, "web_tools", "search", "ai_mode", "ERROR.txt"), err.message);
9834
+ fs12.writeFileSync(path11.join(LOGS_DIR, "web_tools", "search", "ai_mode", "ERROR.txt"), err.message);
9516
9835
  if (browser) await browser.close();
9517
9836
  if (attempt < maxRetries) {
9518
9837
  const backoff = Math.pow(2, attempt) * 1e3;
@@ -9574,7 +9893,7 @@ ${finalResults}`;
9574
9893
  } catch (err) {
9575
9894
  lastError = err;
9576
9895
  if (browser) await browser.close();
9577
- fs11.writeFileSync(path10.join(LOGS_DIR, "web_tools", "search", "standard_mode", "ERROR.txt"), err.message);
9896
+ fs12.writeFileSync(path11.join(LOGS_DIR, "web_tools", "search", "standard_mode", "ERROR.txt"), err.message);
9578
9897
  if (attempt < maxRetries) {
9579
9898
  const backoff = Math.pow(2, attempt) * 1e3;
9580
9899
  await new Promise((r) => setTimeout(r, backoff));
@@ -9588,8 +9907,8 @@ ${finalResults}`;
9588
9907
 
9589
9908
  // src/tools/web_scrape.js
9590
9909
  import puppeteer2 from "puppeteer";
9591
- import fs12 from "fs";
9592
- import path11 from "path";
9910
+ import fs13 from "fs";
9911
+ import path12 from "path";
9593
9912
  var web_scrape;
9594
9913
  var init_web_scrape = __esm({
9595
9914
  "src/tools/web_scrape.js"() {
@@ -9666,7 +9985,7 @@ ${cleanedHtml}${htmlContent.length > 5e4 ? "\n\n[TRUNCATED AT 50K CHARS]" : ""}`
9666
9985
  } catch (err) {
9667
9986
  lastError = err;
9668
9987
  if (browser) await browser.close();
9669
- fs12.writeFileSync(path11.join(LOGS_DIR, "web_tools", "scrape", "standard_mode", "ERROR.txt"), err.message);
9988
+ fs13.writeFileSync(path12.join(LOGS_DIR, "web_tools", "scrape", "standard_mode", "ERROR.txt"), err.message);
9670
9989
  if (attempt < maxRetries) {
9671
9990
  const backoff = Math.pow(2, attempt) * 1e3;
9672
9991
  await new Promise((r) => setTimeout(r, backoff));
@@ -9790,8 +10109,8 @@ var init_chat = __esm({
9790
10109
  });
9791
10110
 
9792
10111
  // src/tools/view_file.js
9793
- import fs13 from "fs";
9794
- import path12 from "path";
10112
+ import fs14 from "fs";
10113
+ import path13 from "path";
9795
10114
  var view_file;
9796
10115
  var init_view_file = __esm({
9797
10116
  "src/tools/view_file.js"() {
@@ -9803,16 +10122,16 @@ var init_view_file = __esm({
9803
10122
  const finalStart = sLine || 1;
9804
10123
  const finalEnd = eLine || (sLine ? sLine + 800 : 800);
9805
10124
  if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
9806
- const absolutePath = path12.resolve(process.cwd(), targetPath);
10125
+ const absolutePath = path13.resolve(process.cwd(), targetPath);
9807
10126
  try {
9808
- if (!fs13.existsSync(absolutePath)) {
10127
+ if (!fs14.existsSync(absolutePath)) {
9809
10128
  return `ERROR: File [${targetPath}] does not exist.`;
9810
10129
  }
9811
- const stats = fs13.statSync(absolutePath);
10130
+ const stats = fs14.statSync(absolutePath);
9812
10131
  if (stats.isDirectory()) {
9813
10132
  return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
9814
10133
  }
9815
- const ext = path12.extname(targetPath).toLowerCase();
10134
+ const ext = path13.extname(targetPath).toLowerCase();
9816
10135
  const videoExtensions = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".mpeg", ".mpg"];
9817
10136
  if (videoExtensions.includes(ext)) {
9818
10137
  const format = ext.slice(1).toUpperCase();
@@ -9832,7 +10151,7 @@ var init_view_file = __esm({
9832
10151
  if (!isMultiModal) {
9833
10152
  return `ERROR: Multimodality is not supported for the current model. Unable to load [${targetPath}].`;
9834
10153
  }
9835
- const buffer = fs13.readFileSync(absolutePath);
10154
+ const buffer = fs14.readFileSync(absolutePath);
9836
10155
  const base64 = buffer.toString("base64");
9837
10156
  const mimeType = mimeMap[ext];
9838
10157
  return {
@@ -9845,7 +10164,7 @@ var init_view_file = __esm({
9845
10164
  }
9846
10165
  };
9847
10166
  }
9848
- let content = fs13.readFileSync(absolutePath, "utf8");
10167
+ let content = fs14.readFileSync(absolutePath, "utf8");
9849
10168
  if (content.startsWith("\uFEFF")) {
9850
10169
  content = content.slice(1);
9851
10170
  }
@@ -9869,8 +10188,8 @@ ${code}`;
9869
10188
  });
9870
10189
 
9871
10190
  // src/tools/write_file.js
9872
- import fs14 from "fs";
9873
- import path13 from "path";
10191
+ import fs15 from "fs";
10192
+ import path14 from "path";
9874
10193
  var write_file;
9875
10194
  var init_write_file = __esm({
9876
10195
  "src/tools/write_file.js"() {
@@ -9881,14 +10200,14 @@ var init_write_file = __esm({
9881
10200
  if (!targetPath) return 'ERROR: Missing "path" argument for write_file.';
9882
10201
  if (content === void 0) return 'ERROR: Missing "content" argument for write_file.';
9883
10202
  content = content.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
9884
- const absolutePath = path13.resolve(process.cwd(), targetPath);
9885
- const parentDir = path13.dirname(absolutePath);
10203
+ const absolutePath = path14.resolve(process.cwd(), targetPath);
10204
+ const parentDir = path14.dirname(absolutePath);
9886
10205
  try {
9887
10206
  await RevertManager.recordFileChange(absolutePath);
9888
10207
  let ancestry = "";
9889
- if (fs14.existsSync(absolutePath)) {
10208
+ if (fs15.existsSync(absolutePath)) {
9890
10209
  try {
9891
- const oldData = fs14.readFileSync(absolutePath, "utf8");
10210
+ const oldData = fs15.readFileSync(absolutePath, "utf8");
9892
10211
  const lines = oldData.split(/\r?\n/);
9893
10212
  ancestry = `Old File contents:
9894
10213
  ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
@@ -9900,16 +10219,16 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
9900
10219
  `;
9901
10220
  }
9902
10221
  }
9903
- if (!fs14.existsSync(parentDir)) {
9904
- fs14.mkdirSync(parentDir, { recursive: true });
10222
+ if (!fs15.existsSync(parentDir)) {
10223
+ fs15.mkdirSync(parentDir, { recursive: true });
9905
10224
  }
9906
10225
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
9907
10226
  const processedContent = strip(content);
9908
10227
  const finalContent = processedContent.endsWith("\n") ? processedContent : processedContent + "\n";
9909
10228
  const lineCount = finalContent.split(/\r?\n/).length;
9910
10229
  const originalSize = Buffer.byteLength(finalContent, "utf8");
9911
- fs14.writeFileSync(absolutePath, finalContent, "utf8");
9912
- let verifiedContent = fs14.readFileSync(absolutePath, "utf8");
10230
+ fs15.writeFileSync(absolutePath, finalContent, "utf8");
10231
+ let verifiedContent = fs15.readFileSync(absolutePath, "utf8");
9913
10232
  const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
9914
10233
  const verifiedLines = verifiedContent.split(/\r?\n/);
9915
10234
  const verifiedLineCount = verifiedLines.length;
@@ -9944,8 +10263,8 @@ ${snippet}`;
9944
10263
  });
9945
10264
 
9946
10265
  // src/tools/update_file.js
9947
- import fs15 from "fs";
9948
- import path14 from "path";
10266
+ import fs16 from "fs";
10267
+ import path15 from "path";
9949
10268
  var update_file;
9950
10269
  var init_update_file = __esm({
9951
10270
  "src/tools/update_file.js"() {
@@ -9961,12 +10280,12 @@ var init_update_file = __esm({
9961
10280
  if (patchPairs.length === 0) {
9962
10281
  return "ERROR: No valid replacement pairs found. Use replaceContent1, newContent1, etc.";
9963
10282
  }
9964
- const absolutePath = path14.resolve(process.cwd(), targetPath);
10283
+ const absolutePath = path15.resolve(process.cwd(), targetPath);
9965
10284
  try {
9966
- if (!fs15.existsSync(absolutePath)) {
10285
+ if (!fs16.existsSync(absolutePath)) {
9967
10286
  return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
9968
10287
  }
9969
- let diskContent = context.forcedContent || fs15.readFileSync(absolutePath, "utf8");
10288
+ let diskContent = context.forcedContent || fs16.readFileSync(absolutePath, "utf8");
9970
10289
  if (diskContent.startsWith("\uFEFF")) diskContent = diskContent.slice(1);
9971
10290
  const originalContent = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
9972
10291
  const { content: finalContent, results } = applyPatches(originalContent, patchPairs);
@@ -9977,7 +10296,7 @@ var init_update_file = __esm({
9977
10296
  ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
9978
10297
  }
9979
10298
  await RevertManager.recordFileChange(absolutePath, originalContent);
9980
- fs15.writeFileSync(absolutePath, finalContent, "utf8");
10299
+ fs16.writeFileSync(absolutePath, finalContent, "utf8");
9981
10300
  const diffText = generateHighFidelityDiff(originalContent, finalContent, results, 12);
9982
10301
  if (failures.length > 0) {
9983
10302
  return `SUCCESS: File [${targetPath}] updated with some blocks failed. [${successes.length}/${patchPairs.length}] blocks applied.
@@ -9999,34 +10318,34 @@ ${diffText}`;
9999
10318
  });
10000
10319
 
10001
10320
  // src/tools/read_folder.js
10002
- import fs16 from "fs";
10003
- import path15 from "path";
10321
+ import fs17 from "fs";
10322
+ import path16 from "path";
10004
10323
  var read_folder;
10005
10324
  var init_read_folder = __esm({
10006
10325
  "src/tools/read_folder.js"() {
10007
10326
  init_arg_parser();
10008
10327
  read_folder = async (args) => {
10009
10328
  const { path: targetPath = "." } = parseArgs(args);
10010
- const absolutePath = path15.resolve(process.cwd(), targetPath);
10329
+ const absolutePath = path16.resolve(process.cwd(), targetPath);
10011
10330
  try {
10012
- if (!fs16.existsSync(absolutePath)) {
10331
+ if (!fs17.existsSync(absolutePath)) {
10013
10332
  return `ERROR: Path [${targetPath}] does not exist.`;
10014
10333
  }
10015
- const stats = fs16.statSync(absolutePath);
10334
+ const stats = fs17.statSync(absolutePath);
10016
10335
  if (!stats.isDirectory()) {
10017
10336
  return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
10018
10337
  }
10019
- const files = fs16.readdirSync(absolutePath);
10338
+ const files = fs17.readdirSync(absolutePath);
10020
10339
  const totalItems = files.length;
10021
10340
  const maxDisplay = 100;
10022
10341
  const displayItems = files.slice(0, maxDisplay);
10023
10342
  const folderData = [];
10024
10343
  for (const file of displayItems) {
10025
- const fPath = path15.join(absolutePath, file);
10344
+ const fPath = path16.join(absolutePath, file);
10026
10345
  let indicator = "\u{1F4C4}";
10027
10346
  let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
10028
10347
  try {
10029
- const fStats = fs16.statSync(fPath);
10348
+ const fStats = fs17.statSync(fPath);
10030
10349
  info = {
10031
10350
  name: file,
10032
10351
  type: fStats.isDirectory() ? "directory" : "file",
@@ -10111,8 +10430,8 @@ var init_ask_user = __esm({
10111
10430
 
10112
10431
  // src/tools/write_pdf.js
10113
10432
  import puppeteer3 from "puppeteer";
10114
- import path16 from "path";
10115
- import fs17 from "fs-extra";
10433
+ import path17 from "path";
10434
+ import fs18 from "fs-extra";
10116
10435
  import { PDFDocument } from "pdf-lib";
10117
10436
  var write_pdf;
10118
10437
  var init_write_pdf = __esm({
@@ -10129,10 +10448,10 @@ var init_write_pdf = __esm({
10129
10448
  } = parseArgs(args);
10130
10449
  if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
10131
10450
  if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
10132
- const absolutePath = path16.resolve(process.cwd(), targetPath);
10451
+ const absolutePath = path17.resolve(process.cwd(), targetPath);
10133
10452
  let browser = null;
10134
10453
  try {
10135
- await fs17.ensureDir(path16.dirname(absolutePath));
10454
+ await fs18.ensureDir(path17.dirname(absolutePath));
10136
10455
  await RevertManager.recordFileChange(absolutePath);
10137
10456
  const pptrConfig = getPuppeteerConfig();
10138
10457
  browser = await puppeteer3.launch({
@@ -10153,11 +10472,11 @@ var init_write_pdf = __esm({
10153
10472
  return null;
10154
10473
  }
10155
10474
  try {
10156
- const imgPath = path16.resolve(process.cwd(), originalSrc);
10157
- if (await fs17.pathExists(imgPath)) {
10158
- const ext = path16.extname(imgPath).toLowerCase().replace(".", "") || "png";
10475
+ const imgPath = path17.resolve(process.cwd(), originalSrc);
10476
+ if (await fs18.pathExists(imgPath)) {
10477
+ const ext = path17.extname(imgPath).toLowerCase().replace(".", "") || "png";
10159
10478
  const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
10160
- const base64 = await fs17.readFile(imgPath, "base64");
10479
+ const base64 = await fs18.readFile(imgPath, "base64");
10161
10480
  return `data:image/${mime};base64,${base64}`;
10162
10481
  }
10163
10482
  } catch (e) {
@@ -10172,9 +10491,9 @@ var init_write_pdf = __esm({
10172
10491
  const fullTag = match[0];
10173
10492
  if (originalHref && fullTag.toLowerCase().includes("stylesheet") && !originalHref.startsWith("http://") && !originalHref.startsWith("https://") && !originalHref.startsWith("data:")) {
10174
10493
  try {
10175
- const cssPath = path16.resolve(process.cwd(), originalHref);
10176
- if (await fs17.pathExists(cssPath)) {
10177
- const cssContent = await fs17.readFile(cssPath, "utf-8");
10494
+ const cssPath = path17.resolve(process.cwd(), originalHref);
10495
+ if (await fs18.pathExists(cssPath)) {
10496
+ const cssContent = await fs18.readFile(cssPath, "utf-8");
10178
10497
  cssCache[fullTag] = `<style>${cssContent}</style>`;
10179
10498
  }
10180
10499
  } catch (e) {
@@ -10255,7 +10574,7 @@ var init_write_pdf = __esm({
10255
10574
  printBackground: true
10256
10575
  });
10257
10576
  const pdfDoc = await PDFDocument.load(pdfBytes);
10258
- const fileName = path16.basename(targetPath);
10577
+ const fileName = path17.basename(targetPath);
10259
10578
  pdfDoc.setTitle(`FluxFlow_${fileName}`);
10260
10579
  pdfDoc.setAuthor("FluxFlow CLI");
10261
10580
  pdfDoc.setSubject("Generated with Agentic AI System");
@@ -10263,8 +10582,8 @@ var init_write_pdf = __esm({
10263
10582
  pdfDoc.setCreator("FluxFlow PDF Engine");
10264
10583
  pdfDoc.setProducer("FluxFlow (Generative AI)");
10265
10584
  const finalPdfBytes = await pdfDoc.save();
10266
- await fs17.writeFile(absolutePath, finalPdfBytes);
10267
- const stats = await fs17.stat(absolutePath);
10585
+ await fs18.writeFile(absolutePath, finalPdfBytes);
10586
+ const stats = await fs18.stat(absolutePath);
10268
10587
  return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
10269
10588
  } catch (err) {
10270
10589
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -10277,8 +10596,8 @@ var init_write_pdf = __esm({
10277
10596
  });
10278
10597
 
10279
10598
  // src/tools/write_docx.js
10280
- import fs18 from "fs-extra";
10281
- import path17 from "path";
10599
+ import fs19 from "fs-extra";
10600
+ import path18 from "path";
10282
10601
  import HTMLtoDOCX from "html-to-docx";
10283
10602
  var write_docx;
10284
10603
  var init_write_docx = __esm({
@@ -10292,11 +10611,11 @@ var init_write_docx = __esm({
10292
10611
  } = parseArgs(args);
10293
10612
  if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
10294
10613
  if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
10295
- const absolutePath = path17.resolve(process.cwd(), targetPath);
10614
+ const absolutePath = path18.resolve(process.cwd(), targetPath);
10296
10615
  try {
10297
- await fs18.ensureDir(path17.dirname(absolutePath));
10616
+ await fs19.ensureDir(path18.dirname(absolutePath));
10298
10617
  await RevertManager.recordFileChange(absolutePath);
10299
- const fileName = path17.basename(targetPath);
10618
+ const fileName = path18.basename(targetPath);
10300
10619
  const fullHtml = content.includes("<html") ? content : `
10301
10620
  <!DOCTYPE html>
10302
10621
  <html lang="en">
@@ -10317,7 +10636,7 @@ var init_write_docx = __esm({
10317
10636
  footer: true,
10318
10637
  pageNumber: true
10319
10638
  });
10320
- await fs18.writeFile(absolutePath, docxBuffer);
10639
+ await fs19.writeFile(absolutePath, docxBuffer);
10321
10640
  return `SUCCESS: Word document [${targetPath}] generated successfully.
10322
10641
  - Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
10323
10642
  } catch (err) {
@@ -10329,21 +10648,21 @@ var init_write_docx = __esm({
10329
10648
  });
10330
10649
 
10331
10650
  // src/tools/search_keyword.js
10332
- import fs19 from "fs/promises";
10333
- import path18 from "path";
10651
+ import fs20 from "fs/promises";
10652
+ import path19 from "path";
10334
10653
  async function getFilesRecursively(dir, excludes, baseDir = dir, depth = 1) {
10335
10654
  if (depth > 12) return [];
10336
10655
  let results = [];
10337
10656
  let list;
10338
10657
  try {
10339
- list = await fs19.readdir(dir, { withFileTypes: true });
10658
+ list = await fs20.readdir(dir, { withFileTypes: true });
10340
10659
  } catch {
10341
10660
  return [];
10342
10661
  }
10343
10662
  for (const file of list) {
10344
- const fullPath = path18.join(dir, file.name);
10345
- const relativePath = path18.relative(baseDir, fullPath);
10346
- const pathSegments = relativePath.split(path18.sep).map((s) => s.toLowerCase());
10663
+ const fullPath = path19.join(dir, file.name);
10664
+ const relativePath = path19.relative(baseDir, fullPath);
10665
+ const pathSegments = relativePath.split(path19.sep).map((s) => s.toLowerCase());
10347
10666
  const isExcluded = excludes.some((ex) => pathSegments.includes(ex.toLowerCase()));
10348
10667
  if (isExcluded) continue;
10349
10668
  if (file.isDirectory()) {
@@ -10444,15 +10763,15 @@ var init_search_keyword = __esm({
10444
10763
  let pathArgType = null;
10445
10764
  if (pathArg) {
10446
10765
  const normalised = pathArg.replace(/[\/\\]+$/, "");
10447
- const fullPath = path18.resolve(rootDir, normalised);
10766
+ const fullPath = path19.resolve(rootDir, normalised);
10448
10767
  try {
10449
- const stat = await fs19.stat(fullPath);
10768
+ const stat = await fs20.stat(fullPath);
10450
10769
  if (stat.isDirectory()) {
10451
10770
  pathArgType = "dir";
10452
10771
  filesToSearch = await getFilesRecursively(fullPath, excludes, rootDir);
10453
10772
  } else if (stat.isFile()) {
10454
10773
  pathArgType = "file";
10455
- filesToSearch.push({ fullPath, relativePath: path18.relative(rootDir, fullPath) });
10774
+ filesToSearch.push({ fullPath, relativePath: path19.relative(rootDir, fullPath) });
10456
10775
  } else {
10457
10776
  return `ERROR: Path is neither a file nor a directory: ${pathArg}`;
10458
10777
  }
@@ -10464,7 +10783,7 @@ var init_search_keyword = __esm({
10464
10783
  }
10465
10784
  const searchPromises = filesToSearch.map(async (fileObj) => {
10466
10785
  try {
10467
- const content = await fs19.readFile(fileObj.fullPath, "utf-8");
10786
+ const content = await fs20.readFile(fileObj.fullPath, "utf-8");
10468
10787
  if (content.includes("\0")) return [];
10469
10788
  const lines = content.split(/\r?\n/);
10470
10789
  const fileMatches = [];
@@ -10536,8 +10855,8 @@ var init_search_keyword = __esm({
10536
10855
  });
10537
10856
 
10538
10857
  // src/tools/generate_image.js
10539
- import fs20 from "fs-extra";
10540
- import path19 from "path";
10858
+ import fs21 from "fs-extra";
10859
+ import path20 from "path";
10541
10860
  var injectPngMetadata, generate_image;
10542
10861
  var init_generate_image = __esm({
10543
10862
  "src/tools/generate_image.js"() {
@@ -10716,12 +11035,12 @@ var init_generate_image = __esm({
10716
11035
  "Seed": String(seed)
10717
11036
  };
10718
11037
  finalBuffer = injectPngMetadata(finalBuffer, metadata);
10719
- const absolutePath = path19.resolve(process.cwd(), outputPath);
10720
- await fs20.ensureDir(path19.dirname(absolutePath));
11038
+ const absolutePath = path20.resolve(process.cwd(), outputPath);
11039
+ await fs21.ensureDir(path20.dirname(absolutePath));
10721
11040
  await RevertManager.recordFileChange(absolutePath);
10722
- await fs20.writeFile(absolutePath, finalBuffer);
11041
+ await fs21.writeFile(absolutePath, finalBuffer);
10723
11042
  await recordImageGeneration(settings);
10724
- const ext = path19.extname(outputPath).toLowerCase();
11043
+ const ext = path20.extname(outputPath).toLowerCase();
10725
11044
  const mimeMap = {
10726
11045
  ".jpg": "image/jpeg",
10727
11046
  ".jpeg": "image/jpeg",
@@ -10836,13 +11155,13 @@ var init_addMemScore = __esm({
10836
11155
  });
10837
11156
 
10838
11157
  // src/utils/parsers.js
10839
- import fs21 from "fs-extra";
10840
- import path20 from "path";
11158
+ import fs22 from "fs-extra";
11159
+ import path21 from "path";
10841
11160
  import https from "https";
10842
11161
  async function downloadWasm(wasmFile, targetUrl = null) {
10843
11162
  const url = targetUrl || `https://unpkg.com/tree-sitter-wasms@0.1.13/out/${wasmFile}`;
10844
- const localPath = path20.join(PARSER_DIR, wasmFile);
10845
- await fs21.ensureDir(PARSER_DIR);
11163
+ const localPath = path21.join(PARSER_DIR, wasmFile);
11164
+ await fs22.ensureDir(PARSER_DIR);
10846
11165
  return new Promise((resolve, reject) => {
10847
11166
  const options = {
10848
11167
  headers: {
@@ -10863,27 +11182,27 @@ async function downloadWasm(wasmFile, targetUrl = null) {
10863
11182
  reject(new Error(`Failed to download ${wasmFile}: HTTP ${response.statusCode}`));
10864
11183
  return;
10865
11184
  }
10866
- const file = fs21.createWriteStream(localPath);
11185
+ const file = fs22.createWriteStream(localPath);
10867
11186
  response.pipe(file);
10868
11187
  file.on("finish", () => {
10869
11188
  file.close();
10870
11189
  resolve();
10871
11190
  });
10872
11191
  }).on("error", (err) => {
10873
- if (fs21.existsSync(localPath)) fs21.unlink(localPath, () => {
11192
+ if (fs22.existsSync(localPath)) fs22.unlink(localPath, () => {
10874
11193
  });
10875
11194
  reject(err);
10876
11195
  });
10877
11196
  });
10878
11197
  }
10879
11198
  function isParserInstalled(wasmFile) {
10880
- const localPath = path20.join(PARSER_DIR, wasmFile);
10881
- return fs21.existsSync(localPath);
11199
+ const localPath = path21.join(PARSER_DIR, wasmFile);
11200
+ return fs22.existsSync(localPath);
10882
11201
  }
10883
11202
  async function deleteParser(wasmFile) {
10884
- const localPath = path20.join(PARSER_DIR, wasmFile);
10885
- if (fs21.existsSync(localPath)) {
10886
- await fs21.unlink(localPath);
11203
+ const localPath = path21.join(PARSER_DIR, wasmFile);
11204
+ if (fs22.existsSync(localPath)) {
11205
+ await fs22.unlink(localPath);
10887
11206
  }
10888
11207
  }
10889
11208
  var EXTENSION_TO_WASM;
@@ -10905,8 +11224,8 @@ var init_parsers = __esm({
10905
11224
  });
10906
11225
 
10907
11226
  // src/tools/file_map.js
10908
- import fs22 from "fs-extra";
10909
- import path21 from "path";
11227
+ import fs23 from "fs-extra";
11228
+ import path22 from "path";
10910
11229
  import { createRequire as createRequire2 } from "module";
10911
11230
  function sanitize(text, limit = 50) {
10912
11231
  if (!text) return "";
@@ -11098,17 +11417,17 @@ var init_file_map = __esm({
11098
11417
  if (!filePath) {
11099
11418
  return 'ERROR: No file path provided. Use [tool:functions.FileMap(path="...")]';
11100
11419
  }
11101
- const absolutePath = path21.isAbsolute(filePath) ? filePath : path21.resolve(process.cwd(), filePath);
11102
- if (!fs22.existsSync(absolutePath)) {
11420
+ const absolutePath = path22.isAbsolute(filePath) ? filePath : path22.resolve(process.cwd(), filePath);
11421
+ if (!fs23.existsSync(absolutePath)) {
11103
11422
  return `ERROR: File not found: ${filePath}`;
11104
11423
  }
11105
- const ext = path21.extname(absolutePath).slice(1).toLowerCase();
11424
+ const ext = path22.extname(absolutePath).slice(1).toLowerCase();
11106
11425
  const wasmFile = EXTENSION_TO_WASM[ext];
11107
11426
  if (!wasmFile) {
11108
11427
  return `ERROR: Unsupported file extension: .${ext}`;
11109
11428
  }
11110
- const wasmPath = path21.resolve(PARSER_DIR, wasmFile);
11111
- if (!fs22.existsSync(wasmPath)) {
11429
+ const wasmPath = path22.resolve(PARSER_DIR, wasmFile);
11430
+ if (!fs23.existsSync(wasmPath)) {
11112
11431
  return `ERROR: Parser for .${ext} not found. Please download it in Settings > Other.`;
11113
11432
  }
11114
11433
  try {
@@ -11116,9 +11435,9 @@ var init_file_map = __esm({
11116
11435
  if (!isParserInitialized) {
11117
11436
  let tsWasmPath;
11118
11437
  try {
11119
- tsWasmPath = path21.join(path21.dirname(require3.resolve("web-tree-sitter")), "tree-sitter.wasm");
11438
+ tsWasmPath = path22.join(path22.dirname(require3.resolve("web-tree-sitter")), "tree-sitter.wasm");
11120
11439
  } catch (e) {
11121
- tsWasmPath = path21.join(process.cwd(), "node_modules", "web-tree-sitter", "tree-sitter.wasm");
11440
+ tsWasmPath = path22.join(process.cwd(), "node_modules", "web-tree-sitter", "tree-sitter.wasm");
11122
11441
  }
11123
11442
  await Parser.init({
11124
11443
  locateFile: (p) => {
@@ -11133,7 +11452,7 @@ var init_file_map = __esm({
11133
11452
  const parser = new Parser();
11134
11453
  const Lang = await TreeSitter.Language.load(wasmPath);
11135
11454
  parser.setLanguage(Lang);
11136
- const sourceCode = await fs22.readFile(absolutePath, "utf8");
11455
+ const sourceCode = await fs23.readFile(absolutePath, "utf8");
11137
11456
  const lines = sourceCode.split("\n").length;
11138
11457
  let maxDepth = 12;
11139
11458
  if (lines > 1e4) maxDepth = 2;
@@ -11156,8 +11475,8 @@ Stack: ${err.stack}` : "";
11156
11475
  });
11157
11476
 
11158
11477
  // src/tools/todo.js
11159
- import fs23 from "fs";
11160
- import path22 from "path";
11478
+ import fs24 from "fs";
11479
+ import path23 from "path";
11161
11480
  var todo;
11162
11481
  var init_todo = __esm({
11163
11482
  "src/tools/todo.js"() {
@@ -11168,8 +11487,8 @@ var init_todo = __esm({
11168
11487
  const { method, tasks, markDone } = parseArgs(args);
11169
11488
  const chatId = context.chatId || "default";
11170
11489
  if (!method) return 'ERROR: Missing "method" argument for todo tool (create/append/get).';
11171
- const todoDir = path22.join(DATA_DIR, "plan", chatId);
11172
- const todoFile = path22.join(todoDir, "todo.md");
11490
+ const todoDir = path23.join(DATA_DIR, "plan", chatId);
11491
+ const todoFile = path23.join(todoDir, "todo.md");
11173
11492
  const parseMessyArray = (input) => {
11174
11493
  if (!input || Array.isArray(input)) return input;
11175
11494
  const trimmed = String(input).trim();
@@ -11229,8 +11548,8 @@ var init_todo = __esm({
11229
11548
  };
11230
11549
  };
11231
11550
  try {
11232
- if (!fs23.existsSync(todoDir)) {
11233
- fs23.mkdirSync(todoDir, { recursive: true });
11551
+ if (!fs24.existsSync(todoDir)) {
11552
+ fs24.mkdirSync(todoDir, { recursive: true });
11234
11553
  }
11235
11554
  if (method === "create") {
11236
11555
  if (!tasks) return 'ERROR: Missing "tasks" for create method.';
@@ -11242,7 +11561,7 @@ var init_todo = __esm({
11242
11561
  markedCount = result.markedCount;
11243
11562
  }
11244
11563
  await RevertManager.recordFileChange(todoFile);
11245
- fs23.writeFileSync(todoFile, content, "utf8");
11564
+ fs24.writeFileSync(todoFile, content, "utf8");
11246
11565
  const total = content.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.startsWith("- [ ]") || l.startsWith("- [x]") || l.startsWith("- [X]")).length;
11247
11566
  if (markedCount > 0) {
11248
11567
  const completed = content.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.startsWith("- [x]") || l.startsWith("- [X]")).length;
@@ -11256,8 +11575,8 @@ ${content}`;
11256
11575
  if (!tasks) return 'ERROR: Missing "tasks" for append method.';
11257
11576
  const appendContent = getTasksString(tasks);
11258
11577
  await RevertManager.recordFileChange(todoFile);
11259
- fs23.appendFileSync(todoFile, appendContent, "utf8");
11260
- const fullContent = fs23.readFileSync(todoFile, "utf8");
11578
+ fs24.appendFileSync(todoFile, appendContent, "utf8");
11579
+ const fullContent = fs24.readFileSync(todoFile, "utf8");
11261
11580
  const lines = fullContent.split(/\r?\n/).map((l) => l.trim());
11262
11581
  const total = lines.filter((l) => l.startsWith("- [ ]") || l.startsWith("- [x]") || l.startsWith("- [X]")).length;
11263
11582
  const completed = lines.filter((l) => l.startsWith("- [x]") || l.startsWith("- [X]")).length;
@@ -11266,10 +11585,10 @@ ${content}`;
11266
11585
  ${fullContent}`;
11267
11586
  }
11268
11587
  if (method === "get") {
11269
- if (!fs23.existsSync(todoFile)) {
11588
+ if (!fs24.existsSync(todoFile)) {
11270
11589
  return "TODO GET: No task list found for this session.";
11271
11590
  }
11272
- let content = fs23.readFileSync(todoFile, "utf8");
11591
+ let content = fs24.readFileSync(todoFile, "utf8");
11273
11592
  let markedCount = 0;
11274
11593
  if (markDone) {
11275
11594
  const result = applyMarkDone(content, markDone);
@@ -11277,7 +11596,7 @@ ${fullContent}`;
11277
11596
  content = result.content;
11278
11597
  markedCount = result.markedCount;
11279
11598
  await RevertManager.recordFileChange(todoFile);
11280
- fs23.writeFileSync(todoFile, content, "utf8");
11599
+ fs24.writeFileSync(todoFile, content, "utf8");
11281
11600
  }
11282
11601
  }
11283
11602
  const totalLines = content.split(/\r?\n/).map((l) => l.trim());
@@ -11673,20 +11992,20 @@ var init_await = __esm({
11673
11992
  });
11674
11993
 
11675
11994
  // src/utils/advanceRevert.js
11676
- import fs24 from "fs-extra";
11677
- import path23 from "path";
11995
+ import fs25 from "fs-extra";
11996
+ import path24 from "path";
11678
11997
  async function scanWorkspace(dir, baseDir = dir) {
11679
11998
  const manifest = {};
11680
- const entries = await fs24.readdir(dir, { withFileTypes: true }).catch(() => []);
11999
+ const entries = await fs25.readdir(dir, { withFileTypes: true }).catch(() => []);
11681
12000
  for (const entry of entries) {
11682
12001
  if (JUNK_DIRECTORIES.includes(entry.name)) continue;
11683
- const fullPath = path23.join(dir, entry.name);
11684
- const relPath = path23.relative(baseDir, fullPath).replace(/\\/g, "/");
12002
+ const fullPath = path24.join(dir, entry.name);
12003
+ const relPath = path24.relative(baseDir, fullPath).replace(/\\/g, "/");
11685
12004
  if (entry.isDirectory()) {
11686
12005
  const sub = await scanWorkspace(fullPath, baseDir);
11687
12006
  Object.assign(manifest, sub);
11688
12007
  } else {
11689
- const stats = await fs24.stat(fullPath).catch(() => null);
12008
+ const stats = await fs25.stat(fullPath).catch(() => null);
11690
12009
  if (stats) {
11691
12010
  manifest[relPath] = {
11692
12011
  size: stats.size,
@@ -11698,34 +12017,34 @@ async function scanWorkspace(dir, baseDir = dir) {
11698
12017
  return manifest;
11699
12018
  }
11700
12019
  async function copyWorkspaceFiles(destDir, manifest) {
11701
- await fs24.ensureDir(destDir);
12020
+ await fs25.ensureDir(destDir);
11702
12021
  for (const relPath of Object.keys(manifest)) {
11703
- const srcPath = path23.join(process.cwd(), relPath);
11704
- const destPath = path23.join(destDir, relPath);
11705
- await fs24.ensureDir(path23.dirname(destPath));
11706
- await fs24.copyFile(srcPath, destPath).catch(() => {
12022
+ const srcPath = path24.join(process.cwd(), relPath);
12023
+ const destPath = path24.join(destDir, relPath);
12024
+ await fs25.ensureDir(path24.dirname(destPath));
12025
+ await fs25.copyFile(srcPath, destPath).catch(() => {
11707
12026
  });
11708
12027
  }
11709
12028
  }
11710
12029
  async function restoreSnapshotDir(srcDir, destDir, stats = null, baseDir = null) {
11711
- if (!await fs24.pathExists(srcDir)) return;
12030
+ if (!await fs25.pathExists(srcDir)) return;
11712
12031
  if (!baseDir) baseDir = srcDir;
11713
- const entries = await fs24.readdir(srcDir, { withFileTypes: true }).catch(() => []);
12032
+ const entries = await fs25.readdir(srcDir, { withFileTypes: true }).catch(() => []);
11714
12033
  for (const entry of entries) {
11715
- const srcPath = path23.join(srcDir, entry.name);
11716
- const destPath = path23.join(destDir, entry.name);
12034
+ const srcPath = path24.join(srcDir, entry.name);
12035
+ const destPath = path24.join(destDir, entry.name);
11717
12036
  if (entry.isDirectory()) {
11718
12037
  await restoreSnapshotDir(srcPath, destPath, stats, baseDir);
11719
12038
  } else {
11720
- const relPath = path23.relative(baseDir, srcPath).replace(/\\/g, "/");
11721
- const existed = await fs24.pathExists(destPath);
12039
+ const relPath = path24.relative(baseDir, srcPath).replace(/\\/g, "/");
12040
+ const existed = await fs25.pathExists(destPath);
11722
12041
  if (existed) {
11723
- await fs24.chmod(destPath, 438).catch(() => {
12042
+ await fs25.chmod(destPath, 438).catch(() => {
11724
12043
  });
11725
12044
  }
11726
- await fs24.ensureDir(path23.dirname(destPath));
11727
- const ok = await fs24.copyFile(srcPath, destPath).then(() => true).catch(() => false);
11728
- await fs24.chmod(destPath, 438).catch(() => {
12045
+ await fs25.ensureDir(path24.dirname(destPath));
12046
+ const ok = await fs25.copyFile(srcPath, destPath).then(() => true).catch(() => false);
12047
+ await fs25.chmod(destPath, 438).catch(() => {
11729
12048
  });
11730
12049
  if (stats) {
11731
12050
  if (!ok) {
@@ -11763,12 +12082,12 @@ var init_advanceRevert = __esm({
11763
12082
  AdvanceRevertManager = {
11764
12083
  async takeInitialSnapshot(chatId) {
11765
12084
  try {
11766
- const snapshotsDir = path23.join(DATA_DIR, "snapshots", chatId);
11767
- await fs24.remove(snapshotsDir).catch(() => {
12085
+ const snapshotsDir = path24.join(DATA_DIR, "snapshots", chatId);
12086
+ await fs25.remove(snapshotsDir).catch(() => {
11768
12087
  });
11769
- await fs24.ensureDir(snapshotsDir);
12088
+ await fs25.ensureDir(snapshotsDir);
11770
12089
  const manifest = await scanWorkspace(process.cwd());
11771
- await copyWorkspaceFiles(path23.join(snapshotsDir, "initial"), manifest);
12090
+ await copyWorkspaceFiles(path24.join(snapshotsDir, "initial"), manifest);
11772
12091
  const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
11773
12092
  ledger[chatId] = {
11774
12093
  initialManifest: manifest,
@@ -11817,7 +12136,7 @@ var init_advanceRevert = __esm({
11817
12136
  for (const file of changedFiles) {
11818
12137
  deltaManifest[file] = currentManifest[file];
11819
12138
  }
11820
- const turnDir = path23.join(DATA_DIR, "snapshots", chatId, `turn_${turnNumber}`);
12139
+ const turnDir = path24.join(DATA_DIR, "snapshots", chatId, `turn_${turnNumber}`);
11821
12140
  await copyWorkspaceFiles(turnDir, deltaManifest);
11822
12141
  }
11823
12142
  session.checkpoints.push({
@@ -11851,28 +12170,28 @@ var init_advanceRevert = __esm({
11851
12170
  const checkpoints = session.checkpoints || [];
11852
12171
  const targetIdx = checkpoints.findIndex((c) => c.id === checkpointId);
11853
12172
  if (targetIdx === -1) throw new Error(`Checkpoint [${checkpointId}] not found.`);
11854
- const snapshotsDir = path23.join(DATA_DIR, "snapshots", chatId);
12173
+ const snapshotsDir = path24.join(DATA_DIR, "snapshots", chatId);
11855
12174
  const stats = { restored: 0, replaced: 0, failed: [] };
11856
12175
  const currentFiles = await scanWorkspace(process.cwd());
11857
12176
  for (const relPath of Object.keys(currentFiles)) {
11858
- const fullPath = path23.join(process.cwd(), relPath);
11859
- await fs24.chmod(fullPath, 438).catch(() => {
12177
+ const fullPath = path24.join(process.cwd(), relPath);
12178
+ await fs25.chmod(fullPath, 438).catch(() => {
11860
12179
  });
11861
- await fs24.remove(fullPath).catch(() => {
12180
+ await fs25.remove(fullPath).catch(() => {
11862
12181
  });
11863
12182
  }
11864
- const initialDir = path23.join(snapshotsDir, "initial");
12183
+ const initialDir = path24.join(snapshotsDir, "initial");
11865
12184
  await restoreSnapshotDir(initialDir, process.cwd(), stats, initialDir);
11866
12185
  for (let i = 1; i <= targetIdx; i++) {
11867
12186
  const cp = checkpoints[i];
11868
- const turnDir = path23.join(snapshotsDir, cp.id);
12187
+ const turnDir = path24.join(snapshotsDir, cp.id);
11869
12188
  await restoreSnapshotDir(turnDir, process.cwd(), stats, turnDir);
11870
12189
  if (cp.deletedFiles && cp.deletedFiles.length > 0) {
11871
12190
  for (const delFile of cp.deletedFiles) {
11872
- const fullPath = path23.join(process.cwd(), delFile);
11873
- await fs24.chmod(fullPath, 438).catch(() => {
12191
+ const fullPath = path24.join(process.cwd(), delFile);
12192
+ await fs25.chmod(fullPath, 438).catch(() => {
11874
12193
  });
11875
- await fs24.remove(fullPath).catch(() => {
12194
+ await fs25.remove(fullPath).catch(() => {
11876
12195
  });
11877
12196
  }
11878
12197
  }
@@ -11904,8 +12223,8 @@ var init_advanceRevert = __esm({
11904
12223
  },
11905
12224
  async cleanup(chatId) {
11906
12225
  try {
11907
- const snapshotsDir = path23.join(DATA_DIR, "snapshots", chatId);
11908
- await fs24.remove(snapshotsDir).catch(() => {
12226
+ const snapshotsDir = path24.join(DATA_DIR, "snapshots", chatId);
12227
+ await fs25.remove(snapshotsDir).catch(() => {
11909
12228
  });
11910
12229
  const ledger = readEncryptedJson(LEDGER_ADVANCE_FILE, {});
11911
12230
  if (ledger[chatId]) {
@@ -12260,8 +12579,8 @@ __export(ai_exports, {
12260
12579
  });
12261
12580
  import dotenv from "dotenv";
12262
12581
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
12263
- import path24, { normalize } from "path";
12264
- import fs25 from "fs";
12582
+ import path25, { normalize } from "path";
12583
+ import fs26 from "fs";
12265
12584
  var RE_STUTTER_CODE_BLOCK_CLOSED, RE_STUTTER_CODE_BLOCK_OPEN, RE_STUTTER_INLINE_CODE, RE_STUTTER_TABLE_ROW, RE_STUTTER_WORD_BOUNDARY, RE_STUTTER_NON_ALNUM, RE_TOOL_CALL_FUNC, RE_TOOL_PARTIAL_ARGS_FALLBACK, RE_STRIP_QUOTES, RE_BACKSLASH_SLASH, client, globalSettings, colorMainWords, withRetry, TERMINATION_SIGNAL, getCleanGroupedLength, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getMistralStream, getNVIDIAStream, wrapNvidiaStreamWithQueueDepth, getOpenRouterStream, signalTermination, isTerminationSignaled, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, translateKimiToolCalls, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, compressHistory, deleteChatSummary, getAIStream, runSubagent;
12266
12585
  var init_ai = __esm({
12267
12586
  async "src/utils/ai.js"() {
@@ -13240,7 +13559,7 @@ var init_ai = __esm({
13240
13559
  return pArgs.id || pArgs.taskId;
13241
13560
  }
13242
13561
  const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
13243
- return filePath ? path24.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
13562
+ return filePath ? path25.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
13244
13563
  } catch (e) {
13245
13564
  return null;
13246
13565
  }
@@ -13505,9 +13824,9 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
13505
13824
  }
13506
13825
  })() : String(err);
13507
13826
  await new Promise((resolve) => setTimeout(resolve, 1e3));
13508
- const janitorErrDir = path24.join(LOGS_DIR, "janitor");
13509
- if (!fs25.existsSync(janitorErrDir)) fs25.mkdirSync(janitorErrDir, { recursive: true });
13510
- fs25.appendFileSync(path24.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${errLog}
13827
+ const janitorErrDir = path25.join(LOGS_DIR, "janitor");
13828
+ if (!fs26.existsSync(janitorErrDir)) fs26.mkdirSync(janitorErrDir, { recursive: true });
13829
+ fs26.appendFileSync(path25.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${errLog}
13511
13830
 
13512
13831
  `);
13513
13832
  if (attempts > MAX_JANITOR_RETRIES) break;
@@ -13516,8 +13835,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
13516
13835
  }
13517
13836
  }
13518
13837
  if (attempts) {
13519
- const janitorErrDir = path24.join(LOGS_DIR, "janitor");
13520
- fs25.appendFileSync(path24.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
13838
+ const janitorErrDir = path25.join(LOGS_DIR, "janitor");
13839
+ fs26.appendFileSync(path25.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
13521
13840
 
13522
13841
  `);
13523
13842
  }
@@ -14050,10 +14369,10 @@ ${newMemoryListStr}
14050
14369
  }
14051
14370
  })() : String(err);
14052
14371
  ;
14053
- const janitorLogDir = path24.join(LOGS_DIR, "janitor");
14054
- if (!fs25.existsSync(janitorLogDir)) fs25.mkdirSync(janitorLogDir, { recursive: true });
14055
- fs25.appendFileSync(
14056
- path24.join(janitorLogDir, "error.log"),
14372
+ const janitorLogDir = path25.join(LOGS_DIR, "janitor");
14373
+ if (!fs26.existsSync(janitorLogDir)) fs26.mkdirSync(janitorLogDir, { recursive: true });
14374
+ fs26.appendFileSync(
14375
+ path25.join(janitorLogDir, "error.log"),
14057
14376
  `[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${errLog}
14058
14377
  `
14059
14378
  );
@@ -14061,7 +14380,7 @@ ${newMemoryListStr}
14061
14380
  };
14062
14381
  compressHistory = async (settings, history, isAuto = false) => {
14063
14382
  const { chatId, aiProvider = "Google" } = settings;
14064
- const summariesFile = path24.join(SECRET_DIR, "chat-summaries.json");
14383
+ const summariesFile = path25.join(SECRET_DIR, "chat-summaries.json");
14065
14384
  const flattenContext = (hist) => {
14066
14385
  return hist.filter(
14067
14386
  (m) => (m.role === "user" || m.role === "agent" || m.role === "system") && m.role !== "think" && !m.isVisualFeedback && !m.isMeta && !String(m.id).startsWith("welcome")
@@ -14136,8 +14455,8 @@ Provide a consolidated summary of the entire session.`;
14136
14455
  };
14137
14456
  deleteChatSummary = (chatId) => {
14138
14457
  try {
14139
- const summariesFile = path24.join(SECRET_DIR, "chat-summaries.json");
14140
- if (fs25.existsSync(summariesFile)) {
14458
+ const summariesFile = path25.join(SECRET_DIR, "chat-summaries.json");
14459
+ if (fs26.existsSync(summariesFile)) {
14141
14460
  const summaries = readEncryptedJson(summariesFile, {});
14142
14461
  if (summaries[chatId]) {
14143
14462
  delete summaries[chatId];
@@ -14153,7 +14472,7 @@ Provide a consolidated summary of the entire session.`;
14153
14472
  if (!client && aiProvider === "Google") throw new Error("AI not initialized");
14154
14473
  const isMemoryEnabled = systemSettings?.memory !== false;
14155
14474
  const originalText = history[history.length - 1].text;
14156
- const summariesFile = path24.join(SECRET_DIR, "chat-summaries.json");
14475
+ const summariesFile = path25.join(SECRET_DIR, "chat-summaries.json");
14157
14476
  let wasCompressedInStream = false;
14158
14477
  const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
14159
14478
  const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
@@ -14399,7 +14718,7 @@ Provide a consolidated summary of the entire session.`;
14399
14718
  ];
14400
14719
  const safeReaddirWithTypes = (dir) => {
14401
14720
  try {
14402
- return fs25.readdirSync(dir, { withFileTypes: true });
14721
+ return fs26.readdirSync(dir, { withFileTypes: true });
14403
14722
  } catch (e) {
14404
14723
  return [];
14405
14724
  }
@@ -14412,16 +14731,16 @@ Provide a consolidated summary of the entire session.`;
14412
14731
  if (COLLAPSED_DIRS_GLOBAL.includes(entry.name)) continue;
14413
14732
  if (entry.isDirectory()) {
14414
14733
  currentCount.value++;
14415
- countFolders(path24.join(dir, entry.name), currentCount, depth + 1);
14734
+ countFolders(path25.join(dir, entry.name), currentCount, depth + 1);
14416
14735
  }
14417
14736
  }
14418
14737
  return currentCount.value;
14419
14738
  };
14420
14739
  const getDirTree = (dir, maxDepth, prefix = "", depth = 1) => {
14421
14740
  const entries = safeReaddirWithTypes(dir);
14422
- const sep = path24.sep;
14741
+ const sep = path25.sep;
14423
14742
  if (entries.length > 100) {
14424
- return `${prefix}\u2514\u2500\u2500 ${path24.basename(dir)}${sep} ...100+ files...
14743
+ return `${prefix}\u2514\u2500\u2500 ${path25.basename(dir)}${sep} ...100+ files...
14425
14744
  `;
14426
14745
  }
14427
14746
  let result = "";
@@ -14439,7 +14758,7 @@ Provide a consolidated summary of the entire session.`;
14439
14758
  ];
14440
14759
  finalItems.forEach((item, index) => {
14441
14760
  const isLast = index === finalItems.length - 1;
14442
- const filePath = path24.join(dir, item.name);
14761
+ const filePath = path25.join(dir, item.name);
14443
14762
  const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
14444
14763
  const childPrefix = prefix + (isLast ? " " : "\u2502 ");
14445
14764
  if (item.isCollapsed) {
@@ -14522,10 +14841,10 @@ ${currentSummary}
14522
14841
  if (isBridgeConnected()) {
14523
14842
  ideBlock = "[IDE CONTEXT]\n";
14524
14843
  if (ideCtx.file_focused !== "none") {
14525
- const relFocused = path24.relative(process.cwd(), ideCtx.file_focused);
14844
+ const relFocused = path25.relative(process.cwd(), ideCtx.file_focused);
14526
14845
  const relOpened = (ideCtx.opened_editors || []).map((p) => {
14527
- const rel = path24.relative(process.cwd(), p);
14528
- return rel.startsWith("..") ? `[External] ${path24.basename(p)}` : rel;
14846
+ const rel = path25.relative(process.cwd(), p);
14847
+ return rel.startsWith("..") ? `[External] ${path25.basename(p)}` : rel;
14529
14848
  });
14530
14849
  ideBlock += `Focused File: ${relFocused}
14531
14850
  Cursor Line: ${ideCtx.cursor_line}
@@ -14567,7 +14886,7 @@ Cursor Line: ${ideCtx.cursor_line}
14567
14886
  }
14568
14887
  const getSumForLimit = (limit, activeFiles2) => {
14569
14888
  return activeFiles2.reduce((sum, f) => {
14570
- const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused || path24.resolve(process.cwd(), f.path) === path24.resolve(ideCtx.file_focused));
14889
+ const isFocused = ideCtx.file_focused && (f.path === ideCtx.file_focused || path25.resolve(process.cwd(), f.path) === path25.resolve(ideCtx.file_focused));
14571
14890
  const fileLimit = isFocused ? Math.ceil(limit * 1.2) : limit;
14572
14891
  return sum + Math.min(f.edits.length, fileLimit);
14573
14892
  }, 0);
@@ -14601,7 +14920,7 @@ Cursor Line: ${ideCtx.cursor_line}
14601
14920
  }
14602
14921
  }
14603
14922
  for (const file of activeFiles) {
14604
- const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused || path24.resolve(process.cwd(), file.path) === path24.resolve(ideCtx.file_focused));
14923
+ const isFocused = ideCtx.file_focused && (file.path === ideCtx.file_focused || path25.resolve(process.cwd(), file.path) === path25.resolve(ideCtx.file_focused));
14605
14924
  const fileLimit = isFocused ? Math.ceil(chosenLimit * 1.2) : chosenLimit;
14606
14925
  if (file.edits.length > fileLimit) {
14607
14926
  file.edits = file.edits.slice(-fileLimit);
@@ -14688,9 +15007,9 @@ ${ideCtx.warnings}
14688
15007
  endLine = matchRange[2] ? parseInt(matchRange[2], 10) : startLine;
14689
15008
  filePath = tagClean.slice(0, matchRange.index);
14690
15009
  }
14691
- const absPath = path24.resolve(process.cwd(), filePath);
14692
- if (fs25.existsSync(absPath)) {
14693
- const stats = fs25.statSync(absPath);
15010
+ const absPath = path25.resolve(process.cwd(), filePath);
15011
+ if (fs26.existsSync(absPath)) {
15012
+ const stats = fs26.statSync(absPath);
14694
15013
  if (stats.isFile()) {
14695
15014
  const pathLower = filePath.toLowerCase();
14696
15015
  const isPdf = pathLower.endsWith(".pdf");
@@ -14699,7 +15018,7 @@ ${ideCtx.warnings}
14699
15018
  const isMultimodalFile = isImage || isPdf || isOfficeFile;
14700
15019
  const isSupported = aiProvider === "Google" || isModelMultimodal(modelName);
14701
15020
  if (isMultimodalFile && !isSupported) {
14702
- const label = `\u2718 Unsupported Modality: ${path24.basename(filePath)}`;
15021
+ const label = `\u2718 Unsupported Modality: ${path25.basename(filePath)}`;
14703
15022
  let terminalWidth = 115;
14704
15023
  if (process.stdout.isTTY) {
14705
15024
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -14715,11 +15034,11 @@ ${ideCtx.warnings}
14715
15034
  if (startLine === null && !isMultimodalFile) {
14716
15035
  let lineCount = 0;
14717
15036
  try {
14718
- lineCount = fs25.readFileSync(absPath, "utf8").split(/\r\n|\r|\n/).length;
15037
+ lineCount = fs26.readFileSync(absPath, "utf8").split(/\r\n|\r|\n/).length;
14719
15038
  } catch (e) {
14720
15039
  }
14721
15040
  if (lineCount > 550) {
14722
- const label = `\u21B7 Skipped (Too Large): ${path24.basename(filePath)}`;
15041
+ const label = `\u21B7 Skipped (Too Large): ${path25.basename(filePath)}`;
14723
15042
  let terminalWidth = 115;
14724
15043
  if (process.stdout.isTTY) {
14725
15044
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -14760,13 +15079,13 @@ ${ideCtx.warnings}
14760
15079
  if (!isError) {
14761
15080
  let label = "";
14762
15081
  if (isImage) {
14763
- label = `\u2714 Processed: ${path24.basename(filePath)}`;
15082
+ label = `\u2714 Processed: ${path25.basename(filePath)}`;
14764
15083
  attachedBinaryPart = binPart;
14765
15084
  } else if (isPdf || isOfficeFile) {
14766
- label = `\u2714 Auto-Analysed: ${path24.basename(filePath)}`;
15085
+ label = `\u2714 Auto-Analysed: ${path25.basename(filePath)}`;
14767
15086
  attachedBinaryPart = binPart;
14768
15087
  } else {
14769
- label = `\u2714 Auto-Read: ${path24.basename(filePath)}`;
15088
+ label = `\u2714 Auto-Read: ${path25.basename(filePath)}`;
14770
15089
  taggedContextBlocks.push(textResult);
14771
15090
  }
14772
15091
  if (label) {
@@ -15441,7 +15760,7 @@ ${ideErr} [/ERROR]`;
15441
15760
  if (keyword !== void 0 && keyword !== null) {
15442
15761
  detail = String(keyword).replace(RE_STRIP_QUOTES, "");
15443
15762
  } else if (filePath) {
15444
- detail = path24.basename(String(filePath).replace(RE_STRIP_QUOTES, "").replace(RE_BACKSLASH_SLASH, "/"));
15763
+ detail = path25.basename(String(filePath).replace(RE_STRIP_QUOTES, "").replace(RE_BACKSLASH_SLASH, "/"));
15445
15764
  } else if (title && (potentialTool === "invoke" || potentialTool === "invoke_sync")) {
15446
15765
  detail = String(title).replace(RE_STRIP_QUOTES, "").substring(0, 30);
15447
15766
  } else if (id && potentialTool === "get_progress") {
@@ -15470,7 +15789,7 @@ ${ideErr} [/ERROR]`;
15470
15789
  if (potentialTool === "invoke" || potentialTool === "invoke_sync" || potentialTool === "get_progress") {
15471
15790
  detail = val.substring(0, 30);
15472
15791
  } else {
15473
- detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val : path24.basename(val.replace(RE_BACKSLASH_SLASH, "/"));
15792
+ detail = potentialTool === "search_keyword" || potentialTool === "file_map" ? val : path25.basename(val.replace(RE_BACKSLASH_SLASH, "/"));
15474
15793
  }
15475
15794
  }
15476
15795
  }
@@ -15676,9 +15995,9 @@ ${ideErr} [/ERROR]`;
15676
15995
  let totalLines = "...";
15677
15996
  let actualEndLine = eLine;
15678
15997
  try {
15679
- const absPath = path24.resolve(process.cwd(), targetPath2);
15680
- if (fs25.existsSync(absPath)) {
15681
- const content = fs25.readFileSync(absPath, "utf8");
15998
+ const absPath = path25.resolve(process.cwd(), targetPath2);
15999
+ if (fs26.existsSync(absPath)) {
16000
+ const content = fs26.readFileSync(absPath, "utf8");
15682
16001
  const lines = content.split("\n").length;
15683
16002
  totalLines = lines;
15684
16003
  actualEndLine = Math.min(eLine, lines);
@@ -15690,16 +16009,16 @@ ${ideErr} [/ERROR]`;
15690
16009
  const isOfficeFile = pathLower.endsWith(".docx") || pathLower.endsWith(".doc") || pathLower.endsWith(".ppt") || pathLower.endsWith(".pptx") || pathLower.endsWith(".xls") || pathLower.endsWith(".xlsx");
15691
16010
  const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
15692
16011
  if (isPdf || isOfficeFile) {
15693
- label = `\u2714 Analyzed: ${path24.basename(targetPath2)}`;
16012
+ label = `\u2714 Analyzed: ${path25.basename(targetPath2)}`;
15694
16013
  } else if (isImage) {
15695
- label = `\u2714 Processed: ${path24.basename(targetPath2)}`;
16014
+ label = `\u2714 Processed: ${path25.basename(targetPath2)}`;
15696
16015
  } else {
15697
- label = `${totalLines !== "..." ? "\u2714" : "\u2718"} Read: ${path24.basename(targetPath2)} \u2192 ${totalLines !== "..." ? `Lines ${sLine} - ${actualEndLine} of ${totalLines}` : "File Not Found"}`;
16016
+ label = `${totalLines !== "..." ? "\u2714" : "\u2718"} Read: ${path25.basename(targetPath2)} \u2192 ${totalLines !== "..." ? `Lines ${sLine} - ${actualEndLine} of ${totalLines}` : "File Not Found"}`;
15698
16017
  }
15699
16018
  } else if (normToolName === "list_files" || normToolName === "read_folder") {
15700
16019
  const action = normToolName === "list_files" ? "List" : "Browsed";
15701
- const path26 = parseArgs(toolCall.args).path;
15702
- label = `\u2714 ${action}: ${path26 === "." ? "./" : path26}`;
16020
+ const path27 = parseArgs(toolCall.args).path;
16021
+ label = `\u2714 ${action}: ${path27 === "." ? "./" : path27}`;
15703
16022
  } else if (normToolName === "write_file" || normToolName === "update_file") {
15704
16023
  const action = normToolName === "write_file" ? "Created" : "Edited";
15705
16024
  label = `\u2714 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
@@ -15710,8 +16029,8 @@ ${ideErr} [/ERROR]`;
15710
16029
  label = `\u2714 Generated: ${parseArgs(toolCall.args).path || "..."}
15711
16030
  `;
15712
16031
  } else if (normToolName === "file_map") {
15713
- const path26 = parseArgs(toolCall.args).path;
15714
- label = `${path26 ? "\u2714" : "\u2718"} Indexed${path26 ? ": " + path26 : " File Not Found"}`;
16032
+ const path27 = parseArgs(toolCall.args).path;
16033
+ label = `${path27 ? "\u2714" : "\u2718"} Indexed${path27 ? ": " + path27 : " File Not Found"}`;
15715
16034
  } else if (normToolName.toLowerCase() === "search_keyword" || normToolName.toLowerCase() === "todo") {
15716
16035
  label = "";
15717
16036
  } else if (normToolName.toLowerCase() === "generate_image") {
@@ -15786,7 +16105,7 @@ ${ideErr} [/ERROR]`;
15786
16105
  const { command } = parseArgs(toolCall.args);
15787
16106
  if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
15788
16107
  const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
15789
- const currentDrive = path24.resolve(process.cwd()).substring(0, 3).toLowerCase();
16108
+ const currentDrive = path25.resolve(process.cwd()).substring(0, 3).toLowerCase();
15790
16109
  const splitCommands = (cmdString) => {
15791
16110
  const commands = [];
15792
16111
  let current = "";
@@ -15915,8 +16234,8 @@ ${ideErr} [/ERROR]`;
15915
16234
  const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
15916
16235
  if (targetPath) {
15917
16236
  const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
15918
- const absoluteTarget = path24.resolve(targetPath);
15919
- const absoluteCwd = path24.resolve(process.cwd());
16237
+ const absoluteTarget = path25.resolve(targetPath);
16238
+ const absoluteCwd = path25.resolve(process.cwd());
15920
16239
  if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
15921
16240
  const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace.`;
15922
16241
  if (normToolName === "write_file" || normToolName === "update_file") {
@@ -16105,7 +16424,7 @@ ${ideErr} [/ERROR]`;
16105
16424
  const toolArgs = parseArgs(toolCall.args);
16106
16425
  const { path: filePath } = toolArgs;
16107
16426
  if (filePath) {
16108
- const absPath = path24.resolve(process.cwd(), filePath);
16427
+ const absPath = path25.resolve(process.cwd(), filePath);
16109
16428
  const normalize2 = (p) => p ? p.toLowerCase().replace(/\\/g, "/").replace(/^[a-z]:/, (m) => m.toUpperCase()) : "";
16110
16429
  const normAbsPath = normalize2(absPath);
16111
16430
  let originalContent = "";
@@ -16115,8 +16434,8 @@ ${ideErr} [/ERROR]`;
16115
16434
  if (currentIDE && normFocused === normAbsPath && currentIDE.full_content) {
16116
16435
  originalContent = currentIDE.full_content;
16117
16436
  hasOriginal = true;
16118
- } else if (fs25.existsSync(absPath)) {
16119
- originalContent = fs25.readFileSync(absPath, "utf8");
16437
+ } else if (fs26.existsSync(absPath)) {
16438
+ originalContent = fs26.readFileSync(absPath, "utf8");
16120
16439
  hasOriginal = true;
16121
16440
  }
16122
16441
  originalContentForReporting = originalContent;
@@ -16143,9 +16462,9 @@ ${ideErr} [/ERROR]`;
16143
16462
  const successes = patchResults.filter((r) => r.success);
16144
16463
  const failures = patchResults.filter((r) => !r.success);
16145
16464
  if (successes.length === 0) {
16146
- const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${path24.basename(absPath)}].
16465
+ const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${path25.basename(absPath)}].
16147
16466
  ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
16148
- const errorLabel = `\u2714 Edited: ${path24.basename(absPath)}`.toUpperCase();
16467
+ const errorLabel = `\u2714 Edited: ${path25.basename(absPath)}`.toUpperCase();
16149
16468
  let terminalWidth = 115;
16150
16469
  if (process.stdout.isTTY) {
16151
16470
  terminalWidth = process.stdout.columns - 5 || 120;
@@ -16163,19 +16482,19 @@ ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
16163
16482
  continue;
16164
16483
  }
16165
16484
  }
16166
- yield { type: "status", content: `Opening Diff in IDE: ${path24.basename(absPath)}` };
16485
+ yield { type: "status", content: `Opening Diff in IDE: ${path25.basename(absPath)}` };
16167
16486
  showDiffInIDE(absPath, originalContent, modifiedContent);
16168
16487
  diffOpened = true;
16169
16488
  await new Promise((r) => setTimeout(r, 50));
16170
16489
  } else if (normToolName === "write_file") {
16171
16490
  const rawContent = toolArgs.content || toolArgs.newContent || "";
16172
16491
  const modifiedContent = rawContent.endsWith("\n") ? rawContent : rawContent + "\n";
16173
- if (!fs25.existsSync(absPath)) {
16492
+ if (!fs26.existsSync(absPath)) {
16174
16493
  isNewFileCreated = true;
16175
- fs25.mkdirSync(path24.dirname(absPath), { recursive: true });
16176
- fs25.writeFileSync(absPath, "", "utf8");
16494
+ fs26.mkdirSync(path25.dirname(absPath), { recursive: true });
16495
+ fs26.writeFileSync(absPath, "", "utf8");
16177
16496
  }
16178
- yield { type: "status", content: `Opening New File Diff in IDE: ${path24.basename(absPath)}` };
16497
+ yield { type: "status", content: `Opening New File Diff in IDE: ${path25.basename(absPath)}` };
16179
16498
  showDiffInIDE(absPath, "", modifiedContent);
16180
16499
  diffOpened = true;
16181
16500
  await new Promise((r) => setTimeout(r, 50));
@@ -16211,11 +16530,11 @@ ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
16211
16530
  if (normToolName === "write_file" || normToolName === "update_file") {
16212
16531
  const { path: filePath } = parseArgs(toolCall.args);
16213
16532
  if (filePath) {
16214
- const absPath = path24.resolve(process.cwd(), filePath);
16533
+ const absPath = path25.resolve(process.cwd(), filePath);
16215
16534
  closeDiffInIDE(absPath, approval);
16216
- if (approval === "deny" && isNewFileCreated && fs25.existsSync(absPath)) {
16535
+ if (approval === "deny" && isNewFileCreated && fs26.existsSync(absPath)) {
16217
16536
  try {
16218
- fs25.unlinkSync(absPath);
16537
+ fs26.unlinkSync(absPath);
16219
16538
  } catch (e) {
16220
16539
  }
16221
16540
  }
@@ -16227,13 +16546,13 @@ ${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
16227
16546
  }
16228
16547
  if (approval === "allow" && diffOpened && isBridgeConnected()) {
16229
16548
  const { path: filePath } = parseArgs(toolCall.args);
16230
- const absPath = path24.resolve(process.cwd(), filePath);
16549
+ const absPath = path25.resolve(process.cwd(), filePath);
16231
16550
  const finalIDE = await getIDEContext();
16232
16551
  let finalContent = "";
16233
16552
  if (finalIDE && finalIDE.file_focused === absPath && finalIDE.full_content) {
16234
16553
  finalContent = finalIDE.full_content;
16235
- } else if (fs25.existsSync(absPath)) {
16236
- finalContent = fs25.readFileSync(absPath, "utf8");
16554
+ } else if (fs26.existsSync(absPath)) {
16555
+ finalContent = fs26.readFileSync(absPath, "utf8");
16237
16556
  }
16238
16557
  const verifiedLines = finalContent.split(/\r?\n/);
16239
16558
  const verifiedLineCount = verifiedLines.length;
@@ -16395,7 +16714,7 @@ ${snippet2}
16395
16714
  try {
16396
16715
  const { path: filePath } = parseArgs(toolCall.args);
16397
16716
  if (filePath) {
16398
- const absPath = path24.resolve(process.cwd(), filePath);
16717
+ const absPath = path25.resolve(process.cwd(), filePath);
16399
16718
  const currentIDE = await getIDEContext();
16400
16719
  if (currentIDE && currentIDE.file_focused === absPath && currentIDE.full_content) {
16401
16720
  execToolContext.forcedContent = currentIDE.full_content;
@@ -16409,7 +16728,7 @@ ${snippet2}
16409
16728
  if ((normToolName === "write_file" || normToolName === "update_file") && result.startsWith("SUCCESS")) {
16410
16729
  const { path: filePath } = parseArgs(toolCall.args);
16411
16730
  if (filePath) {
16412
- const absPath = path24.resolve(process.cwd(), filePath);
16731
+ const absPath = path25.resolve(process.cwd(), filePath);
16413
16732
  openFileInEditor(absPath);
16414
16733
  }
16415
16734
  }
@@ -16426,7 +16745,7 @@ ${snippet2}
16426
16745
  result = result.text;
16427
16746
  }
16428
16747
  if (normToolName === "search_keyword") {
16429
- const { keyword, path: path26 } = parseArgs(toolCall.args);
16748
+ const { keyword, path: path27 } = parseArgs(toolCall.args);
16430
16749
  const _isDir = typeof result === "string" && result.startsWith("[DIR]");
16431
16750
  if (_isDir) result = result.slice(5);
16432
16751
  let matchCount = 0;
@@ -16436,7 +16755,7 @@ ${snippet2}
16436
16755
  matchCount = parseInt(m[1]);
16437
16756
  }
16438
16757
  }
16439
- const _sp = path26 ? path26.replace(/[\/\\]+$/, "") : null;
16758
+ const _sp = path27 ? path27.replace(/[\/\\]+$/, "") : null;
16440
16759
  const displayPath = _sp && _sp !== "." ? `"${_isDir ? `${_sp}/*` : _sp}"` : "./";
16441
16760
  const postLabel = `\u2714 Searched: "${keyword}" in ${displayPath} \u2192 ${matchCount} Match${matchCount === 1 ? "" : "es"}`;
16442
16761
  let terminalWidth = 115;
@@ -16676,9 +16995,9 @@ ${snippet2}
16676
16995
  })() : String(err);
16677
16996
  ;
16678
16997
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
16679
- const agentErrDir = path24.join(LOGS_DIR, "agent");
16680
- if (!fs25.existsSync(agentErrDir)) fs25.mkdirSync(agentErrDir, { recursive: true });
16681
- fs25.appendFileSync(path24.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
16998
+ const agentErrDir = path25.join(LOGS_DIR, "agent");
16999
+ if (!fs26.existsSync(agentErrDir)) fs26.mkdirSync(agentErrDir, { recursive: true });
17000
+ fs26.appendFileSync(path25.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
16682
17001
 
16683
17002
  ----------------------------------------------------------------------
16684
17003
 
@@ -16725,7 +17044,7 @@ ${recoveryText}`
16725
17044
  yield { type: "status", content: `Error Occured. Recovering Stream...` };
16726
17045
  } else {
16727
17046
  throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
16728
- Error Log can be found in ${path24.join(LOGS_DIR, "agent", "error.log")}`);
17047
+ Error Log can be found in ${path25.join(LOGS_DIR, "agent", "error.log")}`);
16729
17048
  }
16730
17049
  } else {
16731
17050
  if (retryCount <= MAX_RETRIES) {
@@ -16743,7 +17062,7 @@ Error Log can be found in ${path24.join(LOGS_DIR, "agent", "error.log")}`);
16743
17062
  yield { type: "status", content: `Trying to reach ${modelName}` };
16744
17063
  } else {
16745
17064
  throw new Error(`Model ${modelName} cannot be reached. (Failed ${MAX_RETRIES} times)
16746
- Error Log can be found in ${path24.join(LOGS_DIR, "agent", "error.log")}`);
17065
+ Error Log can be found in ${path25.join(LOGS_DIR, "agent", "error.log")}`);
16747
17066
  }
16748
17067
  }
16749
17068
  }
@@ -16862,10 +17181,10 @@ Error Log can be found in ${path24.join(LOGS_DIR, "agent", "error.log")}`);
16862
17181
  }
16863
17182
  })() : String(err);
16864
17183
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
16865
- const agentErrDir = path24.join(LOGS_DIR, "agent");
17184
+ const agentErrDir = path25.join(LOGS_DIR, "agent");
16866
17185
  yield { type: "text", content: `\u274C CRITICAL ERROR: ${errLog}` };
16867
- if (!fs25.existsSync(agentErrDir)) fs25.mkdirSync(agentErrDir, { recursive: true });
16868
- fs25.appendFileSync(path24.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${err}
17186
+ if (!fs26.existsSync(agentErrDir)) fs26.mkdirSync(agentErrDir, { recursive: true });
17187
+ fs26.appendFileSync(path25.join(agentErrDir, "error.log"), `CRITICAL ERROR [${date}]: ${err}
16869
17188
 
16870
17189
  ----------------------------------------------------------------------
16871
17190
 
@@ -17009,20 +17328,20 @@ ${cleanResponse}
17009
17328
  } else if (normalizedToolName === "web_scrape" || normalizedToolName === "webscrape") {
17010
17329
  label = `\u2714 \x1B[95mScraped\x1B[0m`;
17011
17330
  } else if (normalizedToolName === "view_file" || normalizedToolName === "viewfile" || normalizedToolName === "readfile") {
17012
- const path26 = parseArgs(toolCall.args).path || "";
17013
- label = `\u2714 \x1B[95mRead\x1B[0m: ${path26}`;
17331
+ const path27 = parseArgs(toolCall.args).path || "";
17332
+ label = `\u2714 \x1B[95mRead\x1B[0m: ${path27}`;
17014
17333
  } else if (normalizedToolName === "list_files" || normalizedToolName === "read_folder" || normalizedToolName === "readfolder") {
17015
- const path26 = parseArgs(toolCall.args).path || "";
17016
- label = `\u2714 \x1B[95mBrowsed\x1B[0m: ${path26}`;
17334
+ const path27 = parseArgs(toolCall.args).path || "";
17335
+ label = `\u2714 \x1B[95mBrowsed\x1B[0m: ${path27}`;
17017
17336
  } else if (normalizedToolName === "write_file" || normalizedToolName === "writefile") {
17018
- const path26 = parseArgs(toolCall.args).path || "";
17019
- label = `\u2714 \x1B[95mCreated\x1B[0m: ${path26}`;
17337
+ const path27 = parseArgs(toolCall.args).path || "";
17338
+ label = `\u2714 \x1B[95mCreated\x1B[0m: ${path27}`;
17020
17339
  } else if (normalizedToolName === "update_file" || normalizedToolName === "updatefile" || normalizedToolName === "patchfile" || normalizedToolName === "patch_file" || normalizedToolName === "patchfile" || normalizedToolName === "updatefile") {
17021
- const path26 = parseArgs(toolCall.args).path || "";
17022
- label = `\u2714 \x1B[95mEdited\x1B[0m: ${path26}`;
17340
+ const path27 = parseArgs(toolCall.args).path || "";
17341
+ label = `\u2714 \x1B[95mEdited\x1B[0m: ${path27}`;
17023
17342
  } else if (normalizedToolName === "file_map" || normalizedToolName === "filemap") {
17024
- const path26 = parseArgs(toolCall.args).path || "";
17025
- label = `\u2714 \x1B[95mIndexed\x1B[0m: ${path26}`;
17343
+ const path27 = parseArgs(toolCall.args).path || "";
17344
+ label = `\u2714 \x1B[95mIndexed\x1B[0m: ${path27}`;
17026
17345
  } else if (normalizedToolName === "await") {
17027
17346
  const { time } = parseArgs(toolCall.args);
17028
17347
  let sec = parseFloat(time) || 0;
@@ -18017,7 +18336,7 @@ var init_RevertModal = __esm({
18017
18336
  import puppeteer4 from "puppeteer";
18018
18337
  import { exec } from "child_process";
18019
18338
  import { promisify } from "util";
18020
- import fs26 from "fs";
18339
+ import fs27 from "fs";
18021
18340
  var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
18022
18341
  var init_setup = __esm({
18023
18342
  "src/utils/setup.js"() {
@@ -18026,11 +18345,11 @@ var init_setup = __esm({
18026
18345
  checkPuppeteerReady = () => {
18027
18346
  try {
18028
18347
  const pptrConfig = getPuppeteerConfig();
18029
- if (pptrConfig.executablePath && fs26.existsSync(pptrConfig.executablePath)) {
18348
+ if (pptrConfig.executablePath && fs27.existsSync(pptrConfig.executablePath)) {
18030
18349
  return true;
18031
18350
  }
18032
18351
  const exePath = puppeteer4.executablePath();
18033
- const exists = exePath && fs26.existsSync(exePath);
18352
+ const exists = exePath && fs27.existsSync(exePath);
18034
18353
  if (exists) return true;
18035
18354
  } catch (e) {
18036
18355
  return false;
@@ -18117,8 +18436,8 @@ __export(app_exports, {
18117
18436
  import os5 from "os";
18118
18437
  import React16, { useState as useState15, useEffect as useEffect12, useRef as useRef4, useMemo as useMemo2 } from "react";
18119
18438
  import { Box as Box14, Text as Text16, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
18120
- import fs27 from "fs-extra";
18121
- import path25 from "path";
18439
+ import fs28 from "fs-extra";
18440
+ import path26 from "path";
18122
18441
  import { exec as exec2 } from "child_process";
18123
18442
  import { fileURLToPath as fileURLToPath3 } from "url";
18124
18443
  import TextInput4 from "ink-text-input";
@@ -18445,10 +18764,10 @@ function App({ args = [] }) {
18445
18764
  const kbPath = getKeybindingsPath(ideName);
18446
18765
  if (!kbPath) return;
18447
18766
  try {
18448
- await fs27.ensureDir(path25.dirname(kbPath));
18767
+ await fs28.ensureDir(path26.dirname(kbPath));
18449
18768
  let bindings = [];
18450
- if (fs27.existsSync(kbPath)) {
18451
- const content = fs27.readFileSync(kbPath, "utf8").trim();
18769
+ if (fs28.existsSync(kbPath)) {
18770
+ const content = fs28.readFileSync(kbPath, "utf8").trim();
18452
18771
  if (content) {
18453
18772
  try {
18454
18773
  bindings = parseJsonc(content);
@@ -18468,7 +18787,7 @@ function App({ args = [] }) {
18468
18787
  },
18469
18788
  "when": "terminalFocus"
18470
18789
  });
18471
- fs27.writeFileSync(kbPath, JSON.stringify(bindings, null, 4), "utf8");
18790
+ fs28.writeFileSync(kbPath, JSON.stringify(bindings, null, 4), "utf8");
18472
18791
  cachedShortcut = "Shift + Enter";
18473
18792
  setMessages((prev) => {
18474
18793
  setCompletedIndex(prev.length + 1);
@@ -19179,7 +19498,7 @@ function App({ args = [] }) {
19179
19498
  useEffect12(() => {
19180
19499
  async function init() {
19181
19500
  try {
19182
- const pkg = JSON.parse(fs27.readFileSync(path25.join(process.cwd(), "package.json"), "utf8"));
19501
+ const pkg = JSON.parse(fs28.readFileSync(path26.join(process.cwd(), "package.json"), "utf8"));
19183
19502
  initBridge(versionFluxflow || pkg.version || "2.0.0");
19184
19503
  } catch (e) {
19185
19504
  initBridge("2.0.0");
@@ -19293,7 +19612,7 @@ function App({ args = [] }) {
19293
19612
  if (!parsedArgs.playground) {
19294
19613
  deleteChat(PLAYGROUND_CHAT_ID).catch(() => {
19295
19614
  });
19296
- fs27.remove(path25.join(DATA_DIR, "playground")).catch(() => {
19615
+ fs28.remove(path26.join(DATA_DIR, "playground")).catch(() => {
19297
19616
  });
19298
19617
  }
19299
19618
  performVersionCheck(false, freshSettings);
@@ -19327,9 +19646,9 @@ function App({ args = [] }) {
19327
19646
  }
19328
19647
  }
19329
19648
  if (parsedArgs.playground) {
19330
- const playgroundDir = path25.join(DATA_DIR, "playground");
19649
+ const playgroundDir = path26.join(DATA_DIR, "playground");
19331
19650
  try {
19332
- fs27.ensureDirSync(playgroundDir);
19651
+ fs28.ensureDirSync(playgroundDir);
19333
19652
  process.chdir(playgroundDir);
19334
19653
  } catch (e) {
19335
19654
  }
@@ -19370,8 +19689,8 @@ function App({ args = [] }) {
19370
19689
  if (kbPath) {
19371
19690
  try {
19372
19691
  let bindings = [];
19373
- if (fs27.existsSync(kbPath)) {
19374
- const content = fs27.readFileSync(kbPath, "utf8").trim();
19692
+ if (fs28.existsSync(kbPath)) {
19693
+ const content = fs28.readFileSync(kbPath, "utf8").trim();
19375
19694
  if (content) {
19376
19695
  bindings = parseJsonc(content);
19377
19696
  }
@@ -19527,7 +19846,14 @@ function App({ args = [] }) {
19527
19846
  { cmd: "/revert", desc: "Revert codebase back to a checkpoint" },
19528
19847
  { cmd: "/gemini", desc: "Get a happy message from Gemini CLI" },
19529
19848
  { cmd: "/save", desc: "Force save current chat" },
19530
- { cmd: "/export", desc: "Export current chat in a .txt file" },
19849
+ {
19850
+ cmd: "/export",
19851
+ desc: "Export current chat or error logs",
19852
+ subs: [
19853
+ { cmd: "chat", desc: "Export current active chat" },
19854
+ { cmd: "logs", desc: "Export error logs" }
19855
+ ]
19856
+ },
19531
19857
  { cmd: "/chats", desc: "List all chat sessions" },
19532
19858
  { cmd: "/btw", desc: "Ask a question without intefering with ongoing tasks" },
19533
19859
  {
@@ -19742,22 +20068,22 @@ ${cleanText}`, color: "magenta" }];
19742
20068
  });
19743
20069
  break;
19744
20070
  }
19745
- const src = path25.join(DATA_DIR, "playground");
19746
- const dest = path25.join(parsedArgs.originalCwd, "playground-export");
20071
+ const src = path26.join(DATA_DIR, "playground");
20072
+ const dest = path26.join(parsedArgs.originalCwd, "playground-export");
19747
20073
  const moveFiles = async () => {
19748
20074
  try {
19749
20075
  setMessages((prev) => {
19750
20076
  setCompletedIndex(prev.length + 1);
19751
20077
  return [...prev, { id: Date.now(), role: "system", text: `[PLAYGROUND] Exporting playground content to ${dest}`, isMeta: true }];
19752
20078
  });
19753
- await fs27.ensureDir(dest);
20079
+ await fs28.ensureDir(dest);
19754
20080
  const excludeDirs = ["node_modules", ".git", ".venv", "venv", "env", ".next", "dist", "build", ".cache"];
19755
- await fs27.copy(src, dest, {
20081
+ await fs28.copy(src, dest, {
19756
20082
  overwrite: true,
19757
20083
  filter: (srcPath) => {
19758
- const relative = path25.relative(src, srcPath);
20084
+ const relative = path26.relative(src, srcPath);
19759
20085
  if (!relative) return true;
19760
- const parts2 = relative.split(path25.sep);
20086
+ const parts2 = relative.split(path26.sep);
19761
20087
  return !parts2.some((part) => excludeDirs.includes(part));
19762
20088
  }
19763
20089
  });
@@ -19819,7 +20145,7 @@ ${cleanText}`, color: "magenta" }];
19819
20145
  }
19820
20146
  }
19821
20147
  setTimeout(() => {
19822
- fs27.emptyDir(path25.join(DATA_DIR, "playground")).catch((err) => {
20148
+ fs28.emptyDir(path26.join(DATA_DIR, "playground")).catch((err) => {
19823
20149
  setMessages((prev) => {
19824
20150
  const newMsgs = [...prev, {
19825
20151
  id: "playground-" + Date.now(),
@@ -20158,80 +20484,31 @@ ${cleanText}`, color: "magenta" }];
20158
20484
  break;
20159
20485
  }
20160
20486
  case "/export": {
20161
- const exportFile = `export-fluxflow-${chatId}.txt`;
20162
- const exportPath = path25.join(process.cwd(), exportFile);
20163
- const exportLines = [];
20164
- let insideAgentBlock = false;
20165
- for (let i = 0; i < messages.length; i++) {
20166
- const msg = messages[i];
20167
- if (!msg) continue;
20168
- if (msg.role === "system" || msg.isMeta || msg.isLogo || String(msg.id).startsWith("welcome")) {
20169
- continue;
20170
- }
20171
- if (msg.role === "user") {
20172
- let cleanUserText = msg.text || "";
20173
- cleanUserText = cleanUserText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
20174
- if (exportLines.length > 0) {
20175
- exportLines.push("");
20176
- }
20177
- exportLines.push("[USER]");
20178
- exportLines.push(cleanUserText);
20179
- insideAgentBlock = false;
20180
- } else if (msg.role === "think") {
20181
- if (!insideAgentBlock) {
20182
- exportLines.push("");
20183
- exportLines.push("[AGENT]");
20184
- insideAgentBlock = true;
20185
- }
20186
- const cleanThinkText = (msg.text || "").replace(/\[\[\s*turn\s*:\s*(continue|finish)\s*\]\]/gi, "").replace(/\[\[END\]\]/gi, "").replace(/\[\[TOOL RESULTS\]\]/gi, "").replace(/\[TOOL RESULTS\]/gi, "").replace(/\[TOOL RESULT\]/gi, "").trim();
20187
- if (cleanThinkText) {
20188
- exportLines.push("[thoughts]");
20189
- exportLines.push(cleanThinkText);
20190
- }
20191
- } else if (msg.role === "agent") {
20192
- if (!insideAgentBlock) {
20193
- exportLines.push("");
20194
- exportLines.push("[AGENT]");
20195
- insideAgentBlock = true;
20196
- }
20197
- const blocks = parseAgentText(msg.text || "");
20198
- for (const block of blocks) {
20199
- if (block.type === "output") {
20200
- const cleanContent = block.content.replace(/\[\[\s*turn\s*:\s*(continue|finish)\s*\]\]/gi, "").replace(/\[\[END\]\]/gi, "").replace(/\[\[TOOL RESULTS\]\]/gi, "").replace(/\[TOOL RESULTS\]/gi, "").replace(/\[TOOL RESULT\]/gi, "").trim();
20201
- if (cleanContent) {
20202
- exportLines.push("[output]");
20203
- exportLines.push(cleanContent);
20204
- }
20205
- } else if (block.type === "tool") {
20206
- exportLines.push("[tool]");
20207
- exportLines.push(`${block.toolName} ${block.args}`);
20208
- }
20209
- }
20487
+ const runExport = async () => {
20488
+ try {
20489
+ const result = await handleExport(parts, { chatId, messages });
20490
+ setMessages((prev) => {
20491
+ setCompletedIndex(prev.length + 1);
20492
+ return [...prev, {
20493
+ id: Date.now(),
20494
+ role: "system",
20495
+ text: result.message,
20496
+ isMeta: true
20497
+ }];
20498
+ });
20499
+ } catch (err) {
20500
+ setMessages((prev) => {
20501
+ setCompletedIndex(prev.length + 1);
20502
+ return [...prev, {
20503
+ id: Date.now(),
20504
+ role: "system",
20505
+ text: `[EXPORT ERROR] Failed to export: ${err.message}`,
20506
+ isMeta: true
20507
+ }];
20508
+ });
20210
20509
  }
20211
- }
20212
- const fileContent = exportLines.join("\n");
20213
- try {
20214
- fs27.writeFileSync(exportPath, fileContent, "utf8");
20215
- setMessages((prev) => {
20216
- setCompletedIndex(prev.length + 1);
20217
- return [...prev, {
20218
- id: Date.now(),
20219
- role: "system",
20220
- text: `[EXPORT] Chat exported to "${exportFile}"`,
20221
- isMeta: true
20222
- }];
20223
- });
20224
- } catch (err) {
20225
- setMessages((prev) => {
20226
- setCompletedIndex(prev.length + 1);
20227
- return [...prev, {
20228
- id: Date.now(),
20229
- role: "system",
20230
- text: `[EXPORT ERROR] Failed to export chat: ${err.message}`,
20231
- isMeta: true
20232
- }];
20233
- });
20234
- }
20510
+ };
20511
+ runExport();
20235
20512
  break;
20236
20513
  }
20237
20514
  case "/chats": {
@@ -20258,12 +20535,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
20258
20535
  setCompletedIndex(prev.length + 1);
20259
20536
  return [...prev, { id: Date.now(), role: "system", text: "[NUCLEAR] Initiating reset...", isMeta: true }];
20260
20537
  });
20261
- if (fs27.existsSync(LOGS_DIR)) fs27.removeSync(LOGS_DIR);
20262
- if (fs27.existsSync(SECRET_DIR)) fs27.removeSync(SECRET_DIR);
20263
- if (fs27.existsSync(SETTINGS_FILE)) fs27.removeSync(SETTINGS_FILE);
20538
+ if (fs28.existsSync(LOGS_DIR)) fs28.removeSync(LOGS_DIR);
20539
+ if (fs28.existsSync(SECRET_DIR)) fs28.removeSync(SECRET_DIR);
20540
+ if (fs28.existsSync(SETTINGS_FILE)) fs28.removeSync(SETTINGS_FILE);
20264
20541
  try {
20265
- const items = fs27.readdirSync(FLUXFLOW_DIR);
20266
- if (items.length === 0) fs27.removeSync(FLUXFLOW_DIR);
20542
+ const items = fs28.readdirSync(FLUXFLOW_DIR);
20543
+ if (items.length === 0) fs28.removeSync(FLUXFLOW_DIR);
20267
20544
  } catch (e) {
20268
20545
  }
20269
20546
  setTimeout(() => {
@@ -20385,15 +20662,15 @@ ${list || "No saved chats found."}`, isMeta: true }];
20385
20662
  # SKILLS & WORKFLOWS
20386
20663
  - [Define custom step-by-step recipes for this project here]
20387
20664
  `;
20388
- const filePath = path25.join(process.cwd(), "FluxFlow.md");
20389
- if (fs27.pathExistsSync(filePath)) {
20665
+ const filePath = path26.join(process.cwd(), "FluxFlow.md");
20666
+ if (fs28.pathExistsSync(filePath)) {
20390
20667
  setMessages((prev) => {
20391
20668
  setCompletedIndex(prev.length + 1);
20392
20669
  return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
20393
20670
  });
20394
20671
  } else {
20395
20672
  try {
20396
- fs27.writeFileSync(filePath, template);
20673
+ fs28.writeFileSync(filePath, template);
20397
20674
  setMessages((prev) => {
20398
20675
  setCompletedIndex(prev.length + 1);
20399
20676
  return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "[SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
@@ -22546,7 +22823,7 @@ Selection: ${val}`,
22546
22823
  return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: colors.borderMuted, width: Math.min(100, (stdout?.columns || 100) - 2), marginTop: 0, marginBottom: 0 }, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text16, { bold: true }, gradient2(colors.logoGradient || ["blue", "purple"])("Agent powering down. Goodbye!"))), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Session ID:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, chatId)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Tool Calls:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, runtimeSession.toolSuccess + runtimeSession.toolFailure + runtimeSession.toolDenied, " ( ", /* @__PURE__ */ React16.createElement(Text16, { color: "green" }, "\u2714 ", runtimeSession.toolSuccess), " ", /* @__PURE__ */ React16.createElement(Text16, { color: "yellow" }, "\u{1F6C7} ", runtimeSession.toolDenied), " ", /* @__PURE__ */ React16.createElement(Text16, { color: "red" }, "\u2718 ", runtimeSession.toolFailure), " )")), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Success Rate:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, successRate, "%")), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Code Changes:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, /* @__PURE__ */ React16.createElement(Text16, { color: "green" }, "+", runtimeSession.linesAdded), " ", /* @__PURE__ */ React16.createElement(Text16, { color: "red" }, "-", runtimeSession.linesRemoved))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Tokens Consumed:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalTokens))), sessionTotalTokens > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 18 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Input Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalTokens - sessionTotalCandidateTokens))), sessionTotalCachedTokens > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4 }, /* @__PURE__ */ React16.createElement(Box14, { width: 16 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Cached:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalCachedTokens))), sessionTotalCandidateTokens > 0 && /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 18 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Output Tokens:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatTokens(sessionTotalCandidateTokens)))), sessionImageCount > 0 && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Images Made:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, sessionImageCount)), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Image Credits:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, Number(((sessionImageCredits || 0) * 1e3).toFixed(0)), " credits")))), /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "Performance"), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Wall Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Box14, { width: 20 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary }, "Agent Active:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 18 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB API Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2 }, /* @__PURE__ */ React16.createElement(Box14, { width: 18 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "\xBB Tool Time:")), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
22547
22824
  })())));
22548
22825
  }
22549
- var shouldClearValue, getPrefilledValue, getIDEName, getIDEDirName, getKeybindingsPath, parseJsonc, hasShiftEnterBinding, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, parseAgentText, getProjectFiles, cachedShortcut, getLatencyColor2, SubagentRow;
22826
+ var shouldClearValue, getPrefilledValue, getIDEName, getIDEDirName, getKeybindingsPath, parseJsonc, hasShiftEnterBinding, getPromoOptions, BridgePromo, SESSION_START_TIME, CHANGELOG_URL, DOCS_URL, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, getProjectFiles, cachedShortcut, getLatencyColor2, SubagentRow;
22550
22827
  var init_app = __esm({
22551
22828
  async "src/app.jsx"() {
22552
22829
  init_build();
@@ -22582,6 +22859,7 @@ var init_app = __esm({
22582
22859
  init_text();
22583
22860
  init_editor();
22584
22861
  init_GlintText();
22862
+ init_export();
22585
22863
  shouldClearValue = (val) => {
22586
22864
  const s = String(val);
22587
22865
  return s.startsWith("999") && s.endsWith("9");
@@ -22632,11 +22910,11 @@ var init_app = __esm({
22632
22910
  if (process.platform === "win32") {
22633
22911
  const appData = process.env.APPDATA;
22634
22912
  if (!appData) return null;
22635
- return path25.join(appData, dirName, "User", "keybindings.json");
22913
+ return path26.join(appData, dirName, "User", "keybindings.json");
22636
22914
  } else if (process.platform === "darwin") {
22637
- return path25.join(home, "Library", "Application Support", dirName, "User", "keybindings.json");
22915
+ return path26.join(home, "Library", "Application Support", dirName, "User", "keybindings.json");
22638
22916
  } else {
22639
- return path25.join(home, ".config", dirName, "User", "keybindings.json");
22917
+ return path26.join(home, ".config", dirName, "User", "keybindings.json");
22640
22918
  }
22641
22919
  };
22642
22920
  parseJsonc = (content) => {
@@ -22680,8 +22958,8 @@ var init_app = __esm({
22680
22958
  SESSION_START_TIME = Date.now();
22681
22959
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog";
22682
22960
  DOCS_URL = "https://fluxflow-cli.onrender.com/";
22683
- packageJsonPath = path25.join(path25.dirname(fileURLToPath3(import.meta.url)), "../package.json");
22684
- packageJson = JSON.parse(fs27.readFileSync(packageJsonPath, "utf8"));
22961
+ packageJsonPath = path26.join(path26.dirname(fileURLToPath3(import.meta.url)), "../package.json");
22962
+ packageJson = JSON.parse(fs28.readFileSync(packageJsonPath, "utf8"));
22685
22963
  versionFluxflow = packageJson.version;
22686
22964
  updatedOn = packageJson.date || "2026-05-20";
22687
22965
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", padding: 0, width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: "white", bold: true, underline: true }, data.startsWith("/btw") ? "QUESTION" : "STEERING HINT", " RESOLUTION")), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, null, "The agent already finished the task before your ", data.startsWith("/btw") ? "question" : "hint", " was consumed.")), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, { italic: true, color: "gray" }, '"', data.replace("/btw", "").trim(), '"')), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: "grey" }, "How would you like to proceed?")), /* @__PURE__ */ React16.createElement(Box14, { marginTop: 0 }, /* @__PURE__ */ React16.createElement(
@@ -22698,74 +22976,6 @@ var init_app = __esm({
22698
22976
  }
22699
22977
  }
22700
22978
  )));
22701
- parseAgentText = (text) => {
22702
- const blocks = [];
22703
- const toolRegex = /\[\s*(?:tool:functions\.|agent:generalist\.)([a-z0-9_]+)\s*\(/gi;
22704
- let lastIdx = 0;
22705
- let match;
22706
- while ((match = toolRegex.exec(text)) !== null) {
22707
- const toolName = match[1];
22708
- const startIdx = match.index + match[0].length - 1;
22709
- let balance = 0;
22710
- let inString = null;
22711
- let endIdx = -1;
22712
- let closingParenIdx = -1;
22713
- for (let i = startIdx; i < text.length; i++) {
22714
- const char = text[i];
22715
- if (inString) {
22716
- if (char === inString) {
22717
- let backslashCount = 0;
22718
- for (let j = i - 1; j >= 0 && text[j] === "\\"; j--) {
22719
- backslashCount++;
22720
- }
22721
- if (backslashCount % 2 === 0) {
22722
- inString = null;
22723
- }
22724
- }
22725
- } else {
22726
- if (char === '"' || char === "'" || char === "`") {
22727
- inString = char;
22728
- } else if (char === "(") {
22729
- balance++;
22730
- } else if (char === ")") {
22731
- balance--;
22732
- if (balance === 0) {
22733
- closingParenIdx = i;
22734
- let j = i + 1;
22735
- while (j < text.length && /\s/.test(text[j])) j++;
22736
- if (j < text.length && text[j] === "]") {
22737
- endIdx = j;
22738
- break;
22739
- }
22740
- }
22741
- }
22742
- }
22743
- }
22744
- if (endIdx !== -1) {
22745
- const beforeText = flattenString(text.substring(lastIdx, match.index));
22746
- if (beforeText.trim()) {
22747
- blocks.push({ type: "output", content: beforeText });
22748
- }
22749
- const finalArgsText = flattenString(text.substring(startIdx + 1, closingParenIdx));
22750
- blocks.push({
22751
- type: "tool",
22752
- toolName: flattenString(toolName.trim()),
22753
- args: flattenString(finalArgsText.trim())
22754
- });
22755
- lastIdx = endIdx + 1;
22756
- toolRegex.lastIndex = lastIdx;
22757
- } else {
22758
- break;
22759
- }
22760
- }
22761
- if (lastIdx < text.length) {
22762
- const remainingText = flattenString(text.substring(lastIdx));
22763
- if (remainingText.trim()) {
22764
- blocks.push({ type: "output", content: remainingText });
22765
- }
22766
- }
22767
- return blocks;
22768
- };
22769
22979
  getProjectFiles = /* @__PURE__ */ (() => {
22770
22980
  let cachedFiles = null;
22771
22981
  let lastScanTime = 0;
@@ -22778,20 +22988,20 @@ var init_app = __esm({
22778
22988
  const scan = (currentDir) => {
22779
22989
  if (fileList.length >= 2e3) return;
22780
22990
  try {
22781
- const files = fs27.readdirSync(currentDir);
22991
+ const files = fs28.readdirSync(currentDir);
22782
22992
  for (const file of files) {
22783
22993
  if (fileList.length >= 2e3) return;
22784
22994
  if (["node_modules", ".git", ".gemini", "dist", "build", ".next", ".cache", "out"].includes(file)) {
22785
22995
  continue;
22786
22996
  }
22787
- const filePath = path25.join(currentDir, file);
22788
- const stat = fs27.statSync(filePath);
22997
+ const filePath = path26.join(currentDir, file);
22998
+ const stat = fs28.statSync(filePath);
22789
22999
  if (stat.isDirectory()) {
22790
23000
  scan(filePath);
22791
23001
  } else {
22792
23002
  fileList.push({
22793
23003
  name: flattenString(file),
22794
- relativePath: flattenString(path25.relative(process.cwd(), filePath))
23004
+ relativePath: flattenString(path26.relative(process.cwd(), filePath))
22795
23005
  });
22796
23006
  }
22797
23007
  }
@@ -22989,13 +23199,32 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
22989
23199
  const isHelp = args.includes("--help") && !isHelpCommands;
22990
23200
  const isVersion = args.includes("--version") || args.includes("-v");
22991
23201
  const isUpdate = args[0] === "--update";
22992
- if (isVersion || isHelp || isHelpCommands || isUpdate) {
22993
- const fs28 = await import("fs");
22994
- const path26 = await import("path");
23202
+ const isExport = args[0] === "--export";
23203
+ if (isVersion || isHelp || isHelpCommands || isUpdate || isExport) {
23204
+ const fs29 = await import("fs");
23205
+ const path27 = await import("path");
22995
23206
  const { fileURLToPath: fileURLToPath5 } = await import("url");
22996
- const packageJsonPath2 = path26.join(path26.dirname(fileURLToPath5(import.meta.url)), "../package.json");
22997
- const packageJson2 = JSON.parse(fs28.readFileSync(packageJsonPath2, "utf8"));
23207
+ const packageJsonPath2 = path27.join(path27.dirname(fileURLToPath5(import.meta.url)), "../package.json");
23208
+ const packageJson2 = JSON.parse(fs29.readFileSync(packageJsonPath2, "utf8"));
22998
23209
  const versionFluxflow2 = packageJson2.version;
23210
+ if (isExport) {
23211
+ const subArg = (args[1] || "").toLowerCase();
23212
+ if (subArg === "error" || subArg === "logs") {
23213
+ try {
23214
+ const { exportErrorLogs: exportErrorLogs2 } = await Promise.resolve().then(() => (init_export(), export_exports));
23215
+ const result = await exportErrorLogs2();
23216
+ console.log(`[EXPORT LOGS] Exported ${result.entryCount} error log entries (FluxFlow: ${result.fluxflowCount}, Memory: ${result.memoryCount}) to "${result.exportFile}"`);
23217
+ process.exit(0);
23218
+ } catch (err) {
23219
+ console.error(`[EXPORT ERROR] Failed to export error logs: ${err.message}`);
23220
+ process.exit(1);
23221
+ }
23222
+ } else {
23223
+ console.error(`[EXPORT ERROR] Invalid export target "${args[1] || ""}". --export only supports 'error'.
23224
+ Usage: fluxflow --export error`);
23225
+ process.exit(1);
23226
+ }
23227
+ }
22999
23228
  if (isVersion) {
23000
23229
  console.log(`v${versionFluxflow2}`);
23001
23230
  process.exit(0);
@@ -23019,6 +23248,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
23019
23248
  --help Show this help menu
23020
23249
  --help commands Show available /commands
23021
23250
  --playground Launch in Playground mode (fixed session, CWD: DATA_DIR/playground)
23251
+ --export error Export system error logs to fluxflow-error-<timestamp>.txt
23022
23252
  --update check Check for new updates
23023
23253
  --update check latest Show the latest version available on npm
23024
23254
  --update [latest] Update the app to the latest version (latest is default)`);
@@ -23033,7 +23263,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
23033
23263
  /compress Summarize and compress chat history
23034
23264
  /revert Revert codebase back to a checkpoint
23035
23265
  /save Force save current chat
23036
- /export Export current chat in a .txt file
23266
+ /export [chat|logs] Export chat session or system error logs
23037
23267
  /chats List all chat sessions
23038
23268
  /btw <question> Send raw inquiry to the agent mid-turn
23039
23269
  /image setup key <default|custom> Configure image API key strategy