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/README.md +80 -71
- package/UI_FEATURES.md +1 -0
- package/dist/fluxflow.js +469 -268
- package/package.json +1 -1
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";
|
|
@@ -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 /
|
|
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="
|
|
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) >
|
|
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
|
|
1690
|
-
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";
|
|
1691
1770
|
function ResumeModal({ onSelect, onDelete, onClose }) {
|
|
1692
|
-
const [history, setHistory] =
|
|
1693
|
-
const [keys, setKeys] =
|
|
1694
|
-
const [selectedIndex, setSelectedIndex] =
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
1723
|
-
}), /* @__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 ")));
|
|
1724
1803
|
}
|
|
1725
1804
|
|
|
1726
1805
|
// src/components/MemoryModal.jsx
|
|
1727
|
-
import
|
|
1728
|
-
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";
|
|
1729
1808
|
function MemoryModal({ onClose }) {
|
|
1730
|
-
const [memories, setMemories] =
|
|
1731
|
-
const [selectedIndex, setSelectedIndex] =
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
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] =
|
|
1786
|
-
const [mode, setMode] =
|
|
1787
|
-
const [terminalSize, setTerminalSize] =
|
|
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
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
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] =
|
|
1834
|
-
const [pendingApproval, setPendingApproval] =
|
|
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] =
|
|
1845
|
-
const [isProcessing, setIsProcessing] =
|
|
1846
|
-
const [escPressed, setEscPressed] =
|
|
1847
|
-
const [escTimer, setEscTimer] =
|
|
1848
|
-
const [queuedPrompt, setQueuedPrompt] =
|
|
1849
|
-
const [resolutionData, setResolutionData] =
|
|
1850
|
-
const [tempModelOverride, setTempModelOverride] =
|
|
1851
|
-
const [messages, setMessages] =
|
|
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] =
|
|
1856
|
-
|
|
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
|
-
|
|
2102
|
+
stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
1972
2103
|
setChatId(targetId);
|
|
1973
|
-
|
|
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
|
-
|
|
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 (
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
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 =
|
|
2283
|
-
|
|
2284
|
-
|
|
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
|
-
|
|
2298
|
-
|
|
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
|
-
|
|
2309
|
-
|
|
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
|
-
|
|
2321
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2536
|
-
|
|
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__ */
|
|
2726
|
+
)), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
|
|
2566
2727
|
case "stats":
|
|
2567
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2742
|
-
})()), /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2784
|
-
|
|
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__ */
|
|
2793
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2829
|
-
|
|
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__ */
|
|
2837
|
-
|
|
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__ */
|
|
3051
|
+
render(/* @__PURE__ */ React10.createElement(App, null));
|