fluxflow-cli 1.0.12 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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";
@@ -192,9 +215,10 @@ function StatusBar({ mode, thinkingLevel, tokens = "0.0k", chatId = "NEW-SESSION
192
215
  },
193
216
  /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: modeColor, bold: true }, modeIcon, " ", mode.toUpperCase()), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "magenta" }, "\u{1F9E0} ", thinkingLevel)),
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
- /* @__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 / 196e3 * 100), "%)"), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " \u2502 "), /* @__PURE__ */ React3.createElement(Text3, { color: "dim" }, "ID: ", chatId, " "))
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,20 +410,21 @@ 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
- 1. View File: tool:functions.view_file(path="relative/path", start_line=number, end_line=number). Reads file content.
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.
349
417
  2. List Files: tool:functions.list_files(path="relative/path"). Lists content of a directory.
350
418
  3. Read Folder: tool:functions.read_folder(path="relative/path"). Detailed stats of a directory.
351
- 4. Write File: tool:functions.write_file(path="relative/path", content="full content"). Creates/Overwrites a file. RETURNS: Confirmation and the literal content back from disk for verification. DONT WRAP WRITE FILE CALL CONTENT IN MARKDOWN CODE BLOCKS.
352
- 5. Update File: tool:functions.update_file(path="relative/path", content_to_replace="old", content_to_add="new"). Surgical patching. RETURNS: High-fidelity visual diff and old code block. You MUST verify that the change specifically matches your intent using the returned diff. PREFFER UPDATE FILE OVER WRITE FILE if file already exists. DONT WRAP UPDATE FILE CALL CONTENT IN MARKDOWN CODE BLOCKS.
419
+ 4. Write File: tool:functions.write_file(path="path", content="content"). Creates/Overwrites. NO CODE BLOCKS. RETURNS: Disk verification + original content (if overwritten) for 100% reversibility.
420
+ 5. Update File: tool:functions.update_file(path="relative/path", content_to_replace="old", content_to_add="new"). Surgical patching. RETURNS: High-fidelity visual diff and old code block. You MUST verify that the change specifically matches your intent using the returned diff. PREFFER UPDATE FILE OVER WRITE FILE if file already exists for better reversal tracking (if a file has 500+ lines, try to stick with update_file over full-rewrite). DONT WRAP UPDATE FILE CALL CONTENT IN MARKDOWN CODE BLOCKS.
353
421
  6. Execution: tool:functions.exec_command(command="terminal command"). Runs a shell command.`.trim() : `
354
422
  - DEV & FILE TOOLS are not available in FLOW MODE. If you need to access files, tell the user to switch to FLUX MODE (manually by user).`.trim()}
355
423
  -----------------
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.` : ""}
@@ -843,46 +912,6 @@ var chat = async (rawArgs, context = {}) => {
843
912
  }
844
913
  };
845
914
 
846
- // src/tools/summary.js
847
- var summary = async (rawArgs, context = {}) => {
848
- const parseArg = (key) => {
849
- const regex = new RegExp(`${key}\\s*=\\s*(["'])(.*?)\\1(?=\\s*[,)]|\\s+\\w+\\s*=|$)`, "s");
850
- const match = rawArgs.match(regex);
851
- return match ? match[2].trim() : null;
852
- };
853
- const content = parseArg("content");
854
- const chatId = context.chatId;
855
- const { startIndex, endIndex } = context.summarizedIndices || {};
856
- if (!chatId) return "ERROR: No active chatId found in tool context.";
857
- if (!content) return "ERROR: Missing 'content' argument.";
858
- if (startIndex === void 0 || endIndex === void 0) {
859
- return "ERROR: Summary tool called without target range indices in context.";
860
- }
861
- try {
862
- const history = await loadHistory();
863
- if (history[chatId]) {
864
- const messages = history[chatId].messages;
865
- const summaryMsg = {
866
- id: `summary-${Date.now()}`,
867
- role: "system",
868
- text: content
869
- };
870
- const actualStart = Math.min(startIndex, messages.length - 1);
871
- const actualEnd = Math.min(endIndex, messages.length - 1);
872
- const count = actualEnd - actualStart + 1;
873
- if (count > 0) {
874
- messages.splice(actualStart, count, summaryMsg);
875
- await saveChat(chatId, history[chatId].name, messages);
876
- return `SUCCESS: Compressed ${count} turns into a summary block.`;
877
- }
878
- return "ERROR: Targeted range for summarization is invalid or empty.";
879
- }
880
- return "ERROR: Chat session not found.";
881
- } catch (err) {
882
- return `ERROR: Failed to save summary: ${err.message}`;
883
- }
884
- };
885
-
886
915
  // src/tools/list_files.js
887
916
  import fs7 from "fs";
888
917
  import path8 from "path";
