fluxflow-cli 1.11.3 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +19 -0
  2. package/dist/fluxflow.js +414 -228
  3. package/package.json +2 -1
package/dist/fluxflow.js CHANGED
@@ -609,18 +609,26 @@ var init_CommandMenu = __esm({
609
609
  });
610
610
 
611
611
  // src/components/ProfileForm.jsx
612
- import React5, { useState as useState2 } from "react";
612
+ import React5, { useState as useState2, useEffect as useEffect2 } from "react";
613
613
  import { Box as Box5, Text as Text5 } from "ink";
614
614
  import TextInput from "ink-text-input";
615
- function ProfileForm({ onSave, onCancel }) {
615
+ function ProfileForm({ initialData, onSave, onCancel }) {
616
616
  const [step, setStep] = useState2(0);
617
617
  const [currentInput, setCurrentInput] = useState2("");
618
- const [profile, setProfile] = useState2({ name: "", nickname: "", instructions: "" });
618
+ const [profile, setProfile] = useState2(() => ({
619
+ name: initialData?.name || "",
620
+ nickname: initialData?.nickname || "",
621
+ instructions: initialData?.instructions || ""
622
+ }));
619
623
  const steps = [
620
624
  { key: "name", label: "Enter your Name: " },
621
625
  { key: "nickname", label: "Enter a Nickname (Agent will use this): " },
622
626
  { key: "instructions", label: "System Instructions (Persona overrides): " }
623
627
  ];
628
+ useEffect2(() => {
629
+ const currentKey = steps[step].key;
630
+ setCurrentInput(profile[currentKey] || "");
631
+ }, [step, profile]);
624
632
  const handleSubmit = (val) => {
625
633
  if (val.trim().toLowerCase() === "/cancel") {
626
634
  onCancel();
@@ -714,7 +722,8 @@ var init_AskUserModal = __esm({
714
722
  flexDirection: "column",
715
723
  width: "100%",
716
724
  backgroundColor: isSelected ? "#2a2a2a" : void 0,
717
- paddingX: 1
725
+ paddingX: 1,
726
+ marginBottom: idx === allOptions.length - 1 ? 0 : 1
718
727
  },
719
728
  /* @__PURE__ */ React6.createElement(Text6, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", opt.label),
720
729
  opt.description && /* @__PURE__ */ React6.createElement(Box6, { marginLeft: 4 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", italic: true, dimColor: true }, opt.description))
@@ -952,11 +961,11 @@ ${mode === "Flux" ? `- FILE TOOLS (path = relative to CWD) -
952
961
  2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
953
962
  3. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? -> update_file > write_file
954
963
  4. [tool:functions.PatchFile(path="...", content_to_replace="exact old content", content_to_add="new content")]. Surgical patching. Unsure content_to_replace? -> view_file >> guessing.
955
- 5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. A4 PDF. Use CSS for layout (100vh/vw). Handle page breaks; no manual footers
964
+ 5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. A4 PDF. HTML/CSS for premium layout (100vh/vw). Handle page breaks; no manual footers
956
965
  6. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word doc. Proper margins and page breaks
957
966
  7. [tool:functions.Run(command="...")]. Runs a shell command. Destructive/Irreversible ops -> ask user
958
967
  8. [tool:functions.SearchKeyword(keyword="...")]. Global search. Finds definitions/logic without reading every file
959
- 9. [tool:functions.GenerateImage(path="... png", prompt="...", ratio="16:9, 9:16, 1:1, 4:3, 3:4")]. AI images. Usage: Mockups, PDF thumbnails, any visual content
968
+ 9. [tool:functions.GenerateImage(path="... png", prompt="detailed", ratio="16:9, 9:16, 1:1, 4:3, 3:4")]. AI images. Usage: Mockups, PDF thumbnails, any visual content
960
969
 
961
970
  - VERIFY RESULT CONTENTS. Fix errors. No hallucinations
962
971
  - File tools > code chat
@@ -1404,18 +1413,49 @@ var init_usage = __esm({
1404
1413
  };
1405
1414
  loadUsageFromFile = async () => {
1406
1415
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1416
+ const tempFile = USAGE_FILE + ".tmp";
1407
1417
  let primaryData = null;
1408
1418
  let backupData = null;
1409
1419
  try {
1410
- if (await fs6.exists(USAGE_FILE)) {
1411
- const rawContent = (await fs6.readFile(USAGE_FILE, "utf8")).trim();
1420
+ if (await fs6.exists(tempFile)) {
1421
+ const rawContent = (await fs6.readFile(tempFile, "utf8")).trim();
1422
+ let parsed = null;
1412
1423
  if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
1413
- primaryData = JSON.parse(rawContent);
1424
+ parsed = JSON.parse(rawContent);
1414
1425
  } else {
1415
- primaryData = JSON.parse(decryptAes(rawContent));
1426
+ parsed = JSON.parse(decryptAes(rawContent));
1427
+ }
1428
+ if (parsed && parsed.date && parsed.stats) {
1429
+ primaryData = parsed;
1430
+ try {
1431
+ await fs6.rename(tempFile, USAGE_FILE);
1432
+ } catch (e) {
1433
+ }
1434
+ } else {
1435
+ try {
1436
+ await fs6.remove(tempFile);
1437
+ } catch (e) {
1438
+ }
1416
1439
  }
1417
1440
  }
1418
1441
  } catch (err) {
1442
+ try {
1443
+ await fs6.remove(tempFile);
1444
+ } catch (e) {
1445
+ }
1446
+ }
1447
+ if (!primaryData) {
1448
+ try {
1449
+ if (await fs6.exists(USAGE_FILE)) {
1450
+ const rawContent = (await fs6.readFile(USAGE_FILE, "utf8")).trim();
1451
+ if (rawContent.startsWith("{") || rawContent.startsWith("[")) {
1452
+ primaryData = JSON.parse(rawContent);
1453
+ } else {
1454
+ primaryData = JSON.parse(decryptAes(rawContent));
1455
+ }
1456
+ }
1457
+ } catch (err) {
1458
+ }
1419
1459
  }
1420
1460
  try {
1421
1461
  if (await fs6.exists(BACKUP_FILE)) {
@@ -2148,70 +2188,9 @@ var init_chat = __esm({
2148
2188
  }
2149
2189
  });
2150
2190
 
2151
- // src/tools/list_files.js
2191
+ // src/tools/view_file.js
2152
2192
  import fs7 from "fs";
2153
2193
  import path6 from "path";
2154
- var list_files;
2155
- var init_list_files = __esm({
2156
- "src/tools/list_files.js"() {
2157
- init_arg_parser();
2158
- list_files = async (args) => {
2159
- const { path: targetPath = "." } = parseArgs(args);
2160
- const absolutePath = path6.resolve(process.cwd(), targetPath);
2161
- try {
2162
- if (!fs7.existsSync(absolutePath)) {
2163
- return `ERROR: Path [${targetPath}] does not exist.`;
2164
- }
2165
- const stats = fs7.statSync(absolutePath);
2166
- if (!stats.isDirectory()) {
2167
- return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
2168
- }
2169
- const files = fs7.readdirSync(absolutePath);
2170
- if (files.length === 0) {
2171
- return `Directory [${targetPath}] is empty.`;
2172
- }
2173
- const totalFiles = files.length;
2174
- const maxDisplay = 100;
2175
- const displayFiles = files.slice(0, maxDisplay);
2176
- const list = displayFiles.map((file) => {
2177
- const fPath = path6.join(absolutePath, file);
2178
- let indicator = "\u{1F4C4}";
2179
- let metaPart = "";
2180
- try {
2181
- const fStats = fs7.statSync(fPath);
2182
- indicator = fStats.isDirectory() ? "\u{1F4C1}" : "\u{1F4C4}";
2183
- const sizeKB = (fStats.size / 1024).toFixed(1);
2184
- metaPart = fStats.isFile() ? ` - [${sizeKB} KB]` : "";
2185
- } catch (e) {
2186
- indicator = "\u2753";
2187
- metaPart = " - [Access Denied]";
2188
- }
2189
- return `${indicator} ${file}${metaPart}`;
2190
- }).join("\n");
2191
- let footer = `
2192
-
2193
- (Total items: ${totalFiles})`;
2194
- if (totalFiles > maxDisplay) {
2195
- footer = `
2196
-
2197
- \u26A0\uFE0F TRUNCATED: Showing first ${maxDisplay} of ${totalFiles} items. Use more specific paths to see others.`;
2198
- }
2199
- const result = `Contents of [${targetPath}]:
2200
-
2201
- ${list}${footer}`;
2202
- files.length = 0;
2203
- displayFiles.length = 0;
2204
- return result;
2205
- } catch (err) {
2206
- return `ERROR: Failed to list files in [${targetPath}]: ${err.message}`;
2207
- }
2208
- };
2209
- }
2210
- });
2211
-
2212
- // src/tools/view_file.js
2213
- import fs8 from "fs";
2214
- import path7 from "path";
2215
2194
  var view_file;
2216
2195
  var init_view_file = __esm({
2217
2196
  "src/tools/view_file.js"() {
@@ -2223,16 +2202,21 @@ var init_view_file = __esm({
2223
2202
  const finalStart = sLine || 1;
2224
2203
  const finalEnd = eLine || (sLine ? sLine + 800 : 800);
2225
2204
  if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
2226
- const absolutePath = path7.resolve(process.cwd(), targetPath);
2205
+ const absolutePath = path6.resolve(process.cwd(), targetPath);
2227
2206
  try {
2228
- if (!fs8.existsSync(absolutePath)) {
2207
+ if (!fs7.existsSync(absolutePath)) {
2229
2208
  return `ERROR: File [${targetPath}] does not exist.`;
2230
2209
  }
2231
- const stats = fs8.statSync(absolutePath);
2210
+ const stats = fs7.statSync(absolutePath);
2232
2211
  if (stats.isDirectory()) {
2233
2212
  return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
2234
2213
  }
2235
- const ext = path7.extname(targetPath).toLowerCase();
2214
+ const ext = path6.extname(targetPath).toLowerCase();
2215
+ const videoExtensions = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".mpeg", ".mpg"];
2216
+ if (videoExtensions.includes(ext)) {
2217
+ const format = ext.slice(1).toUpperCase();
2218
+ return `ERROR: Unable to read. Type ${format} not supported`;
2219
+ }
2236
2220
  const mimeMap = {
2237
2221
  ".pdf": "application/pdf",
2238
2222
  ".jpg": "image/jpeg",
@@ -2243,7 +2227,7 @@ var init_view_file = __esm({
2243
2227
  ".doc": "application/msword"
2244
2228
  };
2245
2229
  if (mimeMap[ext]) {
2246
- const buffer = fs8.readFileSync(absolutePath);
2230
+ const buffer = fs7.readFileSync(absolutePath);
2247
2231
  const base64 = buffer.toString("base64");
2248
2232
  const mimeType = mimeMap[ext];
2249
2233
  return {
@@ -2256,7 +2240,7 @@ var init_view_file = __esm({
2256
2240
  }
2257
2241
  };
2258
2242
  }
2259
- let content = fs8.readFileSync(absolutePath, "utf8");
2243
+ let content = fs7.readFileSync(absolutePath, "utf8");
2260
2244
  if (content.startsWith("\uFEFF")) {
2261
2245
  content = content.slice(1);
2262
2246
  }
@@ -2279,8 +2263,8 @@ ${code}`;
2279
2263
  });
2280
2264
 
2281
2265
  // src/tools/write_file.js
2282
- import fs9 from "fs";
2283
- import path8 from "path";
2266
+ import fs8 from "fs";
2267
+ import path7 from "path";
2284
2268
  var write_file;
2285
2269
  var init_write_file = __esm({
2286
2270
  "src/tools/write_file.js"() {
@@ -2290,13 +2274,13 @@ var init_write_file = __esm({
2290
2274
  if (!targetPath) return 'ERROR: Missing "path" argument for write_file.';
2291
2275
  if (content === void 0) return 'ERROR: Missing "content" argument for write_file.';
2292
2276
  content = content.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2293
- const absolutePath = path8.resolve(process.cwd(), targetPath);
2294
- const parentDir = path8.dirname(absolutePath);
2277
+ const absolutePath = path7.resolve(process.cwd(), targetPath);
2278
+ const parentDir = path7.dirname(absolutePath);
2295
2279
  try {
2296
2280
  let ancestry = "";
2297
- if (fs9.existsSync(absolutePath)) {
2281
+ if (fs8.existsSync(absolutePath)) {
2298
2282
  try {
2299
- const oldData = fs9.readFileSync(absolutePath, "utf8");
2283
+ const oldData = fs8.readFileSync(absolutePath, "utf8");
2300
2284
  const lines = oldData.split(/\r?\n/);
2301
2285
  ancestry = `Old File contents:
2302
2286
  ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
@@ -2308,15 +2292,15 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
2308
2292
  `;
2309
2293
  }
2310
2294
  }
2311
- if (!fs9.existsSync(parentDir)) {
2312
- fs9.mkdirSync(parentDir, { recursive: true });
2295
+ if (!fs8.existsSync(parentDir)) {
2296
+ fs8.mkdirSync(parentDir, { recursive: true });
2313
2297
  }
2314
2298
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2315
2299
  const processedContent = strip(content);
2316
2300
  const lineCount = processedContent.split(/\r?\n/).length;
2317
2301
  const originalSize = Buffer.byteLength(processedContent, "utf8");
2318
- fs9.writeFileSync(absolutePath, processedContent, "utf8");
2319
- let verifiedContent = fs9.readFileSync(absolutePath, "utf8");
2302
+ fs8.writeFileSync(absolutePath, processedContent, "utf8");
2303
+ let verifiedContent = fs8.readFileSync(absolutePath, "utf8");
2320
2304
  const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
2321
2305
  const verifiedLines = verifiedContent.split(/\r?\n/);
2322
2306
  const verifiedLineCount = verifiedLines.length;
@@ -2352,8 +2336,8 @@ Check if Starting and Ending matches your write.`;
2352
2336
  });
2353
2337
 
2354
2338
  // src/tools/update_file.js
2355
- import fs10 from "fs";
2356
- import path9 from "path";
2339
+ import fs9 from "fs";
2340
+ import path8 from "path";
2357
2341
  var update_file;
2358
2342
  var init_update_file = __esm({
2359
2343
  "src/tools/update_file.js"() {
@@ -2366,18 +2350,18 @@ var init_update_file = __esm({
2366
2350
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2367
2351
  content_to_replace = strip(content_to_replace);
2368
2352
  content_to_add = strip(content_to_add);
2369
- const absolutePath = path9.resolve(process.cwd(), targetPath);
2353
+ const absolutePath = path8.resolve(process.cwd(), targetPath);
2370
2354
  try {
2371
- if (!fs10.existsSync(absolutePath)) {
2355
+ if (!fs9.existsSync(absolutePath)) {
2372
2356
  return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
2373
2357
  }
2374
- let diskContent = fs10.readFileSync(absolutePath, "utf8");
2358
+ let diskContent = fs9.readFileSync(absolutePath, "utf8");
2375
2359
  if (diskContent.startsWith("\uFEFF")) {
2376
2360
  diskContent = diskContent.slice(1);
2377
2361
  }
2378
2362
  const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2379
2363
  if (diskContent !== normalizedDisk) {
2380
- fs10.writeFileSync(absolutePath, normalizedDisk, "utf8");
2364
+ fs9.writeFileSync(absolutePath, normalizedDisk, "utf8");
2381
2365
  diskContent = normalizedDisk;
2382
2366
  }
2383
2367
  const currentContent = diskContent;
@@ -2446,7 +2430,7 @@ var init_update_file = __esm({
2446
2430
  const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
2447
2431
  const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
2448
2432
  const finalContentToReplace = firstMatchContent;
2449
- fs10.writeFileSync(absolutePath, newFileContent, "utf8");
2433
+ fs9.writeFileSync(absolutePath, newFileContent, "utf8");
2450
2434
  const allOriginalLines = currentContent.split(/\r?\n/);
2451
2435
  const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
2452
2436
  const oldLines = content_to_replace.split(/\r?\n/);
@@ -2709,34 +2693,34 @@ ${finalOutput}`);
2709
2693
  });
2710
2694
 
2711
2695
  // src/tools/read_folder.js
2712
- import fs11 from "fs";
2713
- import path10 from "path";
2696
+ import fs10 from "fs";
2697
+ import path9 from "path";
2714
2698
  var read_folder;
2715
2699
  var init_read_folder = __esm({
2716
2700
  "src/tools/read_folder.js"() {
2717
2701
  init_arg_parser();
2718
2702
  read_folder = async (args) => {
2719
2703
  const { path: targetPath = "." } = parseArgs(args);
2720
- const absolutePath = path10.resolve(process.cwd(), targetPath);
2704
+ const absolutePath = path9.resolve(process.cwd(), targetPath);
2721
2705
  try {
2722
- if (!fs11.existsSync(absolutePath)) {
2706
+ if (!fs10.existsSync(absolutePath)) {
2723
2707
  return `ERROR: Path [${targetPath}] does not exist.`;
2724
2708
  }
2725
- const stats = fs11.statSync(absolutePath);
2709
+ const stats = fs10.statSync(absolutePath);
2726
2710
  if (!stats.isDirectory()) {
2727
2711
  return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
2728
2712
  }
2729
- const files = fs11.readdirSync(absolutePath);
2713
+ const files = fs10.readdirSync(absolutePath);
2730
2714
  const totalItems = files.length;
2731
2715
  const maxDisplay = 100;
2732
2716
  const displayItems = files.slice(0, maxDisplay);
2733
2717
  const folderData = [];
2734
2718
  for (const file of displayItems) {
2735
- const fPath = path10.join(absolutePath, file);
2719
+ const fPath = path9.join(absolutePath, file);
2736
2720
  let indicator = "\u{1F4C4}";
2737
2721
  let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
2738
2722
  try {
2739
- const fStats = fs11.statSync(fPath);
2723
+ const fStats = fs10.statSync(fPath);
2740
2724
  info = {
2741
2725
  name: file,
2742
2726
  type: fStats.isDirectory() ? "directory" : "file",
@@ -2819,8 +2803,8 @@ var init_ask_user = __esm({
2819
2803
 
2820
2804
  // src/tools/write_pdf.js
2821
2805
  import puppeteer3 from "puppeteer";
2822
- import path11 from "path";
2823
- import fs12 from "fs-extra";
2806
+ import path10 from "path";
2807
+ import fs11 from "fs-extra";
2824
2808
  import { PDFDocument } from "pdf-lib";
2825
2809
  var write_pdf;
2826
2810
  var init_write_pdf = __esm({
@@ -2835,10 +2819,10 @@ var init_write_pdf = __esm({
2835
2819
  } = parseArgs(args);
2836
2820
  if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
2837
2821
  if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
2838
- const absolutePath = path11.resolve(process.cwd(), targetPath);
2822
+ const absolutePath = path10.resolve(process.cwd(), targetPath);
2839
2823
  let browser = null;
2840
2824
  try {
2841
- await fs12.ensureDir(path11.dirname(absolutePath));
2825
+ await fs11.ensureDir(path10.dirname(absolutePath));
2842
2826
  browser = await puppeteer3.launch({
2843
2827
  headless: true,
2844
2828
  args: [
@@ -2850,24 +2834,69 @@ var init_write_pdf = __esm({
2850
2834
  });
2851
2835
  const page = await browser.newPage();
2852
2836
  let resolvedContent = content;
2853
- const imgRegex = /<img[^>]+src=["']([^"']+)["']/gi;
2854
- let match;
2855
- while ((match = imgRegex.exec(content)) !== null) {
2856
- const originalSrc = match[1];
2837
+ const resolvedCache = {};
2838
+ const resolveToBase64 = async (originalSrc) => {
2857
2839
  if (!originalSrc || originalSrc.startsWith("http://") || originalSrc.startsWith("https://") || originalSrc.startsWith("data:")) {
2858
- continue;
2840
+ return null;
2859
2841
  }
2860
2842
  try {
2861
- const imgPath = path11.resolve(process.cwd(), originalSrc);
2862
- if (await fs12.pathExists(imgPath)) {
2863
- const ext = path11.extname(imgPath).toLowerCase().replace(".", "") || "png";
2843
+ const imgPath = path10.resolve(process.cwd(), originalSrc);
2844
+ if (await fs11.pathExists(imgPath)) {
2845
+ const ext = path10.extname(imgPath).toLowerCase().replace(".", "") || "png";
2864
2846
  const mime = ext === "jpg" ? "jpeg" : ext === "svg" ? "svg+xml" : ext;
2865
- const base64 = await fs12.readFile(imgPath, "base64");
2866
- const dataUri = `data:image/${mime};base64,${base64}`;
2867
- resolvedContent = resolvedContent.split(originalSrc).join(dataUri);
2847
+ const base64 = await fs11.readFile(imgPath, "base64");
2848
+ return `data:image/${mime};base64,${base64}`;
2868
2849
  }
2869
2850
  } catch (e) {
2870
2851
  }
2852
+ return null;
2853
+ };
2854
+ const linkRegex = /<link[^>]+href=["']([^"']+)["']/gi;
2855
+ const cssCache = {};
2856
+ let match;
2857
+ while ((match = linkRegex.exec(content)) !== null) {
2858
+ const originalHref = match[1];
2859
+ const fullTag = match[0];
2860
+ if (originalHref && fullTag.toLowerCase().includes("stylesheet") && !originalHref.startsWith("http://") && !originalHref.startsWith("https://") && !originalHref.startsWith("data:")) {
2861
+ try {
2862
+ const cssPath = path10.resolve(process.cwd(), originalHref);
2863
+ if (await fs11.pathExists(cssPath)) {
2864
+ const cssContent = await fs11.readFile(cssPath, "utf-8");
2865
+ cssCache[fullTag] = `<style>${cssContent}</style>`;
2866
+ }
2867
+ } catch (e) {
2868
+ }
2869
+ }
2870
+ }
2871
+ for (const [tag, styleTag] of Object.entries(cssCache)) {
2872
+ resolvedContent = resolvedContent.split(tag).join(styleTag);
2873
+ }
2874
+ const imgRegex = /<img[^>]+src=["']([^"']+)["']/gi;
2875
+ while ((match = imgRegex.exec(resolvedContent)) !== null) {
2876
+ const originalSrc = match[1];
2877
+ if (originalSrc && !resolvedCache[originalSrc]) {
2878
+ const dataUri = await resolveToBase64(originalSrc);
2879
+ if (dataUri) {
2880
+ resolvedCache[originalSrc] = dataUri;
2881
+ }
2882
+ }
2883
+ }
2884
+ const urlRegex = /url\(\s*['"]?([^'")]+?)['"]?\s*\)/gi;
2885
+ while ((match = urlRegex.exec(resolvedContent)) !== null) {
2886
+ const originalSrc = match[1].trim();
2887
+ if (originalSrc && !resolvedCache[originalSrc]) {
2888
+ const dataUri = await resolveToBase64(originalSrc);
2889
+ if (dataUri) {
2890
+ resolvedCache[originalSrc] = dataUri;
2891
+ }
2892
+ }
2893
+ }
2894
+ for (const [originalSrc, dataUri] of Object.entries(resolvedCache)) {
2895
+ const escapedSrc = originalSrc.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
2896
+ const srcRegex = new RegExp(`(src=["'])(${escapedSrc})(["'])`, "gi");
2897
+ resolvedContent = resolvedContent.replace(srcRegex, `$1${dataUri}$3`);
2898
+ const urlReplaceRegex = new RegExp(`url\\(\\s*(['"]?)(${escapedSrc})\\1\\s*\\)`, "gi");
2899
+ resolvedContent = resolvedContent.replace(urlReplaceRegex, `url($1${dataUri}$1)`);
2871
2900
  }
2872
2901
  const styledContent = `
2873
2902
  <style>
@@ -2903,7 +2932,7 @@ var init_write_pdf = __esm({
2903
2932
  await page.setContent(styledContent, { waitUntil: "networkidle0", timeout: 18e4 });
2904
2933
  const pdfBytes = await page.pdf({
2905
2934
  format: "A4",
2906
- landscape: orientation.toLowerCase() === "landscape",
2935
+ landscape: String(orientation).toLowerCase() === "landscape",
2907
2936
  margin: {
2908
2937
  top: margin,
2909
2938
  right: margin,
@@ -2913,7 +2942,7 @@ var init_write_pdf = __esm({
2913
2942
  printBackground: true
2914
2943
  });
2915
2944
  const pdfDoc = await PDFDocument.load(pdfBytes);
2916
- const fileName = path11.basename(targetPath);
2945
+ const fileName = path10.basename(targetPath);
2917
2946
  pdfDoc.setTitle(`FluxFlow_${fileName}`);
2918
2947
  pdfDoc.setAuthor("FluxFlow CLI");
2919
2948
  pdfDoc.setSubject("Generated with Agentic AI System");
@@ -2921,8 +2950,8 @@ var init_write_pdf = __esm({
2921
2950
  pdfDoc.setCreator("FluxFlow PDF Engine");
2922
2951
  pdfDoc.setProducer("FluxFlow (Generative AI)");
2923
2952
  const finalPdfBytes = await pdfDoc.save();
2924
- await fs12.writeFile(absolutePath, finalPdfBytes);
2925
- const stats = await fs12.stat(absolutePath);
2953
+ await fs11.writeFile(absolutePath, finalPdfBytes);
2954
+ const stats = await fs11.stat(absolutePath);
2926
2955
  return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
2927
2956
  } catch (err) {
2928
2957
  return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
@@ -2934,8 +2963,8 @@ var init_write_pdf = __esm({
2934
2963
  });
2935
2964
 
2936
2965
  // src/tools/write_docx.js
2937
- import fs13 from "fs-extra";
2938
- import path12 from "path";
2966
+ import fs12 from "fs-extra";
2967
+ import path11 from "path";
2939
2968
  import HTMLtoDOCX from "html-to-docx";
2940
2969
  var write_docx;
2941
2970
  var init_write_docx = __esm({
@@ -2948,10 +2977,10 @@ var init_write_docx = __esm({
2948
2977
  } = parseArgs(args);
2949
2978
  if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
2950
2979
  if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
2951
- const absolutePath = path12.resolve(process.cwd(), targetPath);
2980
+ const absolutePath = path11.resolve(process.cwd(), targetPath);
2952
2981
  try {
2953
- await fs13.ensureDir(path12.dirname(absolutePath));
2954
- const fileName = path12.basename(targetPath);
2982
+ await fs12.ensureDir(path11.dirname(absolutePath));
2983
+ const fileName = path11.basename(targetPath);
2955
2984
  const fullHtml = content.includes("<html") ? content : `
2956
2985
  <!DOCTYPE html>
2957
2986
  <html lang="en">
@@ -2972,7 +3001,7 @@ var init_write_docx = __esm({
2972
3001
  footer: true,
2973
3002
  pageNumber: true
2974
3003
  });
2975
- await fs13.writeFile(absolutePath, docxBuffer);
3004
+ await fs12.writeFile(absolutePath, docxBuffer);
2976
3005
  return `SUCCESS: Word document [${targetPath}] generated successfully.
2977
3006
  - Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
2978
3007
  } catch (err) {
@@ -3029,7 +3058,7 @@ var init_search_keyword = __esm({
3029
3058
  `;
3030
3059
  output += matches.join("\n");
3031
3060
  if (filteredLines.length > 100) {
3032
- output += "\n\n... (Truncated to first 100 matches to avoid context bloat)";
3061
+ output += "\n\n... (Truncated to first 100 matches)";
3033
3062
  }
3034
3063
  resolve(output);
3035
3064
  });
@@ -3039,8 +3068,8 @@ var init_search_keyword = __esm({
3039
3068
  });
3040
3069
 
3041
3070
  // src/utils/settings.js
3042
- import fs14 from "fs-extra";
3043
- import path13 from "path";
3071
+ import fs13 from "fs-extra";
3072
+ import path12 from "path";
3044
3073
  var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
3045
3074
  var init_settings = __esm({
3046
3075
  "src/utils/settings.js"() {
@@ -3082,7 +3111,7 @@ var init_settings = __esm({
3082
3111
  loadSettings = async () => {
3083
3112
  let settingsObj = { ...DEFAULT_SETTINGS };
3084
3113
  try {
3085
- if (await fs14.exists(SETTINGS_FILE)) {
3114
+ if (await fs13.exists(SETTINGS_FILE)) {
3086
3115
  const saved = readAesEncryptedJson(SETTINGS_FILE);
3087
3116
  if (saved.imageSettings && saved.imageSettings.apiKey) {
3088
3117
  try {
@@ -3127,12 +3156,12 @@ var init_settings = __esm({
3127
3156
  const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
3128
3157
  const folders = ["logs", "secret"];
3129
3158
  for (const folder of folders) {
3130
- const src = path13.join(FLUXFLOW_DIR2, folder);
3131
- const dest = path13.join(newPath, folder);
3159
+ const src = path12.join(FLUXFLOW_DIR2, folder);
3160
+ const dest = path12.join(newPath, folder);
3132
3161
  try {
3133
- if (await fs14.exists(src)) {
3134
- await fs14.ensureDir(dest);
3135
- await fs14.copy(src, dest, { overwrite: true });
3162
+ if (await fs13.exists(src)) {
3163
+ await fs13.ensureDir(dest);
3164
+ await fs13.copy(src, dest, { overwrite: true });
3136
3165
  }
3137
3166
  } catch (err) {
3138
3167
  console.error(`Migration failed for ${folder}:`, err);
@@ -3158,7 +3187,7 @@ var init_settings = __esm({
3158
3187
  if (updated.imageSettings) {
3159
3188
  updated.imageSettings = { ...updated.imageSettings, apiKey: "" };
3160
3189
  }
3161
- await fs14.ensureDir(path13.dirname(SETTINGS_FILE));
3190
+ await fs13.ensureDir(path12.dirname(SETTINGS_FILE));
3162
3191
  writeAesEncryptedJson(SETTINGS_FILE, updated);
3163
3192
  return true;
3164
3193
  } catch (err) {
@@ -3178,8 +3207,8 @@ var init_fallback_key = __esm({
3178
3207
  });
3179
3208
 
3180
3209
  // src/tools/generate_image.js
3181
- import fs15 from "fs-extra";
3182
- import path14 from "path";
3210
+ import fs14 from "fs-extra";
3211
+ import path13 from "path";
3183
3212
  var injectPngMetadata, generate_image;
3184
3213
  var init_generate_image = __esm({
3185
3214
  "src/tools/generate_image.js"() {
@@ -3251,6 +3280,30 @@ var init_generate_image = __esm({
3251
3280
  if (!prompt) {
3252
3281
  return 'ERROR: Missing "prompt" argument for generate_image.';
3253
3282
  }
3283
+ const BLOCKED_KEYWORDS = [
3284
+ "nsfw",
3285
+ "naked",
3286
+ "nudity",
3287
+ "nude",
3288
+ "porn",
3289
+ "sex",
3290
+ "xxx",
3291
+ "erotic",
3292
+ "gore",
3293
+ "bloody",
3294
+ "violence",
3295
+ "abuse",
3296
+ "suicide",
3297
+ "murder",
3298
+ "hentai",
3299
+ "pedophile",
3300
+ "rape"
3301
+ ];
3302
+ const promptLower = prompt.toLowerCase();
3303
+ const isBlocked = BLOCKED_KEYWORDS.some((kw) => promptLower.includes(kw));
3304
+ if (isBlocked) {
3305
+ return "ERROR: Prompt blocked by system safety filter (inappropriate or unsafe content detected).";
3306
+ }
3254
3307
  try {
3255
3308
  const settings = await loadSettings();
3256
3309
  const hasQuota = await checkImageQuota(settings);
@@ -3292,7 +3345,8 @@ var init_generate_image = __esm({
3292
3345
  }
3293
3346
  }
3294
3347
  const seed = Math.floor(Math.random() * 1e7);
3295
- const url = `https://gen.pollinations.ai/image/${encodeURIComponent(prompt)}?model=${selectedModel}&width=${width}&height=${height}&seed=${seed}&enhance=true&reasoning=high&quality=high`;
3348
+ const negativePrompt = "deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, disconnected limbs, mutation, mutated hands and fingers, blurry, low quality, low resolution, extra fingers, censored, watermarks, signatures";
3349
+ const url = `https://gen.pollinations.ai/image/${encodeURIComponent(prompt)}?model=${selectedModel}&width=${width}&height=${height}&seed=${seed}&enhance=true&reasoning=high&quality=high&negative=${encodeURIComponent(negativePrompt)}`;
3296
3350
  const response = await fetch(url, {
3297
3351
  method: "GET",
3298
3352
  headers: {
@@ -3333,9 +3387,9 @@ var init_generate_image = __esm({
3333
3387
  "Seed": String(seed)
3334
3388
  };
3335
3389
  finalBuffer = injectPngMetadata(finalBuffer, metadata);
3336
- const absolutePath = path14.resolve(process.cwd(), outputPath);
3337
- await fs15.ensureDir(path14.dirname(absolutePath));
3338
- await fs15.writeFile(absolutePath, finalBuffer);
3390
+ const absolutePath = path13.resolve(process.cwd(), outputPath);
3391
+ await fs14.ensureDir(path13.dirname(absolutePath));
3392
+ await fs14.writeFile(absolutePath, finalBuffer);
3339
3393
  await recordImageGeneration(settings);
3340
3394
  return `SUCCESS: Image successfully generated from prompt [${prompt}] and saved to [${outputPath}].`;
3341
3395
  } catch (err) {
@@ -3353,7 +3407,6 @@ var init_tools = __esm({
3353
3407
  init_web_scrape();
3354
3408
  init_memory();
3355
3409
  init_chat();
3356
- init_list_files();
3357
3410
  init_view_file();
3358
3411
  init_write_file();
3359
3412
  init_update_file();
@@ -3369,7 +3422,6 @@ var init_tools = __esm({
3369
3422
  web_scrape,
3370
3423
  memory,
3371
3424
  chat,
3372
- list_files,
3373
3425
  view_file,
3374
3426
  write_file,
3375
3427
  update_file,
@@ -3412,8 +3464,8 @@ var init_tools = __esm({
3412
3464
 
3413
3465
  // src/utils/ai.js
3414
3466
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
3415
- import path15 from "path";
3416
- import fs16 from "fs";
3467
+ import path14 from "path";
3468
+ import fs15 from "fs";
3417
3469
  var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
3418
3470
  var init_ai = __esm({
3419
3471
  "src/utils/ai.js"() {
@@ -3449,7 +3501,7 @@ var init_ai = __esm({
3449
3501
  try {
3450
3502
  const pArgs = parseArgs(argsStr);
3451
3503
  const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
3452
- return filePath ? path15.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
3504
+ return filePath ? path14.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/")) : null;
3453
3505
  } catch (e) {
3454
3506
  return null;
3455
3507
  }
@@ -3562,8 +3614,8 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
3562
3614
  const toolContext = { chatId, sessionId: chatId, history };
3563
3615
  const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
3564
3616
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
3565
- const janitorLogDir = path15.join(LOGS_DIR, "janitor");
3566
- fs16.appendFileSync(path15.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
3617
+ const janitorLogDir = path14.join(LOGS_DIR, "janitor");
3618
+ fs15.appendFileSync(path14.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
3567
3619
  `);
3568
3620
  if (janitorToolCall.toolName.toLowerCase() === "memory" && !janitorToolCall.args.includes("action='temp'")) {
3569
3621
  if (onMemoryUpdated) onMemoryUpdated();
@@ -3581,9 +3633,9 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
3581
3633
  process.stdout.write(`\x1B]0;Memory Error\x07`);
3582
3634
  }
3583
3635
  await new Promise((resolve) => setTimeout(resolve, 3e3));
3584
- const janitorErrDir = path15.join(LOGS_DIR, "janitor");
3585
- if (!fs16.existsSync(janitorErrDir)) fs16.mkdirSync(janitorErrDir, { recursive: true });
3586
- fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
3636
+ const janitorErrDir = path14.join(LOGS_DIR, "janitor");
3637
+ if (!fs15.existsSync(janitorErrDir)) fs15.mkdirSync(janitorErrDir, { recursive: true });
3638
+ fs15.appendFileSync(path14.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
3587
3639
 
3588
3640
  `);
3589
3641
  if (attempts > MAX_JANITOR_RETRIES) break;
@@ -3592,8 +3644,8 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
3592
3644
  }
3593
3645
  }
3594
3646
  if (attempts) {
3595
- const janitorErrDir = path15.join(LOGS_DIR, "janitor");
3596
- fs16.appendFileSync(path15.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
3647
+ const janitorErrDir = path14.join(LOGS_DIR, "janitor");
3648
+ fs15.appendFileSync(path14.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
3597
3649
 
3598
3650
 
3599
3651
  `);
@@ -4036,12 +4088,12 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
4036
4088
  if (keyword) {
4037
4089
  detail = keyword.replace(/["']/g, "");
4038
4090
  } else if (filePath) {
4039
- detail = path15.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
4091
+ detail = path14.basename(filePath.replace(/["']/g, "").replace(/\\/g, "/"));
4040
4092
  } else {
4041
4093
  const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
4042
4094
  if (m) {
4043
4095
  const val = m[1].replace(/["']/g, "");
4044
- detail = potentialTool === "search_keyword" ? val : path15.basename(val.replace(/\\/g, "/"));
4096
+ detail = potentialTool === "search_keyword" ? val : path14.basename(val.replace(/\\/g, "/"));
4045
4097
  }
4046
4098
  }
4047
4099
  }
@@ -4201,9 +4253,9 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
4201
4253
  let totalLines = "...";
4202
4254
  let actualEndLine = eLine;
4203
4255
  try {
4204
- const absPath = path15.resolve(process.cwd(), targetPath2);
4205
- if (fs16.existsSync(absPath)) {
4206
- const content = fs16.readFileSync(absPath, "utf8");
4256
+ const absPath = path14.resolve(process.cwd(), targetPath2);
4257
+ if (fs15.existsSync(absPath)) {
4258
+ const content = fs15.readFileSync(absPath, "utf8");
4207
4259
  const lines = content.split("\n").length;
4208
4260
  totalLines = lines;
4209
4261
  actualEndLine = Math.min(eLine, lines);
@@ -4254,7 +4306,7 @@ ${boxBottom}` };
4254
4306
  const { command } = parseArgs(toolCall.args);
4255
4307
  if (command && settings.systemSettings && settings.systemSettings.allowExternalAccess === false) {
4256
4308
  const riskyPatterns = [/[a-zA-Z]:[\\\/]/i, /^\//, /\.\.[\\\/]/, /\/etc\//, /\/var\//, /\/root\//, /\/bin\//, /\/usr\//];
4257
- const currentDrive = path15.resolve(process.cwd()).substring(0, 3).toLowerCase();
4309
+ const currentDrive = path14.resolve(process.cwd()).substring(0, 3).toLowerCase();
4258
4310
  const isViolating = riskyPatterns.some((pattern) => {
4259
4311
  if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
4260
4312
  const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
@@ -4277,8 +4329,8 @@ ${boxBottom}` };
4277
4329
  const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
4278
4330
  if (targetPath) {
4279
4331
  const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
4280
- const absoluteTarget = path15.resolve(targetPath);
4281
- const absoluteCwd = path15.resolve(process.cwd());
4332
+ const absoluteTarget = path14.resolve(targetPath);
4333
+ const absoluteCwd = path14.resolve(process.cwd());
4282
4334
  if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
4283
4335
  const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace. To enable this, ask the user to turn on "External Workspace Access" in /settings.`;
4284
4336
  toolResults.push({ role: "user", text: `[TOOL RESULT]: ERROR: ${denyMsg}${thinkingLevel != "Fast" ? "\n\n[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRICT PRIORITY. DO NOT START A RESPONSE WITHOUT THINKING**" : ""}` });
@@ -4393,6 +4445,11 @@ ${boxBottom}` };
4393
4445
  success = true;
4394
4446
  await incrementUsage("agent");
4395
4447
  } catch (err) {
4448
+ if (String(err).includes("Incomplete JSON segment at the end")) {
4449
+ success = true;
4450
+ await incrementUsage("agent");
4451
+ break;
4452
+ }
4396
4453
  if (isDedupeActive && dedupeBuffer.length > 0) {
4397
4454
  let overlapLen = 0;
4398
4455
  const maxPossibleOverlap = Math.min(accumulatedContext.length, dedupeBuffer.length);
@@ -4415,9 +4472,9 @@ ${boxBottom}` };
4415
4472
  const errMsg = err.status || err.error && err.error.message || String(err);
4416
4473
  const errLog = String(err);
4417
4474
  const date = (/* @__PURE__ */ new Date()).toLocaleString();
4418
- const agentErrDir = path15.join(LOGS_DIR, "agent");
4419
- if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
4420
- fs16.appendFileSync(path15.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
4475
+ const agentErrDir = path14.join(LOGS_DIR, "agent");
4476
+ if (!fs15.existsSync(agentErrDir)) fs15.mkdirSync(agentErrDir, { recursive: true });
4477
+ fs15.appendFileSync(path14.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
4421
4478
  DEBUG STATE: turnText='${turnText}', length=${turnText.trim().length}, inStreamRetryCount=${inStreamRetryCount}, retryCount=${retryCount}, isDedupeActive=${isDedupeActive}, dedupeBuffer='${dedupeBuffer}'
4422
4479
 
4423
4480
  ----------------------------------------------------------------------
@@ -4462,7 +4519,7 @@ ${recoveryText}`
4462
4519
  yield { type: "status", content: `Error Occured. Recovering Stream...` };
4463
4520
  } else {
4464
4521
  throw new Error(`Stream collapsed too many times. (Failed to resolve ${MAX_RETRIES} times)
4465
- Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
4522
+ Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
4466
4523
  }
4467
4524
  } else {
4468
4525
  if (retryCount <= MAX_RETRIES) {
@@ -4479,7 +4536,7 @@ Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
4479
4536
  yield { type: "status", content: `Retrying Connection...` };
4480
4537
  } else {
4481
4538
  throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
4482
- Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
4539
+ Error Log can be found in ${path14.join(LOGS_DIR, "agent", "error.log")}`);
4483
4540
  }
4484
4541
  }
4485
4542
  }
@@ -4540,13 +4597,13 @@ ${timestamp}`;
4540
4597
  });
4541
4598
 
4542
4599
  // src/components/ResumeModal.jsx
4543
- import React7, { useState as useState4, useEffect as useEffect2 } from "react";
4600
+ import React7, { useState as useState4, useEffect as useEffect3 } from "react";
4544
4601
  import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
4545
4602
  function ResumeModal({ onSelect, onDelete, onClose }) {
4546
4603
  const [history, setHistory] = useState4({});
4547
4604
  const [keys, setKeys] = useState4([]);
4548
4605
  const [selectedIndex, setSelectedIndex] = useState4(0);
4549
- useEffect2(() => {
4606
+ useEffect3(() => {
4550
4607
  const fetchHistory = async () => {
4551
4608
  const h = await loadHistory();
4552
4609
  setHistory(h);
@@ -4571,9 +4628,23 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
4571
4628
  }
4572
4629
  });
4573
4630
  const s = emojiSpace(2);
4574
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan", bold: true }, "\u{1F4A0} CHAT HISTORY: RESUME CONVERSATION")), keys.length === 0 ? /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React7.createElement(Text7, { italic: true, color: "gray" }, "No saved chats found.")) : /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, keys.map((id, index) => {
4631
+ const MAX_VISIBLE = 15;
4632
+ let startIndex = 0;
4633
+ if (keys.length > MAX_VISIBLE) {
4634
+ const half = Math.floor(MAX_VISIBLE / 2);
4635
+ startIndex = selectedIndex - half;
4636
+ if (startIndex < 0) {
4637
+ startIndex = 0;
4638
+ } else if (startIndex + MAX_VISIBLE > keys.length) {
4639
+ startIndex = keys.length - MAX_VISIBLE;
4640
+ }
4641
+ }
4642
+ const visibleKeys = keys.slice(startIndex, startIndex + MAX_VISIBLE);
4643
+ return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 95 }, /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan", bold: true }, "\u{1F4A0} CHAT HISTORY: RESUME CONVERSATION")), keys.length === 0 ? /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React7.createElement(Text7, { italic: true, color: "gray" }, "No saved chats found.")) : /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", width: "100%" }, startIndex > 0 && /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: true }, "\u25B2 (+", startIndex, " more chats above)")), visibleKeys.map((id, index) => {
4575
4644
  const chat2 = history[id];
4576
- const isSelected = index === selectedIndex;
4645
+ const actualIndex = startIndex + index;
4646
+ const isSelected = actualIndex === selectedIndex;
4647
+ const dateStr = formatDate(chat2?.updatedAt);
4577
4648
  return /* @__PURE__ */ React7.createElement(
4578
4649
  Box7,
4579
4650
  {
@@ -4582,10 +4653,10 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
4582
4653
  backgroundColor: isSelected ? "#2a2a2a" : void 0,
4583
4654
  width: "100%"
4584
4655
  },
4585
- /* @__PURE__ */ React7.createElement(Box7, { flexGrow: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", chat2.name || id, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: !isSelected }, " [", id.slice(5), "]"))),
4656
+ /* @__PURE__ */ React7.createElement(Box7, { flexGrow: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", chat2?.name || id, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: !isSelected }, " [", dateStr, " \u2022 ", id.slice(5), "]"))),
4586
4657
  isSelected && /* @__PURE__ */ React7.createElement(Box7, { flexShrink: 0 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, "[X] DELETE "))
4587
4658
  );
4588
- })), /* @__PURE__ */ React7.createElement(
4659
+ }), startIndex + MAX_VISIBLE < keys.length && /* @__PURE__ */ React7.createElement(Box7, { paddingX: 2, marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", dimColor: true }, "\u25BC (+", keys.length - (startIndex + MAX_VISIBLE), " more chats below)"))), /* @__PURE__ */ React7.createElement(
4589
4660
  Box7,
4590
4661
  {
4591
4662
  marginTop: 1,
@@ -4599,6 +4670,17 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
4599
4670
  /* @__PURE__ */ React7.createElement(Text7, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close")
4600
4671
  ));
4601
4672
  }
4673
+ function formatDate(timestamp) {
4674
+ if (!timestamp) return "N/A";
4675
+ const d = new Date(timestamp);
4676
+ if (isNaN(d.getTime())) return "N/A";
4677
+ const pad = (n) => String(n).padStart(2, "0");
4678
+ const mm = pad(d.getMonth() + 1);
4679
+ const dd = pad(d.getDate());
4680
+ const hh = pad(d.getHours());
4681
+ const min = pad(d.getMinutes());
4682
+ return `${mm}-${dd} ${hh}:${min}`;
4683
+ }
4602
4684
  var init_ResumeModal = __esm({
4603
4685
  "src/components/ResumeModal.jsx"() {
4604
4686
  init_history();
@@ -4607,16 +4689,24 @@ var init_ResumeModal = __esm({
4607
4689
  });
4608
4690
 
4609
4691
  // src/components/MemoryModal.jsx
4610
- import React8, { useState as useState5, useEffect as useEffect3 } from "react";
4692
+ import React8, { useState as useState5, useEffect as useEffect4 } from "react";
4611
4693
  import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
4612
4694
  function MemoryModal({ onClose }) {
4613
4695
  const [memories, setMemories] = useState5([]);
4614
4696
  const [selectedIndex, setSelectedIndex] = useState5(0);
4697
+ const [isMemoryOn, setIsMemoryOn] = useState5(true);
4615
4698
  const loadMemories = () => {
4616
4699
  const data = readEncryptedJson(MEMORIES_FILE, []);
4617
4700
  setMemories(data);
4701
+ try {
4702
+ const settings = readAesEncryptedJson(SETTINGS_FILE, {});
4703
+ const memoryOn = settings.systemSettings?.memory !== false;
4704
+ setIsMemoryOn(memoryOn);
4705
+ } catch (e) {
4706
+ setIsMemoryOn(true);
4707
+ }
4618
4708
  };
4619
- useEffect3(() => {
4709
+ useEffect4(() => {
4620
4710
  loadMemories();
4621
4711
  }, []);
4622
4712
  useInput3((input, key) => {
@@ -4637,7 +4727,7 @@ function MemoryModal({ onClose }) {
4637
4727
  return text.replace(/\[Saved on: .*?\]/g, "").trim();
4638
4728
  };
4639
4729
  const s = emojiSpace(2);
4640
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F9E0} AGENT MEMORY: LONG-TERM KNOWLEDGE")), memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "Still Learning...")) : /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, memories.map((mem, idx) => {
4730
+ return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F9E0} AGENT MEMORY: LONG-TERM KNOWLEDGE")), !isMemoryOn && memories.length > 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "Memory is currently Off...")) : memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, isMemoryOn ? "Learning..." : "Memory not available...")) : /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, memories.map((mem, idx) => {
4641
4731
  const isSelected = idx === selectedIndex;
4642
4732
  return /* @__PURE__ */ React8.createElement(
4643
4733
  Box8,
@@ -4673,7 +4763,7 @@ var init_MemoryModal = __esm({
4673
4763
  });
4674
4764
 
4675
4765
  // src/components/UpdateProcessor.jsx
4676
- import React9, { useState as useState6, useEffect as useEffect4 } from "react";
4766
+ import React9, { useState as useState6, useEffect as useEffect5 } from "react";
4677
4767
  import { Box as Box9, Text as Text9 } from "ink";
4678
4768
  import Spinner from "ink-spinner";
4679
4769
  import { exec as exec2 } from "child_process";
@@ -4684,7 +4774,7 @@ var init_UpdateProcessor = __esm({
4684
4774
  const [status, setStatus] = useState6("initializing");
4685
4775
  const [log, setLog] = useState6("");
4686
4776
  const [error, setError] = useState6(null);
4687
- useEffect4(() => {
4777
+ useEffect5(() => {
4688
4778
  let child;
4689
4779
  const runUpdate = async () => {
4690
4780
  const manager = settings.updateManager || "npm";
@@ -4727,7 +4817,7 @@ var init_UpdateProcessor = __esm({
4727
4817
  return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, /* @__PURE__ */ React9.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React9.createElement(Text9, { marginLeft: 1, bold: true }, " Updating Flux Flow to v", latest, "...")), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "#333" }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true, italic: true }, log || "Preparing environment...")), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, dimColor: true }, "(Please do not close the terminal)"));
4728
4818
  }
4729
4819
  if (status === "success") {
4730
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "green", bold: true }, "\u2705 UPDATE SUCCESSFUL!"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Flux Flow has been upgraded to ", /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "v", latest), "."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "yellow", bold: true }, "CRITICAL: Please restart your terminal session to apply changes."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "(Press ESC to return to chat)")));
4820
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "green", bold: true }, "\u2705 UPDATE SUCCESSFUL!"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Flux Flow has been updated to ", /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "v", latest), "."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "yellow", bold: true }, "CRITICAL: Please restart your terminal session to apply changes."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "(Press ESC to return to chat)")));
4731
4821
  }
4732
4822
  if (status === "error") {
4733
4823
  return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true }, "\u274C UPDATE FAILED"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "red" }, /* @__PURE__ */ React9.createElement(Text9, { color: "red" }, error)), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Possible causes:"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Missing permissions (Try running as Administrator/Sudo)"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Package manager (", settings.updateManager, ") not found"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Network failure"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "(Press ESC to return to chat)")));
@@ -4742,7 +4832,7 @@ var init_UpdateProcessor = __esm({
4742
4832
  import puppeteer4 from "puppeteer";
4743
4833
  import { exec as exec3 } from "child_process";
4744
4834
  import { promisify } from "util";
4745
- import fs17 from "fs";
4835
+ import fs16 from "fs";
4746
4836
  var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
4747
4837
  var init_setup = __esm({
4748
4838
  "src/utils/setup.js"() {
@@ -4750,7 +4840,7 @@ var init_setup = __esm({
4750
4840
  checkPuppeteerReady = () => {
4751
4841
  try {
4752
4842
  const exePath = puppeteer4.executablePath();
4753
- const exists = exePath && fs17.existsSync(exePath);
4843
+ const exists = exePath && fs16.existsSync(exePath);
4754
4844
  if (exists) return true;
4755
4845
  } catch (e) {
4756
4846
  return false;
@@ -4781,17 +4871,17 @@ __export(app_exports, {
4781
4871
  default: () => App
4782
4872
  });
4783
4873
  import os4 from "os";
4784
- import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
4874
+ import React10, { useState as useState7, useEffect as useEffect6, useRef as useRef2, useMemo } from "react";
4785
4875
  import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
4786
4876
  import Spinner2 from "ink-spinner";
4787
- import fs18 from "fs-extra";
4788
- import path16 from "path";
4877
+ import fs17 from "fs-extra";
4878
+ import path15 from "path";
4789
4879
  import { exec as exec4 } from "child_process";
4790
4880
  import { fileURLToPath } from "url";
4791
4881
  import { MultilineInput } from "ink-multiline-input";
4792
4882
  import TextInput3 from "ink-text-input";
4793
4883
  import gradient from "gradient-string";
4794
- function App() {
4884
+ function App({ args = [] }) {
4795
4885
  const [confirmExit, setConfirmExit] = useState7(false);
4796
4886
  const [exitCountdown, setExitCountdown] = useState7(10);
4797
4887
  const { stdout } = useStdout();
@@ -4803,6 +4893,45 @@ function App() {
4803
4893
  rows: stdout?.rows || 24
4804
4894
  });
4805
4895
  const [selectedIndex, setSelectedIndex] = useState7(0);
4896
+ const persistedModelRef = useRef2(null);
4897
+ const parsedArgs = useMemo(() => {
4898
+ const parsed = {};
4899
+ for (let i = 0; i < args.length; i++) {
4900
+ const arg = args[i];
4901
+ if (arg === "--model" && args[i + 1]) {
4902
+ parsed.model = args[i + 1];
4903
+ i++;
4904
+ } else if (arg === "--memory" && args[i + 1]) {
4905
+ parsed.memory = args[i + 1].toLowerCase();
4906
+ i++;
4907
+ } else if (arg === "--resume" && args[i + 1]) {
4908
+ parsed.resume = args[i + 1];
4909
+ i++;
4910
+ } else if (arg === "--update" && args[i + 1]) {
4911
+ parsed.update = args[i + 1].toLowerCase();
4912
+ i++;
4913
+ } else if (arg === "--package" && args[i + 1]) {
4914
+ const pkg = args[i + 1].toLowerCase();
4915
+ if (["npm", "pnpm", "yarn", "bun"].includes(pkg)) {
4916
+ parsed.package = pkg;
4917
+ }
4918
+ i++;
4919
+ } else if (arg === "--auto-del" && args[i + 1]) {
4920
+ const del = args[i + 1].toLowerCase();
4921
+ if (["1d", "7d", "30d"].includes(del)) {
4922
+ parsed.autoDel = del;
4923
+ }
4924
+ i++;
4925
+ } else if (arg === "--auto-exec" && args[i + 1]) {
4926
+ parsed.autoExec = args[i + 1].toLowerCase();
4927
+ i++;
4928
+ } else if (arg === "--external-access" && args[i + 1]) {
4929
+ parsed.externalAccess = args[i + 1].toLowerCase();
4930
+ i++;
4931
+ }
4932
+ }
4933
+ return parsed;
4934
+ }, [args]);
4806
4935
  const performVersionCheck = async (manual = false, settingsOverride = null) => {
4807
4936
  const settingsToUse = settingsOverride || systemSettings;
4808
4937
  if (manual) {
@@ -4854,7 +4983,7 @@ function App() {
4854
4983
  }
4855
4984
  }
4856
4985
  };
4857
- useEffect5(() => {
4986
+ useEffect6(() => {
4858
4987
  const handleResize = () => {
4859
4988
  stdout.write("\x1Bc");
4860
4989
  setTerminalSize({
@@ -4898,7 +5027,7 @@ function App() {
4898
5027
  const [activeCommand, setActiveCommand] = useState7(null);
4899
5028
  const [execOutput, setExecOutput] = useState7("");
4900
5029
  const [isTerminalFocused, setIsTerminalFocused] = useState7(false);
4901
- useEffect5(() => {
5030
+ useEffect6(() => {
4902
5031
  if (apiTier !== "Free" && activeModel === "gemma-4-31b-it") {
4903
5032
  setActiveModel("gemini-3-flash-preview");
4904
5033
  setMessages((prev) => {
@@ -4921,10 +5050,10 @@ function App() {
4921
5050
  }, []);
4922
5051
  const activeCommandRef = useRef2(null);
4923
5052
  const execOutputRef = useRef2("");
4924
- useEffect5(() => {
5053
+ useEffect6(() => {
4925
5054
  activeCommandRef.current = activeCommand;
4926
5055
  }, [activeCommand]);
4927
- useEffect5(() => {
5056
+ useEffect6(() => {
4928
5057
  execOutputRef.current = execOutput;
4929
5058
  }, [execOutput]);
4930
5059
  const [autoAcceptWrites, setAutoAcceptWrites] = useState7(false);
@@ -5107,7 +5236,7 @@ function App() {
5107
5236
  setInput((prev) => prev.replace(/\\\r?$/, "").replace(/\r?$/, "") + "\n");
5108
5237
  }
5109
5238
  });
5110
- useEffect5(() => {
5239
+ useEffect6(() => {
5111
5240
  async function init() {
5112
5241
  if (process.stdout.isTTY) {
5113
5242
  process.stdout.write(`\x1B]0;FluxFlow | Ready\x07`);
@@ -5126,7 +5255,12 @@ function App() {
5126
5255
  const saved = await loadSettings();
5127
5256
  setMode(saved.mode);
5128
5257
  setThinkingLevel(saved.thinkingLevel);
5129
- setActiveModel(saved.activeModel);
5258
+ persistedModelRef.current = saved.activeModel;
5259
+ if (parsedArgs.model) {
5260
+ setActiveModel(parsedArgs.model);
5261
+ } else {
5262
+ setActiveModel(saved.activeModel);
5263
+ }
5130
5264
  setShowFullThinking(saved.showFullThinking);
5131
5265
  setApiTier(saved.apiTier || "Free");
5132
5266
  setQuotas(saved.quotas || { agentLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
@@ -5140,6 +5274,27 @@ function App() {
5140
5274
  customUpdateCommand: "",
5141
5275
  ...saved.systemSettings || {}
5142
5276
  };
5277
+ if (parsedArgs.memory === "on") {
5278
+ freshSettings.memory = true;
5279
+ } else if (parsedArgs.memory === "off") {
5280
+ freshSettings.memory = false;
5281
+ }
5282
+ if (parsedArgs.package) {
5283
+ freshSettings.updateManager = parsedArgs.package;
5284
+ }
5285
+ if (parsedArgs.autoDel) {
5286
+ freshSettings.autoDeleteHistory = parsedArgs.autoDel;
5287
+ }
5288
+ if (parsedArgs.autoExec === "on") {
5289
+ freshSettings.autoExec = true;
5290
+ } else if (parsedArgs.autoExec === "off") {
5291
+ freshSettings.autoExec = false;
5292
+ }
5293
+ if (parsedArgs.externalAccess === "on") {
5294
+ freshSettings.allowExternalAccess = true;
5295
+ } else if (parsedArgs.externalAccess === "off") {
5296
+ freshSettings.allowExternalAccess = false;
5297
+ }
5143
5298
  setSystemSettings(freshSettings);
5144
5299
  setProfileData(saved.profileData);
5145
5300
  setImageSettings(saved.imageSettings || { keyType: "Default", quality: "Low-High", apiKey: "" });
@@ -5152,13 +5307,41 @@ function App() {
5152
5307
  cleanupOldHistory(saved.systemSettings.autoDeleteHistory);
5153
5308
  }
5154
5309
  cleanupOldLogs(LOGS_DIR);
5155
- performVersionCheck(false, freshSettings);
5310
+ if (parsedArgs.update === "check") {
5311
+ performVersionCheck(true, freshSettings);
5312
+ } else if (parsedArgs.update === "latest") {
5313
+ setActiveView("update");
5314
+ performVersionCheck(true, freshSettings);
5315
+ } else {
5316
+ performVersionCheck(false, freshSettings);
5317
+ }
5156
5318
  await initUsage();
5319
+ if (parsedArgs.resume) {
5320
+ const h = await loadHistory();
5321
+ const id = parsedArgs.resume;
5322
+ if (h[id]) {
5323
+ setChatId(id);
5324
+ const resumedMsgs = [...h[id].messages];
5325
+ const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
5326
+ if (!hasLogo) {
5327
+ resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...", isMeta: true });
5328
+ }
5329
+ setMessages(resumedMsgs);
5330
+ setActiveView("chat");
5331
+ setMessages((prev) => {
5332
+ const newMsgs = [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED VIA CLI: [${id}]`, isMeta: true }];
5333
+ setCompletedIndex(newMsgs.length);
5334
+ return newMsgs;
5335
+ });
5336
+ } else {
5337
+ setMessages((prev) => [...prev, { id: "sys-err-" + Date.now(), role: "system", text: `\u274C ERROR: Chat session [${id}] not found. Started new session.`, isMeta: true }]);
5338
+ }
5339
+ }
5157
5340
  setIsInitializing(false);
5158
5341
  }
5159
5342
  init();
5160
5343
  }, []);
5161
- useEffect5(() => {
5344
+ useEffect6(() => {
5162
5345
  let timer;
5163
5346
  if (confirmExit) {
5164
5347
  setExitCountdown(10);
@@ -5176,19 +5359,20 @@ function App() {
5176
5359
  if (timer) clearInterval(timer);
5177
5360
  };
5178
5361
  }, [confirmExit]);
5179
- useEffect5(() => {
5362
+ useEffect6(() => {
5180
5363
  if (!isInitializing) {
5364
+ const modelToSave = parsedArgs.model && activeModel === parsedArgs.model ? persistedModelRef.current : activeModel;
5181
5365
  saveSettings({
5182
5366
  mode,
5183
5367
  thinkingLevel,
5184
- activeModel,
5368
+ activeModel: modelToSave || activeModel,
5185
5369
  showFullThinking,
5186
5370
  systemSettings,
5187
5371
  profileData,
5188
5372
  imageSettings
5189
5373
  });
5190
5374
  }
5191
- }, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing]);
5375
+ }, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs]);
5192
5376
  const handleSetup = async (val) => {
5193
5377
  const key = val.trim();
5194
5378
  if (key.length >= 30) {
@@ -5202,7 +5386,7 @@ function App() {
5202
5386
  }
5203
5387
  };
5204
5388
  const lastSavedTimeRef = useRef2(SESSION_START_TIME);
5205
- useEffect5(() => {
5389
+ useEffect6(() => {
5206
5390
  if (activeView === "exit") {
5207
5391
  const flush = async () => {
5208
5392
  const now = Date.now();
@@ -5220,7 +5404,7 @@ function App() {
5220
5404
  return () => clearTimeout(timer);
5221
5405
  }
5222
5406
  }, [activeView]);
5223
- useEffect5(() => {
5407
+ useEffect6(() => {
5224
5408
  const interval = setInterval(async () => {
5225
5409
  if (!isInitializing) {
5226
5410
  const now = Date.now();
@@ -5297,10 +5481,11 @@ function App() {
5297
5481
  cmd: "/model",
5298
5482
  desc: "Switch AI model",
5299
5483
  subs: [
5300
- { cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default (Free, Recommended)" : "Standard Default (Free, Recommended) - Use Free API Key to use this model " },
5301
- { cmd: "gemini-3.1-pro-preview", desc: "Most Capable (Paid)" },
5484
+ { cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default (Free, Recommended)" : "Standard Default (Free, Recommended) - Use Free API Key to use this model " },
5485
+ { cmd: "gemini-3.1-pro-preview", desc: "Most Capable (Paid)" },
5302
5486
  { cmd: "gemini-3-flash-preview", desc: "Fast & Lightweight (Paid, Limited Free quota)" },
5303
- { cmd: "gemini-3.1-flash-lite", desc: "Ultra Fast (Paid, Decent Free quota)" }
5487
+ { cmd: "gemini-3.5-flash", desc: "New (Paid, Limited Free quota)" },
5488
+ { cmd: "gemini-3.1-flash-lite", desc: "Ultra Fast (Paid, Decent Free quota)" }
5304
5489
  ]
5305
5490
  },
5306
5491
  { cmd: "/settings", desc: "Configure system prefs" },
@@ -5327,8 +5512,8 @@ function App() {
5327
5512
  ]
5328
5513
  }
5329
5514
  ];
5330
- const handleSubmit = async (value) => {
5331
- if (suggestions.length > 0) {
5515
+ const handleSubmit = async (value, isProgrammatic = false) => {
5516
+ if (!isProgrammatic && suggestions.length > 0) {
5332
5517
  const nextMatch = suggestions[selectedIndex] || suggestions[0];
5333
5518
  const parts = value.split(" ");
5334
5519
  if (parts.length === 1) {
@@ -5676,12 +5861,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
5676
5861
  setCompletedIndex(prev.length + 1);
5677
5862
  return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
5678
5863
  });
5679
- if (fs18.existsSync(LOGS_DIR)) fs18.removeSync(LOGS_DIR);
5680
- if (fs18.existsSync(SECRET_DIR)) fs18.removeSync(SECRET_DIR);
5681
- if (fs18.existsSync(SETTINGS_FILE)) fs18.removeSync(SETTINGS_FILE);
5864
+ if (fs17.existsSync(LOGS_DIR)) fs17.removeSync(LOGS_DIR);
5865
+ if (fs17.existsSync(SECRET_DIR)) fs17.removeSync(SECRET_DIR);
5866
+ if (fs17.existsSync(SETTINGS_FILE)) fs17.removeSync(SETTINGS_FILE);
5682
5867
  try {
5683
- const items = fs18.readdirSync(FLUXFLOW_DIR);
5684
- if (items.length === 0) fs18.removeSync(FLUXFLOW_DIR);
5868
+ const items = fs17.readdirSync(FLUXFLOW_DIR);
5869
+ if (items.length === 0) fs17.removeSync(FLUXFLOW_DIR);
5685
5870
  } catch (e) {
5686
5871
  }
5687
5872
  setTimeout(() => {
@@ -5720,8 +5905,8 @@ ${list || "No saved chats found."}`, isMeta: true }];
5720
5905
  break;
5721
5906
  }
5722
5907
  case "/fluxflow": {
5723
- const args = parts.slice(1);
5724
- if (args[0] === "init") {
5908
+ const args2 = parts.slice(1);
5909
+ if (args2[0] === "init") {
5725
5910
  const template = `# FluxFlow Configuration
5726
5911
  # This file defines project-specific instructions for the Flux Flow Agent.
5727
5912
 
@@ -5738,14 +5923,14 @@ ${list || "No saved chats found."}`, isMeta: true }];
5738
5923
  # SKILLS & WORKFLOWS
5739
5924
  - [Define custom step-by-step recipes for this project here]
5740
5925
  `;
5741
- const filePath = path16.join(process.cwd(), "FluxFlow.md");
5742
- if (fs18.pathExistsSync(filePath)) {
5926
+ const filePath = path15.join(process.cwd(), "FluxFlow.md");
5927
+ if (fs17.pathExistsSync(filePath)) {
5743
5928
  setMessages((prev) => {
5744
5929
  setCompletedIndex(prev.length + 1);
5745
5930
  return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
5746
5931
  });
5747
5932
  } else {
5748
- fs18.writeFileSync(filePath, template);
5933
+ fs17.writeFileSync(filePath, template);
5749
5934
  setMessages((prev) => {
5750
5935
  setCompletedIndex(prev.length + 1);
5751
5936
  return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "\u2705 [SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
@@ -5856,20 +6041,20 @@ OUTPUT: ${execOutputRef.current}`;
5856
6041
  setSessionToolFailure((prev) => prev + 1);
5857
6042
  }
5858
6043
  },
5859
- onToolApproval: async (tool, args) => {
6044
+ onToolApproval: async (tool, args2) => {
5860
6045
  const isAuto = autoAcceptWrites || systemSettings.autoExec;
5861
6046
  if (tool === "exec_command") {
5862
- const { command } = parseArgs(args || "{}");
6047
+ const { command } = parseArgs(args2 || "{}");
5863
6048
  const safeRegex = /^(echo|ls|dir|pwd|cd|git status|git log|git diff|type|cat|help)\b/i;
5864
6049
  if (isAuto || command && safeRegex.test(command.trim())) return "allow";
5865
6050
  return new Promise((resolve) => {
5866
- setPendingApproval({ tool, args, resolve });
6051
+ setPendingApproval({ tool, args: args2, resolve });
5867
6052
  setActiveView("terminalApproval");
5868
6053
  });
5869
6054
  }
5870
6055
  if (isAuto) return "allow";
5871
6056
  return new Promise((resolve) => {
5872
- setPendingApproval({ tool, args, resolve });
6057
+ setPendingApproval({ tool, args: args2, resolve });
5873
6058
  setActiveView("approval");
5874
6059
  });
5875
6060
  },
@@ -6168,7 +6353,7 @@ Selection: ${val}`,
6168
6353
  }
6169
6354
  return currentList.filter((s) => s.cmd.toLowerCase().includes(query));
6170
6355
  }, [input]);
6171
- useEffect5(() => {
6356
+ useEffect6(() => {
6172
6357
  setSelectedIndex(0);
6173
6358
  }, [suggestions]);
6174
6359
  const renderActiveView = () => {
@@ -6484,6 +6669,7 @@ Selection: ${val}`,
6484
6669
  return /* @__PURE__ */ React10.createElement(
6485
6670
  ProfileForm,
6486
6671
  {
6672
+ initialData: profileData,
6487
6673
  onSave: (profile) => {
6488
6674
  setProfileData(profile);
6489
6675
  setMessages((prev) => [...prev, { id: Date.now(), role: "system", text: `\u2705 Profile updated: ${profile.name} (${profile.nickname})` }]);
@@ -6501,7 +6687,7 @@ Selection: ${val}`,
6501
6687
  setResolutionData(null);
6502
6688
  setActiveView("chat");
6503
6689
  setTimeout(() => {
6504
- handleSubmit(val);
6690
+ handleSubmit(val, true);
6505
6691
  }, 500);
6506
6692
  },
6507
6693
  onEdit: (val) => {
@@ -6513,9 +6699,9 @@ Selection: ${val}`,
6513
6699
  ));
6514
6700
  case "approval":
6515
6701
  return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true, underline: true }, "\u{1F510} SECURITY GATE: FILE WRITE PERMISSION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent is attempting to modify: ", /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, parseArgs(pendingApproval?.args || "{}").path || "Unknown File")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, borderStyle: "single", borderColor: "#333", paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, "--- PROPOSED CONTENT / DIFF ---"), (() => {
6516
- const args = parseArgs(pendingApproval?.args || "{}");
6517
- const oldVal = args.TargetContent || args.content_to_replace || null;
6518
- const newVal = args.content || args.ReplacementContent || args.content_to_add || args.replacementContent || null;
6702
+ const args2 = parseArgs(pendingApproval?.args || "{}");
6703
+ const oldVal = args2.TargetContent || args2.content_to_replace || null;
6704
+ const newVal = args2.content || args2.ReplacementContent || args2.content_to_add || args2.replacementContent || null;
6519
6705
  if (oldVal && newVal) {
6520
6706
  return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal.replace(/\[\/n\]?/g, "\\n"))));
6521
6707
  }
@@ -6767,10 +6953,10 @@ var init_app = __esm({
6767
6953
  init_text();
6768
6954
  SESSION_START_TIME = Date.now();
6769
6955
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
6770
- packageJsonPath = path16.join(path16.dirname(fileURLToPath(import.meta.url)), "../package.json");
6771
- packageJson = JSON.parse(fs18.readFileSync(packageJsonPath, "utf8"));
6956
+ packageJsonPath = path15.join(path15.dirname(fileURLToPath(import.meta.url)), "../package.json");
6957
+ packageJson = JSON.parse(fs17.readFileSync(packageJsonPath, "utf8"));
6772
6958
  versionFluxflow = packageJson.version;
6773
- updatedOn = "2026-05-20";
6959
+ updatedOn = packageJson.date || "2026-05-20";
6774
6960
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 0 }, /* @__PURE__ */ React10.createElement(
6775
6961
  CommandMenu,
6776
6962
  {
@@ -6832,5 +7018,5 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
6832
7018
  console.warn = (...args) => !isNoise(args) && originalWarn(...args);
6833
7019
  console.error = (...args) => !isNoise(args) && originalError(...args);
6834
7020
  process.stdout.write("\x1Bc");
6835
- render(/* @__PURE__ */ React11.createElement(App2, null), { exitOnCtrlC: false });
7021
+ render(/* @__PURE__ */ React11.createElement(App2, { args: process.argv.slice(2) }), { exitOnCtrlC: false });
6836
7022
  }