fluxflow-cli 2.10.2 → 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 +137 -36
  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
@@ -3256,7 +3255,7 @@ function ProfileForm({ initialData, onSave, onCancel }) {
3256
3255
  flexDirection: "column",
3257
3256
  width: "100%"
3258
3257
  },
3259
- /* @__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")),
3260
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(
3261
3260
  TextInput2,
3262
3261
  {
@@ -3314,7 +3313,7 @@ var init_AskUserModal = __esm({
3314
3313
  }
3315
3314
  )), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray", italic: true }, "(Press Enter to send)")));
3316
3315
  }
3317
- 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) => {
3318
3317
  const isSelected = idx === selectedIndex;
3319
3318
  return /* @__PURE__ */ React8.createElement(
3320
3319
  Box8,
@@ -3347,7 +3346,7 @@ Your tool syntax is: '[tool:functions.ToolName(args...)]'
3347
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
3348
3347
 
3349
3348
  ${isMemoryEnabled ? `-- User-specific long-term/permanent memory (USE BASED ON CONVERSATION CONTEXT, DO NOT RE-SAVE MEMORY WHICH IS ALREADY SAVED) --
3350
- - 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)
3351
3350
  - Delete: [tool:functions.Memory(action="user", method="delete", id="<memory id>")]
3352
3351
  - Update: [tool:functions.Memory(action="user", method="update", content-new="string to update", id="<memory id>")]
3353
3352
 
@@ -9031,7 +9030,7 @@ ${ideErr} [/ERROR]`;
9031
9030
  return tokens.some((token) => checkToken(token));
9032
9031
  });
9033
9032
  if (isViolating) {
9034
- 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.`;
9035
9034
  if (settings.onExecStart) settings.onExecStart(command || "Unknown");
9036
9035
  yield { type: "exec_start" };
9037
9036
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -9106,8 +9105,105 @@ ${boxBottom}` };
9106
9105
  }
9107
9106
  if (!forcePrompt && !decision) {
9108
9107
  if (systemSettings2.networkAccess === false) {
9109
- const networkCmdRegex = /\b(curl|wget|httpie|fetch|axial|yarn|npm|pnpm|bun|deno|pip|pip3|poetry|uv|gem|cargo|go\s+(get|install)|composer|nuget|ssh|scp|ping|sftp|rsync|docker|podman|kubectl|helm|git\s+(clone|push|pull|fetch)|ftp|telnet|nc|netcat|socat|traceroute|tracert|dig|nslookup|host|nmap|gcloud|aws|az|terraform|ansible-playbook|nix|nix-env)\b/i;
9110
- 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) {
9111
9207
  decision = "deny";
9112
9208
  isNetworkDeny = true;
9113
9209
  }
@@ -9372,7 +9468,7 @@ ${boxBottom}` };
9372
9468
  } else if (denyReason === "network") {
9373
9469
  denyMsg = "Permission Denied: Sandbox Network Access Disabled by User Policy.";
9374
9470
  } else if (denyReason === "prohibited" && normToolName === "exec_command") {
9375
- denyMsg = "Permission Denied: Prohibited Command";
9471
+ denyMsg = "Permission Denied: Prohibited Command in User Policy";
9376
9472
  }
9377
9473
  if (normToolName === "write_file" || normToolName === "update_file") {
9378
9474
  const action = normToolName === "write_file" ? "WRITE DENIED" : "UPDATE DENIED";
@@ -10020,7 +10116,7 @@ function MemoryModal({ onClose }) {
10020
10116
  return "red";
10021
10117
  };
10022
10118
  const s = emojiSpace(2);
10023
- 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) => {
10024
10120
  const isSelected = idx === selectedIndex;
10025
10121
  return /* @__PURE__ */ React10.createElement(
10026
10122
  Box10,
@@ -10031,7 +10127,7 @@ function MemoryModal({ onClose }) {
10031
10127
  width: "100%"
10032
10128
  },
10033
10129
  /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: isSelected ? "white" : "grey", bold: isSelected }, isSelected ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory))),
10034
- 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 "))
10035
10131
  );
10036
10132
  })), /* @__PURE__ */ React10.createElement(
10037
10133
  Box10,
@@ -11172,18 +11268,16 @@ function App({ args = [] }) {
11172
11268
  id: "system-warning",
11173
11269
  role: "system",
11174
11270
  text: `[CRITICAL SECURITY ALERT] SYSTEM DIRECTORY DETECTED`,
11175
- 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.`,
11176
- isHomeWarning: true,
11177
- 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
11178
11273
  });
