fluxflow-cli 1.0.13 → 1.1.1

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.
package/UI_FEATURES.md CHANGED
@@ -14,6 +14,7 @@ You can control the application using `/` commands directly in the chat input:
14
14
  - **/profile**: Update your name, nickname, and custom instructions.
15
15
  - **/memory**: View and manage the persistent memories extracted by the Janitor.
16
16
  - **/resume <chat-id>**: Switch back to a previous conversation.
17
+ - **/changelog**: Open the project's changelog in your default browser.
17
18
  - **/help**: List all available commands.
18
19
 
19
20
  ### Command Shortcuts
package/dist/fluxflow.js CHANGED
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.jsx
4
- import React9 from "react";
4
+ import React10 from "react";
5
5
  import { render } from "ink";
6
6
 
7
7
  // src/app.jsx
8
- import React8, { useState as useState4, useEffect as useEffect3, useRef, useMemo } from "react";
9
- import { Box as Box8, Text as Text8, useInput as useInput3, useStdout, Static } from "ink";
8
+ import React9, { useState as useState5, useEffect as useEffect3, useRef, useMemo } from "react";
9
+ import { Box as Box9, Text as Text9, useInput as useInput4, useStdout } from "ink";
10
10
  import fs14 from "fs-extra";
11
+ import { exec } from "child_process";
11
12
  import { MultilineInput } from "ink-multiline-input";
12
- import TextInput2 from "ink-text-input";
13
+ import TextInput3 from "ink-text-input";
13
14
 
14
15
  // src/components/ChatLayout.jsx
15
16
  import React2 from "react";
@@ -18,15 +19,15 @@ import { Box as Box2, Text as Text2 } from "ink";
18
19
  // src/components/TerminalBox.jsx
19
20
  import React from "react";
20
21
  import { Box, Text } from "ink";
21
- var TerminalBox = ({ command, output, completed = false }) => {
22
+ var TerminalBox = React.memo(({ command, output, completed = false }) => {
22
23
  const cleanOutput = (output || "").replace(/\r/g, "").trim();
23
24
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: completed ? "#334155" : "cyan", paddingX: 2, paddingY: completed ? 0 : 1, width: "100%" }, /* @__PURE__ */ React.createElement(Box, { justifyContent: "space-between" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: completed ? "gray" : "cyan", bold: true }, completed ? "\u{1F3C1} FINISHED:" : "\u26A1 EXECUTING:", " "), /* @__PURE__ */ React.createElement(Text, { color: completed ? "gray" : "white" }, command)), /* @__PURE__ */ React.createElement(Text, { color: completed ? "#475569" : "yellow", bold: true }, completed ? "\u25CF ARCHIVED" : "\u25CF LIVE")), cleanOutput ? /* @__PURE__ */ React.createElement(Box, { marginTop: completed ? 0 : 1, backgroundColor: "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: completed ? "gray" : "green", wrap: "anywhere" }, cleanOutput)) : !completed && /* @__PURE__ */ React.createElement(Box, { marginTop: 1, backgroundColor: "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", italic: true }, "Waiting for output...")), !completed && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true, italic: true }, "Double-press ESC to terminate if hanging.")));
24
- };
25
+ });
25
26
 
26
27
  // src/components/ChatLayout.jsx
27
28
  var cleanSignals = (text) => {
28
29
  if (!text) return text;
29
- let result = "";
30
+ const parts = [];
30
31
  let i = 0;
31
32
  while (i < text.length) {
32
33
  const trigger = "tool:functions.";
@@ -46,64 +47,27 @@ var cleanSignals = (text) => {
46
47
  }
47
48
  i = j;
48
49
  } else {
49
- result += text[i];
50
+ parts.push(text[i]);
50
51
  i++;
51
52
  }
52
53
  }
53
- return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").replace(/\n\s*turn\s*:\s*(continue|finish)\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").trim();
54
+ return parts.join("").replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").replace(/\n\s*turn\s*:\s*(continue|finish)\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").trim();
54
55
  };
