fluxflow-cli 2.10.1 → 2.10.3

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 +170 -46
  2. package/package.json +4 -3
package/dist/fluxflow.js CHANGED
@@ -1745,7 +1745,7 @@ var init_ChatLayout = __esm({
1745
1745
  const level = headingMatch[1].length;
1746
1746
  const hText = headingMatch[2];
1747
1747
  result.push(
1748
- /* @__PURE__ */ React3.createElement(Box3, { key: i, marginTop: 1, marginBottom: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: level === 1 ? "cyan" : level === 2 ? "magenta" : level === 3 ? "yellow" : level === 4 ? "green" : level === 5 ? "blue" : "white", underline: true }, hText.toUpperCase()))
1748
+ /* @__PURE__ */ React3.createElement(Box3, { key: i, marginTop: 1, marginBottom: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: level === 1 ? "cyan" : level === 2 ? "purple" : level === 3 ? "yellow" : level === 4 ? "green" : level === 5 ? "blue" : "white", underline: true }, hText.toUpperCase()))
1749
1749
  );
1750
1750
  return;
1751
1751
  }
@@ -1852,13 +1852,13 @@ var init_ChatLayout = __esm({
1852
1852
  const isTerminalRecord = msg.isTerminalRecord;
1853
1853
  const isHomeWarning = msg.isHomeWarning;
1854
1854
  if (isHomeWarning) {
1855
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", dimColor: true, padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, backgroundColor: "#3a0000" }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, msg.text)), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 0, marginBottom: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, msg.subText))));
1855
+ return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "white", dimColor: true, padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, msg.text)), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 0, marginBottom: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, msg.subText))));
1856
1856
  }
1857
1857
  if (msg.isLogo) {
1858
1858
  return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", alignItems: "flex-start", width: "100%", marginY: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, getFluxLogo(version, aiProvider)));
1859
1859
  }
1860
1860
  if (msg.id && String(msg.id).startsWith("welcome")) {
1861
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", alignItems: "center", width: "100%", marginY: 1 }, /* @__PURE__ */ React3.createElement(Box3, { borderStyle: "round", borderColor: "gray", paddingX: 3, paddingY: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan", bold: true }, msg.text.trim())));
1861
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", alignItems: "center", width: "100%", marginY: 1 }, /* @__PURE__ */ React3.createElement(Box3, { borderStyle: "round", borderColor: "grey", paddingX: 3, paddingY: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, msg.text.trim())));
1862
1862
  }
1863
1863
  if (msg.isVisualFeedback) {
1864
1864
  return (
@@ -1871,13 +1871,13 @@ var init_ChatLayout = __esm({
1871
1871
  }
1872
1872
  if (msg.role === "system" && msg.text?.includes("[TOOL RESULT]") && !isDiffResult && !isTerminalRecord && !isPatchError) return null;
1873
1873
  if (msg.isImageStats) {
1874
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, backgroundColor: "#0e1b21" }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan", bold: true }, "\u{1F4B3} IMAGE STATS")), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1, flexDirection: "column" }, msg.text.split("\n").map((line, i) => /* @__PURE__ */ React3.createElement(Text3, { key: i, color: "white" }, line)))));
1874
+ return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "grey", padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, backgroundColor: "#0e1b21" }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, "IMAGE STATS")), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1, flexDirection: "column" }, msg.text.split("\n").map((line, i) => /* @__PURE__ */ React3.createElement(Text3, { key: i, color: "grey" }, line)))));
1875
1875
  }
1876
1876
  if (msg.isAskRecord) {
1877
1877
  const selectionMatch = msg.text.match(/Selection: (.*)/);
1878
1878
  const selection = selectionMatch ? selectionMatch[1] : "No selection";
1879
1879
  const s = emojiSpace(2);
1880
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan", bold: true }, "\u{1F4AC} AGENT REQUEST: RESOLVED")), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, "Selection: ", /* @__PURE__ */ React3.createElement(Text3, { color: "yellow", bold: true }, selection)))));
1880
+ return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, "AGENT REQUEST: RESOLVED")), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, "Selection: ", /* @__PURE__ */ React3.createElement(Text3, { color: "grey", bold: true }, selection)))));
1881
1881
  }
