fluxflow-cli 2.8.10 → 2.9.0

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 +133 -11
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -1852,7 +1852,7 @@ 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: "red", padding: 0, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { paddingX: 1, backgroundColor: "#3a0000" }, /* @__PURE__ */ React3.createElement(Text3, { color: "red", 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: "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))));
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)));
@@ -2223,7 +2223,7 @@ ${mode === "Flux" ? "- **File Tools >> Code in chat**\n\n" : ""}- COMMUNICATION
2223
2223
  2. [tool:functions.WebScrape(url="...")]. Proactive use for specific webpage/docs/api
2224
2224
 
2225
2225
  ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
2226
- 1. [tool:functions.ReadFile(path="...", startLine=number, endLine=number)]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs. User gives image/doc: VIEW FIRST` : `No Multimodal support`}` : `Supports images/docs. User gives image/doc: VIEW FIRST`}
2226
+ 1. [tool:functions.ReadFile(path="...", startLine=number, endLine=number)]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs. **User gives image/doc: VIEW FIRST**` : `No Multimodal support`}` : `Supports images/docs. **User gives image/doc: VIEW FIRST**`}
2227
2227
  2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats including File Sizes
2228
2228
  3. [tool:functions.FileMap(path="path/file")]. Shows file structure, dependency, functions, variable maps
2229
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**
@@ -6370,6 +6370,7 @@ var init_ai = __esm({
6370
6370
  await init_tools();
6371
6371
  init_crypto();
6372
6372
  init_arg_parser();
6373
+ init_view_file();
6373
6374
  init_terminal();
6374
6375
  init_text();
6375
6376
  init_paths();
@@ -8028,12 +8029,133 @@ ${ideCtx.warnings}
8028
8029
  }
8029
8030
  }
8030
8031
  const cleanAgentText = agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