55
- var formatThinkText = (text) => {
56
- const cleaned = cleanSignals(text);
56
+ var formatThinkText = (cleaned) => {
57
57
  if (!cleaned) return null;
58
58
  const lines = cleaned.split("\n").filter((l) => l.trim() !== "");
59
59
  return lines.map((line, i) => {
60
60
  const trimmed = line.trim();
61
61
  if (trimmed.startsWith("**") && trimmed.endsWith("**") || trimmed.startsWith("#")) {
62
- return /* @__PURE__ */ React2.createElement(Box2, { key: i, marginTop: i === 0 ? 0 : 1, marginBottom: 0 }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, trimmed.replace(/\*|#/g, "").trim()));
62
+ return /* @__PURE__ */ React2.createElement(Box2, { key: i, marginTop: i === 0 ? 0 : 1, marginBottom: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, trimmed.replace(/\*|#/g, "").trim()));
63
63
  }
64
64
  const isBullet = trimmed.startsWith("*");
65
- return /* @__PURE__ */ React2.createElement(Box2, { key: i, marginLeft: isBullet ? 2 : 0 }, /* @__PURE__ */ React2.createElement(Text2, { italic: true, color: "gray", wrap: "anywhere" }, isBullet ? "\u2022 " : "", trimmed.replace(/^\*|\s\*/g, "").trim()));
65
+ return /* @__PURE__ */ React2.createElement(Box2, { key: i, marginLeft: isBullet ? 2 : 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { italic: true, color: "gray", wrap: "anywhere" }, isBullet ? "\u2022 " : "", trimmed.replace(/^\*|\s\*/g, "").trim()));
66
66
  });
67
67
  };
68
- var CodeRenderer = ({ text }) => {
68
+ var MarkdownText = React2.memo(({ text, color = "white" }) => {
69
69
  if (!text) return null;
70
- if (text.includes("[DIFF_START]")) {
71
- const beforeDiff = text.substring(0, text.indexOf("[DIFF_START]")).trim();
72
- const afterDiff = text.substring(text.indexOf("[DIFF_END]") + 10).trim();
73
- const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
74
- const diffBody = match ? match[1].trim() : "";
75
- const diffLines = diffBody.split("\n");
76
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, beforeDiff && /* @__PURE__ */ React2.createElement(MarkdownText, { text: beforeDiff }), /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 1, backgroundColor: "#1a1a1a", paddingY: 0 }, diffLines.map((line, i) => {
77
- const isContext = line.includes("[UI_CONTEXT]");
78
- const cleanLine = line.replace("[UI_CONTEXT]", "");
79
- const isRemoval = cleanLine.startsWith("-");
80
- const isAddition = cleanLine.startsWith("+");
81
- const parts = cleanLine.substring(1).split("|");
82
- const lineNum = parts[0]?.trim() || "";
83
- const content = parts.slice(1).join("|");
84
- const bgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : "#1a1a1a";
85
- const textColor = isRemoval ? "#ff4d4d" : isAddition ? "#4dff88" : "white";
86
- return /* @__PURE__ */ React2.createElement(Box2, { key: i, backgroundColor: bgColor, paddingX: 1 }, /* @__PURE__ */ React2.createElement(Box2, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React2.createElement(Text2, { color: isRemoval ? "#cf3a3a" : isAddition ? "#3acf65" : "gray", dimColor: true }, lineNum)), /* @__PURE__ */ React2.createElement(Box2, { width: 2, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: textColor, bold: true }, isRemoval ? "-" : isAddition ? "+" : " ")), /* @__PURE__ */ React2.createElement(Box2, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: textColor, wrap: "anywhere" }, content)));
87
- })), afterDiff && /* @__PURE__ */ React2.createElement(MarkdownText, { text: afterDiff }));
88
- }
89
- if (text.includes("```")) {
90
- const parts = text.split(/(```[\s\S]*?```)/g);
91
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, parts.map((part, i) => {
92
- if (part.startsWith("```") && part.endsWith("```")) {
93
- const match = part.match(/```(\w*)\n([\s\S]*?)```/);
94
- const lang = match ? match[1] : "code";
95
- const code = match ? match[2] : part.slice(3, -3);
96
- return /* @__PURE__ */ React2.createElement(Box2, { key: i, flexDirection: "column", marginY: 1, backgroundColor: "#111", borderStyle: "round", borderColor: "#333", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Box2, { alignSelf: "flex-end", marginTop: -1, marginRight: 1 }, /* @__PURE__ */ React2.createElement(Text2, { backgroundColor: "#333", color: "white" }, " ", lang.toUpperCase(), " ")), /* @__PURE__ */ React2.createElement(Box2, { paddingY: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", wrap: "anywhere" }, code.trim())));
97
- }
98
- return /* @__PURE__ */ React2.createElement(MarkdownText, { key: i, text: part });
99
- }));
100
- }
101
- return /* @__PURE__ */ React2.createElement(MarkdownText, { text });
102
- };
103
- var MarkdownText = ({ text, color = "white" }) => {
104
- const cleaned = cleanSignals(text);
105
- if (!cleaned) return null;
106
- const lines = cleaned.split("\n");
70
+ const lines = text.split("\n");
107
71
  return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, lines.map((line, i) => {
108
72
  const trimmed = line.trim();
109
73
  if (trimmed === "---" || trimmed === "***" || trimmed === "___") {
@@ -113,7 +77,7 @@ var MarkdownText = ({ text, color = "white" }) => {
113
77
  if (headingMatch) {
114
78
  const level = headingMatch[1].length;
115
79
  const hText = headingMatch[2];
116
- return /* @__PURE__ */ React2.createElement(Box2, { key: i, marginTop: 1, marginBottom: 0 }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: level === 1 ? "cyan" : level === 2 ? "magenta" : "yellow", underline: true }, hText.toUpperCase()));
80
+ return /* @__PURE__ */ React2.createElement(Box2, { key: i, marginTop: 1, marginBottom: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: level === 1 ? "cyan" : level === 2 ? "magenta" : "yellow", underline: true }, hText.toUpperCase()));
117
81
  }
118
82
  const isUnordered = trimmed.startsWith("* ") || trimmed.startsWith("- ");
119
83
  const isOrdered = /^\d+\.\s/.test(trimmed);
@@ -122,7 +86,7 @@ var MarkdownText = ({ text, color = "white" }) => {
122
86
  content = (isUnordered ? " \u2022 " : "") + trimmed.replace(/^[\*\-\d+\.]+\s/, "");
123
87
  }
124
88
  const parts = content.split(/(\*\*.*?\*\*|\*.*?\*|`.*?`)/g);
125
- return /* @__PURE__ */ React2.createElement(Text2, { key: i, color, wrap: "anywhere" }, parts.map((part, j) => {
89
+ return /* @__PURE__ */ React2.createElement(Box2, { key: i, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color, wrap: "anywhere" }, parts.map((part, j) => {
126
90
  if (part.startsWith("**") && part.endsWith("**")) {
127
91
  return /* @__PURE__ */ React2.createElement(Text2, { key: j, bold: true, color: "white" }, part.slice(2, -2));
128
92
  }
@@ -133,50 +97,109 @@ var MarkdownText = ({ text, color = "white" }) => {
133
97
  return /* @__PURE__ */ React2.createElement(Text2, { key: j, color: "cyan", backgroundColor: "#003333" }, " ", part.slice(1, -1), " ");
134
98
  }
135
99
  return part;
136
- }));
100
+ })));
137
101
  }));
138
- };
139
- function ChatLayout({ messages, showFullThinking }) {
140
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, messages.map((msg, idx) => {
141
- const isDiffResult = msg.role === "system" && msg.text.includes("[DIFF_START]");
142
- const isTerminalRecord = msg.isTerminalRecord;
143
- if (msg.role === "system" && msg.text.includes("[TOOL_RESULT]") && !isDiffResult && !isTerminalRecord) return null;
144
- if (isTerminalRecord) {
145
- const cmdMatch = msg.text.match(/COMMAND: (.*)\n/);
146
- const outputMatch = msg.text.match(/OUTPUT: ([\s\S]*)$/);
147
- const cmd = cmdMatch ? cmdMatch[1] : "Unknown";
148
- const outputList = outputMatch ? outputMatch[1] : "";
149
- return /* @__PURE__ */ React2.createElement(Box2, { key: idx, marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(TerminalBox, { command: cmd, output: outputList, completed: true }));
150
- }
151
- let color = "white";
152
- let content = cleanSignals(msg.text);
102
+ });
103
+ var DiffLine = React2.memo(({ line }) => {
104
+ const isContext = line.includes("[UI_CONTEXT]");
105
+ const cleanLine = line.replace("[UI_CONTEXT]", "");
106
+ const isRemoval = cleanLine.startsWith("-");
107
+ const isAddition = cleanLine.startsWith("+");
108
+ const parts = cleanLine.substring(1).split("|");
109
+ const lineNum = parts[0]?.trim() || "";
110
+ const content = parts.slice(1).join("|");
111
+ const bgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : "#1a1a1a";
112
+ const textColor = isRemoval ? "#ff4d4d" : isAddition ? "#4dff88" : "white";
113
+ return /* @__PURE__ */ React2.createElement(Box2, { backgroundColor: bgColor, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React2.createElement(Text2, { color: isRemoval ? "#cf3a3a" : isAddition ? "#3acf65" : "gray", dimColor: true }, lineNum)), /* @__PURE__ */ React2.createElement(Box2, { width: 2, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: textColor, bold: true }, isRemoval ? "-" : isAddition ? "+" : " ")), /* @__PURE__ */ React2.createElement(Box2, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: textColor, wrap: "anywhere" }, content)));
114
+ });
115
+ var DiffBlock = React2.memo(({ text }) => {
116
+ const beforeDiff = text.substring(0, text.indexOf("[DIFF_START]")).trim();
117
+ const afterDiff = text.substring(text.indexOf("[DIFF_END]") + 10).trim();
118
+ const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
119
+ const diffBody = match ? match[1].trim() : "";
120
+ const diffLines = diffBody.split("\n");
121
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, beforeDiff && /* @__PURE__ */ React2.createElement(MarkdownText, { text: beforeDiff }), /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 1, backgroundColor: "#1a1a1a", paddingY: 0, width: "100%" }, diffLines.map((line, i) => /* @__PURE__ */ React2.createElement(DiffLine, { key: i, line }))), afterDiff && /* @__PURE__ */ React2.createElement(MarkdownText, { text: afterDiff }));
122
+ });
123
+ var CodeRenderer = React2.memo(({ text }) => {
124
+ if (!text) return null;
125
+ if (text.includes("[DIFF_START]")) {
126
+ return /* @__PURE__ */ React2.createElement(DiffBlock, { text });
127
+ }
128
+ if (text.includes("```")) {
129
+ const parts = text.split(/(```[\s\S]*?```)/g);
130
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, parts.map((part, i) => {
131
+ if (part.startsWith("```") && part.endsWith("```")) {
132
+ const match = part.match(/```(\w*)\n([\s\S]*?)```/);
133
+ const lang = match ? match[1] : "code";
134
+ const code = match ? match[2] : part.slice(3, -3);
135
+ return /* @__PURE__ */ React2.createElement(Box2, { key: i, flexDirection: "column", marginY: 1, backgroundColor: "#111", borderStyle: "round", borderColor: "#333", paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { alignSelf: "flex-end", marginTop: -1, marginRight: 1 }, /* @__PURE__ */ React2.createElement(Text2, { backgroundColor: "#333", color: "white" }, " ", lang.toUpperCase(), " ")), /* @__PURE__ */ React2.createElement(Box2, { paddingY: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", wrap: "anywhere" }, code.trim())));
136
+ }
137
+ return /* @__PURE__ */ React2.createElement(MarkdownText, { key: i, text: part });
138
+ }));
139
+ }
140
+ return /* @__PURE__ */ React2.createElement(MarkdownText, { text });
141
+ });
142
+ var MessageItem = React2.memo(({ msg, showFullThinking }) => {
143
+ const isDiffResult = msg.role === "system" && msg.text.includes("[DIFF_START]");
144
+ const isTerminalRecord = msg.isTerminalRecord;
145
+ if (msg.role === "system" && msg.text.includes("[TOOL_RESULT]") && !isDiffResult && !isTerminalRecord) return null;
146
+ if (msg.isAskRecord) {
147
+ const selectionMatch = msg.text.match(/Selection: (.*)/);
148
+ const selection = selectionMatch ? selectionMatch[1] : "No selection";
149
+ return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan", bold: true, underline: true }, "\u{1F4AC} ASK USER"), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 0 }, /* @__PURE__ */ React2.createElement(Text2, { color: "white" }, "Selection: ", /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", bold: true }, selection)))));
150
+ }
151
+ if (msg.isUpdateNotification) {
152
+ return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", bold: true, underline: true }, "\u{1F680} UPDATE AVAILABLE"), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(CodeRenderer, { text: msg.text }))));
153
+ }
154
+ if (isTerminalRecord) {
155
+ const cmdMatch = msg.text.match(/COMMAND: (.*)\n/);
156
+ const outputMatch = msg.text.match(/OUTPUT: ([\s\S]*)$/);
157
+ const cmd = cmdMatch ? cmdMatch[1] : "Unknown";
158
+ const outputList = outputMatch ? outputMatch[1] : "";
159
+ return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(TerminalBox, { command: cmd, output: outputList, completed: true }));
160
+ }
161
+ const content = React2.useMemo(() => cleanSignals(msg.text), [msg.text]);
162
+ const finalContent = React2.useMemo(() => {
153
163
  if (msg.role === "think" && !showFullThinking) {
154
- content = content.split("\n").filter((line) => {
164
+ const lines = content.split("\n").filter((line) => {
155
165
  const trimmed = line.trim();
156
166
  const isHeading = trimmed.startsWith("# ");
157
167
  const isActionStep = trimmed.startsWith("**") && trimmed.endsWith("**");
158
168
  return isHeading || isActionStep;
159
- }).join("\n");
160
- if (!content.trim()) content = "*Reasoning...*";
169
+ });
170
+ if (lines.length === 0) return "*Reasoning...*";
171
+ return lines.join("\n");
161
172
  }
162
- return /* @__PURE__ */ React2.createElement(Box2, { key: idx, marginBottom: 1, flexDirection: "column", flexShrink: 0, width: "100%" }, msg.role === "user" ? /* @__PURE__ */ React2.createElement(
163
- Box2,
164
- {
165
- backgroundColor: "#262626",
166
- paddingX: 1,
167
- paddingY: 1,
168
- width: "100%",
169
- flexDirection: "column"
170
- },
171
- content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\\\n/g, "\n").replace(/\\$/, "").split("\n").map((line, lineIdx) => /* @__PURE__ */ React2.createElement(Box2, { key: lineIdx, flexDirection: "row" }, /* @__PURE__ */ React2.createElement(Box2, { flexShrink: 0, width: 2 }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, lineIdx === 0 ? "\u276F" : " ")), /* @__PURE__ */ React2.createElement(Box2, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: msg.color || "white", wrap: "anywhere" }, line))))
172
- ) : msg.role === "think" ? /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, "Thinking..."), /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, paddingLeft: 2, flexDirection: "column" }, formatThinkText(content))) : /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React2.createElement(CodeRenderer, { text: content }), msg.memoryUpdated && /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", italic: true }, "\u2728 [Memory Updated]"))));
173
- }));
174
- }
173
+ return content;
174
+ }, [content, msg.role, showFullThinking]);
175
+ return /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, flexDirection: "column", flexShrink: 0, width: "100%" }, msg.role === "user" ? /* @__PURE__ */ React2.createElement(
176
+ Box2,
177
+ {
178
+ backgroundColor: "#262626",
179
+ paddingX: 1,
180
+ paddingY: 1,
181
+ width: "100%",
182
+ flexDirection: "column"
183
+ },
184
+ finalContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\\\n/g, "\n").replace(/\\$/, "").split("\n").map((line, lineIdx) => /* @__PURE__ */ React2.createElement(Box2, { key: lineIdx, flexDirection: "row", width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexShrink: 0, width: 2 }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, lineIdx === 0 ? "\u276F" : " ")), /* @__PURE__ */ React2.createElement(Box2, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: msg.color || "white", wrap: "anywhere" }, line))))
185
+ ) : msg.role === "think" ? /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, "Thinking..."), /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, paddingLeft: 2, flexDirection: "column", width: "100%" }, formatThinkText(finalContent))) : /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingX: 1, marginTop: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(CodeRenderer, { text: finalContent }), msg.memoryUpdated && /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", italic: true }, "\u2728 [Memory Updated]"))));
186
+ });
187
+ var ChatLayout = React2.memo(({ messages, showFullThinking }) => {
188
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, messages.map((msg, idx) => /* @__PURE__ */ React2.createElement(
189
+ MessageItem,
190
+ {
191
+ key: msg.id || idx,
192
+ msg,
193
+ showFullThinking
194
+ }
195
+ )));
196
+ });
197
+ var ChatLayout_default = ChatLayout;
175
198
 