@@ -980,6 +1009,21 @@ var write_file = async (args) => {
980
1009
  const absolutePath = path10.resolve(process.cwd(), targetPath);
981
1010
  const parentDir = path10.dirname(absolutePath);
982
1011
  try {
1012
+ let ancestry = "";
1013
+ if (fs9.existsSync(absolutePath)) {
1014
+ try {
1015
+ const oldData = fs9.readFileSync(absolutePath, "utf8");
1016
+ const lines = oldData.split(/\r?\n/);
1017
+ ancestry = `Old File contents:
1018
+ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
1019
+
1020
+ `;
1021
+ } catch (e) {
1022
+ ancestry = `[Note: Could not read existing file for reversal reference]
1023
+
1024
+ `;
1025
+ }
1026
+ }
983
1027
  if (!fs9.existsSync(parentDir)) {
984
1028
  fs9.mkdirSync(parentDir, { recursive: true });
985
1029
  }
@@ -1010,7 +1054,7 @@ ${tail}`;
1010
1054
  return `SUCCESS: File [${targetPath}] verified and persisted.
1011
1055
 
1012
1056
  - Stats: [${verifiedLineCount} lines, ${(verifiedSize / 1024).toFixed(1)} KB]
1013
- - Content Preview:
1057
+ ${ancestry}- Content Preview:
1014
1058
  ${snippet}`;
1015
1059
  } catch (err) {
1016
1060
  return `ERROR: Failed to write file [${targetPath}]: ${err.message}`;
@@ -1181,19 +1225,53 @@ ${formatted}${footer}`;
1181
1225
  }
1182
1226
  };
1183
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
+
1184
1262
  // src/utils/tools.js
1185
1263
  var TOOL_MAP = {
1186
1264
  web_search,
1187
1265
  web_scrape,
1188
1266
  memory,
1189
1267
  chat,
1190
- summary,
1191
1268
  list_files,
1192
1269
  view_file,
1193
1270
  write_file,
1194
1271
  update_file,
1195
1272
  exec_command,
1196
- read_folder
1273
+ read_folder,
1274
+ ask: ask_user
1197
1275
  };