1882
1882
  if (msg.isAboutRecord) {
1883
1883
  return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, "ABOUT FLUX FLOW")), /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, msg.text))));
@@ -1913,7 +1913,7 @@ var init_ChatLayout = __esm({
1913
1913
  { cmd: "/fluxflow", desc: "Project management" },
1914
1914
  { cmd: "/update", desc: "Check/Install updates" }
1915
1915
  ];
1916
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Text3, { color: "magenta", bold: true, underline: true }, "\u{1F4DC} COMMAND REFERENCE"), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, commandList.map((c, i) => /* @__PURE__ */ React3.createElement(Box3, { key: i, flexDirection: "row" }, /* @__PURE__ */ React3.createElement(Box3, { width: 15 }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan", bold: true }, c.cmd)), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " - ", c.desc))))));
1916
+ return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true, underline: true }, "COMMAND REFERENCE"), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, commandList.map((c, i) => /* @__PURE__ */ React3.createElement(Box3, { key: i, flexDirection: "row" }, /* @__PURE__ */ React3.createElement(Box3, { width: 15 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", bold: true }, c.cmd)), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " - ", c.desc))))));
1917
1917
  }
1918
1918
  if (msg.isTerminalRecord) {
1919
1919
  const cmdMatch = msg.text.match(/COMMAND: (.*)/);
@@ -2009,14 +2009,13 @@ function CommandMenu({ title, subtitle, items, onSelect }) {
2009
2009
  Box5,
2010
2010
  {
2011
2011
  flexDirection: "column",
2012
- borderStyle: "round",
2013
2012
  borderColor: "white",
2014
2013
  padding: 0,
2015
- marginTop: 1,
2014
+ marginTop: 0,
2016
2015
  flexShrink: 0,
2017
2016
  width: "100%"
2018
2017
  },
2019
- /* @__PURE__ */ React5.createElement(Box5, { paddingX: 1, paddingY: 0, marginBottom: subtitle ? 0 : 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", bold: true }, "\u{1F527} ", typeof title === "string" ? title.toUpperCase() : title)),
2018
+ title && /* @__PURE__ */ React5.createElement(Box5, { paddingX: 1, paddingY: 0, marginBottom: subtitle ? 0 : 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", bold: true }, typeof title === "string" ? title.toUpperCase() : title)),
2020
2019
  subtitle && /* @__PURE__ */ React5.createElement(Box5, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "gray", italic: true }, " ", subtitle)),
2021
2020
  /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React5.createElement(
2022
2021
  SelectInput,
@@ -2211,10 +2210,10 @@ var init_main_tools = __esm({
2211
2210
  };
2212
2211
  TOOL_PROTOCOL = (mode, osDetected, isMultiModal, aiProvider) => `
2213
2212
  -- TOOL DEFINITIONS --
2214
- Internal tools. MUST use the EXACT syntax '[tool:functions.ToolName(args)]'. **NEVER USE OTHER SYNTAX/MARKERS, BRACKETS SHOULD BE PROPERLY USED AS PER SCHEMA**
2213
+ Internal tools. MUST use the EXACT syntax '[tool:functions.ToolName(args)]'. **NO OTHER SYNTAX/MARKERS ALLOWED, BRACKETS SHOULD BE PROPERLY USED AS PER SCHEMA**
2215
2214
 
2216
2215
  **TOOL USAGE POLICY:**
2217
- - **MAX 3 TOOL CALLS PER TURN${mode === "Flux" ? " (EXCEPTION FOR Todo TOOL: 3+ CALLS ALLOWED)" : ""}. Next Turn, verify tool results, plan next**
2216
+ - **MAX 3 TOOL CALLS PER TURN${mode === "Flux" ? " (EXCEPTION FOR Todo TOOL: 3+ CALLS ALLOWED, Run: Limit to 2 MAX)" : ""}. Next Turn, verify tool results, plan next**
2218
2217
  ${mode === "Flux" ? "- USE multiple search & replace on patch tool if editing same file/path with many changes \u2190 **HIGHLY RECOMMENDED**\n- Tool execution denied? MUST use 'Ask' tool immediately for user reason/changes. NEVER END RESPONSE OR PROCEED BLINDLY \u2190 **MANDATORY**\n- FileMap >> ReadFile to understand file efficiently\n- Want spefific STRING across project/file? SearchKeyword >> Guessing/ReadFile\n- HUGE FILES? SearchKeyword >> FileMap/Full File read\n- **MUST MARK DONE/APPEND Todos BASED ON REALTIME TASK PROGRESS ON *EACH TURN***" : ""}
2219
2218
  ${mode === "Flux" ? "- **File Tools >> Code in chat**\n\n" : ""}- COMMUNICATION TOOLS -
2220
2219
  1. [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish. Suggest best options; don't ask for preferences
@@ -2230,7 +2229,7 @@ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST A
2230
2229
  4. [tool:functions.PatchFile(path="...", replaceContent1="full line/block", newContent1="...", ...MAX 6)]. Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile >> guessing. **MUST VERIFY DIFF**
2231
2230
  5. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
2232
2231
  6. [tool:functions.SearchKeyword(keyword="...", file="optional")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
2233
- 7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `${isPtyAvailable ? "Interactive " : ""}WINDOWS POWERSHELL ONLY` : `${isPtyAvailable ? "Interactive " : ""}WINDOWS CMD ONLY` : `${isPtyAvailable ? "Interactive " : ""}BASH`} command. Destructive/Irreversible ops -> Ask user. **TOOL DENY RULE APPLIES**. **1 CALL LIMIT FOR RUN**
2232
+ 7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `${isPtyAvailable ? "Interactive " : ""}WINDOWS POWERSHELL ONLY` : `${isPtyAvailable ? "Interactive " : ""}WINDOWS CMD ONLY` : `${isPtyAvailable ? "Interactive " : ""}BASH`} command. Destructive/Irreversible ops -> Ask user
2234
2233
  8. [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASK STRINGS])]. Task List, Markdown IN ARRAY NOT ALLOWED. USAGE: ANALYZE USER REQUEST **IF** MULTIPLE TASK \u2192 BREAK DOWN TASK \u2192 CREATE TODO **BEFORE** DIVING IN. 'tasks' & 'markDone' OPTIONAL PARAMETERS WITH method 'get'. USE 'get' method WITH 'markDone' to mark task completed`.trim() : `- CREATIVE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
2235
2234
  1. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
2236
2235
  2. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word document
@@ -2711,8 +2710,20 @@ var init_exec_command = __esm({
2711
2710
  return new Promise((resolve) => {
2712
2711
  const attempt = (usePowerShell) => {
2713
2712
  const command = adjustWindowsCommand(rawCommand, usePowerShell);
2714
- const shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
2715
- const shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
2713
+ let shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
2714
+ let shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
2715
+ if (systemSettings.networkAccess === false && !isWin) {
2716
+ const originalShell = shell;
2717
+ const originalArgs = [...shellArgs];
2718
+ if (process.platform === "linux") {
2719
+ shell = "unshare";
2720
+ shellArgs = ["-n", "-r", originalShell, ...originalArgs];
2721
+ } else if (process.platform === "darwin") {
2722
+ const sbProfile = '(version 1)\n(allow default)\n(deny network-outbound)\n(allow network-outbound (remote ip "localhost:*"))\n(allow network-outbound (remote ip "127.0.0.1:*"))\n';
2723
+ shell = "sandbox-exec";
2724
+ shellArgs = ["-p", sbProfile, originalShell, ...originalArgs];
2725
+ }
2726
+ }
2716
2727
  if (pty) {
2717
2728
  try {
2718
2729
  const ptyProcess = pty.spawn(shell, shellArgs, {
@@ -2765,11 +2776,11 @@ ${finalOutput}`);
2765
2776
  if (isWin && usePowerShell && err.code === "ENOENT") {
2766
2777
  return false;
2767
2778
  }
2768
- runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell);
2779
+ runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell, systemSettings);
2769
2780
  return true;
2770
2781
  }
2771
2782
  } else {
2772
- runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell);
2783
+ runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell, systemSettings);
2773
2784
  return true;
2774
2785
  }
2775
2786
  };
@@ -2782,12 +2793,23 @@ ${finalOutput}`);
2782
2793
  }
2783
2794
  });
2784
2795
  };
2785
- runStandardSpawn = (resolve, command, rawCommand, netEnv, onChunk, usePowerShell = true) => {
2796
+ runStandardSpawn = (resolve, command, rawCommand, netEnv, onChunk, usePowerShell = true, systemSettings = {}) => {
2786
2797
  const isWin = process.platform === "win32";
2787
- const shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
2788
- const shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
2789
- const child = isWin ? spawn(shell, shellArgs, { cwd: process.cwd(), env: { ...process.env, ...netEnv } }) : spawn(command, {
2790
- shell: true,
2798
+ let shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
2799
+ let shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
2800
+ if (systemSettings.networkAccess === false && !isWin) {
2801
+ const originalShell = shell;
2802
+ const originalArgs = [...shellArgs];
2803
+ if (process.platform === "linux") {
2804
+ shell = "unshare";
2805
+ shellArgs = ["-n", "-r", originalShell, ...originalArgs];
2806
+ } else if (process.platform === "darwin") {
2807
+ const sbProfile = '(version 1)\n(allow default)\n(deny network-outbound)\n(allow network-outbound (remote ip "localhost:*"))\n(allow network-outbound (remote ip "127.0.0.1:*"))\n';
2808
+ shell = "sandbox-exec";
2809
+ shellArgs = ["-p", sbProfile, originalShell, ...originalArgs];
2810
+ }
2811
+ }
2812
+ const child = isWin ? spawn(shell, shellArgs, { cwd: process.cwd(), env: { ...process.env, ...netEnv } }) : spawn(shell, shellArgs, {
2791
2813
  cwd: process.cwd(),
2792
2814
  env: {
2793
2815
  ...process.env,
@@ -2854,7 +2876,7 @@ ${finalOutput}`);
2854
2876
  child.on("error", (err) => {
2855
2877
  if (isWin && usePowerShell && err.code === "ENOENT") {
2856
2878
  const cmdCommand = adjustWindowsCommand(rawCommand, false);
2857
- return runStandardSpawn(resolve, cmdCommand, rawCommand, netEnv, onChunk, false);
2879
+ return runStandardSpawn(resolve, cmdCommand, rawCommand, netEnv, onChunk, false, systemSettings);
2858
2880
  }
2859
2881
  activeChildProcess = null;
2860
2882
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -3233,7 +3255,7 @@ function ProfileForm({ initialData, onSave, onCancel }) {
3233
3255
  flexDirection: "column",
3234
3256
  width: "100%"
3235
3257
  },
3236
- /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "white", bold: true }, "\u{1F464} DEVELOPER PROFILE CONFIGURATION")),
3258
+ /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "white", bold: true }, "DEVELOPER PROFILE CONFIGURATION")),
3237
3259
  /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "white", bold: true }, steps[step].label), /* @__PURE__ */ React7.createElement(
3238
3260
  TextInput2,
3239
3261
  {
@@ -3291,7 +3313,7 @@ var init_AskUserModal = __esm({
3291
3313
  }
3292
3314
  )), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray", italic: true }, "(Press Enter to send)")));
3293
3315
  }