176
199
  // src/components/StatusBar.jsx
177
200
  import React3 from "react";
178
201
  import { Box as Box3, Text as Text3 } from "ink";
179
- function StatusBar({ mode, thinkingLevel, tokens = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true }) {
202
+ var StatusBar = React3.memo(({ mode, thinkingLevel, tokens = "0.0k", chatId = "NEW-SESSION", isMemoryEnabled = true }) => {
180
203
  const modeColor = mode === "Flux" ? "yellow" : "cyan";
181
204
  const modeIcon = mode === "Flux" ? "\u26A1" : "\u{1F30A}";
182
205
  const memStatus = isMemoryEnabled ? "ON" : "OFF";
@@ -194,7 +217,8 @@ function StatusBar({ mode, thinkingLevel, tokens = "0.0k", chatId = "NEW-SESSION
194
217
  /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1, justifyContent: "center", paddingX: 2 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, "\u{1F4C1} "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue", dimColor: true, italic: true }, process.cwd())),
195
218
  /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, "MEM: "), /* @__PURE__ */ React3.createElement(Text3, { color: memStatus === "ON" ? "green" : "red" }, memStatus), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, " Tokens ", tokens > 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : tokens, " (", Math.round(tokens / 254e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, "ID: ", chatId, " "))
196
219
  );
197
- }
220
+ });
221
+ var StatusBar_default = StatusBar;
198
222
 
199
223
  // src/components/CommandMenu.jsx
200
224
  import React4 from "react";
@@ -250,6 +274,49 @@ function ProfileForm({ onSave, onCancel }) {
250
274
  )), /* @__PURE__ */ React5.createElement(Text5, { color: "gray", dimColor: true, marginTop: 1 }, "(Press Enter to submit, type /cancel to abort)"));
251
275
  }
252
276
 
277
+ // src/components/AskUserModal.jsx
278
+ import React6, { useState as useState2 } from "react";
279
+ import { Box as Box6, Text as Text6, useInput } from "ink";
280
+ import TextInput2 from "ink-text-input";
281
+ var AskUserModal = ({ question, options, onResolve }) => {
282
+ const [isSuggestingElse, setIsSuggestingElse] = useState2(false);
283
+ const [customInput, setCustomInput] = useState2("");
284
+ const [selectedIndex, setSelectedIndex] = useState2(0);
285
+ const allOptions = [...options, { id: "CUSTOM", label: "Suggest something else...", description: "Provide a custom response" }];
286
+ useInput((input, key) => {
287
+ if (isSuggestingElse) return;
288
+ if (key.leftArrow || key.upArrow) {
289
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
290
+ }
291
+ if (key.rightArrow || key.downArrow) {
292
+ setSelectedIndex((prev) => Math.min(allOptions.length - 1, prev + 1));
293
+ }
294
+ if (key.return) {
295
+ const selected = allOptions[selectedIndex];
296
+ if (selected.id === "CUSTOM") {
297
+ setIsSuggestingElse(true);
298
+ } else {
299
+ onResolve(selected.label);
300
+ }
301
+ }
302
+ });
303
+ if (isSuggestingElse) {
304
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true, underline: true }, "\u{1F4AC} SUGGEST SOMETHING ELSE"), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { italic: true, color: "gray" }, "Replying to: ", question)), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, flexDirection: "row" }, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u276F "), /* @__PURE__ */ React6.createElement(
305
+ TextInput2,
306
+ {
307
+ value: customInput,
308
+ onChange: setCustomInput,
309
+ onSubmit: () => onResolve(customInput)
310
+ }
311
+ )), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true, italic: true }, "(Press Enter to send)")));
312
+ }
313
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true, underline: true }, "\u{1F4AC} ASK USER"), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, question)), /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "row", flexWrap: "wrap", width: "100%" }, options.map((opt, idx) => {
314
+ const isSelected = idx === selectedIndex;
315
+ return /* @__PURE__ */ React6.createElement(Box6, { key: opt.id, flexDirection: "column", marginRight: 4, marginBottom: 1, width: 30 }, /* @__PURE__ */ React6.createElement(Text6, { color: isSelected ? "cyan" : "white", bold: isSelected }, isSelected ? "\u276F " : " ", opt.label), opt.description && /* @__PURE__ */ React6.createElement(Box6, { marginLeft: 4 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", italic: true, dimColor: true }, opt.description)));
316
+ })), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: selectedIndex === options.length ? "cyan" : "white", bold: selectedIndex === options.length }, selectedIndex === options.length ? "\u276F " : " ", "Suggest something else...")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true, italic: true }, "(Use Arrows to navigate, Enter to confirm)")));
317
+ };
318
+ var AskUserModal_default = AskUserModal;
319
+
253
320
  // src/app.jsx
254
321
  import gradient from "gradient-string";
255
322
 
@@ -343,6 +410,7 @@ tool:functions.tool_name(arguments)
343
410
  - WEB TOOLS (Available in Flux & Flow) -
344
411
  1. Web Search: tool:functions.web_search(query="<query>", limit=number). Find info. limit is optional (3-10, default 10). If user asks about something that is not in your training data, proactively use this tool to find the information.Winder search recomemded (limit = 10) when exploring a topic.
345
412
  2. Web Scrape: tool:functions.web_scrape(url="<url>"). provides detail from a URL.
413
+ 3. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). Use this ONLY when you reach a decision point with multiple valid paths and need user preference to proceed / confirmation. This allows you to pause for guidance without ending your task loop. Format options as 'Short Label::Detailed Description'. You can provide 2 - 4 options (optionA, optionB, optionC, optionD). Tool can also return result as none of the 4 if user write custom one.
346
414
  ${mode === "Flux" ? `
347
415
  - DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
348
416
  1. View File: tool:functions.view_file(path="relative/path", start_line=number, end_line=number). Reads file content. Auto-truncates at 500 lines unless start_line and end_line are provided.
@@ -356,7 +424,7 @@ ${mode === "Flux" ? `
356
424
  Results will be provided in the next loop as: [TOOL_RESULT]: [content]
357
425
  WHEN CALLING TOOLS, YOU **MUST** END YOUR RESPONSE WITH '[turn: continue]' AFTER CALLING FUNCTIONS.
358
426
  Do NOT over-use tools. Use them only when strictly necessary for the user's objective. You can stack multiple tool calls 1-by-1.
359
- Distinguish clearly between tool discussion and execution. Use the 'tool:' prefix ONLY when calling a function. When discussing tools with the user, refer to them by name as nouns (e.g., 'write_file', 'list_files') to avoid accidental triggers and context bloat.
427
+ Distinguish clearly between tool discussion and execution. Use the 'tool:' prefix ONLY when calling a function. When discussing tools with the user, refer to them by name as nouns (e.g., 'write_file', 'list_files') to avoid accidental triggers and context bloat. Even in your <think> ... </think> tags, do not use the 'tool:' prefix when planning to select a tool.
360
428
  -- END FUNCTION CALLING PROTOCOL --`.trim();
361
429
 
362
430
  // src/data/janitor_tools.js
@@ -471,7 +539,8 @@ YOU ARE A SILENT BACKGROUND SYSTEM PROCESS. YOU HAVE NO MOUTH. YOUR ONLY OUTPUT
471
539
  1. OUTPUT ONLY 'tool:functions.xxx' CALLS.
472
540
  2. DO NOT EXPLAIN. DO NOT SUMMARIZE AGENT RAWS. DO NOT TALK TO THE USER.
473
541
  3. NON-TOOL TEXT WILL BREAK THE SYSTEM.
474
- 4.
542
+ 4. DO NOT REPEAT AGENT RAWS IN YOUR RESPONSE.
543
+ 5. IF YOU GET ONLY USER RESPONSE AND NO AGENT RAWS, THEN JUST USE TEMP MEMORY TO LOG THE SUMMARY OF USER QUERY.
475
544
 
476
545
  YOUR JOB: Analyze the 'User prompt' and 'Agent Raws' to extract facts for long-term memory or handle system tasks.
477
546
  ${isMemoryEnabled ? `If user tell something that is important (like, hobbies, preferences, facts about user, hates, likes, etc) to know user better over time, use long term memory tools.` : ""}
@@ -1156,6 +1225,40 @@ ${formatted}${footer}`;
1156
1225
  }
1157
1226
  };
1158
1227
 
1228
+ // src/tools/ask_user.js
1229
+ var ask_user = async (args, context) => {
1230
+ const parsed = parseArgs(args);
1231
+ const { question } = parsed;
1232
+ if (!question) return 'ERROR: Missing "question" argument for ask_user.';
1233
+ if (!context.onAskUser) return "ERROR: onAskUser callback not provided in tool context.";
1234
+ const options = [];
1235
+ Object.keys(parsed).forEach((key) => {
1236
+ if (key.startsWith("option")) {
1237
+ const val = parsed[key];
1238
+ if (typeof val === "string" && val.includes("::")) {
1239
+ const [label, desc] = val.split("::");
1240
+ options.push({
1241
+ id: key,
1242
+ label: label.trim(),
1243
+ description: desc.trim()
1244
+ });
1245
+ } else {
1246
+ options.push({
1247
+ id: key,
1248
+ label: String(val).trim(),
1249
+ description: ""
1250
+ });
1251
+ }
1252
+ }
1253
+ });
1254
+ try {
1255
+ const choice = await context.onAskUser(question, options);
1256
+ return `USER CHOOSE: ${choice}`;
1257
+ } catch (err) {
1258
+ return `ERROR: Failed to get user input: ${err.message}`;
1259
+ }
1260
+ };
1261
+
1159
1262
  // src/utils/tools.js