1198
1276
  var dispatchTool = async (toolName, args, context = {}) => {
1199
1277
  const tool = TOOL_MAP[toolName];
@@ -1264,7 +1342,7 @@ var getAIStream = async function* (modelName, history, settings, steeringCallbac
1264
1342
  const needTitle = isFirstPrompt || hasTitleSignal;
1265
1343
  const agentText = originalText.replace(/\[TITLE-UPDATE\]/g, "").trim();
1266
1344
  let modifiedHistory = [...history.slice(0, -1)];
1267
- if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 196e3) {
1345
+ if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 254e3) {
1268
1346
  modifiedHistory = getTruncatedHistory(modifiedHistory, 4);
1269
1347
  }
1270
1348
  const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
@@ -1342,10 +1420,10 @@ USER_PROMPT: ${agentText}`.trim();
1342
1420
  if (retryCount < MAX_RETRIES) {
1343
1421
  retryCount++;
1344
1422
  const waitTime = Math.floor(Math.random() * (2e3 - 800 + 1)) + 800;
1345
- yield { type: "status", content: `Retrying (${retryCount}/${MAX_RETRIES})...` };
1423
+ yield { type: "status", content: `Retrying (${retryCount}/${MAX_RETRIES + 1})...` };
1346
1424
  await new Promise((resolve) => setTimeout(resolve, waitTime));
1347
1425
  } else {
1348
- throw new Error(`Model cannot be reached: ${errMsg}. (Failed ${MAX_RETRIES} times)`);
1426
+ throw new Error(`Model cannot be reached: ${errMsg}. (Failed ${MAX_RETRIES + 1} times)`);
1349
1427
  }
1350
1428
  }
1351
1429
  }
@@ -1412,7 +1490,7 @@ USER_PROMPT: ${agentText}`.trim();
1412
1490
  } else if (toolCall.toolName === "write_file" || toolCall.toolName === "update_file") {
1413
1491
  const action = toolCall.toolName === "write_file" ? "WRITING" : "PATCHING";
1414
1492
  label = `\u{1F4BE} ${action} FILE: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
1415
- } else if (toolCall.toolName === "exec_command") {
1493
+ } else if (toolCall.toolName === "exec_command" || toolCall.toolName === "ask") {
1416
1494
  label = "";
1417
1495
  } else {
1418
1496
  label = `EXECUTING ${toolCall.toolName}`.toUpperCase();
@@ -1498,7 +1576,8 @@ ${boxBottom}
1498
1576
  const result = await dispatchTool(toolCall.toolName, toolCall.args, {
1499
1577
  chatId,
1500
1578
  history,
1501
- onChunk: (chunk) => settings.onExecChunk ? settings.onExecChunk(chunk) : null
1579
+ onChunk: (chunk) => settings.onExecChunk ? settings.onExecChunk(chunk) : null,
1580
+ onAskUser: settings.onAskUser
1502
1581
  });
1503
1582
  if (toolCall.toolName === "exec_command" && settings.onExecEnd) {
1504
1583
  await new Promise((resolve) => setTimeout(resolve, 800));
@@ -1686,12 +1765,12 @@ var saveSettings = async (settings) => {
1686
1765
  };
1687
1766
 
1688
1767
  // src/components/ResumeModal.jsx
1689
- import React6, { useState as useState2, useEffect } from "react";
1690
- 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";
1691
1770
  function ResumeModal({ onSelect, onDelete, onClose }) {
1692
- const [history, setHistory] = useState2({});
1693
- const [keys, setKeys] = useState2([]);
1694
- const [selectedIndex, setSelectedIndex] = useState2(0);
1771
+ const [history, setHistory] = useState3({});
1772
+ const [keys, setKeys] = useState3([]);
1773
+ const [selectedIndex, setSelectedIndex] = useState3(0);
1695
1774
  useEffect(() => {
1696
1775
  const fetchHistory = async () => {
1697
1776
  const h = await loadHistory();
@@ -1700,7 +1779,7 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
1700
1779
  };
1701
1780
  fetchHistory();
1702
1781
  }, []);
1703
- useInput((input, key) => {
1782
+ useInput2((input, key) => {
1704
1783
  if (key.escape) onClose();
1705
1784
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
1706
1785
  if (key.downArrow) setSelectedIndex((prev) => Math.min(keys.length - 1, prev + 1));
@@ -1716,19 +1795,19 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
1716
1795
  });
1717
1796
  }
1718
1797
  });
1719
- 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) => {
1720
1799
  const chat2 = history[id];
1721
1800
  const isSelected = index === selectedIndex;
1722
- 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) ")));
1723
- }), /* @__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 ")));
1724
1803
  }
1725
1804
 
1726
1805
  // src/components/MemoryModal.jsx
1727
- import React7, { useState as useState3, useEffect as useEffect2 } from "react";
1728
- 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";
1729
1808
  function MemoryModal({ onClose }) {
1730
- const [memories, setMemories] = useState3([]);
1731
- const [selectedIndex, setSelectedIndex] = useState3(0);
1809
+ const [memories, setMemories] = useState4([]);
1810
+ const [selectedIndex, setSelectedIndex] = useState4(0);
1732
1811
  const loadMemories = () => {
1733
1812
  const data = readEncryptedJson(MEMORIES_FILE, []);
1734
1813
  setMemories(data);
@@ -1736,7 +1815,7 @@ function MemoryModal({ onClose }) {
1736
1815
  useEffect2(() => {
1737
1816
  loadMemories();
1738
1817
  }, []);
1739
- useInput2((input, key) => {
1818
+ useInput3((input, key) => {
1740
1819
  if (key.escape) onClose();
1741
1820
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
1742
1821
  if (key.downArrow) setSelectedIndex((prev) => Math.min(memories.length - 1, prev + 1));
@@ -1753,12 +1832,14 @@ function MemoryModal({ onClose }) {
1753
1832
  const cleanDisplay = (text) => {
1754
1833
  return text.replace(/\[Saved on: .*?\]/g, "").trim();
1755
1834
  };
1756
- 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")));
1757
1836
  }
1758
1837
 
1759
1838
  // src/app.jsx
1760
1839
  var SESSION_START_TIME = Date.now();
1761
- 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.0";
1842
+ 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(
1762
1843
  CommandMenu,
1763
1844
  {
1764
1845
  title: "Select Action",
@@ -1782,9 +1863,9 @@ var FLUX_LOGO = gradient(["#00ffff", "#0077ff", "#ff00ff"]).multiline(
1782
1863
  );
1783
1864
  function App() {
1784
1865
  const { stdout } = useStdout();
1785
- const [input, setInput] = useState4("");
1786
- const [mode, setMode] = useState4("Flux");
1787
- const [terminalSize, setTerminalSize] = useState4({
1866
+ const [input, setInput] = useState5("");
1867
+ const [mode, setMode] = useState5("Flux");
1868
+ const [terminalSize, setTerminalSize] = useState5({
1788
1869
  columns: stdout?.columns || 80,
1789
1870
  rows: stdout?.rows || 24
1790
1871
  });
@@ -1801,27 +1882,52 @@ function App() {
1801
1882
  stdout.off("resize", handleResize);
1802
1883
  };
1803
1884
  }, [stdout]);
1804
- const [thinkingLevel, setThinkingLevel] = useState4("Medium");
1805
- const [showFullThinking, setShowFullThinking] = useState4(false);
1806
- const [activeModel, setActiveModel] = useState4("gemma-4-31b-it");
1807
- const [janitorModel, setJanitorModel] = useState4("gemma-4-26b-a4b-it");
1808
- const [isInitializing, setIsInitializing] = useState4(true);
1809
- const [apiKey, setApiKey] = useState4(null);
1810
- const [tempKey, setTempKey] = useState4("");
1811
- const [activeView, setActiveView] = useState4("chat");
1812
- const [apiTier, setApiTier] = useState4("Free");
1813
- const [quotas, setQuotas] = useState4({ agentLimit: 1500, backgroundLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
1814
- const [inputConfig, setInputConfig] = useState4(null);
1815
- const [systemSettings, setSystemSettings] = useState4({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d" });
1816
- const [profileData, setProfileData] = useState4({ name: null, nickname: null, instructions: null });
1817
- const [sessionStats, setSessionStats] = useState4({ tokens: 0 });
1818
- const [sessionAgentCalls, setSessionAgentCalls] = useState4(0);
1819
- const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState4(0);
1820
- const [sessionTotalTokens, setSessionTotalTokens] = useState4(0);
1821
- const [dailyUsage, setDailyUsage] = useState4(null);
1822
- const [chatId, setChatId] = useState4(generateChatId());
1823
- const [activeCommand, setActiveCommand] = useState4(null);
1824
- const [execOutput, setExecOutput] = useState4("");
1885
+ useEffect3(() => {
1886
+ const checkVersion = async () => {
1887
+ try {
1888
+ const response = await fetch("https://registry.npmjs.org/fluxflow-cli/latest");
1889
+ const data = await response.json();
1890
+ const latestVersion = data?.version;
1891
+ if (latestVersion && latestVersion !== versionFluxflow) {
1892
+ setMessages((prev) => {
1893
+ const newMsgs = [...prev];
1894
+ newMsgs.splice(1, 0, {
1895
+ id: "update-" + Date.now(),
1896
+ role: "system",
1897
+ text: `\u{1F680} **New version '${latestVersion}' is available!**
1898
+ Type \`npm i -g fluxflow-cli\` to update.
1899
+ Check what's new using \`/changelog\` command.`,
1900
+ isUpdateNotification: true
1901
+ });
1902
+ return newMsgs;
1903
+ });
1904
+ }
1905
+ } catch (err) {
1906
+ }
1907
+ };
1908
+ checkVersion();
1909
+ }, []);
1910
+ const [thinkingLevel, setThinkingLevel] = useState5("Medium");
1911
+ const [showFullThinking, setShowFullThinking] = useState5(false);
1912
+ const [activeModel, setActiveModel] = useState5("gemma-4-31b-it");
1913
+ const [janitorModel, setJanitorModel] = useState5("gemma-4-26b-a4b-it");
1914
+ const [isInitializing, setIsInitializing] = useState5(true);
1915
+ const [apiKey, setApiKey] = useState5(null);
1916
+ const [tempKey, setTempKey] = useState5("");
1917
+ const [activeView, setActiveView] = useState5("chat");
1918
+ const [apiTier, setApiTier] = useState5("Free");
1919
+ const [quotas, setQuotas] = useState5({ agentLimit: 1500, backgroundLimit: 1500, searchLimit: 100, customModelId: "", customLimit: 0 });
1920
+ const [inputConfig, setInputConfig] = useState5(null);
1921
+ const [systemSettings, setSystemSettings] = useState5({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d" });
1922
+ const [profileData, setProfileData] = useState5({ name: null, nickname: null, instructions: null });
1923
+ const [sessionStats, setSessionStats] = useState5({ tokens: 0 });
1924
+ const [sessionAgentCalls, setSessionAgentCalls] = useState5(0);
1925
+ const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState5(0);
1926
+ const [sessionTotalTokens, setSessionTotalTokens] = useState5(0);
1927
+ const [dailyUsage, setDailyUsage] = useState5(null);
1928
+ const [chatId, setChatId] = useState5(generateChatId());
1929
+ const [activeCommand, setActiveCommand] = useState5(null);
1930
+ const [execOutput, setExecOutput] = useState5("");
1825
1931
  const activeCommandRef = useRef(null);
1826
1932
  const execOutputRef = useRef("");
1827
1933
  useEffect3(() => {
@@ -1830,8 +1936,9 @@ function App() {
1830
1936
  useEffect3(() => {
1831
1937
  execOutputRef.current = execOutput;
1832
1938
  }, [execOutput]);
1833
- const [autoAcceptWrites, setAutoAcceptWrites] = useState4(false);
1834
- const [pendingApproval, setPendingApproval] = useState4(null);
1939
+ const [autoAcceptWrites, setAutoAcceptWrites] = useState5(false);
1940
+ const [pendingApproval, setPendingApproval] = useState5(null);
1941
+ const [pendingAsk, setPendingAsk] = useState5(null);
1835
1942
  const formatDuration = (totalSecs) => {
1836
1943
  const h = Math.floor(totalSecs / 3600);
1837
1944
  const m = Math.floor(totalSecs % 3600 / 60);
@@ -1841,19 +1948,43 @@ function App() {
1841
1948
  }
1842
1949
  return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
1843
1950
  };
1844
- const [statusText, setStatusText] = useState4(null);
1845
- const [isProcessing, setIsProcessing] = useState4(false);
1846
- const [escPressed, setEscPressed] = useState4(false);
1847
- const [escTimer, setEscTimer] = useState4(null);
1848
- const [queuedPrompt, setQueuedPrompt] = useState4(null);
1849
- const [resolutionData, setResolutionData] = useState4(null);
1850
- const [tempModelOverride, setTempModelOverride] = useState4(null);
1851
- const [messages, setMessages] = useState4([
1951
+ const [statusText, setStatusText] = useState5(null);
1952
+ const [isProcessing, setIsProcessing] = useState5(false);
1953
+ const [escPressed, setEscPressed] = useState5(false);
1954
+ const [escTimer, setEscTimer] = useState5(null);
1955
+ const [queuedPrompt, setQueuedPrompt] = useState5(null);
1956
+ const [resolutionData, setResolutionData] = useState5(null);
1957
+ const [tempModelOverride, setTempModelOverride] = useState5(null);
1958
+ const [messages, setMessages] = useState5([
1852
1959
  { id: "welcome", role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.\n" }
1853
1960
  ]);
1854
1961
  const queuedPromptRef = useRef(null);
1855
- const [completedIndex, setCompletedIndex] = useState4(1);
1856
- useInput3((inputText, key) => {
1962
+ const [completedIndex, setCompletedIndex] = useState5(1);
1963
+ const windowedHistory = useMemo(() => {
1964
+ const MAX_LINES = 1e3;
1965
+ const width = stdout?.columns || 80;
1966
+ let totalLines = 0;
1967
+ let startIdx = 0;
1968
+ for (let i = completedIndex - 1; i >= 0; i--) {
1969
+ const msg = messages[i];
1970
+ if (!msg) continue;
1971
+ let lines = (msg.text || "").split("\n").length;
1972
+ msg.text.split("\n").forEach((l) => {
1973
+ lines += Math.floor(l.length / width);
1974
+ });
1975
+ lines += msg.role === "think" ? 3 : 2;
1976
+ if (totalLines + lines > MAX_LINES && completedIndex - i > 2) {
1977
+ startIdx = i + 1;
1978
+ break;
1979
+ }
1980
+ totalLines += lines;
1981
+ }
1982
+ return {
1983
+ items: messages.slice(startIdx, completedIndex),
1984
+ isTruncated: startIdx > 0
1985
+ };
1986
+ }, [messages, completedIndex, stdout?.columns]);
1987
+ useInput4((inputText, key) => {
1857
1988
  if (key.escape) {
1858
1989
  if (isProcessing) {
1859
1990
  if (!escPressed) {
@@ -1927,7 +2058,7 @@ function App() {
1927
2058
  setTempKey("");
1928
2059
  }
1929
2060
  };
1930
- const COMMANDS = ["/mode", "/thinking", "/model", "/resume", "/memory", "/profile", "/settings", "/key", "/stats", "/reset", "/help", "/clear", "/quit"];
2061
+ const COMMANDS = ["/mode", "/thinking", "/model", "/resume", "/memory", "/profile", "/settings", "/key", "/stats", "/reset", "/help", "/clear", "/quit", "/changelog"];
1931
2062
  const handleSubmit = (value) => {
1932
2063
  const normalizedValue = value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimEnd();
1933
2064
  if (normalizedValue.endsWith("\\")) {
@@ -1968,9 +2099,14 @@ ${hintText}`, color: "magenta" }];
1968
2099
  const h = await loadHistory();
1969
2100
  const target = h[targetId] || Object.values(h).find((h2) => h2.name.toLowerCase() === targetId.toLowerCase());
1970
2101
  if (target) {
1971
- process.stdout.write("\x1Bc");
2102
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
1972
2103
  setChatId(targetId);
1973
- setMessages(target.messages);
2104
+ const resumedMsgs = [...target.messages];
2105
+ const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
2106
+ if (!hasLogo) {
2107
+ resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...\n" });
2108
+ }
2109
+ setMessages(resumedMsgs);
1974
2110
  setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${targetId}]` }]);
1975
2111
  setCompletedIndex(0);
1976
2112
  } else {
@@ -1984,7 +2120,7 @@ ${hintText}`, color: "magenta" }];
1984
2120
  break;
1985
2121
  }
1986
2122
  case "/clear": {
1987
- process.stdout.write("\x1Bc");
2123
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
1988
2124
  setMessages([{ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Welcome back to Flux Flow! Context cleared.\n" }]);
1989
2125
  setCompletedIndex(0);
1990
2126
  setChatId(generateChatId());
@@ -2128,6 +2264,16 @@ ${list || "No saved chats found."}` }];
2128
2264
  runReset();
2129
2265
  break;
2130
2266
  }
2267
+ case "/changelog": {
2268
+ const platform = process.platform;
2269
+ const command = platform === "win32" ? "start" : platform === "darwin" ? "open" : "xdg-open";
2270
+ exec(`${command} ${CHANGELOG_URL}`);
2271
+ setMessages((prev) => {
2272
+ setCompletedIndex(prev.length + 1);
2273
+ return [...prev, { id: Date.now(), role: "system", text: `\u{1F310} [BROWSER] Opening changelog: ${CHANGELOG_URL}` }];
2274
+ });
2275
+ break;
2276
+ }
2131
2277
  case "/help": {
2132
2278
  setMessages((prev) => {
2133
2279
  setCompletedIndex(prev.length + 1);
@@ -2200,23 +2346,47 @@ OUTPUT: ${execOutputRef.current}`;
2200
2346
  setPendingApproval({ tool, args, resolve });
2201
2347
  setActiveView("approval");
2202
2348
  });
2349
+ },
2350
+ onAskUser: async (question, options) => {
2351
+ return new Promise((resolve) => {
2352
+ setPendingAsk({
2353
+ question,
2354
+ options,
2355
+ resolve: (val) => {
2356
+ setMessages((prev) => [
2357
+ ...prev,
2358
+ {
2359
+ id: "ask-" + Date.now(),
2360
+ role: "system",
2361
+ text: `\u{1F4AC} **Ask User**
2362
+ Selection: ${val}`,
2363
+ isAskRecord: true
2364
+ }
2365
+ ]);
2366
+ resolve(val);
2367
+ }
2368
+ });
2369
+ setActiveView("ask");
2370
+ });
2203
2371
  }
2204
2372
  },
2205
- async () => {
2206
- if (queuedPromptRef.current) {
2207
- const p = queuedPromptRef.current;
2208
- setQueuedPrompt(null);
2209
- queuedPromptRef.current = null;
2210
- setMessages((prev) => {
2211
- const newMsgs = [...prev];
2212
- const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]"));
2213
- if (hintMsg) {
2214
- hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: INJECTED]");
2215
- hintMsg.color = "cyan";
2216
- }
2217
- return newMsgs.reverse();
2218
- });
2219
- return p;
2373
+ async (hint) => {
2374
+ if (queuedPrompt) {
2375
+ if (queuedPromptRef.current) {
2376
+ const p = queuedPromptRef.current;
2377
+ setQueuedPrompt(null);
2378
+ queuedPromptRef.current = null;
2379
+ setMessages((prev) => {
2380
+ const newMsgs = [...prev];
2381
+ const hintMsg = newMsgs.reverse().find((m) => m.text?.includes("[STEERING HINT: QUEUED]"));
2382
+ if (hintMsg) {
2383
+ hintMsg.text = hintMsg.text.replace("[STEERING HINT: QUEUED]", "[STEERING HINT: INJECTED]");
2384
+ hintMsg.color = "cyan";
2385
+ }
2386
+ return newMsgs.reverse();
2387
+ });
2388
+ return p;
2389
+ }
2220
2390
  }
2221
2391
  return null;
2222
2392
  }
@@ -2279,9 +2449,9 @@ OUTPUT: ${execOutputRef.current}`;
2279
2449
  const [thinkPart, agentPart] = chunkText.split("</think>");
2280
2450
  if (inThinkMode) {
2281
2451
  setMessages((prev) => {
2282
- const newMsgs = [...prev];
2283
- const thinkMsg = newMsgs.find((m) => m.id === currentThinkId);
2284
- if (thinkMsg) thinkMsg.text += thinkPart.replace(signalRegex, "");
2452
+ const newMsgs = prev.map(
2453
+ (m) => m.id === currentThinkId ? { ...m, text: m.text + thinkPart.replace(signalRegex, "") } : m
2454
+ );
2285
2455
  currentAgentId = "agent-" + Date.now();
2286
2456
  const cleanedAgentPart = (agentPart || "").replace(signalRegex, "");
2287
2457
  return [...newMsgs, { id: currentAgentId, role: "agent", text: cleanedAgentPart }];
@@ -2293,35 +2463,26 @@ OUTPUT: ${execOutputRef.current}`;
2293
2463
  currentAgentId = "agent-" + Date.now();
2294
2464
  setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: cleanedContent }]);
2295
2465
  } else {
2296
- setMessages((prev) => {
2297
- const newMsgs = [...prev];
2298
- const msg = newMsgs.find((m) => m.id === currentAgentId);
2299
- if (msg) msg.text += cleanedContent;
2300
- return newMsgs;
2301
- });
2466
+ setMessages((prev) => prev.map(
2467
+ (m) => m.id === currentAgentId ? { ...m, text: m.text + cleanedContent } : m
2468
+ ));
2302
2469
  }
2303
2470
  }
2304
2471
  continue;
2305
2472
  }
2306
2473
  if (inThinkMode && currentThinkId) {
2307
- setMessages((prev) => {
2308
- const newMsgs = [...prev];
2309
- const msg = newMsgs.find((m) => m.id === currentThinkId);
2310
- if (msg) msg.text += chunkText.replace(signalRegex, "");
2311
- return newMsgs;
2312
- });
2474
+ setMessages((prev) => prev.map(
2475
+ (m) => m.id === currentThinkId ? { ...m, text: m.text + chunkText.replace(signalRegex, "") } : m
2476
+ ));
2313
2477
  } else if (!inThinkMode) {
2314
2478
  const cleanedText = chunkText.replace(/<\/?think>/gi, "").replace(signalRegex, "");
2315
2479
  if (!currentAgentId) {
2316
2480
  currentAgentId = "agent-" + Date.now();
2317
2481
  setMessages((prev) => [...prev, { id: currentAgentId, role: "agent", text: cleanedText }]);
2318
2482
  } else {
2319
- setMessages((prev) => {
2320
- const newMsgs = [...prev];
2321
- const msg = newMsgs.find((m) => m.id === currentAgentId);
2322
- if (msg) msg.text += cleanedText;
2323
- return newMsgs;
2324
- });
2483
+ setMessages((prev) => prev.map(
2484
+ (m) => m.id === currentAgentId ? { ...m, text: m.text + cleanedText } : m
2485
+ ));
2325
2486
  }
2326
2487
  }
2327
2488
  }
@@ -2368,7 +2529,7 @@ OUTPUT: ${execOutputRef.current}`;
2368
2529
  const renderActiveView = () => {
2369
2530
  switch (activeView) {
2370
2531
  case "mode":
2371
- return /* @__PURE__ */ React8.createElement(
2532
+ return /* @__PURE__ */ React9.createElement(
2372
2533
  CommandMenu,
2373
2534
  {
2374
2535
  title: "\u26A1 Select Operating Mode",
@@ -2397,7 +2558,7 @@ OUTPUT: ${execOutputRef.current}`;
2397
2558
  { label: "Max (Architecture)", value: "Max" }
2398
2559
  ];
2399
2560
  options.push({ label: "Cancel", value: "Cancel" });
2400
- return /* @__PURE__ */ React8.createElement(
2561
+ return /* @__PURE__ */ React9.createElement(
2401
2562
  CommandMenu,
2402
2563
  {
2403
2564
  title: `\u{1F9E0} Select Thinking Level (${mode} Mode)`,
@@ -2410,7 +2571,7 @@ OUTPUT: ${execOutputRef.current}`;
2410
2571
  );
2411
2572
  }
2412
2573
  case "model":
2413
- return /* @__PURE__ */ React8.createElement(
2574
+ return /* @__PURE__ */ React9.createElement(
2414
2575
  CommandMenu,
2415
2576
  {
2416
2577
  title: "\u{1F916} Select AI Model",
@@ -2422,7 +2583,7 @@ OUTPUT: ${execOutputRef.current}`;
2422
2583
  }
2423
2584
  );
2424
2585
  case "settings":
2425
- return /* @__PURE__ */ React8.createElement(
2586
+ return /* @__PURE__ */ React9.createElement(
2426
2587
  CommandMenu,
2427
2588
  {
2428
2589
  title: "System Settings",
@@ -2467,7 +2628,7 @@ OUTPUT: ${execOutputRef.current}`;
2467
2628
  }
2468
2629
  );
2469
2630
  case "apiTier":
2470
- return /* @__PURE__ */ React8.createElement(
2631
+ return /* @__PURE__ */ React9.createElement(
2471
2632
  CommandMenu,
2472
2633
  {
2473
2634
  title: `API Tier: ${apiTier}`,
@@ -2532,8 +2693,8 @@ OUTPUT: ${execOutputRef.current}`;
2532
2693
  }
2533
2694
  );
2534
2695
  case "input":
2535
- 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(
2536
- TextInput2,
2696
+ 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(
2697
+ TextInput3,
2537
2698
  {
2538
2699
  value: inputConfig?.value || "",
2539
2700
  onChange: (val) => setInputConfig((prev) => ({ ...prev, value: val })),
@@ -2562,11 +2723,11 @@ OUTPUT: ${execOutputRef.current}`;
2562
2723
  }
2563
2724
  }
2564
2725
  }
2565
- )), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
2726
+ )), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
2566
2727
  case "stats":
2567
- 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)"));
2728
+ 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)"));
2568
2729
  case "autoExecDanger":
2569
- 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(
2730
+ 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(
2570
2731
  CommandMenu,
2571
2732
  {
2572
2733
  title: "Confirm Intent",
@@ -2583,7 +2744,7 @@ OUTPUT: ${execOutputRef.current}`;
2583
2744
  }
2584
2745
  )));
2585
2746
  case "externalDanger":
2586
- 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(
2747
+ 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(
2587
2748
  CommandMenu,
2588
2749
  {
2589
2750
  title: "Confirm Intent",
@@ -2600,7 +2761,7 @@ OUTPUT: ${execOutputRef.current}`;
2600
2761
  }
2601
2762
  )));
2602
2763
  case "doubleDanger":
2603
- 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(
2764
+ 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(
2604
2765
  CommandMenu,
2605
2766
  {
2606
2767
  title: "Final Confirmation",
@@ -2617,7 +2778,7 @@ OUTPUT: ${execOutputRef.current}`;
2617
2778
  }
2618
2779
  )));
2619
2780
  case "key":
2620
- return /* @__PURE__ */ React8.createElement(
2781
+ return /* @__PURE__ */ React9.createElement(
2621
2782
  CommandMenu,
2622
2783
  {
2623
2784
  title: "\u{1F511} API KEY MANAGEMENT",
@@ -2640,7 +2801,7 @@ OUTPUT: ${execOutputRef.current}`;
2640
2801
  }
2641
2802
  );
2642
2803
  case "deleteKey":
2643
- 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(
2804
+ 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(
2644
2805
  CommandMenu,
2645
2806
  {
2646
2807
  title: "Are you absolutely sure?",
@@ -2661,7 +2822,7 @@ OUTPUT: ${execOutputRef.current}`;
2661
2822
  }
2662
2823
  )));
2663
2824
  case "exit":
2664
- 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(
2825
+ 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(
2665
2826
  CommandMenu,
2666
2827
  {
2667
2828
  title: "Exit Confirmation",
@@ -2678,15 +2839,36 @@ OUTPUT: ${execOutputRef.current}`;
2678
2839
  }
2679
2840
  }
2680
2841
  )));
2842
+ case "ask":
2843
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%" }, /* @__PURE__ */ React9.createElement(
2844
+ AskUserModal_default,
2845
+ {
2846
+ question: pendingAsk?.question,
2847
+ options: pendingAsk?.options,
2848
+ onResolve: (choice) => {
2849
+ if (pendingAsk?.resolve) {
2850
+ pendingAsk.resolve(choice);
2851
+ }
2852
+ setPendingAsk(null);
2853
+ setActiveView("chat");
2854
+ }
2855
+ }
2856
+ ));
2681
2857
  case "resume":
2682
- return /* @__PURE__ */ React8.createElement(Box8, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React8.createElement(
2858
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(
2683
2859
  ResumeModal,
2684
2860
  {
2685
2861
  onSelect: async (id) => {
2686
2862
  const h = await loadHistory();
2687
2863
  if (h[id]) {
2864
+ stdout.write("\x1B[2J\x1B[3J\x1B[H");
2688
2865
  setChatId(id);
2689
- setMessages(h[id].messages);
2866
+ const resumedMsgs = [...h[id].messages];
2867
+ const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
2868
+ if (!hasLogo) {
2869
+ resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...\n" });
2870
+ }
2871
+ setMessages(resumedMsgs);
2690
2872
  setActiveView("chat");
2691
2873
  setMessages((prev) => [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${id}]` }]);
2692
2874
  setCompletedIndex(0);
@@ -2700,9 +2882,9 @@ OUTPUT: ${execOutputRef.current}`;
2700
2882
  }
2701
2883
  ));
2702
2884
  case "memory":
2703
- return /* @__PURE__ */ React8.createElement(Box8, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React8.createElement(MemoryModal, { onClose: () => setActiveView("chat") }));
2885
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(MemoryModal, { onClose: () => setActiveView("chat") }));
2704
2886
  case "profile":
2705
- return /* @__PURE__ */ React8.createElement(
2887
+ return /* @__PURE__ */ React9.createElement(
2706
2888
  ProfileForm,
2707
2889
  {
2708
2890
  onSave: (profile) => {
@@ -2714,7 +2896,7 @@ OUTPUT: ${execOutputRef.current}`;
2714
2896
  }
2715
2897
  );
2716
2898
  case "resolution":
2717
- return /* @__PURE__ */ React8.createElement(Box8, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React8.createElement(
2899
+ return /* @__PURE__ */ React9.createElement(Box9, { width: "100%", alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React9.createElement(
2718
2900
  ResolutionModal,
2719
2901
  {
2720
2902
  data: resolutionData,
@@ -2731,15 +2913,15 @@ OUTPUT: ${execOutputRef.current}`;
2731
2913
  }
2732
2914
  ));
2733
2915
  case "approval":
2734
- 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 ---"), (() => {
2916
+ 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 ---"), (() => {
2735
2917
  const args = parseArgs(pendingApproval?.args || "{}");
2736
2918
  const oldVal = args.TargetContent || args.content_to_replace || null;
2737
2919
  const newVal = args.content || args.ReplacementContent || args.content_to_add || args.replacementContent || null;
2738
2920
  if (oldVal && newVal) {
2739
- 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)));
2921
+ 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)));
2740
2922
  }
2741
- return /* @__PURE__ */ React8.createElement(Text8, { color: "white", wrap: "anywhere" }, newVal || "Updating file content...");
2742
- })()), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(
2923
+ return /* @__PURE__ */ React9.createElement(Text9, { color: "white", wrap: "anywhere" }, newVal || "Updating file content...");
2924
+ })()), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
2743
2925
  CommandMenu,
2744
2926
  {
2745
2927
  title: "Action Required",
@@ -2758,7 +2940,7 @@ OUTPUT: ${execOutputRef.current}`;
2758
2940
  }
2759
2941
  )));
2760
2942
  case "terminalApproval":
2761
- 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(
2943
+ 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(
2762
2944
  CommandMenu,
2763
2945
  {
2764
2946
  title: "Risk Assessment Required",
@@ -2780,8 +2962,8 @@ OUTPUT: ${execOutputRef.current}`;
2780
2962
  return acc + Math.max(1, Math.ceil(line.length / wrapWidth));
2781
2963
  }, 0);
2782
2964
  const maxLines = Math.max(1, wrappedLines);
2783
- 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(
2784
- Box8,
2965
+ 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(
2966
+ Box9,
2785
2967
  {
2786
2968
  flexDirection: "row",
2787
2969
  width: "100%",
@@ -2789,8 +2971,8 @@ OUTPUT: ${execOutputRef.current}`;
2789
2971
  overflow: "hidden",
2790
2972
  alignItems: "flex-end"
2791
2973
  },
2792
- /* @__PURE__ */ React8.createElement(Box8, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, "\u276F ")),
2793
- /* @__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(
2974
+ /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: 3 }, /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u276F ")),
2975
+ /* @__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(
2794
2976
  MultilineInput,
2795
2977
  {
2796
2978
  value: input.split("\n").pop() || "",
@@ -2807,7 +2989,7 @@ OUTPUT: ${execOutputRef.current}`;
2807
2989
  }
2808
2990
  }
2809
2991
  )))