8032
+ const tagRegex = /@\[([^\]]+)\]/g;
8033
+ let match;
8034
+ const tagsFound = [];
8035
+ tagRegex.lastIndex = 0;
8036
+ while ((match = tagRegex.exec(cleanAgentText)) !== null) {
8037
+ tagsFound.push(match[1]);
8038
+ }
8039
+ let taggedContextBlocks = [];
8040
+ let attachedBinaryPart = null;
8041
+ for (const tag of tagsFound) {
8042
+ try {
8043
+ let tagClean = tag.trim().replace(/^["']|["']$/g, "");
8044
+ const lineRangeRegex = /[:#]L?(\d+)(?:-L?(\d+))?$/i;
8045
+ const matchRange = tagClean.match(lineRangeRegex);
8046
+ let filePath = tagClean;
8047
+ let startLine = null;
8048
+ let endLine = null;
8049
+ if (matchRange) {
8050
+ startLine = parseInt(matchRange[1], 10);
8051
+ endLine = matchRange[2] ? parseInt(matchRange[2], 10) : startLine;
8052
+ filePath = tagClean.slice(0, matchRange.index);
8053
+ }
8054
+ const absPath = path19.resolve(process.cwd(), filePath);
8055
+ if (fs20.existsSync(absPath)) {
8056
+ const stats = fs20.statSync(absPath);
8057
+ if (stats.isFile()) {
8058
+ const pathLower = filePath.toLowerCase();
8059
+ const isPdf = pathLower.endsWith(".pdf");
8060
+ const isOfficeFile = pathLower.endsWith(".docx") || pathLower.endsWith(".doc") || pathLower.endsWith(".ppt") || pathLower.endsWith(".pptx") || pathLower.endsWith(".xls") || pathLower.endsWith(".xlsx");
8061
+ const isImage = /\.(png|jpg|jpeg|webp|gif|bmp)$/.test(pathLower);
8062
+ const isMultimodalFile = isImage || isPdf || isOfficeFile;
8063
+ const isSupported = aiProvider === "Google" || MULTIMODAL_MODELS.includes(modelName);
8064
+ if (isMultimodalFile && !isSupported) {
8065
+ let terminalWidth = 115;
8066
+ if (process.stdout.isTTY) {
8067
+ terminalWidth = process.stdout.columns - 10 || 120;
8068
+ }
8069
+ const boxLines = [`${isImage ? "\u{1F4F8}" : "\u{1F4C4}"} UNSUPPORTED MODALITY FOR THIS MODEL`];
8070
+ const maxLen = Math.max(...boxLines.map((l) => l.length));
8071
+ const boxWidth = Math.min(maxLen + 4, terminalWidth);
8072
+ const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8073
+ const boxMid = boxLines.map((line) => `\u2502 ${line.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`).join("\n");
8074
+ const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
8075
+ yield { type: "visual_feedback", content: `${boxTop}
8076
+ ${boxMid}
8077
+ ${boxBottom}` };
8078
+ continue;
8079
+ }
8080
+ const finalStart = startLine !== null ? startLine : 1;
8081
+ let finalEnd = endLine !== null ? endLine : startLine !== null ? startLine : finalStart + 499;
8082
+ if (finalEnd - finalStart > 500) {
8083
+ finalEnd = finalStart + 500;
8084
+ }
8085
+ const argsStr = `path=${JSON.stringify(filePath)}, startLine=${finalStart}, endLine=${finalEnd}`;
8086
+ const result = await view_file(argsStr, { isMultiModal: isSupported });
8087
+ let isError = false;
8088
+ let textResult = "";
8089
+ let binPart = null;
8090
+ if (typeof result === "string") {
8091
+ if (result.trim().startsWith("ERROR")) {
8092
+ isError = true;
8093
+ } else {
8094
+ textResult = result;
8095
+ }
8096
+ } else if (result && typeof result === "object") {
8097
+ if (result.binaryPart) {
8098
+ binPart = result.binaryPart;
8099
+ textResult = result.text || "";
8100
+ } else {
8101
+ isError = true;
8102
+ }
8103
+ } else {
8104
+ isError = true;
8105
+ }
8106
+ if (!isError) {
8107
+ let label = "";
8108
+ if (isImage) {
8109
+ label = `\u{1F4F8} Viewed: ${filePath}`;
8110
+ attachedBinaryPart = binPart;
8111
+ } else if (isPdf || isOfficeFile) {
8112
+ label = `\u{1F4C4} Viewed: ${filePath}`;
8113
+ attachedBinaryPart = binPart;
8114
+ } else {
8115
+ let totalLines = "...";
8116
+ try {
8117
+ const content = fs20.readFileSync(absPath, "utf8");
8118
+ totalLines = content.split("\n").length;
8119
+ } catch (e) {
8120
+ }
8121
+ label = `\u{1F4C4} Read: ${filePath} \u2192 Lines ${finalStart} - ${Math.min(finalEnd, totalLines)} of ${totalLines}`;
8122
+ taggedContextBlocks.push(textResult);
8123
+ }
8124
+ if (label) {
8125
+ let terminalWidth = 115;
8126
+ if (process.stdout.isTTY) {
8127
+ terminalWidth = process.stdout.columns - 10 || 120;
8128
+ }
8129
+ const boxLines = [label];
8130
+ const maxLen = Math.max(...boxLines.map((l) => l.length));
8131
+ const boxWidth = Math.min(maxLen + 4, terminalWidth);
8132
+ const boxTop = `\u256D${"\u2500".repeat(boxWidth)}\u256E`;
8133
+ const boxMid = boxLines.map((line) => `\u2502 ${line.padEnd(boxWidth - 2).substring(0, boxWidth - 2)} \u2502`).join("\n");
8134
+ const boxBottom = `\u2570${"\u2500".repeat(boxWidth)}\u256F`;
8135
+ yield { type: "visual_feedback", content: `${boxTop}
8136
+ ${boxMid}
8137
+ ${boxBottom}` };
8138
+ }
8139
+ }
8140
+ }
8141
+ }
8142
+ } catch (e) {
8143
+ }
8144
+ }
8145
+ let taggedContextStr = "";
8146
+ if (taggedContextBlocks.length > 0) {
8147
+ taggedContextStr = "[TAGGED CONTEXT]\n" + taggedContextBlocks.join("\n\n") + "\n[/TAGGED CONTEXT]\n";
8148
+ }
8031
8149
  const firstUserMsg = `[SYSTEM METADATA (PRIORITY: DYNAMIC), Chat Context >> Metadata] Time: ${dateTimeStr}
8032
8150
  CWD: ${process.cwd()}${cwdMismatch ? ` (WARNING: CWD Mismatch! Previous Path: ${lastCwd})` : ""}
8033
8151
  **DIRECTORY STRUCTURE**
8034
8152
  ${dirStructure}${memoryPrompt}${ideBlock}
8035
- ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}[USER] ${cleanAgentText.trim()} [/USER]`.trim();
8036
- modifiedHistory.push({ role: "user", text: firstUserMsg });
8153
+ ${activeSummaryBlock}${thinkingLevel !== "Fast" && thinkingLevel !== "xHigh" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>** [/SYSTEM]\n" : ""}` : ""}${taggedContextStr}[USER] ${cleanAgentText.trim()} [/USER]`.trim();
8154
+ const userMsgObj = { role: "user", text: firstUserMsg };
8155
+ if (attachedBinaryPart) {
8156
+ userMsgObj.binaryPart = attachedBinaryPart;
8157
+ }
8158
+ modifiedHistory.push(userMsgObj);
8037
8159
  if (activeSummaryBlock && history[history.length - 1]?.id) {
8038
8160
  yield { type: "summary_injected", content: { id: history[history.length - 1].id, text: firstUserMsg } };
8039
8161
  }
@@ -8353,14 +8475,14 @@ ${ideErr} [/ERROR]`;
8353
8475
  { type: "end", idx: endIdx, start: "[[END]]", end: "[[END]]" }
8354
8476
  ].filter((i) => i.idx !== -1).sort((a, b) => a.idx - b.idx);
8355
8477
  if (indices.length > 0) {
8356
- const match = indices[0];
8357
- if (match.idx > 0) {
8358
- msgs.push({ type: "text", content: remaining.substring(0, match.idx) });
8478
+ const match2 = indices[0];
8479
+ if (match2.idx > 0) {
8480
+ msgs.push({ type: "text", content: remaining.substring(0, match2.idx) });
8359
8481
  }
8360
8482
  isBufferingToolCall = true;
8361
- activeBufferType = match.type;
8483
+ activeBufferType = match2.type;
8362
8484
  toolCallBuffer = "";
8363
- remaining = remaining.substring(match.idx);
8485
+ remaining = remaining.substring(match2.idx);
8364
8486
  } else {
8365
8487
  const potentialStarts = ["[tool", "[[END]]"];
8366
8488
  let splitPoint = -1;
@@ -12594,7 +12716,7 @@ Selection: ${val}`,
12594
12716
  }
12595
12717
  if (packet.type === "visual_feedback") {
12596
12718
  setMessages((prev) => [...prev, {
12597
- id: "feedback-" + Date.now(),
12719
+ id: "feedback-" + Date.now() + "-" + Math.random().toString(36).substring(2, 9),
12598
12720
  role: "system",
12599
12721
  text: packet.content,
12600
12722
  isVisualFeedback: true
@@ -13295,7 +13417,7 @@ Selection: ${val}`,
13295
13417
  }
13296
13418
  ));
13297
13419
  case "keybindingsPrompt":
13298
- return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { color: "cyan", bold: true, underline: true }, "\u2328\uFE0F CONFIGURE SHIFT+ENTER NEWLINE"), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "To support multi-line inputs with ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white" }, "Shift + Enter"), " for newline, a terminal sequence keybinding needs to be added to your IDE configuration."), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "Would you like FluxFlow to automatically add this to your ", getIDEName(), " keybindings?"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
13420
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React14.createElement(Text14, { color: "white", bold: true, underline: true }, "\u2328 CONFIGURE SHIFT+ENTER NEWLINE"), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "To support multi-line inputs with ", /* @__PURE__ */ React14.createElement(Text14, { bold: true, color: "white" }, "Shift + Enter"), " for newline, a terminal sequence keybinding needs to be added to your IDE configuration."), /* @__PURE__ */ React14.createElement(Text14, { marginTop: 1 }, "Would you like FluxFlow to automatically add this to your ", getIDEName(), " keybindings?"), /* @__PURE__ */ React14.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
13299
13421
  CommandMenu,
13300
13422
  {
13301
13423
  title: "Add Keybinding?",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "2.8.10",
3
+ "version": "2.9.0",
4
4
  "date": "2026-06-19",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [