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