11179
11274
  } else if (isHomeDir) {
11180
11275
  msgs.push({
11181
11276
  id: "home-warning",
11182
11277
  role: "system",
11183
11278
  text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
11184
- 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.`,
11185
- isHomeWarning: true,
11186
- 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
11187
11281
  });
11188
11282
  }
11189
11283
  return msgs;
@@ -12110,7 +12204,7 @@ ${cleanText}`, color: "magenta" }];
12110
12204
  const s2 = emojiSpace(2);
12111
12205
  setMessages((prev) => {
12112
12206
  setCompletedIndex(prev.length + 1);
12113
- 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 }];
12114
12208
  });
12115
12209
  }
12116
12210
  });
@@ -12468,7 +12562,7 @@ ${list || "No saved chats found."}`, isMeta: true }];
12468
12562
  } catch (err) {
12469
12563
  setMessages((prev) => {
12470
12564
  setCompletedIndex(prev.length + 1);
12471
- 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}` }];
12472
12566
  });
12473
12567
  }
12474
12568
  };
@@ -12652,6 +12746,13 @@ ${list || "No saved chats found."}`, isMeta: true }];
12652
12746
  });
12653
12747
  break;
12654
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
+ }
12655
12756
  default:
12656
12757
  const s = emojiSpace(2);
12657
12758
  setMessages((prev) => {
@@ -13487,7 +13588,7 @@ Selection: ${val}`,
13487
13588
  title: "API KEY MANAGEMENT",
13488
13589
  items: [
13489
13590
  { label: "Edit Current Key (Update)", value: "edit" },
13490
- { label: "Remove Current Key (Purge)", value: "remove" },
13591
+ { label: "Remove Current Key (Delete)", value: "remove" },
13491
13592
  { label: "Cancel", value: "Cancel" }
13492
13593
  ],
13493
13594
  onSelect: (item) => {
@@ -13507,13 +13608,13 @@ Selection: ${val}`,
13507
13608
  case "deleteKey":
13508
13609
  return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1 }, (() => {
13509
13610
  const s = emojiSpace(2);
13510
- return /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true }, "DANGER: PURGE API KEY");
13511
- })(), /* @__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(
13512
13613
  CommandMenu,
13513
13614
  {
13514
- title: "Are you absolutely sure?",
13615
+ title: "Are you sure?",
13515
13616
  items: [
13516
- { label: "YES, PURGE KEY", value: "yes" },
13617
+ { label: "YES, CLEAR CREDENTIALS", value: "yes" },
13517
13618
  { label: "NO, GO BACK", value: "no" }
13518
13619
  ],
13519
13620
  onSelect: async (item) => {
@@ -13522,7 +13623,7 @@ Selection: ${val}`,
13522
13623
  setApiKey(null);
13523
13624
  setActiveView("chat");
13524
13625
  const s = emojiSpace(2);
13525
- 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.` }]);
13526
13627
  } else {
13527
13628
  setActiveView("key");
13528
13629
  }
@@ -13878,7 +13979,7 @@ Selection: ${val}`,
13878
13979
  aiProvider,
13879
13980
  version: versionFluxflow
13880
13981
  }
13881
- ), 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(
13882
13983
  CommandMenu,
13883
13984
  {
13884
13985
  items: [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.10.2",
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": {