fluxflow-cli 1.9.1 → 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 +147 -28
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -395,11 +395,15 @@ var init_ChatLayout = __esm({
395
395
  const isDiffResult = msg.role === "system" && msg.text?.includes("[DIFF_START]");
396
396
  const isPatchError = msg.role === "system" && msg.text?.includes("[TOOL_RESULT]: ERROR:") && (msg.toolName === "update_file" || msg.text?.includes("Could not find exact match"));
397
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
+ }
398
405
  if (msg.id && String(msg.id).startsWith("welcome")) {
399
- const parts = msg.text.split("\n\n");
400
- const logo = parts[0];
401
- const greeting = parts[1] || "";
402
- 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())));
403
407
  }
404
408
  if (msg.isVisualFeedback) {
405
409
  return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, msg.text));
@@ -412,7 +416,7 @@ var init_ChatLayout = __esm({
412
416
  const selectionMatch = msg.text.match(/Selection: (.*)/);
413
417
  const selection = selectionMatch ? selectionMatch[1] : "No selection";
414
418
  const s = emojiSpace(2);
415
- 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)))));
416
420
  }
417
421
  if (msg.isAboutRecord) {
418
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))));
@@ -466,6 +470,13 @@ var init_ChatLayout = __esm({
466
470
  { cmd: "/reset", desc: "Wipe all project data" },
467
471
  { cmd: "/about", desc: "Project info & credits" },
468
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
+ },
469
480
  {
470
481
  cmd: "/update",
471
482
  desc: "Check/Install updates",
@@ -691,7 +702,7 @@ var init_AskUserModal = __esm({
691
702
  });
692
703
  const s = emojiSpace(2);
693
704
  if (isSuggestingElse) {
694
- 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(
695
706
  TextInput2,
696
707
  {
697
708
  value: customInput,
@@ -700,7 +711,7 @@ var init_AskUserModal = __esm({
700
711
  }
701
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)")));
702
713
  }
703
- 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) => {
704
715
  const isSelected = idx === selectedIndex;
705
716
  return /* @__PURE__ */ React6.createElement(
706
717
  Box6,
@@ -974,6 +985,18 @@ var init_prompts = __esm({
974
985
  ` : "";
975
986
  const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString();
976
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
+ })();
977
1000
  const tempMemoriesStr = tempMemories?.length > 0 && !isContext32k ? `
978
1001
  -- RECENT CONTEXT FROM OTHER CHAT THREADS (PRIORITY: LOW, RECENT > OLD) --
979
1002
  ${tempMemories.split("\n").map((line) => ` ${line}`).join("\n")}
@@ -990,8 +1013,8 @@ ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
990
1013
  --- START SYSTEM INSTRUCTION (STRICT PRIORITY, OVERRIDES EVERYTHING) ---
991
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.`}
992
1015
  MUST FOLLOW THE "CRITICAL THINKING POLICY"${mode === "Flux" ? `, "CRITICAL NEWLINE PROTOCOL", "CRITICAL QUOTE ESCAPE POLICY"` : ""} ALWAYS. **NO EXCEPTIONS.**
993
- CURRENT_WORKING_DIRECTORY: ${cwdStr}.
994
- 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." : ""}
995
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.
996
1019
 
997
1020
  -- START THINKING INSTRUCTIONS --
@@ -1010,8 +1033,10 @@ ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
1010
1033
  -- START PROJECT SPECIFIC INSTRUCTIONS --
1011
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.
1012
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.
1013
- 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.
1014
- 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.
1015
1040
 
1016
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.
1017
1042
  -- END PROJECT SPECIFIC INSTRUCTIONS --
@@ -1061,7 +1086,7 @@ ${userMemories.split("\n").map((line) => ` ${line}`).join("\n")}
1061
1086
  -- END REPONSE FINISH PROTOCOL --
1062
1087
 
1063
1088
  [SYSTEM METADATA (PRIORITY: DYNAMIC)] Current date and Time is: ${dateTimeStr}
1064
- [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.
1065
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.
1066
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.
1067
1092
  --- END SYSTEM INSTRUCTION ---`.trim();
@@ -3137,8 +3162,11 @@ USER_PROMPT: "${agentText}"`.trim();
3137
3162
  }
3138
3163
  const cleanText = dedupeBuffer.substring(overlapLen);
3139
3164
  if (cleanText) {
3140
- turnText += cleanText;
3141
- 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
+ }
3142
3170
  }
3143
3171
  isDedupeActive = false;
3144
3172
  dedupeBuffer = "";
@@ -3420,8 +3448,11 @@ ${boxBottom}
3420
3448
  }
3421
3449
  const cleanText = dedupeBuffer.substring(overlapLen);
3422
3450
  if (cleanText) {
3423
- turnText += cleanText;
3424
- 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
+ }
3425
3456
  }
3426
3457
  isDedupeActive = false;
3427
3458
  dedupeBuffer = "";
@@ -3448,7 +3479,7 @@ ${boxBottom}
3448
3479
  if (toolResults.length > 0) {
3449
3480
  toolResults.forEach((tr) => modifiedHistory.push(tr));
3450
3481
  }
3451
- 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." });
3452
3483
  accumulatedContext += turnText;
3453
3484
  for (let i = waitTime / 1e3; i > 0; i--) {
3454
3485
  yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
@@ -3863,10 +3894,12 @@ var app_exports = {};
3863
3894
  __export(app_exports, {
3864
3895
  default: () => App
3865
3896
  });
3897
+ import os2 from "os";
3866
3898
  import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
3867
3899
  import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
3868
3900
  import Spinner2 from "ink-spinner";
3869
3901
  import fs19 from "fs-extra";
3902
+ import path18 from "path";
3870
3903
  import { exec as exec4 } from "child_process";
3871
3904
  import { MultilineInput } from "ink-multiline-input";
3872
3905
  import TextInput3 from "ink-text-input";
@@ -3892,20 +3925,23 @@ function App() {
3892
3925
  });
3893
3926
  }
3894
3927
  try {
3895
- 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" });
3896
3929
  const data = await response.json();
3897
- const latestVersion = data?.version;
3930
+ const latestVersion = data["dist-tags"]?.latest;
3931
+ const stableVersion = data["dist-tags"]?.stable;
3898
3932
  if (latestVersion) setLatestVer(latestVersion);
3899
3933
  if (latestVersion && latestVersion !== versionFluxflow) {
3934
+ const versionDisplay = latestVersion === stableVersion ? `v${latestVersion}-stable` : `v${latestVersion}`;
3900
3935
  if (!manual && settingsToUse.autoUpdate) {
3901
3936
  setActiveView("update");
3902
3937
  } else {
3903
3938
  setMessages((prev) => {
3904
3939
  const newMsgs = [...prev];
3905
- newMsgs.splice(manual ? newMsgs.length : 1, 0, {
3940
+ const spliceIdx = manual ? newMsgs.length : Math.min(newMsgs.length, 3);
3941
+ newMsgs.splice(spliceIdx, 0, {
3906
3942
  id: "update-" + Date.now(),
3907
3943
  role: "system",
3908
- text: `A new version (v${latestVersion}) is here.
3944
+ text: `A new version (${versionDisplay}) is here.
3909
3945
 
3910
3946
  \u2022 Type \`/update latest\` to apply the update.
3911
3947
  \u2022 Type \`/changelog\` to view the release notes.`,
@@ -3918,7 +3954,8 @@ function App() {
3918
3954
  } else if (manual) {
3919
3955
  setMessages((prev) => {
3920
3956
  setCompletedIndex(prev.length + 1);
3921
- 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 }];
3922
3959
  });
3923
3960
  }
3924
3961
  } catch (err) {
@@ -4025,11 +4062,46 @@ function App() {
4025
4062
  const [queuedPrompt, setQueuedPrompt] = useState7(null);
4026
4063
  const [resolutionData, setResolutionData] = useState7(null);
4027
4064
  const [tempModelOverride, setTempModelOverride] = useState7(null);
4028
- const [messages, setMessages] = useState7([
4029
- { id: "welcome", role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true }
4030
- ]);
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
+ });
4031
4103
  const queuedPromptRef = useRef2(null);
4032
- const [completedIndex, setCompletedIndex] = useState7(1);
4104
+ const [completedIndex, setCompletedIndex] = useState7(messages.length);
4033
4105
  const windowedHistory = useMemo(() => {
4034
4106
  const MAX_HISTORY_LINES = 2e3;
4035
4107
  const width = terminalSize.columns || 80;
@@ -4308,6 +4380,13 @@ function App() {
4308
4380
  { cmd: "/reset", desc: "Wipe all project data" },
4309
4381
  { cmd: "/about", desc: "Project info & credits" },
4310
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
+ },
4311
4390
  {
4312
4391
  cmd: "/update",
4313
4392
  desc: "Check/Install updates",
@@ -4585,6 +4664,46 @@ ${list || "No saved chats found."}`, isMeta: true }];
4585
4664
  });
4586
4665
  break;
4587
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
+ }
4588
4707
  case "/update": {
4589
4708
  const arg = parts[1]?.toLowerCase();
4590
4709
  if (arg === "check") {
@@ -5545,8 +5664,8 @@ var init_app = __esm({
5545
5664
  init_text();
5546
5665
  SESSION_START_TIME = Date.now();
5547
5666
  CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
5548
- versionFluxflow = "1.9.1";
5549
- updatedOn = "2026-05-13";
5667
+ versionFluxflow = "1.9.2";
5668
+ updatedOn = "2026-05-14";
5550
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(
5551
5670
  CommandMenu,
5552
5671
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",