3294
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "white", bold: true }, "\u{1F4AC} AGENT REQUEST: ACTION REQUIRED")), /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "white" }, question)), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: "100%" }, allOptions.map((opt, idx) => {
3316
+ return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "white", bold: true }, "AGENT REQUEST: ACTION REQUIRED")), /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "white" }, question)), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: "100%" }, allOptions.map((opt, idx) => {
3295
3317
  const isSelected = idx === selectedIndex;
3296
3318
  return /* @__PURE__ */ React8.createElement(
3297
3319
  Box8,
@@ -3324,7 +3346,7 @@ Your tool syntax is: '[tool:functions.ToolName(args...)]'
3324
3346
  [tool:functions.Memory(action="temp", content="<summary of the user prompt & model responses ONLY FROM LATEST PROMPT UNDER 40 WORDS>. [Talked on: <date> <hour>]")]. Time format: YYYY-MM-DD HH am/pm
3325
3347
 
3326
3348
  ${isMemoryEnabled ? `-- User-specific long-term/permanent memory (USE BASED ON CONVERSATION CONTEXT, DO NOT RE-SAVE MEMORY WHICH IS ALREADY SAVED) --
3327
- - Add: [tool:functions.Memory(action="user", method="add", content="<string to add>. [Saved on: <date ONLY>]", score=2)] (Set score=2 ONLY if the user explicitly asked to "remember" or "save" this information, else omit this parameter entirely to default to 0.5)
3349
+ - Add: [tool:functions.Memory(action="user", method="add", content="<string to add>. [Saved on: <date ONLY>]", score=2)] (Set score=2 ONLY if the user explicitly asked to "remember" or "save" this information, else omit this parameter entirely)
3328
3350
  - Delete: [tool:functions.Memory(action="user", method="delete", id="<memory id>")]
3329
3351
  - Update: [tool:functions.Memory(action="user", method="update", content-new="string to update", id="<memory id>")]
3330
3352
 
@@ -9008,7 +9030,7 @@ ${ideErr} [/ERROR]`;
9008
9030
  return tokens.some((token) => checkToken(token));
9009
9031
  });
9010
9032
  if (isViolating) {
9011
- const denyMsg = `Access Denied. Terminal is prohibited from accessing system drives (C://) or external directories while "External Workspace Access" is disabled.`;
9033
+ const denyMsg = `Access Denied. Prohibited from accessing external directories while "External Workspace Access" is disabled.`;
9012
9034
  if (settings.onExecStart) settings.onExecStart(command || "Unknown");
9013
9035
  yield { type: "exec_start" };
9014
9036
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -9083,8 +9105,105 @@ ${boxBottom}` };
9083
9105
  }
9084
9106
  if (!forcePrompt && !decision) {
9085
9107
  if (systemSettings2.networkAccess === false) {
9086
- const networkCmdRegex = /\b(curl|wget|npm|yarn|pnpm|pip|pip3|ssh|docker|git\s+(clone|push|pull|fetch))\b/i;
9087
- if (networkCmdRegex.test(cmdTrimmed)) {
9108
+ let normalized = cmdTrimmed.trim().replace(/\s+/g, " ").replace(/^['"]+|['"]+$/g, "").toLowerCase();
9109
+ const tokens = normalized.split(" ");
9110
+ const rawCmd = tokens[0];
9111
+ const cmd = rawCmd.split("/").pop().split("\\").pop().replace(/\.exe$/, "");
9112
+ const blockedCommands = /* @__PURE__ */ new Set([
9113
+ "curl",
9114
+ "wget",
9115
+ "httpie",
9116
+ "xh",
9117
+ "ssh",
9118
+ "scp",
9119
+ "sftp",
9120
+ "rsync",
9121
+ "ftp",
9122
+ "lftp",
9123
+ "tftp",
9124
+ "telnet",
9125
+ "nc",
9126
+ "netcat",
9127
+ "socat",
9128
+ "ping",
9129
+ "traceroute",
9130
+ "tracert",
9131
+ "dig",
9132
+ "nslookup",
9133
+ "host",
9134
+ "whois",
9135
+ "nmap",
9136
+ "docker",
9137
+ "podman",
9138
+ "kubectl",
9139
+ "helm",
9140
+ "gcloud",
9141
+ "aws",
9142
+ "az",
9143
+ "terraform",
9144
+ "ansible-playbook",
9145
+ "nix",
9146
+ "nix-env",
9147
+ "apt",
9148
+ "apt-get",
9149
+ "dpkg",
9150
+ "yum",
9151
+ "dnf",
9152
+ "pacman",
9153
+ "zypper",
9154
+ "brew",
9155
+ "apk",
9156
+ "choco",
9157
+ "scoop",
9158
+ "conda",
9159
+ "mamba",
9160
+ "aria2c",
9161
+ "axel",
9162
+ "smbclient",
9163
+ "lynx",
9164
+ "w3m",
9165
+ "links",
9166
+ "elinks",
9167
+ "heroku",
9168
+ "netlify",
9169
+ "vercel",
9170
+ "firebase",
9171
+ "supabase",
9172
+ "wrangler",
9173
+ "flyctl",
9174
+ "powershell",
9175
+ "pwsh",
9176
+ "certutil",
9177
+ "bitsadmin",
9178
+ "cloudflared",
9179
+ "ngrok",
9180
+ "tailscale",
9181
+ "zerotier",
9182
+ "rclone"
9183
+ ]);
9184
+ let deny = false;
9185
+ if (blockedCommands.has(cmd)) {
9186
+ deny = true;
9187
+ }
9188
+ const hasSubcmd = (list) => tokens.slice(1).some((token) => list.includes(token));
9189
+ const shouldDenyPkgManager = (dangerCommands) => {
9190
+ const dangerIdx = tokens.findIndex((t) => dangerCommands.includes(t));
9191
+ const safeIdx = tokens.findIndex((t) => ["run", "exec", "test"].includes(t));
9192
+ return dangerIdx !== -1 && !(safeIdx !== -1 && safeIdx < dangerIdx);
9193
+ };
9194
+ if (cmd === "git" && hasSubcmd(["clone", "pull", "push", "fetch"])) deny = true;
9195
+ if (cmd === "go" && hasSubcmd(["get", "install"])) deny = true;
9196
+ if (cmd === "npm" && shouldDenyPkgManager(["install", "i", "update", "add"])) deny = true;
9197
+ if (cmd === "yarn" && shouldDenyPkgManager(["add", "install", "upgrade"])) deny = true;
9198
+ if (cmd === "pnpm" && shouldDenyPkgManager(["add", "install", "update"])) deny = true;
9199
+ if (cmd === "bun" && shouldDenyPkgManager(["add", "install", "update"])) deny = true;
9200
+ if (cmd === "deno" && hasSubcmd(["install", "add"])) deny = true;
9201
+ if (cmd === "pip" && hasSubcmd(["install", "download"])) deny = true;
9202
+ if (cmd === "pip3" && hasSubcmd(["install", "download"])) deny = true;
9203
+ if (cmd === "cargo" && hasSubcmd(["install", "add"])) deny = true;
9204
+ if (["bash", "sh", "zsh", "fish"].includes(cmd) && hasSubcmd(["-c"])) deny = true;
9205
+ if (cmd === "cmd" && hasSubcmd(["/c"])) deny = true;
9206
+ if (deny) {
9088
9207
  decision = "deny";
9089
9208
  isNetworkDeny = true;
9090
9209
  }
@@ -9349,7 +9468,7 @@ ${boxBottom}` };
9349
9468
  } else if (denyReason === "network") {
9350
9469
  denyMsg = "Permission Denied: Sandbox Network Access Disabled by User Policy.";
9351
9470
  } else if (denyReason === "prohibited" && normToolName === "exec_command") {
9352
- denyMsg = "Permission Denied: Prohibited Command";
9471
+ denyMsg = "Permission Denied: Prohibited Command in User Policy";
9353
9472
  }
9354
9473
  if (normToolName === "write_file" || normToolName === "update_file") {
9355
9474
  const action = normToolName === "write_file" ? "WRITE DENIED" : "UPDATE DENIED";
@@ -9997,7 +10116,7 @@ function MemoryModal({ onClose }) {
9997
10116
  return "red";
9998
10117
  };
9999
10118
  const s = emojiSpace(2);
10000
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginBottom: 1, justifyContent: "space-between" }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true }, "AGENT MEMORY: LONG-TERM KNOWLEDGE"), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, "Vault: "), /* @__PURE__ */ React10.createElement(Text10, { color: getBarColor() }, barStr), /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true }, " ", usagePercent, "%"))), !isMemoryOn && memories.length > 0 ? /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, "Memory is currently Off...")) : memories.length === 0 ? /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, isMemoryOn ? "Learning..." : "Memory not available...")) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, memories.map((mem, idx) => {
10119
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginBottom: 1, justifyContent: "space-between" }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true }, "SAVED MEMORIES"), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, "Vault: "), /* @__PURE__ */ React10.createElement(Text10, { color: getBarColor() }, barStr), /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true }, " ", usagePercent, "%"))), !isMemoryOn && memories.length > 0 ? /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, "Memory is currently Off...")) : memories.length === 0 ? /* @__PURE__ */ React10.createElement(Box10, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, isMemoryOn ? "Learning..." : "Memory not available...")) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, memories.map((mem, idx) => {
10001
10120
  const isSelected = idx === selectedIndex;
10002
10121
  return /* @__PURE__ */ React10.createElement(
10003
10122
  Box10,
@@ -10008,7 +10127,7 @@ function MemoryModal({ onClose }) {
10008
10127
  width: "100%"
10009
10128
  },
10010
10129
  /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: isSelected ? "white" : "grey", bold: isSelected }, isSelected ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory))),