1160
1263
  var TOOL_MAP = {
1161
1264
  web_search,
@@ -1167,7 +1270,8 @@ var TOOL_MAP = {
1167
1270
  write_file,
1168
1271
  update_file,
1169
1272
  exec_command,
1170
- read_folder
1273
+ read_folder,
1274
+ ask: ask_user
1171
1275
  };
1172
1276
  var dispatchTool = async (toolName, args, context = {}) => {
1173
1277
  const tool = TOOL_MAP[toolName];
@@ -1386,7 +1490,7 @@ USER_PROMPT: ${agentText}`.trim();
1386
1490
  } else if (toolCall.toolName === "write_file" || toolCall.toolName === "update_file") {
1387
1491
  const action = toolCall.toolName === "write_file" ? "WRITING" : "PATCHING";
1388
1492
  label = `\u{1F4BE} ${action} FILE: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
1389
- } else if (toolCall.toolName === "exec_command") {
1493
+ } else if (toolCall.toolName === "exec_command" || toolCall.toolName === "ask") {
1390
1494
  label = "";
1391
1495
  } else {
1392
1496
  label = `EXECUTING ${toolCall.toolName}`.toUpperCase();
@@ -1472,7 +1576,8 @@ ${boxBottom}
1472
1576
  const result = await dispatchTool(toolCall.toolName, toolCall.args, {
1473
1577
  chatId,
1474
1578
  history,
1475
- onChunk: (chunk) => settings.onExecChunk ? settings.onExecChunk(chunk) : null
1579
+ onChunk: (chunk) => settings.onExecChunk ? settings.onExecChunk(chunk) : null,
1580
+ onAskUser: settings.onAskUser
1476
1581
  });
1477
1582
  if (toolCall.toolName === "exec_command" && settings.onExecEnd) {
1478
1583
  await new Promise((resolve) => setTimeout(resolve, 800));
@@ -1660,12 +1765,12 @@ var saveSettings = async (settings) => {
1660
1765
  };
1661
1766
 
1662
1767
  // src/components/ResumeModal.jsx
1663
- import React6, { useState as useState2, useEffect } from "react";
1664
- import { Box as Box6, Text as Text6, useInput } from "ink";
1768
+ import React7, { useState as useState3, useEffect } from "react";
1769
+ import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
1665
1770
  function ResumeModal({ onSelect, onDelete, onClose }) {
1666
- const [history, setHistory] = useState2({});
1667
- const [keys, setKeys] = useState2([]);
1668
- const [selectedIndex, setSelectedIndex] = useState2(0);
1771
+ const [history, setHistory] = useState3({});
1772
+ const [keys, setKeys] = useState3([]);
1773
+ const [selectedIndex, setSelectedIndex] = useState3(0);
1669
1774
  useEffect(() => {
1670
1775
  const fetchHistory = async () => {
1671
1776
  const h = await loadHistory();
@@ -1674,7 +1779,7 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
1674
1779
  };
1675
1780
  fetchHistory();
1676
1781
  }, []);
1677
- useInput((input, key) => {
1782
+ useInput2((input, key) => {
1678
1783
  if (key.escape) onClose();
1679
1784
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
1680
1785
  if (key.downArrow) setSelectedIndex((prev) => Math.min(keys.length - 1, prev + 1));
@@ -1690,19 +1795,19 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
1690
1795
  });
1691
1796
  }
1692
1797
  });
1693
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", padding: 1, width: 80 }, /* @__PURE__ */ React6.createElement(Box6, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, " \u{1F4C2} RESUME SESSION ")), keys.length === 0 ? /* @__PURE__ */ React6.createElement(Text6, { italic: true, color: "gray" }, " No saved chats found. ") : keys.map((id, index) => {
1798
+ return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", padding: 1, width: 80 }, /* @__PURE__ */ React7.createElement(Box7, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, " \u{1F4C2} RESUME SESSION ")), keys.length === 0 ? /* @__PURE__ */ React7.createElement(Text7, { italic: true, color: "gray" }, " No saved chats found. ") : keys.map((id, index) => {
1694
1799
  const chat2 = history[id];
1695
1800
  const isSelected = index === selectedIndex;
1696
- return /* @__PURE__ */ React6.createElement(Box6, { key: id, paddingX: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: isSelected ? "cyan" : "white" }, isSelected ? "\u276F " : " ", /* @__PURE__ */ React6.createElement(Text6, { bold: isSelected }, chat2.name || id), /* @__PURE__ */ React6.createElement(Text6, { color: "gray" }, " [", id.slice(5), "]")), isSelected && /* @__PURE__ */ React6.createElement(Box6, { marginLeft: "auto" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, " (x to delete) ")));
1697
- }), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, justifyContent: "center", borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close ")));
1801
+ return /* @__PURE__ */ React7.createElement(Box7, { key: id, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? "cyan" : "white" }, isSelected ? "\u276F " : " ", /* @__PURE__ */ React7.createElement(Text7, { bold: isSelected }, chat2.name || id), /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, " [", id.slice(5), "]")), isSelected && /* @__PURE__ */ React7.createElement(Box7, { marginLeft: "auto" }, /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, " (x to delete) ")));
1802
+ }), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, justifyContent: "center", borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " \u2191\u2193 navigate \u2022 Enter select \u2022 x delete \u2022 Esc close ")));
1698
1803
  }
1699
1804
 
1700
1805
  // src/components/MemoryModal.jsx
1701
- import React7, { useState as useState3, useEffect as useEffect2 } from "react";
1702
- import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
1806
+ import React8, { useState as useState4, useEffect as useEffect2 } from "react";
1807
+ import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
1703
1808
  function MemoryModal({ onClose }) {
1704
- const [memories, setMemories] = useState3([]);
1705
- const [selectedIndex, setSelectedIndex] = useState3(0);
1809
+ const [memories, setMemories] = useState4([]);
1810
+ const [selectedIndex, setSelectedIndex] = useState4(0);
1706
1811
  const loadMemories = () => {
1707
1812
  const data = readEncryptedJson(MEMORIES_FILE, []);
1708
1813
  setMemories(data);
@@ -1710,7 +1815,7 @@ function MemoryModal({ onClose }) {
1710
1815
  useEffect2(() => {
1711
1816
  loadMemories();
1712
1817
  }, []);
1713
- useInput2((input, key) => {
1818
+ useInput3((input, key) => {
1714
1819
  if (key.escape) onClose();
1715
1820
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
1716
1821
  if (key.downArrow) setSelectedIndex((prev) => Math.min(memories.length - 1, prev + 1));
@@ -1727,12 +1832,15 @@ function MemoryModal({ onClose }) {
1727
1832
  const cleanDisplay = (text) => {
1728
1833
  return text.replace(/\[Saved on: .*?\]/g, "").trim();
1729
1834
  };
1730
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "yellow", padding: 1, width: 80 }, /* @__PURE__ */ React7.createElement(Box7, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "yellow" }, "\u{1F9E0} LONG-TERM MEMORY VAULT")), memories.length === 0 ? /* @__PURE__ */ React7.createElement(Box7, { justifyContent: "center", paddingY: 2 }, /* @__PURE__ */ React7.createElement(Text7, { italic: true, color: "gray" }, "The vault is currently empty...")) : memories.map((mem, idx) => /* @__PURE__ */ React7.createElement(Box7, { key: mem.id, paddingX: 1, backgroundColor: idx === selectedIndex ? "#333" : void 0 }, /* @__PURE__ */ React7.createElement(Text7, { color: idx === selectedIndex ? "yellow" : "white" }, idx === selectedIndex ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory)))), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "\u2191/\u2193 Navigate \u2022 ", /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, "x"), " Delete Memory \u2022 ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, "Esc"), " Back to Chat")));
1835
+ return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "double", borderColor: "yellow", padding: 1, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "center", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "yellow" }, "\u{1F9E0} LONG-TERM MEMORY VAULT")), memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "center", paddingY: 2 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "The vault is currently empty...")) : memories.map((mem, idx) => /* @__PURE__ */ React8.createElement(Box8, { key: mem.id, paddingX: 1, backgroundColor: idx === selectedIndex ? "#333" : void 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: idx === selectedIndex ? "yellow" : "white" }, idx === selectedIndex ? "\u276F " : " ", idx + 1, ". ", cleanDisplay(mem.memory)))), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "\u2191/\u2193 Navigate \u2022 ", /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, "x"), " Delete Memory \u2022 ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, "Esc"), " Back to Chat")));
1731
1836
  }
1732
1837
 
1733
1838
  // src/app.jsx
1734
1839
  var SESSION_START_TIME = Date.now();
1735
- var ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1 }, "The agent already finished the task (turn: finish) before your hint was consumed."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
1840
+ var CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
1841
+ var versionFluxflow = "1.1.1";
1842
+ var updatedOn = "2026-04-26";
1843
+ var ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "The agent already finished the task (turn: finish) before your hint was consumed."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
1736
1844
  CommandMenu,
