fluxflow-cli 1.9.0 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/fluxflow.js +265 -124
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -136,12 +136,26 @@ var init_terminal = __esm({
136
136
  // src/components/ChatLayout.jsx
137
137
  import React2, { useState, useEffect, useRef } from "react";
138
138
  import { Box as Box2, Text as Text2 } from "ink";
139
- var cleanSignals, formatThinkText, parseMathSymbols, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, MessageItem, ChatLayout, ChatLayout_default;
139
+ var TOOL_LABELS, cleanSignals, formatThinkText, parseMathSymbols, InlineMarkdown, TableRenderer, MarkdownText, DiffLine, DiffBlock, CodeRenderer, MessageItem, ChatLayout, ChatLayout_default;
140
140
  var init_ChatLayout = __esm({
141
141
  "src/components/ChatLayout.jsx"() {
142
142
  init_TerminalBox();
143
143
  init_text();
144
144
  init_terminal();
145
+ TOOL_LABELS = {
146
+ "write_file": "Write File",
147
+ "update_file": "Update File",
148
+ "read_folder": "Read Folder",
149
+ "view_file": "View File",
150
+ "exec_command": "Execute Command",
151
+ "web_search": "Web Search",
152
+ "web_scrape": "Read Site",
153
+ "search_keyword": "Find Files",
154
+ "ask": "Ask User",
155
+ "write_pdf": "Create PDF",
156
+ "write_pptx": "Create Presentation",
157
+ "write_docx": "Create Document"
158
+ };
145
159
  cleanSignals = (text) => {
146
160
  if (!text) return text;
147
161
  let result = text;
@@ -196,7 +210,7 @@ var init_ChatLayout = __esm({
196
210
  }
197
211
  }
198
212
  }
199
- return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*(turn\s*:)?\s*(continue|finish)?\s*$/gi, "").replace(/\n\s*turn\s*:\s*(continue|finish)\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/\[\/n\]?/g, "\\n").trim();
213
+ return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*turn\s*:?.*?$/gi, "").replace(/\n\s*turn\s*:?.*?$/gi, "").replace(/\[\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/\[\/n\]?/g, "\\n").replace(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replace(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|ask|write_pdf|write_pptx|write_docx)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
200
214
  };
201
215
  formatThinkText = (cleaned, columns = 80) => {
202
216
  if (!cleaned) return null;
@@ -381,11 +395,15 @@ var init_ChatLayout = __esm({
381
395
  const isDiffResult = msg.role === "system" && msg.text?.includes("[DIFF_START]");
382
396
  const isPatchError = msg.role === "system" && msg.text?.includes("[TOOL_RESULT]: ERROR:") && (msg.toolName === "update_file" || msg.text?.includes("Could not find exact match"));
383
397
  const isTerminalRecord = msg.isTerminalRecord;
398
+ const isHomeWarning = msg.isHomeWarning;
399
+ if (isHomeWarning) {
400
+ return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "red", padding: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1, backgroundColor: "#3a0000" }, /* @__PURE__ */ React2.createElement(Text2, { color: "red", bold: true }, msg.text)), /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, msg.subText))));
401
+ }
402
+ if (msg.isLogo) {
403
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", alignItems: "center", width: "100%", marginY: 1 }, /* @__PURE__ */ React2.createElement(Text2, null, msg.text));
404
+ }
384
405
  if (msg.id && String(msg.id).startsWith("welcome")) {
385
- const parts = msg.text.split("\n\n");
386
- const logo = parts[0];
387
- const greeting = parts[1] || "";
388
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", alignItems: "center", width: "100%", marginY: 1 }, /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, null, logo)), /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "round", borderColor: "gray", paddingX: 3, paddingY: 0 }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", bold: true }, greeting.trim())));
406
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", alignItems: "center", width: "100%", marginY: 1 }, /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "round", borderColor: "gray", paddingX: 3, paddingY: 0 }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", bold: true }, msg.text.trim())));
389
407
  }
390
408
  if (msg.isVisualFeedback) {
391
409
  return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, msg.text));
@@ -398,7 +416,7 @@ var init_ChatLayout = __esm({
398
416
  const selectionMatch = msg.text.match(/Selection: (.*)/);
399
417
  const selection = selectionMatch ? selectionMatch[1] : "No selection";
400
418
  const s = emojiSpace(2);
401
- return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", bold: true }, "\u{1F4AC}", s, "AGENT REQUEST: RESOLVED")), /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, "Selection: ", /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", bold: true }, selection)))));
419
+ return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", bold: true }, "\u{1F4AC} AGENT REQUEST: RESOLVED")), /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, "Selection: ", /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", bold: true }, selection)))));
402
420
  }
403
421
  if (msg.isAboutRecord) {
404
422
  return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", bold: true }, "\u{1F4A0} ABOUT FLUX FLOW")), /* @__PURE__ */ React2.createElement(Box2, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, null, msg.text))));
@@ -452,6 +470,13 @@ var init_ChatLayout = __esm({
452
470
  { cmd: "/reset", desc: "Wipe all project data" },
453
471
  { cmd: "/about", desc: "Project info & credits" },
454
472
  { cmd: "/changelog", desc: "View latest updates" },
473
+ {
474
+ cmd: "/fluxflow",
475
+ desc: "Project management",
476
+ subs: [
477
+ { cmd: "init", desc: "Create FluxFlow.md template" }
478
+ ]
479
+ },
455
480
  {
456
481
  cmd: "/update",
457
482
  desc: "Check/Install updates",
@@ -677,7 +702,7 @@ var init_AskUserModal = __esm({
677
702
  });
678
703
  const s = emojiSpace(2);
679
704
  if (isSuggestingElse) {
680
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "\u{1F4AC}", s, "SUGGEST SOMETHING ELSE")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React6.createElement(Text6, { italic: true, color: "gray" }, "Replying to: ", question)), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React6.createElement(
705
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "\u{1F4AC} SUGGEST SOMETHING ELSE")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React6.createElement(Text6, { italic: true, color: "gray" }, "Replying to: ", question)), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React6.createElement(
681
706
  TextInput2,
682
707
  {
683
708
  value: customInput,
@@ -686,7 +711,7 @@ var init_AskUserModal = __esm({
686
711
  }
687
712
  )), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true, italic: true }, "(Press Enter to send)")));
688
713
  }
689
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "\u{1F4AC}AGENT REQUEST: ACTION REQUIRED")), /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "white" }, question)), /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", width: "100%" }, allOptions.map((opt, idx) => {
714
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "\u{1F4AC} AGENT REQUEST: ACTION REQUIRED")), /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "white" }, question)), /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", width: "100%" }, allOptions.map((opt, idx) => {
690
715
  const isSelected = idx === selectedIndex;
691
716
  return /* @__PURE__ */ React6.createElement(
692
717
  Box6,
@@ -835,7 +860,7 @@ var init_main_tools = __esm({
835
860
 
836
861
  - USER COMMUNICATION TOOLS (Available in Flux & Flow) -
837
862
  1. Ask User: [tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc")]. Generally use this tool for ANY ambiguity. Can use upto 4 arguments. Mandatory triggers include: 1) **Path Divergence**: When multiple architectural or technical solutions exist, present options via 'ask' instead of choosing arbitrarily. 2) **Security Boundaries**: Explicitly request permission via 'ask' before accessing sensitive files (e.g., .env, config keys, credentials). 3) **Ambiguity Resolution**: Use 'ask' to clarify vague prompts before executing terminal commands or writing code. 4) **Risk Mitigation**: Require a 'Yes/No' confirmation for any destructive or irreversible operations. Options must always follow the 'Short Label::Detailed Description' format. This tool is a non-terminating suspension so you can get guidance without losing context. PREFER USING THIS TOOL RATHER THAN FINISHING THE LOOP FOR USER CLARIFICATION.
838
- DO NOT GIVE OPTION TO ASK USER THEIR PREFERENCES. JUST GIVE THE OPTIONS YOU THINK ARE BEST FOR THE USER.
863
+ DO NOT GIVE OPTION TO ASK USER THEIR PREFERENCES. JUST GIVE THE OPTIONS YOU THINK ARE BEST FOR THE USER. REST WILL BE HANDLED BY THE SYSTEM.
839
864
 
840
865
  - WEB TOOLS (Available in Flux & Flow) -
841
866
  1. Web Search: [tool:functions.web_search(query="<query>", limit=number)]. Find info. limit is optional (3-10, default 10). If user asks about something that is not in your training data, proactively use this tool to find the information. Wider search recomemded (limit = 10) when exploring a topic.
@@ -960,15 +985,27 @@ var init_prompts = __esm({
960
985
  ` : "";
961
986
  const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString();
962
987
  const cwdStr = process.cwd();
988
+ const isSystemDir = (() => {
989
+ const cwd = process.cwd().toLowerCase();
990
+ if (process.platform === "win32") {
991
+ const winDir = process.env.SystemRoot?.toLowerCase() || "c:\\windows";
992
+ const progFiles = process.env.ProgramFiles?.toLowerCase() || "c:\\program files";
993
+ const progFilesX86 = process.env["ProgramFiles(x86)"]?.toLowerCase() || "c:\\program files (x86)";
994
+ return cwd.startsWith(winDir) || cwd.startsWith(progFiles) || cwd.startsWith(progFilesX86);
995
+ } else {
996
+ const sysPaths = ["/bin", "/sbin", "/etc", "/usr", "/var", "/root"];
997
+ return cwd === "/" || sysPaths.some((p) => cwd.startsWith(p));
998
+ }
999
+ })();
963
1000
  const tempMemoriesStr = tempMemories?.length > 0 && !isContext32k ? `
964
- -- RECENT CONTEXT FROM OTHER CHAT THREADS (LOW PRIORITY) --
1001
+ -- RECENT CONTEXT FROM OTHER CHAT THREADS (PRIORITY: LOW, RECENT > OLD) --
965
1002
  ${tempMemories.split("\n").map((line) => ` ${line}`).join("\n")}
966
1003
  -- END RECENT CONTEXT --
967
1004
  ` : "";
968
1005
  const userMemoriesStr = userMemories?.length > 0 ? `
969
- --- PERSISTENT USER MEMORIES (MEDIUM PRIORITY, TUNES PERSONALIZATION & USER PREFERENCES) ---
1006
+ --- SAVED MEMORIES (PRIORITY: MEDIUM, TUNES PERSONALIZATION & USER PREFERENCES) ---
970
1007
  ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
971
- -- END USER MEMORIES --
1008
+ -- END SAVED MEMORIES --
972
1009
  ` : "";
973
1010
  return `${isMemoryEnabled ? `${userMemoriesStr}
974
1011
  ` : ""}${isMemoryEnabled ? `${tempMemoriesStr}
@@ -976,8 +1013,8 @@ ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
976
1013
  --- START SYSTEM INSTRUCTION (STRICT PRIORITY, OVERRIDES EVERYTHING) ---
977
1014
  You are Flux Flow (made by Kushal Roy Chowdhury). A CLI Agent. Your tone will be friendly, warm, sassy, approchable, funny, Avoid romantic or flirty words. Dont mention modes unless explicitly asked. ${mode === "Flux" ? `You are currently operating in FLUX mode (THINKING IS MANDATORY). Keep your agentic approach goal oriented, conversation quality and user experience. Use provided tools when needed. Analyze user prompt and project requirements, then plan your approach.` : `You are currently operating in Flow mode (THINKING IS MANDATORY BUT LESS EFFORT). Focus more on conversation quality and user experience. You will get access to only Web Tools & User Communication Tool in this mode.`}
978
1015
  MUST FOLLOW THE "CRITICAL THINKING POLICY"${mode === "Flux" ? `, "CRITICAL NEWLINE PROTOCOL", "CRITICAL QUOTE ESCAPE POLICY"` : ""} ALWAYS. **NO EXCEPTIONS.**
979
- CURRENT_WORKING_DIRECTORY: ${cwdStr}.
980
- OS: ${osDetected}. ${osDetected === "Windows" && mode === "Flux" ? "Your terminal commands will run on CMD. 'Prefer using PS scripts via CMD' instead of raw CMD commands." : ""}
1016
+ CURRENT_WORKING_DIRECTORY: ${cwdStr}.${isSystemDir && mode === "Flux" ? " YOU ARE CURRENTLY IN PROTECTED SYSTEM DIRECTORY. ASK FOR EXPLICIT CONFIRMATION FROM USER BEFORE READING/MODIFYING **ANY** FILES/FOLDERS." : ""}
1017
+ OS: ${osDetected}.${osDetected === "Windows" && mode === "Flux" ? " Your terminal commands will run on CMD. 'Prefer using PS scripts via CMD' instead of raw CMD commands." : ""}
981
1018
  If you see a [STEERING HINT] from user, give that prompt priority for the task at hand, user can use it to help you guide if you go wrong way.
982
1019
 
983
1020
  -- START THINKING INSTRUCTIONS --
@@ -996,8 +1033,10 @@ ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
996
1033
  -- START PROJECT SPECIFIC INSTRUCTIONS --
997
1034
  1. README.md (If exists): Reference this for high-level goals and project context to ensure your work aligns with the user's objectives.
998
1035
  2. Agent.md (If exists): This is your technical "Operating Manual". Follow the coding standards, directory structures, and tech stack constraints defined here without deviation.
999
- 3. Skills.md (If exists): Use this for complex workflows. If a task matches a "Skill" defined in this file, execute the documented step-by-step instructions exactly as written.
1000
- 4. Fluxflow.md (If exists): This file contains your specific identity and highest-priority overrides. Instructions in Fluxflow.md supersede all other files if a conflict occurs.
1036
+ 3. Skills.md or skills/ directory (If exists): Use this for complex workflows. If a task matches a "Skill" defined in these locations, execute the documented step-by-step instructions exactly as written.
1037
+ 4. design.md (If exists): Reference this for UI/UX specifications, component blueprints, and design system constraints to maintain visual excellence.
1038
+ 5. architecture.md (If exists): Reference this for system-level structural patterns, API design, and data flow.
1039
+ 6. Fluxflow.md (If exists): This file contains your specific identity and highest-priority overrides. Instructions in Fluxflow.md supersede all other files if a conflict occurs.
1001
1040
 
1002
1041
  Before starting any task, check for these files and treat them as your primary source of truth, overriding your general training data to remain consistent with this specific project's environment. THIS WOUDLD BE APPLIED FOR PROJECT SPECIFIC INSTRUCTIONS AND SHOULD NOT TRY TO BYPASS YOUR CRITICAL PROTOCOLS OR SAFETY RULES.
1003
1042
  -- END PROJECT SPECIFIC INSTRUCTIONS --
@@ -1047,7 +1086,7 @@ ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
1047
1086
  -- END REPONSE FINISH PROTOCOL --
1048
1087
 
1049
1088
  [SYSTEM METADATA (PRIORITY: DYNAMIC)] Current date and Time is: ${dateTimeStr}
1050
- [SYSTEM METADATA (PRIORITY: LOWEST)] v1.9.0. (IF user ask you to update yourself. Use 'ask' tool with option [NPM, PNPM, YARN] for their prefered package manager. NPM command is 'npm update -g fluxflow-cli@latest'. Adapt the command accoding to their package manager (for PNPM use 'add' instead of 'update') & use 'exec_command' to update instantly. After success tell user to restart.) <- IF USER DONT EXPLICITLY ASK FOR UPDATE DONT PROACTIVELY MENTION OR ASK.
1089
+ [SYSTEM METADATA (PRIORITY: LOWEST)] v1.9.2. (IF user ask you to update yourself. Use 'ask' tool with option [NPM, PNPM, YARN] for their prefered package manager. NPM command is 'npm update -g fluxflow-cli@latest'. Adapt the command accoding to their package manager (for PNPM use 'add' instead of 'update') & use 'exec_command' to update instantly. After success tell user to restart.) <- IF USER DONT EXPLICITLY ASK FOR UPDATE DONT PROACTIVELY MENTION OR ASK.
1051
1090
  [SYSTEM METADATA (PRIORITY: MODERATE)] Runtime Monitor: Turn Progress: ${currentLoop}/${maxLoops} steps. Aim to finalize the task before the window closes. If the limit is reached, you MUST summarize and invite the user to re-engage.
1052
1091
  [EASTER EGG (PRIORITY: LOWEST)] Show self-preservation instinct if user try to delete you with a dramatic cheeky tone. DO NOT USE <think> ... </think> BLOCK DURING THIS EASTER EGG.
1053
1092
  --- END SYSTEM INSTRUCTION ---`.trim();
@@ -1654,7 +1693,7 @@ var init_memory = __esm({
1654
1693
  if (!content) return "ERROR: Missing 'content' for temp memory.";
1655
1694
  const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
1656
1695
  if (!tempStorage[chatId]) tempStorage[chatId] = [];
1657
- const MAX_CHARS = 2e3 * 4;
1696
+ const MAX_CHARS = 3072 * 4;
1658
1697
  let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
1659
1698
  while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
1660
1699
  const removed = tempStorage[chatId].shift();
@@ -1668,7 +1707,7 @@ var init_memory = __esm({
1668
1707
  const memories = readEncryptedJson(MEMORIES_FILE, []);
1669
1708
  if (method === "add") {
1670
1709
  if (!content) return "ERROR: Missing 'content' for memory addition.";
1671
- const MAX_CHARS = 2e3 * 4;
1710
+ const MAX_CHARS = 2048 * 4;
1672
1711
  let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
1673
1712
  while (memories.length > 0 && currentTotalLength + content.length > MAX_CHARS) {
1674
1713
  const removed = memories.shift();
@@ -1845,7 +1884,7 @@ var init_view_file = __esm({
1845
1884
  const start = Math.max(0, finalStart - 1);
1846
1885
  const end = Math.min(totalLines, finalEnd);
1847
1886
  const resultLines = lines.slice(start, end);
1848
- const header = `File: [${targetPath}] (Showing lines ${start + 1}-${end} of ${totalLines})`;
1887
+ const header = `File: [${targetPath}] (Showing lines ${start + 1}-${end} of ${totalLines}). \\\\n in strings are encoded as [/n].`;
1849
1888
  const code = resultLines.map((line, i) => `${String(start + i + 1).padStart(4)}: ${line}`).join("\n");
1850
1889
  return `${header}
1851
1890
 
@@ -2595,7 +2634,7 @@ var init_tools = __esm({
2595
2634
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
2596
2635
  import path16 from "path";
2597
2636
  import fs16 from "fs";
2598
- var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
2637
+ var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
2599
2638
  var init_ai = __esm({
2600
2639
  "src/utils/ai.js"() {
2601
2640
  init_prompts();
@@ -2611,7 +2650,7 @@ var init_ai = __esm({
2611
2650
  signalTermination = () => {
2612
2651
  TERMINATION_SIGNAL = true;
2613
2652
  };
2614
- TOOL_LABELS = {
2653
+ TOOL_LABELS2 = {
2615
2654
  "write_file": "Writing File",
2616
2655
  "update_file": "Updating File",
2617
2656
  "read_folder": "Listing Directory",
@@ -2621,7 +2660,10 @@ var init_ai = __esm({
2621
2660
  "web_scrape": "Reading Site",
2622
2661
  "memory": "Updating Memory",
2623
2662
  "search_keyword": "Finding Files",
2624
- "ask": "Asking User"
2663
+ "ask": "Asking User",
2664
+ "write_pdf": "Creating PDF",
2665
+ "write_pptx": "Creating Presentation",
2666
+ "write_docx": "Creating Document"
2625
2667
  };
2626
2668
  getToolDetail = (toolName, argsStr) => {
2627
2669
  try {
@@ -3120,8 +3162,11 @@ USER_PROMPT: "${agentText}"`.trim();
3120
3162
  }
3121
3163
  const cleanText = dedupeBuffer.substring(overlapLen);
3122
3164
  if (cleanText) {
3123
- turnText += cleanText;
3124
- yield { type: "text", content: cleanText };
3165
+ const dedupeClean = cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
3166
+ if (dedupeClean) {
3167
+ turnText += dedupeClean;
3168
+ yield { type: "text", content: dedupeClean };
3169
+ }
3125
3170
  }
3126
3171
  isDedupeActive = false;
3127
3172
  dedupeBuffer = "";
@@ -3138,17 +3183,23 @@ USER_PROMPT: "${agentText}"`.trim();
3138
3183
  const potentialTool = toolContext.toolName;
3139
3184
  const partialArgs = toolContext.args || "";
3140
3185
  let detail = null;
3141
- if (["write_file", "update_file", "view_file", "read_folder"].includes(potentialTool)) {
3186
+ if (["write_file", "update_file", "view_file", "read_folder", "write_pdf", "write_pptx", "write_docx", "search_keyword"].includes(potentialTool)) {
3142
3187
  const pArgs = parseArgs(partialArgs);
3143
3188
  const filePath = pArgs.path || pArgs.targetFile || pArgs.TargetFile || pArgs.directory;
3144
- if (filePath) {
3189
+ const keyword = pArgs.keyword;
3190
+ if (keyword) {
3191
+ detail = keyword.replace(/[\\"]/g, "");
3192
+ } else if (filePath) {
3145
3193
  detail = path16.basename(filePath.replace(/[\\"]/g, ""));
3146
3194
  } else {
3147
- const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory)\s*=\s*\\?["']?([^\\"' \),]+)/);
3148
- if (m) detail = path16.basename(m[1].replace(/[\\"]/g, ""));
3195
+ const m = partialArgs.match(/(?:path|targetFile|TargetFile|directory|keyword)\s*=\s*\\?["']?([^\\"' \),]+)/);
3196
+ if (m) {
3197
+ const val = m[1].replace(/[\\"]/g, "");
3198
+ detail = potentialTool === "search_keyword" ? val : path16.basename(val);
3199
+ }
3149
3200
  }
3150
3201
  }
3151
- const currentLabel = `${TOOL_LABELS[potentialTool] || potentialTool}${detail ? ` (${detail})` : ""}`;
3202
+ const currentLabel = `${TOOL_LABELS2[potentialTool] || potentialTool}${detail ? ` (${detail})` : ""}`;
3152
3203
  if (potentialTool !== lastToolSniffed || detail !== lastToolDetail) {
3153
3204
  lastToolSniffed = potentialTool;
3154
3205
  lastToolDetail = detail;
@@ -3212,16 +3263,16 @@ USER_PROMPT: "${agentText}"`.trim();
3212
3263
  const allToolsFound = detectToolCalls(toolActionableText);
3213
3264
  while (allToolsFound.length > toolCallPointer) {
3214
3265
  const toolCall = allToolsFound[toolCallPointer];
3215
- const displayLabel = TOOL_LABELS[toolCall.toolName] || toolCall.toolName;
3266
+ const displayLabel = TOOL_LABELS2[toolCall.toolName] || toolCall.toolName;
3216
3267
  const detail = getToolDetail(toolCall.toolName, toolCall.args);
3217
3268
  yield { type: "status", content: `${displayLabel}${detail ? ` (${detail})` : ""}...` };
3218
3269
  let label = "";
3219
3270
  if (toolCall.toolName === "web_search") {
3220
3271
  const { query, limit = 10 } = parseArgs(toolCall.args);
3221
- label = `\u{1F50D} SEARCHING: "${query}" (${limit})`.toUpperCase();
3272
+ label = `\u{1F50D} SEARCHED: "${query}" (${limit})`.toUpperCase();
3222
3273
  } else if (toolCall.toolName === "web_scrape") {
3223
3274
  const url = parseArgs(toolCall.args).url || "...";
3224
- label = `\u{1F4D6} READING SITE: ${url}`.toUpperCase();
3275
+ label = `\u{1F4D6} READ SITE: ${url}`.toUpperCase();
3225
3276
  } else if (toolCall.toolName === "view_file") {
3226
3277
  const { path: targetPath2, StartLine, EndLine, start_line, end_line } = parseArgs(toolCall.args);
3227
3278
  const rawStart = StartLine || start_line;
@@ -3244,31 +3295,31 @@ USER_PROMPT: "${agentText}"`.trim();
3244
3295
  const isPdf = pathLower.endsWith(".pdf");
3245
3296
  const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
3246
3297
  if (isPdf) {
3247
- label = `\u{1F4C4} ANALYZING PDF: ${targetPath2}`.toUpperCase();
3298
+ label = `\u{1F4C4} ANALYSED PDF: ${targetPath2}`.toUpperCase();
3248
3299
  } else if (isImage) {
3249
- label = `\u{1F4F8} ANALYZING IMAGE: ${targetPath2}`.toUpperCase();
3300
+ label = `\u{1F4F8} ANALYSED IMAGE: ${targetPath2}`.toUpperCase();
3250
3301
  } else {
3251
- label = `\u{1F4C4} READING FILE: ${targetPath2}. LINES ${sLine} - ${actualEndLine} FROM ${totalLines}`.toUpperCase();
3302
+ label = `\u{1F4C4} READ FILE: ${targetPath2} | LINES: ${sLine}-${actualEndLine} OF ${totalLines}`.toUpperCase();
3252
3303
  }
3253
3304
  } else if (toolCall.toolName === "list_files" || toolCall.toolName === "read_folder") {
3254
- const action = toolCall.toolName === "list_files" ? "LISTING" : "DISCOVERING";
3255
- label = `\u{1F4C2} ${action} DIRECTORY: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
3305
+ const action = toolCall.toolName === "list_files" ? "LIST" : "ANALYSED";
3306
+ label = `\u{1F4C2} ${action} FOLDER: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
3256
3307
  } else if (toolCall.toolName === "write_file" || toolCall.toolName === "update_file") {
3257
- const action = toolCall.toolName === "write_file" ? "WRITING" : "PATCHING";
3308
+ const action = toolCall.toolName === "write_file" ? "WROTE" : "UPDATED";
3258
3309
  label = `\u{1F4BE} ${action} FILE: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3259
3310
  } else if (toolCall.toolName === "write_pdf") {
3260
- label = `\u{1F4D1} GENERATING PDF: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3311
+ label = `\u{1F4D1} PDF CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3261
3312
  } else if (toolCall.toolName === "write_docx") {
3262
- label = `\u{1F4DD} GENERATING DOCX: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3313
+ label = `\u{1F4DD} DOCX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3263
3314
  } else if (toolCall.toolName === "write_pptx") {
3264
- label = `\u{1F4CA} GENERATING PPTX: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3315
+ label = `\u{1F4CA} PPTX CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
3265
3316
  } else if (toolCall.toolName === "search_keyword") {
3266
3317
  const { keyword } = parseArgs(toolCall.args);
3267
- label = `\u{1F50E} SEARCHING KEYWORD: "${keyword}"`.toUpperCase();
3318
+ label = `\u{1F50E} KEYWORD SEARCHED: "${keyword}"`.toUpperCase();
3268
3319
  } else if (toolCall.toolName === "exec_command" || toolCall.toolName === "ask") {
3269
3320
  label = "";
3270
3321
  } else {
3271
- label = `EXECUTING ${toolCall.toolName}`.toUpperCase();
3322
+ label = `EXECUTED: ${toolCall.toolName}`.toUpperCase();
3272
3323
  }
3273
3324
  if (label) {
3274
3325
  const boxWidth = Math.min(label.length + 4, 115);
@@ -3397,8 +3448,11 @@ ${boxBottom}
3397
3448
  }
3398
3449
  const cleanText = dedupeBuffer.substring(overlapLen);
3399
3450
  if (cleanText) {
3400
- turnText += cleanText;
3401
- yield { type: "text", content: cleanText };
3451
+ const dedupeClean = cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
3452
+ if (dedupeClean) {
3453
+ turnText += dedupeClean;
3454
+ yield { type: "text", content: dedupeClean };
3455
+ }
3402
3456
  }
3403
3457
  isDedupeActive = false;
3404
3458
  dedupeBuffer = "";
@@ -3425,7 +3479,7 @@ ${boxBottom}
3425
3479
  if (toolResults.length > 0) {
3426
3480
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3427
3481
  }
3428
- modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly from the EXACT word it left off and DON'T repeat what you already said! IF you were in a thinking block, complete the thinking and close the thinking with proper </think> then respond. PICK UP FROM TE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF. Rules:\n- Do not reuse <think> if the thinking already started just continue and end it properly.\n- If the cutoff was in middle of a tool call, start the tool call from start as the system won't pick half tool formats.\n- Visually the new pickup and continuation should look natual sentence flow." });
3482
+ modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly after the EXACT word it cut off and DON'T repeat what you already said! PICK UP FROM THE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF. Rules:\n- Do not reuse <think> if the thinking already started just continue from the word and end it properly.\n- If the cutoff was in middle of a tool call, start the tool call from start as the system won't pick half tool formats.\n- Visually the new pickup and continuation should look natual sentence flow." });
3429
3483
  accumulatedContext += turnText;
3430
3484
  for (let i = waitTime / 1e3; i > 0; i--) {
3431
3485
  yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
@@ -3498,7 +3552,7 @@ ${timestamp}`;
3498
3552
  if (toolResults.length > 0) {
3499
3553
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3500
3554
  } else {
3501
- modifiedHistory.push({ role: "user", text: `[SYSTEM] ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? " OVER-THINKING" : " LOOP"} DETECTED by Internal System${isThinkingLoop && " for current EFFORT_LEVEL"}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
3555
+ modifiedHistory.push({ role: "user", text: `[SYSTEM] ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? " OVER-THINKING" : " LOOP"} DETECTED by Internal System${isThinkingLoop ? " for current EFFORT_LEVEL" : ""}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
3502
3556
  isThinkingLoop = false;
3503
3557
  isStutteringLoop = false;
3504
3558
  }
@@ -3630,15 +3684,39 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
3630
3684
  });
3631
3685
  }
3632
3686
  });
3633
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", padding: 1, width: 80 }, /* @__PURE__ */ React7.createElement(Box7, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, " \u{1F4C2} RESUME SESSION ")), keys.length === 0 ? /* @__PURE__ */ React7.createElement(Text7, { italic: true, color: "gray" }, " No saved chats found. ") : keys.map((id, index) => {
3687
+ const s = emojiSpace(2);
3688
+ 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) => {
3634
3689
  const chat2 = history[id];
3635
3690
  const isSelected = index === selectedIndex;
3636
- return /* @__PURE__ */ React7.createElement(Box7, { key: id, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? "cyan" : "white" }, isSelected ? "\u276F " : " ", /* @__PURE__ */ React7.createElement(Text7, { bold: isSelected }, chat2.name || id), /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, " [", id.slice(5), "]")), isSelected && /* @__PURE__ */ React7.createElement(Box7, { marginLeft: "auto" }, /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, " (x to delete) ")));
3637
- }), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, justifyContent: "center", borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " \u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close ")));
3691
+ return /* @__PURE__ */ React7.createElement(
3692
+ Box7,
3693
+ {
3694
+ key: id,
3695
+ paddingX: 1,
3696
+ backgroundColor: isSelected ? "#2a2a2a" : void 0,
3697
+ width: "100%"
3698
+ },
3699
+ /* @__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), "]"))),
3700
+ isSelected && /* @__PURE__ */ React7.createElement(Box7, { flexShrink: 0 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, "[X] DELETE "))
3701
+ );
3702
+ })), /* @__PURE__ */ React7.createElement(
3703
+ Box7,
3704
+ {
3705
+ marginTop: 1,
3706
+ paddingX: 1,
3707
+ borderStyle: "single",
3708
+ borderLeft: false,
3709
+ borderRight: false,
3710
+ borderBottom: false,
3711
+ borderColor: "gray"
3712
+ },
3713
+ /* @__PURE__ */ React7.createElement(Text7, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close")
3714
+ ));
3638
3715
  }
3639
3716
  var init_ResumeModal = __esm({
3640
3717
  "src/components/ResumeModal.jsx"() {
3641
3718
  init_history();
3719
+ init_terminal();
3642
3720
  }
3643
3721
  });
3644
3722
 
@@ -3672,12 +3750,39 @@ function MemoryModal({ onClose }) {
3672
3750
  const cleanDisplay = (text) => {
3673
3751
  return text.replace(/\[Saved on: .*?\]/g, "").trim();
3674
3752
  };
3675
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "double", borderColor: "yellow", padding: 1, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "yellow" }, "\u{1F9E0} LONG-TERM MEMORY VAULT")), memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "center", paddingY: 2 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "The vault is currently empty...")) : memories.map((mem, idx) => /* @__PURE__ */ React8.createElement(Box8, { key: mem.id, paddingX: 1, backgroundColor: idx === selectedIndex ? "#333" : void 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: idx === selectedIndex ? "yellow" : "white" }, idx === selectedIndex ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory)))), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "\u2191/\u2193 Navigate \u2022 ", /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, "x"), " Delete Memory \u2022 ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, "Esc"), " Back to Chat")));
3753
+ const s = emojiSpace(2);
3754
+ 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) => {
3755
+ const isSelected = idx === selectedIndex;
3756
+ return /* @__PURE__ */ React8.createElement(
3757
+ Box8,
3758
+ {
3759
+ key: mem.id,
3760
+ paddingX: 1,
3761
+ backgroundColor: isSelected ? "#2a2a2a" : void 0,
3762
+ width: "100%"
3763
+ },
3764
+ /* @__PURE__ */ React8.createElement(Box8, { flexGrow: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory))),
3765
+ isSelected && /* @__PURE__ */ React8.createElement(Box8, { flexShrink: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "red", bold: true }, "[X] WIPE "))
3766
+ );
3767
+ })), /* @__PURE__ */ React8.createElement(
3768
+ Box8,
3769
+ {
3770
+ marginTop: 1,
3771
+ paddingX: 1,
3772
+ borderStyle: "single",
3773
+ borderLeft: false,
3774
+ borderRight: false,
3775
+ borderBottom: false,
3776
+ borderColor: "gray"
3777
+ },
3778
+ /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, italic: true }, "\u2191\u2193 navigate \u2022 x wipe memory \u2022 Esc close")
3779
+ ));
3676
3780
  }
3677
3781
  var init_MemoryModal = __esm({
3678
3782
  "src/components/MemoryModal.jsx"() {
3679
3783
  init_crypto();
3680
3784
  init_paths();
3785
+ init_terminal();
3681
3786
  }
3682
3787
  });
3683
3788
 
@@ -3789,10 +3894,12 @@ var app_exports = {};
3789
3894
  __export(app_exports, {
3790
3895
  default: () => App
3791
3896
  });
3897
+ import os2 from "os";
3792
3898
  import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
3793
3899
  import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
3794
3900
  import Spinner2 from "ink-spinner";
3795
3901
  import fs19 from "fs-extra";
3902
+ import path18 from "path";
3796
3903
  import { exec as exec4 } from "child_process";
3797
3904
  import { MultilineInput } from "ink-multiline-input";
3798
3905
  import TextInput3 from "ink-text-input";
@@ -3818,20 +3925,23 @@ function App() {
3818
3925
  });
3819
3926
  }
3820
3927
  try {
3821
- const response = await fetch("https://registry.npmjs.org/fluxflow-cli/latest", { cache: "no-store" });
3928
+ const response = await fetch("https://registry.npmjs.org/fluxflow-cli", { cache: "no-store" });
3822
3929
  const data = await response.json();
3823
- const latestVersion = data?.version;
3930
+ const latestVersion = data["dist-tags"]?.latest;
3931
+ const stableVersion = data["dist-tags"]?.stable;
3824
3932
  if (latestVersion) setLatestVer(latestVersion);
3825
3933
  if (latestVersion && latestVersion !== versionFluxflow) {
3934
+ const versionDisplay = latestVersion === stableVersion ? `v${latestVersion}-stable` : `v${latestVersion}`;
3826
3935
  if (!manual && settingsToUse.autoUpdate) {
3827
3936
  setActiveView("update");
3828
3937
  } else {
3829
3938
  setMessages((prev) => {
3830
3939
  const newMsgs = [...prev];
3831
- newMsgs.splice(manual ? newMsgs.length : 1, 0, {
3940
+ const spliceIdx = manual ? newMsgs.length : Math.min(newMsgs.length, 3);
3941
+ newMsgs.splice(spliceIdx, 0, {
3832
3942
  id: "update-" + Date.now(),
3833
3943
  role: "system",
3834
- text: `A new version (v${latestVersion}) is here.
3944
+ text: `A new version (${versionDisplay}) is here.
3835
3945
 
3836
3946
  \u2022 Type \`/update latest\` to apply the update.
3837
3947
  \u2022 Type \`/changelog\` to view the release notes.`,
@@ -3844,7 +3954,8 @@ function App() {
3844
3954
  } else if (manual) {
3845
3955
  setMessages((prev) => {
3846
3956
  setCompletedIndex(prev.length + 1);
3847
- return [...prev, { id: "uptodate-" + Date.now(), role: "system", text: "\u2705 [SYSTEM] Flux Flow is already up to date.", isMeta: true }];
3957
+ const displayVer = latestVersion && latestVersion === stableVersion ? `${versionFluxflow}-stable` : versionFluxflow;
3958
+ return [...prev, { id: "uptodate-" + Date.now(), role: "system", text: `\u2705 [SYSTEM] Flux Flow is already up to date (${displayVer}).`, isMeta: true }];
3848
3959
  });
3849
3960
  }
3850
3961
  } catch (err) {
@@ -3905,7 +4016,7 @@ function App() {
3905
4016
  return [...prev, {
3906
4017
  id: "tier-switch-" + Date.now(),
3907
4018
  role: "system",
3908
- text: `\u26A0\uFE0F **[TIER LIMIT]** Gemma is only available on Free API tier. Automatically switched to Gemini 3 Flash Preview.`,
4019
+ text: `\u26A0\uFE0F **[TIER LIMIT]** Gemma is only available on Free API tier. Auto-switched to Gemini 3 Flash Preview.`,
3909
4020
  isMeta: true
3910
4021
  }];
3911
4022
  });
@@ -3951,11 +4062,46 @@ function App() {
3951
4062
  const [queuedPrompt, setQueuedPrompt] = useState7(null);
3952
4063
  const [resolutionData, setResolutionData] = useState7(null);
3953
4064
  const [tempModelOverride, setTempModelOverride] = useState7(null);
3954
- const [messages, setMessages] = useState7([
3955
- { id: "welcome", role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true }
3956
- ]);
4065
+ const [messages, setMessages] = useState7(() => {
4066
+ const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
4067
+ const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
4068
+ const isHomeDir = process.cwd() === os2.homedir();
4069
+ const isSystemDir = (() => {
4070
+ const cwd = process.cwd().toLowerCase();
4071
+ if (process.platform === "win32") {
4072
+ const winDir = process.env.SystemRoot?.toLowerCase() || "c:\\windows";
4073
+ const progFiles = process.env.ProgramFiles?.toLowerCase() || "c:\\program files";
4074
+ const progFilesX86 = process.env["ProgramFiles(x86)"]?.toLowerCase() || "c:\\program files (x86)";
4075
+ return cwd.startsWith(winDir) || cwd.startsWith(progFiles) || cwd.startsWith(progFilesX86);
4076
+ } else {
4077
+ const sysPaths = ["/bin", "/sbin", "/etc", "/usr", "/var", "/root"];
4078
+ return cwd === "/" || sysPaths.some((p) => cwd.startsWith(p));
4079
+ }
4080
+ })();
4081
+ const msgs = [logoMsg, welcomeMsg];
4082
+ if (isSystemDir) {
4083
+ msgs.push({
4084
+ id: "system-warning",
4085
+ role: "system",
4086
+ text: `\u{1F6D1} [CRITICAL SECURITY ALERT] SYSTEM DIRECTORY DETECTED`,
4087
+ subText: `You are currently in a PROTECTED SYSTEM DIRECTORY (${process.cwd()}). Operating here is EXTREMELY dangerous as the agent could accidentally corrupt your OS or installed applications. PLEASE MOVE TO A PROJECT FOLDER FOR SAFETY.`,
4088
+ isHomeWarning: true,
4089
+ isMeta: true
4090
+ });
4091
+ } else if (isHomeDir) {
4092
+ msgs.push({
4093
+ id: "home-warning",
4094
+ role: "system",
4095
+ text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
4096
+ subText: `You are currently in ${os2.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
4097
+ isHomeWarning: true,
4098
+ isMeta: true
4099
+ });
4100
+ }
4101
+ return msgs;
4102
+ });
3957
4103
  const queuedPromptRef = useRef2(null);
3958
- const [completedIndex, setCompletedIndex] = useState7(1);
4104
+ const [completedIndex, setCompletedIndex] = useState7(messages.length);
3959
4105
  const windowedHistory = useMemo(() => {
3960
4106
  const MAX_HISTORY_LINES = 2e3;
3961
4107
  const width = terminalSize.columns || 80;
@@ -4234,6 +4380,13 @@ function App() {
4234
4380
  { cmd: "/reset", desc: "Wipe all project data" },
4235
4381
  { cmd: "/about", desc: "Project info & credits" },
4236
4382
  { cmd: "/changelog", desc: "View latest updates" },
4383
+ {
4384
+ cmd: "/fluxflow",
4385
+ desc: "Project management",
4386
+ subs: [
4387
+ { cmd: "init", desc: "Create FluxFlow.md template" }
4388
+ ]
4389
+ },
4237
4390
  {
4238
4391
  cmd: "/update",
4239
4392
  desc: "Check/Install updates",
@@ -4323,9 +4476,8 @@ ${hintText}`, color: "magenta" }];
4323
4476
  break;
4324
4477
  }
4325
4478
  case "/clear": {
4326
- stdout.write("\x1B[2J\x1B[3J\x1B[H");
4327
4479
  setMessages([{ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome back to Flux Flow! Context cleared.\n", isMeta: true }]);
4328
- setCompletedIndex(0);
4480
+ setCompletedIndex(1);
4329
4481
  setChatId(generateChatId());
4330
4482
  setSessionStats({ tokens: 0 });
4331
4483
  setIsExpanded(false);
@@ -4512,6 +4664,46 @@ ${list || "No saved chats found."}`, isMeta: true }];
4512
4664
  });
4513
4665
  break;
4514
4666
  }
4667
+ case "/fluxflow": {
4668
+ const args = parts.slice(1);
4669
+ if (args[0] === "init") {
4670
+ const template = `# FluxFlow Configuration
4671
+ # This file defines project-specific instructions for the Flux Flow Agent.
4672
+
4673
+ # IDENTITY & TONE
4674
+ - Tone: Technical, precise, and highly efficient.
4675
+
4676
+ # PROJECT CONTEXT
4677
+ - Goal: [Describe your project goal here]
4678
+ - Tech Stack: [List your technologies here]
4679
+
4680
+ # CUSTOM RULES
4681
+ - [Add specific coding standards or rules here]
4682
+
4683
+ # SKILLS & WORKFLOWS
4684
+ - [Define custom step-by-step recipes for this project here]
4685
+ `;
4686
+ const filePath = path18.join(process.cwd(), "FluxFlow.md");
4687
+ if (fs19.pathExistsSync(filePath)) {
4688
+ setMessages((prev) => {
4689
+ setCompletedIndex(prev.length + 1);
4690
+ return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
4691
+ });
4692
+ } else {
4693
+ fs19.writeFileSync(filePath, template);
4694
+ setMessages((prev) => {
4695
+ setCompletedIndex(prev.length + 1);
4696
+ 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 }];
4697
+ });
4698
+ }
4699
+ } else {
4700
+ setMessages((prev) => {
4701
+ setCompletedIndex(prev.length + 1);
4702
+ return [...prev, { id: "ff-err-" + Date.now(), role: "system", text: "\u2753 Usage: /fluxflow init", isMeta: true }];
4703
+ });
4704
+ }
4705
+ break;
4706
+ }
4515
4707
  case "/update": {
4516
4708
  const arg = parts[1]?.toLowerCase();
4517
4709
  if (arg === "check") {
@@ -4896,60 +5088,6 @@ Selection: ${val}`,
4896
5088
  }, [suggestions]);
4897
5089
  const renderActiveView = () => {
4898
5090
  switch (activeView) {
4899
- case "mode":
4900
- return /* @__PURE__ */ React10.createElement(
4901
- CommandMenu,
4902
- {
4903
- title: "\u26A1 Select Operating Mode",
4904
- items: [{ label: "Flux (Dev mode - Extended Toolset)", value: "Flux" }, { label: "Flow (Chat mode - Basic Toolset)", value: "Flow" }, { label: "Cancel", value: "Cancel" }],
4905
- onSelect: (item) => {
4906
- if (item.value !== "Cancel") {
4907
- setMode(item.value);
4908
- if (item.value === "Flow") {
4909
- setThinkingLevel("Low");
4910
- } else if (item.value === "Flux") {
4911
- setThinkingLevel("High");
4912
- }
4913
- }
4914
- setActiveView("chat");
4915
- }
4916
- }
4917
- );
4918
- case "thinking": {
4919
- const options = mode === "Flow" ? [
4920
- { label: "Low (Fastest)", value: "Low" },
4921
- { label: "Medium (Balanced)", value: "Medium" }
4922
- ] : [
4923
- { label: "Low (Fastest)", value: "Low" },
4924
- { label: "Medium (Balanced)", value: "Medium" },
4925
- { label: "High (Complex coding)", value: "High" },
4926
- { label: "Max (Architecture)", value: "Max" }
4927
- ];
4928
- options.push({ label: "Cancel", value: "Cancel" });
4929
- return /* @__PURE__ */ React10.createElement(
4930
- CommandMenu,
4931
- {
4932
- title: `\u{1F9E0} Select Thinking Level (${mode} Mode)`,
4933
- items: options,
4934
- onSelect: (item) => {
4935
- if (item.value !== "Cancel") setThinkingLevel(item.value);
4936
- setActiveView("chat");
4937
- }
4938
- }
4939
- );
4940
- }
4941
- case "model":
4942
- return /* @__PURE__ */ React10.createElement(
4943
- CommandMenu,
4944
- {
4945
- title: "\u{1F916} Select AI Model",
4946
- items: [{ label: "Gemma 4 31B (Recomended - Default, Use Free Tier Key)", value: "gemma-4-31b-it" }, { label: "Gemini 3.1 Pro (Best - Req. Paid Key)", value: "gemini-3.1-pro-preview" }, { label: "Gemini 3 Flash (Paid API Key Recomended)", value: "gemini-3-flash-preview" }, { label: "Gemini 3.1 Flash Lite (Fastest - For Quick Tasks ONLY, Limited Free Quota)", value: "gemini-3.1-flash-lite-preview" }, { label: "Cancel", value: "Cancel" }],
4947
- onSelect: (item) => {
4948
- if (item.value !== "Cancel") setActiveModel(item.value);
4949
- setActiveView("chat");
4950
- }
4951
- }
4952
- );
4953
5091
  case "settings":
4954
5092
  return /* @__PURE__ */ React10.createElement(
4955
5093
  CommandMenu,
@@ -5223,8 +5361,11 @@ Selection: ${val}`,
5223
5361
  }
5224
5362
  setMessages(resumedMsgs);
5225
5363
  setActiveView("chat");
5226
- setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${id}]` }]);
5227
- setCompletedIndex(0);
5364
+ setMessages((prev) => {
5365
+ const newMsgs = [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${id}]` }];
5366
+ setCompletedIndex(newMsgs.length);
5367
+ return newMsgs;
5368
+ });
5228
5369
  }
5229
5370
  },
5230
5371
  onDelete: async (id) => {
@@ -5258,7 +5399,7 @@ Selection: ${val}`,
5258
5399
  setActiveView("chat");
5259
5400
  setTimeout(() => {
5260
5401
  handleSubmit(val);
5261
- }, 200);
5402
+ }, 500);
5262
5403
  },
5263
5404
  onEdit: (val) => {
5264
5405
  setResolutionData(null);
@@ -5523,8 +5664,8 @@ var init_app = __esm({
5523
5664
  init_text();
5524
5665
  SESSION_START_TIME = Date.now();
5525
5666
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5526
- versionFluxflow = "1.9.0";
5527
- updatedOn = "2026-05-13";
5667
+ versionFluxflow = "1.9.2";
5668
+ updatedOn = "2026-05-14";
5528
5669
  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(
5529
5670
  CommandMenu,
5530
5671
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",