10011
- isSelected && /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0 }, /* @__PURE__ */ React10.createElement(Text10, { color: "grey", bold: true }, "[X] WIPE "))
10130
+ isSelected && /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0 }, /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true }, "[ "), " ", /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true, italic: true }, mem.score), /* @__PURE__ */ React10.createElement(Text10, { color: "grey", dimColor: true }, " ]"), /* @__PURE__ */ React10.createElement(Text10, { color: "grey", bold: true }, "[X] WIPE "))
10012
10131
  );
10013
10132
  })), /* @__PURE__ */ React10.createElement(
10014
10133
  Box10,
@@ -11149,18 +11268,16 @@ function App({ args = [] }) {
11149
11268
  id: "system-warning",
11150
11269
  role: "system",
11151
11270
  text: `[CRITICAL SECURITY ALERT] SYSTEM DIRECTORY DETECTED`,
11152
- 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.`,
11153
- isHomeWarning: true,
11154
- isMeta: true
11271
+ 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. Open FluxFlow in project folder to work safely.`,
11272
+ isHomeWarning: true
11155
11273
  });
11156
11274
  } else if (isHomeDir) {
11157
11275
  msgs.push({
11158
11276
  id: "home-warning",
11159
11277
  role: "system",
11160
11278
  text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
11161
- subText: `You are currently in ${os4.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
11162
- isHomeWarning: true,
11163
- isMeta: true
11279
+ subText: `You are currently in ${os4.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please open FluxFlow in project folder.`,
11280
+ isHomeWarning: true
11164
11281
  });
11165
11282
  }
11166
11283
  return msgs;
@@ -12087,7 +12204,7 @@ ${cleanText}`, color: "magenta" }];
12087
12204
  const s2 = emojiSpace(2);
12088
12205
  setMessages((prev) => {
12089
12206
  setCompletedIndex(prev.length + 1);
12090
- return [...prev, { id: "revert-empty-" + Date.now(), role: "system", text: `No revert checkpoints found for this session.`, isMeta: true }];
12207
+ return [...prev, { id: "revert-empty-" + Date.now(), role: "system", text: `Nothing to revert to.`, isMeta: true }];
12091
12208
  });
12092
12209
  }
12093
12210
  });