1737
1845
  {
1738
1846
  title: "Select Action",
@@ -1756,9 +1864,9 @@ var FLUX_LOGO = gradient(["#00ffff", "#0077ff", "#ff00ff"]).multiline(
1756
1864
  );
1757
1865
  function App() {
1758
1866
  const { stdout } = useStdout();
1759
- const [input, setInput] = useState4("");
1760
- const [mode, setMode] = useState4("Flux");
1761
- const [terminalSize, setTerminalSize] = useState4({
1867
+ const [input, setInput] = useState5("");
1868
+ const [mode, setMode] = useState5("Flux");
1869
+ const [terminalSize, setTerminalSize] = useState5({
1762
1870
  columns: stdout?.columns || 80,
1763
1871
  rows: stdout?.rows || 24
1764
1872
  });
@@ -1775,27 +1883,54 @@ function App() {
1775
1883
  stdout.off("resize", handleResize);
1776
1884
  };
1777
1885
  }, [stdout]);
1778
- const [thinkingLevel, setThinkingLevel] = useState4("Medium");
1779
- const [showFullThinking, setShowFullThinking] = useState4(false);
1780
- const [activeModel, setActiveModel] = useState4("gemma-4-31b-it");
1781
- const [janitorModel, setJanitorModel] = useState4("gemma-4-26b-a4b-it");
1782
- const [isInitializing, setIsInitializing] = useState4(true);
1783
- const [apiKey, setApiKey] = useState4(null);
1784
- const [tempKey, setTempKey] = useState4("");
1785
- const [activeView, setActiveView] = useState4("chat");
1786
- const [apiTier, setApiTier] = useState4("Free");
1787
- const [quotas, setQuotas] = useState4({ agentLimit: 1500, backgroundLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
1788
- const [inputConfig, setInputConfig] = useState4(null);
1789
- const [systemSettings, setSystemSettings] = useState4({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d" });
1790
- const [profileData, setProfileData] = useState4({ name: null, nickname: null, instructions: null });
1791
- const [sessionStats, setSessionStats] = useState4({ tokens: 0 });
1792
- const [sessionAgentCalls, setSessionAgentCalls] = useState4(0);
1793
- const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState4(0);
1794
- const [sessionTotalTokens, setSessionTotalTokens] = useState4(0);
1795
- const [dailyUsage, setDailyUsage] = useState4(null);
1796
- const [chatId, setChatId] = useState4(generateChatId());
1797
- const [activeCommand, setActiveCommand] = useState4(null);
1798
- const [execOutput, setExecOutput] = useState4("");
1886
+ useEffect3(() => {
1887
+ const checkVersion = async () => {
1888
+ try {
1889
+ const response = await fetch("https://registry.npmjs.org/fluxflow-cli/latest");
1890
+ const data = await response.json();
1891
+ const latestVersion = data?.version;
1892
+ if (latestVersion) setLatestVer(latestVersion);
1893
+ if (latestVersion && latestVersion !== versionFluxflow) {
1894
+ setMessages((prev) => {
1895
+ const newMsgs = [...prev];
1896
+ newMsgs.splice(1, 0, {
1897
+ id: "update-" + Date.now(),
1898
+ role: "system",
1899
+ text: `\u{1F680} **New version 'v${latestVersion}' is available!**
1900
+ Type \`npm i -g fluxflow-cli\` to update.
1901
+ Check what's new using \`/changelog\` command.`,
1902
+ isUpdateNotification: true
1903
+ });
1904
+ return newMsgs;
1905
+ });
1906
+ }
1907
+ } catch (err) {
1908
+ }
1909
+ };
1910
+ checkVersion();
1911
+ }, []);
1912
+ const [thinkingLevel, setThinkingLevel] = useState5("Medium");
1913
+ const [latestVer, setLatestVer] = useState5(null);
1914
+ const [showFullThinking, setShowFullThinking] = useState5(false);
1915
+ const [activeModel, setActiveModel] = useState5("gemma-4-31b-it");
1916
+ const [janitorModel, setJanitorModel] = useState5("gemma-4-26b-a4b-it");
1917
+ const [isInitializing, setIsInitializing] = useState5(true);
1918
+ const [apiKey, setApiKey] = useState5(null);
1919
+ const [tempKey, setTempKey] = useState5("");
1920
+ const [activeView, setActiveView] = useState5("chat");
1921
+ const [apiTier, setApiTier] = useState5("Free");
1922
+ const [quotas, setQuotas] = useState5({ agentLimit: 1500, backgroundLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
1923
+ const [inputConfig, setInputConfig] = useState5(null);
1924
+ const [systemSettings, setSystemSettings] = useState5({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d" });
1925
+ const [profileData, setProfileData] = useState5({ name: null, nickname: null, instructions: null });
1926
+ const [sessionStats, setSessionStats] = useState5({ tokens: 0 });
1927
+ const [sessionAgentCalls, setSessionAgentCalls] = useState5(0);
1928
+ const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState5(0);
1929
+ const [sessionTotalTokens, setSessionTotalTokens] = useState5(0);
1930
+ const [dailyUsage, setDailyUsage] = useState5(null);
1931
+ const [chatId, setChatId] = useState5(generateChatId());
1932
+ const [activeCommand, setActiveCommand] = useState5(null);
1933
+ const [execOutput, setExecOutput] = useState5("");
1799
1934
  const activeCommandRef = useRef(null);
1800
1935
  const execOutputRef = useRef("");
1801
1936
  useEffect3(() => {
@@ -1804,8 +1939,9 @@ function App() {
1804
1939
  useEffect3(() => {
1805
1940
  execOutputRef.current = execOutput;
1806
1941
  }, [execOutput]);
1807
- const [autoAcceptWrites, setAutoAcceptWrites] = useState4(false);
1808
- const [pendingApproval, setPendingApproval] = useState4(null);
1942
+ const [autoAcceptWrites, setAutoAcceptWrites] = useState5(false);
1943
+ const [pendingApproval, setPendingApproval] = useState5(null);
1944
+ const [pendingAsk, setPendingAsk] = useState5(null);
1809
1945
  const formatDuration = (totalSecs) => {
1810
1946
  const h = Math.floor(totalSecs / 3600);
1811
1947
  const m = Math.floor(totalSecs % 3600 / 60);
@@ -1815,19 +1951,43 @@ function App() {
1815
1951
  }
1816
1952
  return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
1817
1953
  };
1818
- const [statusText, setStatusText] = useState4(null);
1819
- const [isProcessing, setIsProcessing] = useState4(false);
1820
- const [escPressed, setEscPressed] = useState4(false);
1821
- const [escTimer, setEscTimer] = useState4(null);
1822
- const [queuedPrompt, setQueuedPrompt] = useState4(null);
1823
- const [resolutionData, setResolutionData] = useState4(null);
1824
- const [tempModelOverride, setTempModelOverride] = useState4(null);
1825
- const [messages, setMessages] = useState4([
1954
+ const [statusText, setStatusText] = useState5(null);
1955
+ const [isProcessing, setIsProcessing] = useState5(false);
1956
+ const [escPressed, setEscPressed] = useState5(false);
1957
+ const [escTimer, setEscTimer] = useState5(null);
1958
+ const [queuedPrompt, setQueuedPrompt] = useState5(null);
1959
+ const [resolutionData, setResolutionData] = useState5(null);
1960
+ const [tempModelOverride, setTempModelOverride] = useState5(null);
1961
+ const [messages, setMessages] = useState5([
1826
1962
  { id: "welcome", role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.\n" }
1827
1963
  ]);
1828
1964
  const queuedPromptRef = useRef(null);
1829
- const [completedIndex, setCompletedIndex] = useState4(1);
1830
- useInput3((inputText, key) => {
1965
+ const [completedIndex, setCompletedIndex] = useState5(1);
1966
+ const windowedHistory = useMemo(() => {
1967
+ const MAX_LINES = 1e3;
1968
+ const width = stdout?.columns || 80;
1969
+ let totalLines = 0;
1970
+ let startIdx = 0;
1971
+ for (let i = completedIndex - 1; i >= 0; i--) {
1972
+ const msg = messages[i];
1973
+ if (!msg) continue;
1974
+ let lines = (msg.text || "").split("\n").length;
1975
+ msg.text.split("\n").forEach((l) => {
1976
+ lines += Math.floor(l.length / width);
1977
+ });
1978
+ lines += msg.role === "think" ? 3 : 2;
1979
+ if (totalLines + lines > MAX_LINES && completedIndex - i > 2) {
1980
+ startIdx = i + 1;
1981
+ break;
1982
+ }
1983
+ totalLines += lines;
1984
+ }
1985
+ return {
1986
+ items: messages.slice(startIdx, completedIndex),
1987
+ isTruncated: startIdx > 0
1988
+ };
1989
+ }, [messages, completedIndex, stdout?.columns]);
1990
+ useInput4((inputText, key) => {
1831
1991
  if (key.escape) {
1832
1992
  if (isProcessing) {
1833
1993
  if (!escPressed) {
@@ -1901,7 +2061,7 @@ function App() {
1901
2061
  setTempKey("");
1902
2062
  }
1903
2063
  };
1904
- const COMMANDS = ["/mode", "/thinking", "/model", "/resume", "/memory", "/profile", "/settings", "/key", "/stats", "/reset", "/help", "/clear", "/quit"];
2064
+ const COMMANDS = ["/mode", "/thinking", "/model", "/resume", "/memory", "/profile", "/settings", "/key", "/stats", "/reset", "/help", "/clear", "/quit", "/changelog", "/about"];
1905
2065
  const handleSubmit = (value) => {
1906
2066
  const normalizedValue = value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimEnd();
1907
2067
  if (normalizedValue.endsWith("\\")) {
@@ -1942,9 +2102,14 @@ ${hintText}`, color: "magenta" }];
1942
2102
  const h = await loadHistory();
1943
2103
  const target = h[targetId] || Object.values(h).find((h2) => h2.name.toLowerCase() === targetId.toLowerCase());
1944
2104
  if (target) {
1945
- process.stdout.write("\x1Bc");
2105
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
1946
2106
  setChatId(targetId);
1947
- setMessages(target.messages);
2107
+ const resumedMsgs = [...target.messages];
2108
+ const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
2109
+ if (!hasLogo) {
2110
+ resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...\n" });
2111
+ }
2112
+ setMessages(resumedMsgs);
1948
2113
  setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${targetId}]` }]);
1949
2114
  setCompletedIndex(0);
1950
2115
  } else {
@@ -1958,7 +2123,7 @@ ${hintText}`, color: "magenta" }];
1958
2123
  break;
1959
2124
  }
1960
2125
  case "/clear": {
1961
- process.stdout.write("\x1Bc");
2126
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
1962
2127
  setMessages([{ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome back to Flux Flow! Context cleared.\n" }]);
1963
2128
  setCompletedIndex(0);
1964
2129
  setChatId(generateChatId());
@@ -2102,6 +2267,27 @@ ${list || "No saved chats found."}` }];
2102
2267
  runReset();
2103
2268
  break;
2104
2269
  }
2270
+ case "/about": {
2271
+ const updateStatus = latestVer ? latestVer !== versionFluxflow ? `Update Available [v${latestVer}]` : "No Update Available" : "Checking for updates...";
2272
+ const aboutText = `\u2139\uFE0F **FluxFlow Version:** v${versionFluxflow}
2273
+ \u{1F504} **Status:** ${updateStatus}
2274
+ \u{1F4C5} **Updated on:** ${updatedOn}`;
2275
+ setMessages((prev) => {
2276
+ setCompletedIndex(prev.length + 1);
2277
+ return [...prev, { id: Date.now(), role: "system", text: aboutText }];
2278
+ });
2279
+ break;
2280
+ }
2281
+ case "/changelog": {
2282
+ const platform = process.platform;
2283
+ const command = platform === "win32" ? "start" : platform === "darwin" ? "open" : "xdg-open";
2284
+ exec(`${command} ${CHANGELOG_URL}`);
2285
+ setMessages((prev) => {
2286
+ setCompletedIndex(prev.length + 1);
2287
+ return [...prev, { id: Date.now(), role: "system", text: `\u{1F310} [BROWSER] Opening changelog: ${CHANGELOG_URL}` }];
2288
+ });
2289
+ break;
2290
+ }
2105
2291
  case "/help": {
2106
2292
  setMessages((prev) => {
2107
2293
  setCompletedIndex(prev.length + 1);
@@ -2174,23 +2360,47 @@ OUTPUT: ${execOutputRef.current}`;
2174
2360
  setPendingApproval({ tool, args, resolve });
2175
2361
  setActiveView("approval");
2176
2362
  });
2363
+ },
2364
+ onAskUser: async (question, options) => {
2365
+ return new Promise((resolve) => {
2366
+ setPendingAsk({
2367
+ question,
2368
+ options,
2369
+ resolve: (val) => {
2370
+ setMessages((prev) => [
2371
+ ...prev,
2372
+ {
2373
+ id: "ask-" + Date.now(),
2374
+ role: "system",
2375
+ text: `\u{1F4AC} **Ask User**
2376
+ Selection: ${val}`,
2377
+ isAskRecord: true
2378
+ }
2379
+ ]);
2380
+ resolve(val);
2381
+ }
2382
+ });
2383
+ setActiveView("ask");
2384
+ });
2177
2385
  }
2178
2386
  },
2179
- async () => {
2180
- if (queuedPromptRef.current) {
2181
- const p = queuedPromptRef.current;
2182
- setQueuedPrompt(null);
2183
- queuedPromptRef.current = null;
2184
- setMessages((prev) => {
2185
- const newMsgs = [...prev];
2186
- const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]"));
2187
- if (hintMsg) {
2188
- hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: INJECTED]");
2189
- hintMsg.color = "cyan";
2190
- }
2191
- return newMsgs.reverse();
2192
- });
2193
- return p;
2387
+ async (hint) => {
2388
+ if (queuedPrompt) {
2389
+ if (queuedPromptRef.current) {
2390
+ const p = queuedPromptRef.current;
2391
+ setQueuedPrompt(null);
2392
+ queuedPromptRef.current = null;
2393
+ setMessages((prev) => {
2394
+ const newMsgs = [...prev];
2395
+ const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]"));
2396
+ if (hintMsg) {
2397
+ hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: INJECTED]");
2398
+ hintMsg.color = "cyan";
2399
+ }
2400
+ return newMsgs.reverse();
2401
+ });
2402
+ return p;
2403
+ }
2194
2404
  }
2195
2405
  return null;
2196
2406
  }
@@ -2253,9 +2463,9 @@ OUTPUT: ${execOutputRef.current}`;
2253
2463
  const [thinkPart, agentPart] = chunkText.split("</think>");
2254
2464
  if (inThinkMode) {
2255
2465
  setMessages((prev) => {
2256
- const newMsgs = [...prev];
2257
- const thinkMsg = newMsgs.find((m) => m.id === currentThinkId);
2258
- if (thinkMsg) thinkMsg.text += thinkPart.replace(signalRegex, "");
2466
+ const newMsgs = prev.map(
2467
+ (m) => m.id === currentThinkId ? { ...m, text: m.text + thinkPart.replace(signalRegex, "") } : m
2468
+ );
2259
2469
  currentAgentId = "agent-" + Date.now();
2260
2470
  const cleanedAgentPart = (agentPart || "").replace(signalRegex, "");
2261
2471
  return [...newMsgs, { id: currentAgentId, role: "agent", text: cleanedAgentPart }];
@@ -2267,35 +2477,26 @@ OUTPUT: ${execOutputRef.current}`;
2267
2477
  currentAgentId = "agent-" + Date.now();
2268
2478
  setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: cleanedContent }]);
2269
2479
  } else {
2270
- setMessages((prev) => {
2271
- const newMsgs = [...prev];
2272
- const msg = newMsgs.find((m) => m.id === currentAgentId);
2273
- if (msg) msg.text += cleanedContent;
2274
- return newMsgs;
2275
- });
2480
+ setMessages((prev) => prev.map(
2481
+ (m) => m.id === currentAgentId ? { ...m, text: m.text + cleanedContent } : m
2482
+ ));
2276
2483
  }
2277
2484
  }
2278
2485
  continue;
2279
2486
  }
2280
2487
  if (inThinkMode && currentThinkId) {
2281
- setMessages((prev) => {
2282
- const newMsgs = [...prev];
2283
- const msg = newMsgs.find((m) => m.id === currentThinkId);
2284
- if (msg) msg.text += chunkText.replace(signalRegex, "");
2285
- return newMsgs;
2286
- });
2488
+ setMessages((prev) => prev.map(
2489
+ (m) => m.id === currentThinkId ? { ...m, text: m.text + chunkText.replace(signalRegex, "") } : m
2490
+ ));
2287
2491
  } else if (!inThinkMode) {
2288
2492
  const cleanedText = chunkText.replace(/<\/?think>/gi, "").replace(signalRegex, "");
2289
2493
  if (!currentAgentId) {
2290
2494
  currentAgentId = "agent-" + Date.now();
2291
2495
  setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: cleanedText }]);
2292
2496
  } else {
2293
- setMessages((prev) => {
2294
- const newMsgs = [...prev];
2295
- const msg = newMsgs.find((m) => m.id === currentAgentId);
2296
- if (msg) msg.text += cleanedText;
2297
- return newMsgs;
2298
- });
2497
+ setMessages((prev) => prev.map(
2498
+ (m) => m.id === currentAgentId ? { ...m, text: m.text + cleanedText } : m
2499
+ ));
2299
2500
  }
2300
2501
  }
2301
2502
  }
@@ -2342,7 +2543,7 @@ OUTPUT: ${execOutputRef.current}`;
2342
2543
  const renderActiveView = () => {
2343
2544
  switch (activeView) {
2344
2545
  case "mode":
2345
- return /* @__PURE__ */ React8.createElement(
2546
+ return /* @__PURE__ */ React9.createElement(
2346
2547
  CommandMenu,
2347
2548
  {
2348
2549
  title: "\u26A1 Select Operating Mode",
@@ -2371,7 +2572,7 @@ OUTPUT: ${execOutputRef.current}`;
2371
2572
  { label: "Max (Architecture)", value: "Max" }
2372
2573
  ];
2373
2574
  options.push({ label: "Cancel", value: "Cancel" });
2374
- return /* @__PURE__ */ React8.createElement(
2575
+ return /* @__PURE__ */ React9.createElement(
2375
2576
  CommandMenu,
2376
2577
  {
2377
2578
  title: `\u{1F9E0} Select Thinking Level (${mode} Mode)`,
@@ -2384,7 +2585,7 @@ OUTPUT: ${execOutputRef.current}`;
2384
2585
  );
2385
2586
  }
2386
2587
  case "model":
2387
- return /* @__PURE__ */ React8.createElement(
2588
+ return /* @__PURE__ */ React9.createElement(
2388
2589
  CommandMenu,
2389
2590
  {
2390
2591
  title: "\u{1F916} Select AI Model",
@@ -2396,7 +2597,7 @@ OUTPUT: ${execOutputRef.current}`;
2396
2597
  }
2397
2598
  );
2398
2599
  case "settings":
2399
- return /* @__PURE__ */ React8.createElement(
2600
+ return /* @__PURE__ */ React9.createElement(
2400
2601
  CommandMenu,
2401
2602
  {
2402
2603
  title: "System Settings",
@@ -2441,7 +2642,7 @@ OUTPUT: ${execOutputRef.current}`;
2441
2642
  }
2442
2643
  );
2443
2644
  case "apiTier":
2444
- return /* @__PURE__ */ React8.createElement(
2645
+ return /* @__PURE__ */ React9.createElement(
2445
2646
  CommandMenu,
2446
2647
  {
2447
2648
  title: `API Tier: ${apiTier}`,
@@ -2506,8 +2707,8 @@ OUTPUT: ${execOutputRef.current}`;
2506
2707
  }
2507
2708
  );
2508
2709
  case "input":
2509
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 }, inputConfig?.note && /* @__PURE__ */ React8.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow", dimColor: true }, inputConfig.note)), /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, inputConfig?.label), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2510
- TextInput2,
2710
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 }, inputConfig?.note && /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", dimColor: true }, inputConfig.note)), /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, inputConfig?.label), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2711
+ TextInput3,
2511
2712
  {
2512
2713
  value: inputConfig?.value || "",
2513
2714
  onChange: (val) => setInputConfig((prev) => ({ ...prev, value: val })),
@@ -2536,11 +2737,11 @@ OUTPUT: ${execOutputRef.current}`;
2536
2737
  }
2537
2738
  }
2538
2739
  }
2539
- )), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
2740
+ )), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
2540
2741
  case "stats":
2541
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F4CA} DAILY PERFORMANCE LEDGER"), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Agent Model Calls: ", /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, dailyUsage?.agent || 0)), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Background Tasks: ", /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, dailyUsage?.background || 0))), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, marginTop: 1 }, "(Press ESC to return to chat)"));
2742
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan", bold: true }, "\u{1F4CA} DAILY PERFORMANCE LEDGER"), /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Agent Model Calls: ", /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, dailyUsage?.agent || 0)), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Background Tasks: ", /* @__PURE__ */ React9.createElement(Text9, { color: "blue" }, dailyUsage?.background || 0))), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true, marginTop: 1 }, "(Press ESC to return to chat)"));
2542
2743
  case "autoExecDanger":
2543
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: AUTO-EXEC MODE"), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1 }, "Turning this ON allows the agent to execute terminal commands automatically without requiring your approval for each step."), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 The agent may execute destructive commands (rm -rf, etc.) by mistake."), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Unintended system changes if the agent hallucinates a path or command."), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Reduced control over the agent's step-by-step decision making."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2744
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: AUTO-EXEC MODE"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Turning this ON allows the agent to execute terminal commands automatically without requiring your approval for each step."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 The agent may execute destructive commands (rm -rf, etc.) by mistake."), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Unintended system changes if the agent hallucinates a path or command."), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Reduced control over the agent's step-by-step decision making."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2544
2745
  CommandMenu,
2545
2746
  {
2546
2747
  title: "Confirm Intent",
@@ -2557,7 +2758,7 @@ OUTPUT: ${execOutputRef.current}`;
2557
2758
  }
2558
2759
  )));
2559
2760
  case "externalDanger":
2560
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { color: "red", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: EXTERNAL WORKSPACE ACCESS"), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1 }, "Turning this ON allows the agent to execute tools (Read/Write/Exec) outside of the current active workspace directory."), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Access to sensitive system files (SSH keys, Browser data, etc.)"), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Potential for accidental or malicious deletion of OS-critical files."), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Unauthorized script execution across your entire file system."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2761
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: EXTERNAL WORKSPACE ACCESS"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Turning this ON allows the agent to execute tools (Read/Write/Exec) outside of the current active workspace directory."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Access to sensitive system files (SSH keys, Browser data, etc.)"), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Potential for accidental or malicious deletion of OS-critical files."), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Unauthorized script execution across your entire file system."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2561
2762
  CommandMenu,
2562
2763
  {
2563
2764
  title: "Confirm Intent",
@@ -2574,7 +2775,7 @@ OUTPUT: ${execOutputRef.current}`;
2574
2775
  }
2575
2776
  )));
2576
2777
  case "doubleDanger":
2577
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { color: "red", bold: true, underline: true }, "\u26D4 CRITICAL SECURITY WARNING: COMBINED SYSTEM RISK"), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1 }, "You are attempting to enable BOTH [Auto-Exec] and [External Workspace Access] simultaneously."), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1, color: "red", bold: true }, "THIS IS NOT RECOMMENDED."), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1, color: "yellow" }, "THE CRITICAL RISK:"), /* @__PURE__ */ React8.createElement(Text8, null, "The agent will have the power to execute any command across your entire system WITHOUT your approval or supervision."), /* @__PURE__ */ React8.createElement(Text8, { color: "red", italic: true, marginTop: 1 }, "A single hallucination or error could result in full system wipe or data theft."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2778
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true, underline: true }, "\u26D4 CRITICAL SECURITY WARNING: COMBINED SYSTEM RISK"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "You are attempting to enable BOTH [Auto-Exec] and [External Workspace Access] simultaneously."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "red", bold: true }, "THIS IS NOT RECOMMENDED."), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1, color: "yellow" }, "THE CRITICAL RISK:"), /* @__PURE__ */ React9.createElement(Text9, null, "The agent will have the power to execute any command across your entire system WITHOUT your approval or supervision."), /* @__PURE__ */ React9.createElement(Text9, { color: "red", italic: true, marginTop: 1 }, "A single hallucination or error could result in full system wipe or data theft."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2578
2779
  CommandMenu,
2579
2780
  {
2580
2781
  title: "Final Confirmation",
@@ -2591,7 +2792,7 @@ OUTPUT: ${execOutputRef.current}`;
2591
2792
  }
2592
2793
  )));
2593
2794
  case "key":
2594
- return /* @__PURE__ */ React8.createElement(
2795
+ return /* @__PURE__ */ React9.createElement(
2595
2796
  CommandMenu,
2596
2797
  {
2597
2798
  title: "\u{1F511} API KEY MANAGEMENT",
@@ -2614,7 +2815,7 @@ OUTPUT: ${execOutputRef.current}`;
2614
2815
  }
2615
2816
  );
2616
2817
  case "deleteKey":
2617
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "red", bold: true }, "\u26A0\uFE0F DANGER: PURGE API KEY"), /* @__PURE__ */ React8.createElement(Text8, { 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__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2818
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true }, "\u26A0\uFE0F DANGER: PURGE API KEY"), /* @__PURE__ */ React9.createElement(Text9, { 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__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2618
2819
  CommandMenu,
2619
2820
  {
2620
2821
  title: "Are you absolutely sure?",
@@ -2635,7 +2836,7 @@ OUTPUT: ${execOutputRef.current}`;
2635
2836
  }
2636
2837
  )));
2637
2838
  case "exit":
2638
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "red" }, /* @__PURE__ */ React8.createElement(Text8, { color: "red", bold: true }, "\u{1F3C1} SESSION DASHBOARD"), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Agent Active For: ", /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, formatDuration(Math.floor((Date.now() - SESSION_START_TIME) / 1e3)))), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Total Agent Queries: ", /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, sessionAgentCalls)), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Memory Tasks: ", /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, sessionBackgroundCalls)), /* @__PURE__ */ React8.createElement(Text8, null, "\u2022 Total Tokens Consumed: ", /* @__PURE__ */ React8.createElement(Text8, { color: "magenta" }, (sessionTotalTokens / 1e3).toFixed(2), "k"))), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1 }, "Are you sure you want to exit?"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2839
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "red" }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true }, "\u{1F3C1} SESSION DASHBOARD"), /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Agent Active For: ", /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, formatDuration(Math.floor((Date.now() - SESSION_START_TIME) / 1e3)))), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Total Agent Queries: ", /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, sessionAgentCalls)), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Memory Tasks: ", /* @__PURE__ */ React9.createElement(Text9, { color: "blue" }, sessionBackgroundCalls)), /* @__PURE__ */ React9.createElement(Text9, null, "\u2022 Total Tokens Consumed: ", /* @__PURE__ */ React9.createElement(Text9, { color: "magenta" }, (sessionTotalTokens / 1e3).toFixed(2), "k"))), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "Are you sure you want to exit?"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2639
2840
  CommandMenu,
2640
2841
  {
2641
2842
  title: "Exit Confirmation",
@@ -2652,15 +2853,36 @@ OUTPUT: ${execOutputRef.current}`;
2652
2853
  }
2653
2854
  }
2654
2855
  )));
2856
+ case "ask":
2857
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%" }, /* @__PURE__ */ React9.createElement(
2858
+ AskUserModal_default,
2859
+ {
2860
+ question: pendingAsk?.question,
2861
+ options: pendingAsk?.options,
2862
+ onResolve: (choice) => {
2863
+ if (pendingAsk?.resolve) {
2864
+ pendingAsk.resolve(choice);
2865
+ }
2866
+ setPendingAsk(null);
2867
+ setActiveView("chat");
2868
+ }
2869
+ }
2870
+ ));
2655
2871
  case "resume":
2656
- return /* @__PURE__ */ React8.createElement(Box8, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React8.createElement(
2872
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(
2657
2873
  ResumeModal,
2658
2874
  {
2659
2875
  onSelect: async (id) => {
2660
2876
  const h = await loadHistory();
2661
2877
  if (h[id]) {
2878
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
2662
2879
  setChatId(id);
2663
- setMessages(h[id].messages);
2880
+ const resumedMsgs = [...h[id].messages];
2881
+ const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
2882
+ if (!hasLogo) {
2883
+ resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...\n" });
2884
+ }
2885
+ setMessages(resumedMsgs);
2664
2886
  setActiveView("chat");
2665
2887
  setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${id}]` }]);
2666
2888
  setCompletedIndex(0);
@@ -2674,9 +2896,9 @@ OUTPUT: ${execOutputRef.current}`;
2674
2896
  }
2675
2897
  ));
2676
2898
  case "memory":
2677
- return /* @__PURE__ */ React8.createElement(Box8, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React8.createElement(MemoryModal, { onClose: () => setActiveView("chat") }));
2899
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(MemoryModal, { onClose: () => setActiveView("chat") }));
2678
2900
  case "profile":
2679
- return /* @__PURE__ */ React8.createElement(
2901
+ return /* @__PURE__ */ React9.createElement(
2680
2902
  ProfileForm,
2681
2903
  {
2682
2904
  onSave: (profile) => {
@@ -2688,7 +2910,7 @@ OUTPUT: ${execOutputRef.current}`;
2688
2910
  }
2689
2911
  );
2690
2912
  case "resolution":
2691
- return /* @__PURE__ */ React8.createElement(Box8, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React8.createElement(
2913
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(
2692
2914
  ResolutionModal,
2693
2915
  {
2694
2916
  data: resolutionData,
@@ -2705,15 +2927,15 @@ OUTPUT: ${execOutputRef.current}`;
2705
2927
  }
2706
2928
  ));
2707
2929
  case "approval":
2708
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow", bold: true, underline: true }, "\u{1F6E1}\uFE0F SECURITY GATE: FILE WRITE PERMISSION"), /* @__PURE__ */ React8.createElement(Text8, { marginTop: 1 }, "The agent is attempting to modify: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, parseArgs(pendingApproval?.args || "{}").path || "Unknown File")), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, borderStyle: "single", borderColor: "#333", paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "--- PROPOSED CONTENT / DIFF ---"), (() => {
2930
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", bold: true, underline: true }, "\u{1F6E1}\uFE0F SECURITY GATE: FILE WRITE PERMISSION"), /* @__PURE__ */ React9.createElement(Text9, { marginTop: 1 }, "The agent is attempting to modify: ", /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, parseArgs(pendingApproval?.args || "{}").path || "Unknown File")), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, borderStyle: "single", borderColor: "#333", paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, "--- PROPOSED CONTENT / DIFF ---"), (() => {
2709
2931
  const args = parseArgs(pendingApproval?.args || "{}");
2710
2932
  const oldVal = args.TargetContent || args.content_to_replace || null;
2711
2933
  const newVal = args.content || args.ReplacementContent || args.content_to_add || args.replacementContent || null;
2712
2934
  if (oldVal && newVal) {
2713
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal)));
2935
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "red", wrap: "anywhere", bold: true }, "- ", oldVal)), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "green", wrap: "anywhere", bold: true }, "+ ", newVal)));
2714
2936
  }