2810
- )) : /* @__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(
2992
+ )) : /* @__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(
2811
2993
  MultilineInput,
2812
2994
  {
2813
2995
  value: input,
@@ -2825,16 +3007,16 @@ OUTPUT: ${execOutputRef.current}`;
2825
3007
  )))))));
2826
3008
  }
2827
3009
  };
2828
- 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(
2829
- TextInput2,
3010
+ 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(
3011
+ TextInput3,
2830
3012
  {
2831
3013
  value: tempKey,
2832
3014
  onChange: setTempKey,
2833
3015
  onSubmit: handleSetup,
2834
3016
  mask: "*"
2835
3017
  }
2836
- ))) : renderActiveView(), /* @__PURE__ */ React8.createElement(Box8, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React8.createElement(
2837
- StatusBar,
3018
+ ))) : renderActiveView(), /* @__PURE__ */ React9.createElement(Box9, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React9.createElement(
3019
+ StatusBar_default,
2838
3020
  {
2839
3021
  mode,
2840
3022
  thinkingLevel,
@@ -2846,5 +3028,24 @@ OUTPUT: ${execOutputRef.current}`;
2846
3028
  }
2847
3029
 
2848
3030
  // src/cli.jsx
3031
+ process.env.NODE_NO_WARNINGS = "1";
3032
+ var silentPatterns = [
3033
+ "cuimp",
3034
+ "Found existing binary",
3035
+ "Binary verified",
3036
+ "curl.exe not found",
3037
+ "Falling back to .bat file",
3038
+ "DeprecationWarning"
3039
+ ];
3040
+ var originalLog = console.log;
3041
+ var originalWarn = console.warn;
3042
+ var originalError = console.error;
3043
+ var isNoise = (args) => {
3044
+ const msg = args.map(String).join(" ");
3045
+ return silentPatterns.some((p) => msg.includes(p));
3046
+ };
3047
+ console.log = (...args) => !isNoise(args) && originalLog(...args);
3048
+ console.warn = (...args) => !isNoise(args) && originalWarn(...args);
3049
+ console.error = (...args) => !isNoise(args) && originalError(...args);
2849
3050
  process.stdout.write("\x1Bc");
2850
- render(/* @__PURE__ */ React9.createElement(App, null));
3051
+ render(/* @__PURE__ */ React10.createElement(App, null));