@@ -12445,7 +12562,7 @@ ${list || "No saved chats found."}`, isMeta: true }];
12445
12562
  } catch (err) {
12446
12563
  setMessages((prev) => {
12447
12564
  setCompletedIndex(prev.length + 1);
12448
- return [...prev, { id: Date.now(), role: "system", text: `[RESET ERROR] Failed to purge data: ${err.message}` }];
12565
+ return [...prev, { id: Date.now(), role: "system", text: `[RESET ERROR] Failed to clear data: ${err.message}` }];
12449
12566
  });
12450
12567
  }
12451
12568
  };
@@ -12629,6 +12746,13 @@ ${list || "No saved chats found."}`, isMeta: true }];
12629
12746
  });
12630
12747
  break;
12631
12748
  }
12749
+ case "/btw": {
12750
+ setMessages((prev) => {
12751
+ setCompletedIndex(prev.length + 1);
12752
+ return [...prev, { id: Date.now(), role: "system", text: `[SYSTEM] /btw only available when agent is working`, isMeta: true }];
12753
+ });
12754
+ break;
12755
+ }
12632
12756
  default:
12633
12757
  const s = emojiSpace(2);
12634
12758
  setMessages((prev) => {
@@ -13464,7 +13588,7 @@ Selection: ${val}`,
13464
13588
  title: "API KEY MANAGEMENT",
13465
13589
  items: [
13466
13590
  { label: "Edit Current Key (Update)", value: "edit" },
13467
- { label: "Remove Current Key (Purge)", value: "remove" },
13591
+ { label: "Remove Current Key (Delete)", value: "remove" },
13468
13592
  { label: "Cancel", value: "Cancel" }
13469
13593
  ],
13470
13594
  onSelect: (item) => {
@@ -13484,13 +13608,13 @@ Selection: ${val}`,
13484
13608
  case "deleteKey":
13485
13609
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1 }, (() => {
13486
13610
  const s = emojiSpace(2);
13487
- return /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, "DANGER: PURGE API KEY");
13488
- })(), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "This will permanently delete the saved API key from the project vault. You will need to enter it again to use Flux."), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
13611
+ return /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, "DANGER: CLEAR CREDENTIALS");
13612
+ })(), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "This will permanently delete all saved API keys in credential cache. You will need to enter it again to use Flux."), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
13489
13613
  CommandMenu,
13490
13614
  {
13491
- title: "Are you absolutely sure?",
13615
+ title: "Are you sure?",
13492
13616
  items: [
13493
- { label: "YES, PURGE KEY", value: "yes" },
13617
+ { label: "YES, CLEAR CREDENTIALS", value: "yes" },
13494
13618
  { label: "NO, GO BACK", value: "no" }
13495
13619
  ],
13496
13620
  onSelect: async (item) => {
@@ -13499,7 +13623,7 @@ Selection: ${val}`,
13499
13623
  setApiKey(null);
13500
13624
  setActiveView("chat");
13501
13625
  const s = emojiSpace(2);
13502
- setMessages((prev) => [...prev, { id: Date.now(), role: "system", text: `[VAULT PURGED] API Key removed successfully.` }]);
13626
+ setMessages((prev) => [...prev, { id: Date.now(), role: "system", text: `[CREDENTIAL CLEARED] API Key removed successfully.` }]);
13503
13627
  } else {
13504
13628
  setActiveView("key");
13505
13629
  }
@@ -13855,7 +13979,7 @@ Selection: ${val}`,
13855
13979
  aiProvider,
13856
13980
  version: versionFluxflow
13857
13981
  }
13858
- ), activeCommand && /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty }))), isInitializing ? /* @__PURE__ */ React14.createElement(Box14, { borderStyle: "double", borderColor: "grey", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, "Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React14.createElement(Box14, { borderStyle: "round", borderColor: "white", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, "\u{1F511}", emojiSpace(2), "API KEY REQUIRED")), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, flexDirection: "column" }, setupStep === 0 ? /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, "Select your Preferred Provider:"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
13982
+ ), activeCommand && /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty }))), isInitializing ? /* @__PURE__ */ React14.createElement(Box14, { borderStyle: "double", borderColor: "grey", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, "Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React14.createElement(Box14, { borderStyle: "round", borderColor: "white", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text14, { color: "gray", bold: true }, "API KEY REQUIRED")), /* @__PURE__ */ React14.createElement(Box14, { paddingX: 1, flexDirection: "column" }, setupStep === 0 ? /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Text14, { color: "white" }, "Select your Preferred Provider:"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
13859
13983
  CommandMenu,
13860
13984
  {
13861
13985
  items: [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.10.1",
4
- "date": "2026-06-20",
3
+ "version": "2.10.3",
4
+ "date": "2026-06-21",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",
@@ -10,7 +10,8 @@
10
10
  "cli",
11
11
  "gemini",
12
12
  "ink",
13
- "flux"
13
+ "flux",
14
+ "fluxflow"
14
15
  ],
15
16
  "license": "MIT",
16
17
  "repository": {