2715
- return /* @__PURE__ */ React8.createElement(Text8, { color: "white", wrap: "anywhere" }, newVal || "Updating file content...");
2716
- })()), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2937
+ return /* @__PURE__ */ React9.createElement(Text9, { color: "white", wrap: "anywhere" }, newVal || "Updating file content...");
2938
+ })()), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2717
2939
  CommandMenu,
2718
2940
  {
2719
2941
  title: "Action Required",
@@ -2732,7 +2954,7 @@ OUTPUT: ${execOutputRef.current}`;
2732
2954
  }
2733
2955
  )));
2734
2956
  case "terminalApproval":
2735
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Text8, { color: "red", bold: true, underline: true }, "\u{1F6E1}\uFE0F SECURITY GATE: TERMINAL COMMAND OVERSIGHT"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "Agent requested to run: ", /* @__PURE__ */ React8.createElement(Text8, { color: "yellow", bold: true }, parseArgs(pendingApproval?.args || "{}").command || "Unknown Command"))), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2957
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Text9, { color: "red", bold: true, underline: true }, "\u{1F6E1}\uFE0F SECURITY GATE: TERMINAL COMMAND OVERSIGHT"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, null, "Agent requested to run: ", /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", bold: true }, parseArgs(pendingApproval?.args || "{}").command || "Unknown Command"))), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2736
2958
  CommandMenu,
2737
2959
  {
2738
2960
  title: "Risk Assessment Required",
@@ -2754,8 +2976,8 @@ OUTPUT: ${execOutputRef.current}`;
2754
2976
  return acc + Math.max(1, Math.ceil(line.length / wrapWidth));
2755
2977
  }, 0);
2756
2978
  const maxLines = Math.max(1, wrappedLines);
2757
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React8.createElement(Box8, null, statusText && /* @__PURE__ */ React8.createElement(Text8, { color: "magenta", italic: true }, "\u23F3 ", statusText)), /* @__PURE__ */ React8.createElement(Text8, { color: "gray", dimColor: true }, "(", tempModelOverride || activeModel, ")")), suggestions.length > 0 && /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "\u{1F4A1} Suggestions: "), suggestions.map((s, i) => /* @__PURE__ */ React8.createElement(Text8, { key: s, color: "yellow", bold: i === 0 }, " ", s, " "))), /* @__PURE__ */ React8.createElement(Box8, { backgroundColor: "#333333", paddingX: 1, paddingY: 1, width: "100%" }, /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: "100%" }, maxLines > 3 ? /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: "100%", paddingY: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray", dimColor: true }, "[\u{1F4E6} ", maxLines, " lines of text in buffer - Full content will be sent]"), /* @__PURE__ */ React8.createElement(
2758
- Box8,
2979
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, null, statusText && /* @__PURE__ */ React9.createElement(Text9, { color: "magenta", italic: true }, "\u23F3 ", statusText)), /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "(", tempModelOverride || activeModel, ")")), suggestions.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, "\u{1F4A1} Suggestions: "), suggestions.map((s, i) => /* @__PURE__ */ React9.createElement(Text9, { key: s, color: "yellow", bold: i === 0 }, " ", s, " "))), /* @__PURE__ */ React9.createElement(Box9, { backgroundColor: "#333333", paddingX: 1, paddingY: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%" }, maxLines > 3 ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%", paddingY: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "[\u{1F4E6} ", maxLines, " lines of text in buffer - Full content will be sent]"), /* @__PURE__ */ React9.createElement(
2980
+ Box9,
2759
2981
  {
2760
2982
  flexDirection: "row",
2761
2983
  width: "100%",
@@ -2763,8 +2985,8 @@ OUTPUT: ${execOutputRef.current}`;
2763
2985
  overflow: "hidden",
2764
2986
  alignItems: "flex-end"
2765
2987
  },
2766
- /* @__PURE__ */ React8.createElement(Box8, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, "\u276F ")),
2767
- /* @__PURE__ */ React8.createElement(Box8, { flexGrow: 1 }, /* @__PURE__ */ React8.createElement(Box8, { flexGrow: 1, position: "relative" }, input.split("\n").pop() === "" && !isProcessing && /* @__PURE__ */ React8.createElement(Box8, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray", dimColor: true }, "Type your message...")), /* @__PURE__ */ React8.createElement(
2988
+ /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")),
2989
+ /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1 }, /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, position: "relative" }, input.split("\n").pop() === "" && !isProcessing && /* @__PURE__ */ React9.createElement(Box9, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, "Type your message...")), /* @__PURE__ */ React9.createElement(
2768
2990
  MultilineInput,
2769
2991
  {
2770
2992
  value: input.split("\n").pop() || "",
@@ -2781,7 +3003,7 @@ OUTPUT: ${execOutputRef.current}`;
2781
3003
  }
2782
3004
  }
2783
3005
  )))
2784
- )) : /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React8.createElement(Box8, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React8.createElement(Box8, { flexGrow: 1 }, /* @__PURE__ */ React8.createElement(Box8, { flexGrow: 1, position: "relative" }, input === "" && !isProcessing && /* @__PURE__ */ React8.createElement(Box8, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray", dimColor: true }, escPressed ? " Press ESC again to cancel the request." : " Type your message or /command...")), /* @__PURE__ */ React8.createElement(
3006
+ )) : /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")), /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1 }, /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, position: "relative" }, input === "" && !isProcessing && /* @__PURE__ */ React9.createElement(Box9, { position: "absolute", paddingLeft: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true }, escPressed ? " Press ESC again to cancel the request." : " Type your message or /command...")), /* @__PURE__ */ React9.createElement(
2785
3007
  MultilineInput,
2786
3008
  {
2787
3009
  value: input,
@@ -2799,16 +3021,16 @@ OUTPUT: ${execOutputRef.current}`;
2799
3021
  )))))));
2800
3022
  }
2801
3023
  };
2802
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, messages.slice(0, completedIndex).map((msg, idx) => /* @__PURE__ */ React8.createElement(ChatLayout, { key: msg.id || idx, messages: [msg], showFullThinking }))), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", padding: 1, width: "100%" }, activeView === "chat" && /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React8.createElement(ChatLayout, { messages: messages.slice(completedIndex), showFullThinking }), activeCommand && /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(TerminalBox, { command: activeCommand, output: execOutput }))), isInitializing ? /* @__PURE__ */ React8.createElement(Box8, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React8.createElement(Box8, { borderStyle: "bold", borderColor: "yellow", padding: 1, flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow", bold: true }, "\u{1F511} API KEY REQUIRED"), /* @__PURE__ */ React8.createElement(Text8, null, "Please enter your Gemini API Key to initialize the agent's brain."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, "\u276F "), /* @__PURE__ */ React8.createElement(
2803
- TextInput2,
3024
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%" }, windowedHistory.isTruncated && /* @__PURE__ */ React9.createElement(Box9, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1, width: "100%", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(Text9, { color: "gray", dimColor: true, italic: true }, "[ \u2191 History truncated for performance (showing last ~1000 lines) ]")), /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, windowedHistory.items.map((msg, idx) => /* @__PURE__ */ React9.createElement(MessageItem, { key: msg.id || idx, msg, showFullThinking }))), /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", padding: 1, width: "100%" }, (activeView === "chat" || ["ask", "approval", "terminalApproval"].includes(activeView)) && /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React9.createElement(ChatLayout_default, { messages: messages.slice(completedIndex), showFullThinking }), activeCommand && /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(TerminalBox, { command: activeCommand, output: execOutput }))), isInitializing ? /* @__PURE__ */ React9.createElement(Box9, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React9.createElement(Box9, { borderStyle: "bold", borderColor: "yellow", padding: 1, flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", bold: true }, "\u{1F511} API KEY REQUIRED"), /* @__PURE__ */ React9.createElement(Text9, null, "Please enter your Gemini API Key to initialize the agent's brain."), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, "\u276F "), /* @__PURE__ */ React9.createElement(
3025
+ TextInput3,
2804
3026
  {
2805
3027
  value: tempKey,
2806
3028
  onChange: setTempKey,
2807
3029
  onSubmit: handleSetup,
2808
3030
  mask: "*"
2809
3031
  }
2810
- ))) : renderActiveView(), /* @__PURE__ */ React8.createElement(Box8, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React8.createElement(
2811
- StatusBar,
3032
+ ))) : renderActiveView(), /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(
3033
+ StatusBar_default,
2812
3034
  {
2813
3035
  mode,
2814
3036
  thinkingLevel,
@@ -2820,5 +3042,24 @@ OUTPUT: ${execOutputRef.current}`;
2820
3042
  }
2821
3043
 
2822
3044
  // src/cli.jsx
3045
+ process.env.NODE_NO_WARNINGS = "1";
3046
+ var silentPatterns = [
3047
+ "cuimp",
3048
+ "Found existing binary",
3049
+ "Binary verified",
3050
+ "curl.exe not found",
3051
+ "Falling back to .bat file",
3052
+ "DeprecationWarning"
3053
+ ];
3054
+ var originalLog = console.log;
3055
+ var originalWarn = console.warn;
3056
+ var originalError = console.error;
3057
+ var isNoise = (args) => {
3058
+ const msg = args.map(String).join(" ");
3059
+ return silentPatterns.some((p) => msg.includes(p));
3060
+ };
3061
+ console.log = (...args) => !isNoise(args) && originalLog(...args);
3062
+ console.warn = (...args) => !isNoise(args) && originalWarn(...args);
3063
+ console.error = (...args) => !isNoise(args) && originalError(...args);
2823
3064
  process.stdout.write("\x1Bc");
2824
- render(/* @__PURE__ */ React9.createElement(App, null));
3065
+ render(/* @__PURE__ */ React10.createElement(App, null));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.0.13",
3
+ "version": "1.1.1",
4
4
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
5
5
  "keywords": [
6
6
  "ai",