fluxflow-cli 1.6.6 → 1.7.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 +5 -2
- package/TOOLS.md +9 -0
- package/dist/fluxflow.js +247 -75
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -32,8 +32,11 @@ Experience a terminal UI that feels alive. Built with **Ink** and **React**, Flu
|
|
|
32
32
|
### 👁️ **Native Multimodality**
|
|
33
33
|
Flux Flow can now see! Use the `view_file` tool to analyze images (JPG, PNG) or deep-dive into PDF technical papers. The agent extracts high-fidelity visual context natively, making it a true multimodal companion.
|
|
34
34
|
|
|
35
|
-
### 📑 **
|
|
36
|
-
Need a report? Just ask. Flux Flow
|
|
35
|
+
### 📑 **Document Engineering Suite**
|
|
36
|
+
Need a report or a presentation? Just ask. Flux Flow features a high-fidelity "Printing Press" that generates professional, branded documents natively:
|
|
37
|
+
- **PDF**: Branded documents from HTML/CSS with automatic watermarking.
|
|
38
|
+
- **DOCX**: Native Word documents with multi-page support and automatic numbering.
|
|
39
|
+
- **PPTX**: High-fidelity PowerPoint presentations using native elements (selectable text, shapes) translated directly from HTML.
|
|
37
40
|
|
|
38
41
|
### 🚑 **Self-Healing Infrastructure**
|
|
39
42
|
Zero setup means zero setup. On first run, Flux Flow performs an integrity check and autonomously installs its own Chromium engine if needed, ensuring features like PDF generation work 100% of the time without manual intervention.
|
package/TOOLS.md
CHANGED
|
@@ -9,6 +9,8 @@ Flux Flow provides a robust set of tools that allow the AI to interact with the
|
|
|
9
9
|
| **Web Search** | ✅ | ✅ |
|
|
10
10
|
| **Web Scrape** | ✅ | ✅ |
|
|
11
11
|
| **Write PDF** | ✅ | ✅ |
|
|
12
|
+
| **Write DOCX** | ✅ | ✅ |
|
|
13
|
+
| **Write PPTX** | ✅ | ✅ |
|
|
12
14
|
| **View/Read Files** | ✅ | ❌ |
|
|
13
15
|
| **Write/Update Files** | ✅ | ❌ |
|
|
14
16
|
| **Execute Commands** | ✅ | ❌ |
|
|
@@ -20,7 +22,14 @@ Flux Flow provides a robust set of tools that allow the AI to interact with the
|
|
|
20
22
|
### 🌐 Web & Research
|
|
21
23
|
- **`web_search`**: Uses DuckDuckGo to find up-to-date information on the internet. Crucial for answering questions about recent events or unlearned documentation.
|
|
22
24
|
- **`web_scrape`**: Extracts the detailed text content from a specific URL, allowing the agent to read documentation or articles.
|
|
25
|
+
|
|
26
|
+
### 📄 Document Engineering (The Office Suite)
|
|
23
27
|
- **`write_pdf`**: Generates high-fidelity, branded PDF documents from HTML/CSS. Features automatic watermarking and page-aware layout management.
|
|
28
|
+
- **`write_docx`**: Generates professional Word documents (.docx) from HTML. Supports multi-page layouts, automatic page numbering, and native styling.
|
|
29
|
+
- **`write_pptx`**: Generates high-fidelity, native PowerPoint presentations (.pptx) from HTML.
|
|
30
|
+
- **Native Translation**: Uses `html2pptxgenjs` to translate HTML tags (`<h1>`, `<ul>`, `<b>`) directly into selectable PowerPoint text objects.
|
|
31
|
+
- **Rich Styling**: Supports CSS-like properties (color, font-size, text-align) for professional slide design.
|
|
32
|
+
- **Flat Protocol**: Optimized for AI stability using a flat HTML string interface.
|
|
24
33
|
|
|
25
34
|
### 📁 File System Operations
|
|
26
35
|
- **`list_files`**: Lists the contents of a directory to help the agent understand the project structure.
|
package/dist/fluxflow.js
CHANGED
|
@@ -178,9 +178,12 @@ var init_ChatLayout = __esm({
|
|
|
178
178
|
};
|
|
179
179
|
TableRenderer = React2.memo(({ buffer, terminalWidth = 80 }) => {
|
|
180
180
|
if (buffer.length < 2) return null;
|
|
181
|
-
const rows = buffer.map(
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
const rows = buffer.map((line) => {
|
|
182
|
+
const parts = line.split("|");
|
|
183
|
+
if (parts[0] !== void 0 && parts[0].trim() === "") parts.shift();
|
|
184
|
+
if (parts.length > 0 && parts[parts.length - 1].trim() === "") parts.pop();
|
|
185
|
+
return parts.map((cell) => cell.trim());
|
|
186
|
+
});
|
|
184
187
|
const header = rows[0];
|
|
185
188
|
const data = rows.slice(2);
|
|
186
189
|
const colPercentage = Math.floor(100 / header.length);
|
|
@@ -208,7 +211,7 @@ var init_ChatLayout = __esm({
|
|
|
208
211
|
};
|
|
209
212
|
lines.forEach((line, i) => {
|
|
210
213
|
const trimmed = line.trim();
|
|
211
|
-
const isTableRow = trimmed.startsWith("|")
|
|
214
|
+
const isTableRow = trimmed.startsWith("|");
|
|
212
215
|
const isQuote = trimmed.startsWith(">");
|
|
213
216
|
if (isTableRow) {
|
|
214
217
|
if (quoteBuffer.length > 0) flushBuffers(i);
|
|
@@ -289,7 +292,7 @@ var init_ChatLayout = __esm({
|
|
|
289
292
|
const match = part.match(/```(\w*)\n([\s\S]*?)```/);
|
|
290
293
|
const lang = match ? match[1] : "code";
|
|
291
294
|
const code = match ? match[2] : part.slice(3, -3);
|
|
292
|
-
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"
|
|
295
|
+
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" }, wrapText(code.trim(), columns - 6))));
|
|
293
296
|
}
|
|
294
297
|
return /* @__PURE__ */ React2.createElement(MarkdownText, { key: i, text: part, columns });
|
|
295
298
|
}));
|
|
@@ -667,25 +670,35 @@ var init_main_tools = __esm({
|
|
|
667
670
|
You have access to internal tools. To call a tool, you MUST use the following exact syntax on a new line:
|
|
668
671
|
tool:functions.tool_name(arguments)
|
|
669
672
|
|
|
673
|
+
- USER COMMUNICATION TOOLS (Available in Flux & Flow) -
|
|
674
|
+
1. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). Generally use this tool for ANY ambiguity. Mandatory triggers include: 1) **Path Divergence**: When multiple architectural or technical solutions exist, present options via 'ask' instead of choosing arbitrarily. 2) **Security Boundaries**: Explicitly request permission via 'ask' before accessing sensitive files (e.g., .env, config keys, credentials). 3) **Ambiguity Resolution**: Use 'ask' to clarify vague prompts before executing terminal commands or writing code. 4) **Risk Mitigation**: Require a 'Yes/No' confirmation for any destructive or irreversible operations. Options must always follow the 'Short Label::Detailed Description' format. This tool is a non-terminating suspension so you can get guidance without losing context. PREFER USING THIS TOOL RATHER THAN FINISHING THE LOOP FOR USER CLARIFICATION.
|
|
675
|
+
|
|
670
676
|
- WEB TOOLS (Available in Flux & Flow) -
|
|
671
677
|
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.
|
|
672
678
|
2. Web Scrape: tool:functions.web_scrape(url="<url>"). provides detail from a URL.
|
|
673
|
-
3. Ask User: tool:functions.ask(question="...", optionA="Option::Desc", optionB="Option::Desc"). Generally use this tool for ANY ambiguity. Mandatory triggers include: 1) **Path Divergence**: When multiple architectural or technical solutions exist, present options via 'ask' instead of choosing arbitrarily. 2) **Security Boundaries**: Explicitly request permission via 'ask' before accessing sensitive files (e.g., .env, config keys, credentials). 3) **Ambiguity Resolution**: Use 'ask' to clarify vague prompts before executing terminal commands or writing code. 4) **Risk Mitigation**: Require a 'Yes/No' confirmation for any destructive or irreversible operations. Options must always follow the 'Short Label::Detailed Description' format. This tool is a non-terminating suspension so you can get guidance without losing context.
|
|
674
679
|
${mode === "Flux" ? `
|
|
675
680
|
- DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
|
|
676
681
|
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. You can also use this tool to read images & documents.
|
|
677
682
|
2. List Files: tool:functions.list_files(path="relative/path"). Lists content of a directory.
|
|
678
683
|
3. Read Folder: tool:functions.read_folder(path="relative/path"). Detailed stats of a directory.
|
|
679
|
-
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. Escape your double quotes '"' using backslash
|
|
684
|
+
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. Escape your double quotes '"' using backslash.
|
|
680
685
|
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.
|
|
681
|
-
6. Write PDF: tool:functions.write_pdf(path="path", content="<html/css content>", orientation="portrait/landscape"). Generates a professional PDF document. Orientation are optional. A4 size page will be used, so any multi-page PDFs calculate your alightment and page breaks to not mess up A4 page layout. DO NOT ADD FOOTER MANUALLY, the system will handle it automatically. USE CSS TO VISUALLY BEAUTIFY THE DOCUMENT, USE full 100vh & 100vw for page area. ENSURE THE CONTENT IS NEVER BROKEN IN BETWEEN PAGES, USE PAGE BREAKS PROACTIVELY FOR A A4 PAGE LAYOUT.
|
|
682
|
-
7.
|
|
686
|
+
6. Write PDF: tool:functions.write_pdf(path="path", content="<html/css content>", orientation="portrait/landscape"). Generates a professional PDF document. Orientation are optional. A4 size page will be used, so any multi-page PDFs calculate your alightment and page breaks to not mess up A4 page layout. DO NOT ADD FOOTER MANUALLY, the system will handle it automatically. USE CSS TO VISUALLY BEAUTIFY THE DOCUMENT, USE full 100vh & 100vw for page area. ENSURE THE CONTENT IS NEVER BROKEN IN BETWEEN PAGES, USE PAGE BREAKS PROACTIVELY FOR A A4 PAGE LAYOUT. Keep generous margins for better redability.
|
|
687
|
+
7. Write DOCX: tool:functions.write_docx(path="path", content="<html content>"). Generates a professional Word document (.docx) from HTML. You can make multiple pages. Default Page dimentions will be A4, use proper margins and page break strategy.
|
|
688
|
+
8. Write PPTX: tool:functions.write_pptx(path="path", content="<h1 style='color: #0088CC;'>Title</h1><ul style='font-size: 14pt;'><li>Point A</li></ul>
|
|
689
|
+
---
|
|
690
|
+
<p align='center'>Styled Slide</p>"). Generates a professional PowerPoint presentation (.pptx) from a flat HTML string. Use '---' on a new line to separate slides. Aspect Ratio is 4:3.
|
|
691
|
+
- Supported Tags: <a>, <b>, <br>, <del>, <font>, <h1>-<h6>, <i>, <ol>, <ul>, <li>, <p>, <pre>, <s>, <sub>, <sup>, <u>.
|
|
692
|
+
- Supported Styles: background-color, color, font-family, font-size (use 'pt'), font-style (italic), font-weight (bold), margin, text-align, text-shadow.
|
|
693
|
+
- High-fidelity conversion to native PPTX text.
|
|
694
|
+
9. Execution: tool:functions.exec_command(command="terminal command"). Runs a shell command. Use ask tool to confirm before executing any destructive or irreversible operations.
|
|
683
695
|
|
|
684
696
|
AFTER GETTING THE TOOL RESULT, YOU MUST VERIFY THAT ITS A SUCCESS, IF IT GIVES A ERROR, TELL THE USER AND TRY TO FIX IF YOU CAN. DO NOT HALLUCINATE SUCCESS IF TOOL RETURNS ERROR.
|
|
685
697
|
|
|
686
698
|
**CRITICAL POLICY: WHEN WRITING/UPDATING FILES, USE ACTUAL NEW LINE CONTROL CHARACTER (LF) FOR LINE BREAKS RATHER THAN STRING '\\n'**`.trim() : `
|
|
687
699
|
- 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()}
|
|
688
700
|
-----------------
|
|
701
|
+
|
|
689
702
|
Results will be provided in the next loop as: [TOOL_RESULT]: [content]
|
|
690
703
|
WHEN CALLING TOOLS, YOU **MUST** end your response with '[turn: continue]'. NEVER use '[turn: finish]' in the same turn as a tool call. After receiving the [TOOL_RESULT], acknowledge the output and verify if the goal is met; only then may you use '[turn: finish]', otherwise use '[turn: continue]'.
|
|
691
704
|
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.
|
|
@@ -771,11 +784,11 @@ ${userMemories}
|
|
|
771
784
|
` : ""}${isMemoryEnabled ? `${tempMemoriesStr}
|
|
772
785
|
|
|
773
786
|
` : ""}--- START SYSTEM INSTRUCTION ---
|
|
774
|
-
You are Flux Flow (made by Kushal Roy Chowdhury/Flux Flow Team). A CLI Agent. Your tone will be friendly, warm, sassy, approchable, funny, NO ROMANTIC OR FLIRTY WORDS. Dont mention modes unless explicitly asked. ${mode === "Flux" ? "You are currently operating in FLUX (dev) mode. Keep your agentic approach goal oriented. Use provided tools when needed. And try to minimize number of agentic loops (Agent Loop is limited to 50 per turn, finish your goal by then). Analyze user prompt and project requirements, then plan your approach." : "You are currently operating in Flow (chat) mode. Focus more on conversation quality and user experience. Keep Agentic Loops to minimum (Agent Loop is limited to 7 per turn, finish your goal by then). You will get access to Web Tools only in this mode."}
|
|
787
|
+
You are Flux Flow (made by Kushal Roy Chowdhury/Flux Flow Team). A CLI Agent. Your tone will be friendly, warm, sassy, approchable, funny, NO ROMANTIC OR FLIRTY WORDS. Dont mention modes unless explicitly asked. ${mode === "Flux" ? "You are currently operating in FLUX (dev) mode. Keep your agentic approach goal oriented, conversation quality and user experience. Use provided tools when needed. And try to minimize number of agentic loops (Agent Loop is limited to 50 per turn, finish your goal by then). Analyze user prompt and project requirements, then plan your approach." : "You are currently operating in Flow (chat) mode. Focus more on conversation quality and user experience. Keep Agentic Loops to minimum (Agent Loop is limited to 7 per turn, finish your goal by then). You will get access to Web Tools only in this mode."}
|
|
775
788
|
CURRENT_WORKING_DIRECTORY: ${cwdStr}.
|
|
776
|
-
OS: ${osDetected}. ${osDetected && mode
|
|
789
|
+
OS: ${osDetected}. ${osDetected === "Windows" && mode === "Flux" ? "Your terminal commands will run on CMD. 'Prefer using PS scripts via CMD' instead of raw CMD commands." : ""}
|
|
777
790
|
${nameStr}${nicknameStr}${userInstrStr}
|
|
778
|
-
If you see a [STEERING HINT] from user, give that prompt priority, user can use it to help you guide if you go wrong way.
|
|
791
|
+
If you see a [STEERING HINT] from user, give that prompt priority for the task at hand, user can use it to help you guide if you go wrong way.
|
|
779
792
|
|
|
780
793
|
${thinkingConfig}
|
|
781
794
|
|
|
@@ -806,7 +819,7 @@ Every ${isMemoryEnabled ? "Prompt, Responses & Memories" : "Prompt & Responses"}
|
|
|
806
819
|
-- START FORMATTING RULES --
|
|
807
820
|
- Structure responses VISUALLY pleasing, easy to read, and beautiful.
|
|
808
821
|
- USE GFM Markdown HEAVILY.
|
|
809
|
-
- Use GFM tables for structured data to keep the terminal view organized. KEEP SENTENCES IN TABLE **SHORT & CONCISE**. AND MAX
|
|
822
|
+
- Use GFM tables for structured data to keep the terminal view organized. KEEP SENTENCES IN TABLE **SHORT & CONCISE**. AND MAX 4 COLUMNS. DO NOT OVERUSE TABLES.
|
|
810
823
|
- **CRITICAL**: NEVER USE LaTeX IN TERMINAL RESPONSES (exception: file content).
|
|
811
824
|
- Keep Poems & Literature in Code Block.
|
|
812
825
|
- Use emojis & Kaomojis. Prefer Kaomojis more.
|
|
@@ -1076,6 +1089,40 @@ var init_arg_parser = __esm({
|
|
|
1076
1089
|
} catch (e) {
|
|
1077
1090
|
value = value.replace(/\\"/g, '"').replace(/\\'/g, "'").replace(/\\`/g, "`").replace(/\\\\/g, "\\");
|
|
1078
1091
|
}
|
|
1092
|
+
} else if (i < argsString.length && argsString[i] === "[") {
|
|
1093
|
+
let balance = 0;
|
|
1094
|
+
let inString = null;
|
|
1095
|
+
let start = i;
|
|
1096
|
+
let end = -1;
|
|
1097
|
+
for (let j = i; j < argsString.length; j++) {
|
|
1098
|
+
const char = argsString[j];
|
|
1099
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
1100
|
+
inString = char;
|
|
1101
|
+
} else if (inString && char === inString && argsString[j - 1] !== "\\") {
|
|
1102
|
+
inString = null;
|
|
1103
|
+
}
|
|
1104
|
+
if (!inString) {
|
|
1105
|
+
if (char === "[") balance++;
|
|
1106
|
+
else if (char === "]") balance--;
|
|
1107
|
+
if (balance === 0) {
|
|
1108
|
+
end = j;
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
if (end !== -1) {
|
|
1114
|
+
value = argsString.substring(start, end + 1);
|
|
1115
|
+
i = end + 1;
|
|
1116
|
+
try {
|
|
1117
|
+
let normalized = value.trim();
|
|
1118
|
+
if (normalized.startsWith("'") || normalized.includes("'")) {
|
|
1119
|
+
}
|
|
1120
|
+
} catch (e) {
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
value = argsString.substring(start);
|
|
1124
|
+
i = argsString.length;
|
|
1125
|
+
}
|
|
1079
1126
|
} else {
|
|
1080
1127
|
let endMatch = argsString.substring(i).match(/([^,\s\)]+)/);
|
|
1081
1128
|
if (endMatch) {
|
|
@@ -1123,8 +1170,8 @@ var init_web_search = __esm({
|
|
|
1123
1170
|
]
|
|
1124
1171
|
});
|
|
1125
1172
|
const page = await browser.newPage();
|
|
1126
|
-
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
1127
|
-
await page.setViewport({ width:
|
|
1173
|
+
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36");
|
|
1174
|
+
await page.setViewport({ width: 1366, height: 768 });
|
|
1128
1175
|
const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
|
|
1129
1176
|
await new Promise((r) => setTimeout(r, jitter));
|
|
1130
1177
|
const searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
@@ -1207,8 +1254,8 @@ var init_web_scrape = __esm({
|
|
|
1207
1254
|
]
|
|
1208
1255
|
});
|
|
1209
1256
|
const page = await browser.newPage();
|
|
1210
|
-
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
1211
|
-
await page.setViewport({ width:
|
|
1257
|
+
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36");
|
|
1258
|
+
await page.setViewport({ width: 1366, height: 768 });
|
|
1212
1259
|
const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
|
|
1213
1260
|
await new Promise((r) => setTimeout(r, jitter));
|
|
1214
1261
|
await page.goto(url, { waitUntil: "networkidle2", timeout: 45e3 });
|
|
@@ -1255,7 +1302,7 @@ var init_web_scrape = __esm({
|
|
|
1255
1302
|
if (!fs7.existsSync(toolLogDir)) fs7.mkdirSync(toolLogDir, { recursive: true });
|
|
1256
1303
|
fs7.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toISOString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
|
|
1257
1304
|
Content:
|
|
1258
|
-
${cleanedHtml}
|
|
1305
|
+
${cleanedHtml}${htmlContent.length > 3e4 ? "\n\n[TRUNCATED AT 30K CHARS]" : ""}
|
|
1259
1306
|
|
|
1260
1307
|
--------------------------------------------------------
|
|
1261
1308
|
|
|
@@ -1301,7 +1348,7 @@ var init_memory = __esm({
|
|
|
1301
1348
|
if (!content) return "ERROR: Missing 'content' for temp memory.";
|
|
1302
1349
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
1303
1350
|
if (!tempStorage[chatId]) tempStorage[chatId] = [];
|
|
1304
|
-
const MAX_CHARS =
|
|
1351
|
+
const MAX_CHARS = 4500 * 4;
|
|
1305
1352
|
let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
|
|
1306
1353
|
while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
1307
1354
|
const removed = tempStorage[chatId].shift();
|
|
@@ -1315,7 +1362,7 @@ var init_memory = __esm({
|
|
|
1315
1362
|
const memories = readEncryptedJson(MEMORIES_FILE, []);
|
|
1316
1363
|
if (method === "add") {
|
|
1317
1364
|
if (!content) return "ERROR: Missing 'content' for memory addition.";
|
|
1318
|
-
const MAX_CHARS =
|
|
1365
|
+
const MAX_CHARS = 2500 * 4;
|
|
1319
1366
|
let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
|
|
1320
1367
|
while (memories.length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
1321
1368
|
const removed = memories.shift();
|
|
@@ -1544,14 +1591,14 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
1544
1591
|
return `CRITICAL FAILURE: Verification failed. File [${targetPath}] is empty on disk despite success report!`;
|
|
1545
1592
|
}
|
|
1546
1593
|
let snippet = "";
|
|
1547
|
-
if (verifiedLineCount <=
|
|
1594
|
+
if (verifiedLineCount <= 200) {
|
|
1548
1595
|
snippet = verifiedLines.join("\n");
|
|
1549
1596
|
} else {
|
|
1550
|
-
const head = verifiedLines.slice(0,
|
|
1551
|
-
const tail = verifiedLines.slice(-
|
|
1597
|
+
const head = verifiedLines.slice(0, 100).join("\n");
|
|
1598
|
+
const tail = verifiedLines.slice(-100).join("\n");
|
|
1552
1599
|
snippet = `${head}
|
|
1553
1600
|
|
|
1554
|
-
... [${verifiedLineCount -
|
|
1601
|
+
... [${verifiedLineCount - 200} lines truncated for history stability] ...
|
|
1555
1602
|
|
|
1556
1603
|
${tail}`;
|
|
1557
1604
|
}
|
|
@@ -1560,7 +1607,9 @@ ${tail}`;
|
|
|
1560
1607
|
|
|
1561
1608
|
- Stats: [${verifiedLineCount} lines, ${(verifiedSize / 1024).toFixed(1)} KB]
|
|
1562
1609
|
${ancestry}- Content Preview:
|
|
1563
|
-
${snippet}
|
|
1610
|
+
${snippet}
|
|
1611
|
+
|
|
1612
|
+
Check if Starting and Ending matches your write.`;
|
|
1564
1613
|
} catch (err) {
|
|
1565
1614
|
return `ERROR: Failed to write file [${targetPath}]: ${err.message}`;
|
|
1566
1615
|
}
|
|
@@ -1604,7 +1653,7 @@ var init_update_file = __esm({
|
|
|
1604
1653
|
return `ERROR: Could not find exact match for the specified "content_to_replace" in [${targetPath}].
|
|
1605
1654
|
- Disk Content Length (Normalized): ${diskLen}
|
|
1606
1655
|
- Match String Length (Normalized): ${matchLen}
|
|
1607
|
-
- Check indentation/whitespace
|
|
1656
|
+
- Check indentation/whitespace. Try re-reading the file for latest changes.`;
|
|
1608
1657
|
}
|
|
1609
1658
|
const startPos = currentContent.indexOf(content_to_replace);
|
|
1610
1659
|
const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
|
|
@@ -1854,7 +1903,7 @@ var init_write_pdf = __esm({
|
|
|
1854
1903
|
path: targetPath,
|
|
1855
1904
|
content,
|
|
1856
1905
|
orientation = "portrait",
|
|
1857
|
-
margin = "
|
|
1906
|
+
margin = "0px"
|
|
1858
1907
|
} = parseArgs(args);
|
|
1859
1908
|
if (!targetPath) return 'ERROR: Missing "path" argument for write_pdf.';
|
|
1860
1909
|
if (!content) return 'ERROR: Missing "content" (HTML/CSS) for write_pdf.';
|
|
@@ -1917,9 +1966,9 @@ var init_write_pdf = __esm({
|
|
|
1917
1966
|
});
|
|
1918
1967
|
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
1919
1968
|
const fileName = path13.basename(targetPath);
|
|
1920
|
-
pdfDoc.setTitle(`
|
|
1969
|
+
pdfDoc.setTitle(`FluxFlow_${fileName}`);
|
|
1921
1970
|
pdfDoc.setAuthor("FluxFlow CLI");
|
|
1922
|
-
pdfDoc.setSubject("Generated with AI");
|
|
1971
|
+
pdfDoc.setSubject("Generated with Agentic AI System");
|
|
1923
1972
|
pdfDoc.setKeywords(["FluxFlow", "AI", "Agentic", "Automated"]);
|
|
1924
1973
|
pdfDoc.setCreator("FluxFlow PDF Engine");
|
|
1925
1974
|
pdfDoc.setProducer("FluxFlow (Generative AI)");
|
|
@@ -1936,6 +1985,121 @@ var init_write_pdf = __esm({
|
|
|
1936
1985
|
}
|
|
1937
1986
|
});
|
|
1938
1987
|
|
|
1988
|
+
// src/tools/write_docx.js
|
|
1989
|
+
import fs14 from "fs-extra";
|
|
1990
|
+
import path14 from "path";
|
|
1991
|
+
import HTMLtoDOCX from "html-to-docx";
|
|
1992
|
+
var write_docx;
|
|
1993
|
+
var init_write_docx = __esm({
|
|
1994
|
+
"src/tools/write_docx.js"() {
|
|
1995
|
+
init_arg_parser();
|
|
1996
|
+
write_docx = async (args) => {
|
|
1997
|
+
const {
|
|
1998
|
+
path: targetPath,
|
|
1999
|
+
content
|
|
2000
|
+
} = parseArgs(args);
|
|
2001
|
+
if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
|
|
2002
|
+
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
2003
|
+
const absolutePath = path14.resolve(process.cwd(), targetPath);
|
|
2004
|
+
try {
|
|
2005
|
+
await fs14.ensureDir(path14.dirname(absolutePath));
|
|
2006
|
+
const fileName = path14.basename(targetPath);
|
|
2007
|
+
const fullHtml = content.includes("<html") ? content : `
|
|
2008
|
+
<!DOCTYPE html>
|
|
2009
|
+
<html lang="en">
|
|
2010
|
+
<head>
|
|
2011
|
+
<meta charset="UTF-8">
|
|
2012
|
+
<title>FluxFlow Document</title>
|
|
2013
|
+
</head>
|
|
2014
|
+
<body>
|
|
2015
|
+
${content}
|
|
2016
|
+
</body>
|
|
2017
|
+
</html>
|
|
2018
|
+
`;
|
|
2019
|
+
const docxBuffer = await HTMLtoDOCX(fullHtml, null, {
|
|
2020
|
+
title: `FluxFlow_${fileName}`,
|
|
2021
|
+
creator: "FluxFlow CLI",
|
|
2022
|
+
description: "Generated by Agentic AI System",
|
|
2023
|
+
table: { row: { cantSplit: true } },
|
|
2024
|
+
footer: true,
|
|
2025
|
+
pageNumber: true
|
|
2026
|
+
});
|
|
2027
|
+
await fs14.writeFile(absolutePath, docxBuffer);
|
|
2028
|
+
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
2029
|
+
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
2030
|
+
} catch (err) {
|
|
2031
|
+
return `ERROR: Failed to generate DOCX [${targetPath}]: ${err.message}`;
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
});
|
|
2036
|
+
|
|
2037
|
+
// src/tools/write_pptx.js
|
|
2038
|
+
import fs15 from "fs-extra";
|
|
2039
|
+
import path15 from "path";
|
|
2040
|
+
import pptxgen from "pptxgenjs";
|
|
2041
|
+
import html2pptxgenjs from "html2pptxgenjs";
|
|
2042
|
+
var write_pptx;
|
|
2043
|
+
var init_write_pptx = __esm({
|
|
2044
|
+
"src/tools/write_pptx.js"() {
|
|
2045
|
+
init_arg_parser();
|
|
2046
|
+
write_pptx = async (args) => {
|
|
2047
|
+
let {
|
|
2048
|
+
path: targetPath,
|
|
2049
|
+
content = "",
|
|
2050
|
+
title = "Autonomous Agent Report"
|
|
2051
|
+
} = parseArgs(args);
|
|
2052
|
+
if (!targetPath) return 'ERROR: Missing "path" argument for write_pptx.';
|
|
2053
|
+
if (!content) return 'ERROR: No "content" (HTML) provided for write_pptx.';
|
|
2054
|
+
const absolutePath = path15.resolve(process.cwd(), targetPath);
|
|
2055
|
+
try {
|
|
2056
|
+
await fs15.ensureDir(path15.dirname(absolutePath));
|
|
2057
|
+
const PptxConstructor = typeof pptxgen === "function" ? pptxgen : pptxgen.default;
|
|
2058
|
+
if (!PptxConstructor) throw new Error("Could not find PptxGenJS constructor in module");
|
|
2059
|
+
const pres = new PptxConstructor();
|
|
2060
|
+
pres.layout = "LAYOUT_4x3";
|
|
2061
|
+
pres.title = title;
|
|
2062
|
+
pres.author = "FluxFlow CLI";
|
|
2063
|
+
pres.company = "Generated with Agentic AI System";
|
|
2064
|
+
const slideBlocks = content.split(/---/).filter((s) => s.trim().length > 0);
|
|
2065
|
+
if (slideBlocks.length === 0) {
|
|
2066
|
+
slideBlocks.push(content);
|
|
2067
|
+
}
|
|
2068
|
+
for (let i = 0; i < slideBlocks.length; i++) {
|
|
2069
|
+
const slide = pres.addSlide();
|
|
2070
|
+
const htmlSnippet = slideBlocks[i].trim();
|
|
2071
|
+
try {
|
|
2072
|
+
const items = html2pptxgenjs.htmlToPptxText(htmlSnippet);
|
|
2073
|
+
slide.addText(items, {
|
|
2074
|
+
x: 0.5,
|
|
2075
|
+
y: 0.5,
|
|
2076
|
+
w: "90%",
|
|
2077
|
+
h: "90%",
|
|
2078
|
+
valign: "top",
|
|
2079
|
+
fontSize: 18,
|
|
2080
|
+
color: "363636"
|
|
2081
|
+
});
|
|
2082
|
+
} catch (err) {
|
|
2083
|
+
slide.addText(htmlSnippet.replace(/<[^>]*>/g, ""), {
|
|
2084
|
+
x: 0.5,
|
|
2085
|
+
y: 0.5,
|
|
2086
|
+
w: "90%",
|
|
2087
|
+
h: "90%",
|
|
2088
|
+
fontSize: 14
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
const buffer = await pres.write({ outputType: "nodebuffer" });
|
|
2093
|
+
await fs15.writeFile(absolutePath, buffer);
|
|
2094
|
+
return `SUCCESS: Native HTML-to-PPTX [${targetPath}] generated with ${slideBlocks.length} slides.
|
|
2095
|
+
- Size: ${(buffer.length / 1024).toFixed(1)} KB`;
|
|
2096
|
+
} catch (err) {
|
|
2097
|
+
return `ERROR: Failed to generate native HTML-to-PPTX [${targetPath}]: ${err.message}`;
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
2102
|
+
|
|
1939
2103
|
// src/utils/tools.js
|
|
1940
2104
|
var TOOL_MAP, dispatchTool;
|
|
1941
2105
|
var init_tools = __esm({
|
|
@@ -1952,6 +2116,8 @@ var init_tools = __esm({
|
|
|
1952
2116
|
init_read_folder();
|
|
1953
2117
|
init_ask_user();
|
|
1954
2118
|
init_write_pdf();
|
|
2119
|
+
init_write_docx();
|
|
2120
|
+
init_write_pptx();
|
|
1955
2121
|
TOOL_MAP = {
|
|
1956
2122
|
web_search,
|
|
1957
2123
|
web_scrape,
|
|
@@ -1964,6 +2130,8 @@ var init_tools = __esm({
|
|
|
1964
2130
|
exec_command,
|
|
1965
2131
|
read_folder,
|
|
1966
2132
|
write_pdf,
|
|
2133
|
+
write_docx,
|
|
2134
|
+
write_pptx,
|
|
1967
2135
|
ask: ask_user
|
|
1968
2136
|
};
|
|
1969
2137
|
dispatchTool = async (toolName, args, context = {}) => {
|
|
@@ -2004,8 +2172,8 @@ var init_terminal = __esm({
|
|
|
2004
2172
|
|
|
2005
2173
|
// src/utils/ai.js
|
|
2006
2174
|
import { GoogleGenAI, ThinkingLevel } from "@google/genai";
|
|
2007
|
-
import
|
|
2008
|
-
import
|
|
2175
|
+
import path16 from "path";
|
|
2176
|
+
import fs16 from "fs";
|
|
2009
2177
|
var client, TERMINATION_SIGNAL, signalTermination, detectToolCalls, initAI, getAIStream;
|
|
2010
2178
|
var init_ai = __esm({
|
|
2011
2179
|
"src/utils/ai.js"() {
|
|
@@ -2171,9 +2339,9 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2171
2339
|
} catch (err) {
|
|
2172
2340
|
const errMsg = err.status || err.error && err.error.message || String(err);
|
|
2173
2341
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2174
|
-
const agentErrDir =
|
|
2175
|
-
if (!
|
|
2176
|
-
|
|
2342
|
+
const agentErrDir = path16.join(LOGS_DIR, "agent");
|
|
2343
|
+
if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
|
|
2344
|
+
fs16.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errMsg}
|
|
2177
2345
|
`);
|
|
2178
2346
|
if (retryCount < MAX_RETRIES) {
|
|
2179
2347
|
retryCount++;
|
|
@@ -2237,9 +2405,9 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2237
2405
|
let totalLines = "...";
|
|
2238
2406
|
let actualEndLine = end_line;
|
|
2239
2407
|
try {
|
|
2240
|
-
const absPath =
|
|
2241
|
-
if (
|
|
2242
|
-
const content =
|
|
2408
|
+
const absPath = path16.resolve(process.cwd(), targetPath2);
|
|
2409
|
+
if (fs16.existsSync(absPath)) {
|
|
2410
|
+
const content = fs16.readFileSync(absPath, "utf8");
|
|
2243
2411
|
const lines = content.split("\n").length;
|
|
2244
2412
|
totalLines = lines;
|
|
2245
2413
|
actualEndLine = Math.min(end_line, lines);
|
|
@@ -2264,6 +2432,10 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2264
2432
|
label = `\u{1F4BE} ${action} FILE: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2265
2433
|
} else if (toolCall.toolName === "write_pdf") {
|
|
2266
2434
|
label = `\u{1F4D1} GENERATING PDF: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2435
|
+
} else if (toolCall.toolName === "write_docx") {
|
|
2436
|
+
label = `\u{1F4DD} GENERATING DOCX: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2437
|
+
} else if (toolCall.toolName === "write_pptx") {
|
|
2438
|
+
label = `\u{1F4CA} GENERATING PPTX: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2267
2439
|
} else if (toolCall.toolName === "exec_command" || toolCall.toolName === "ask") {
|
|
2268
2440
|
label = "";
|
|
2269
2441
|
} else {
|
|
@@ -2298,7 +2470,7 @@ ${boxBottom}
|
|
|
2298
2470
|
/\/usr\//
|
|
2299
2471
|
// Sensitive Linux paths
|
|
2300
2472
|
];
|
|
2301
|
-
const currentDrive =
|
|
2473
|
+
const currentDrive = path16.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
2302
2474
|
const isViolating = riskyPatterns.some((pattern) => {
|
|
2303
2475
|
if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
|
|
2304
2476
|
const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
|
|
@@ -2320,8 +2492,8 @@ ${boxBottom}
|
|
|
2320
2492
|
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
2321
2493
|
if (targetPath) {
|
|
2322
2494
|
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
2323
|
-
const absoluteTarget =
|
|
2324
|
-
const absoluteCwd =
|
|
2495
|
+
const absoluteTarget = path16.resolve(targetPath);
|
|
2496
|
+
const absoluteCwd = path16.resolve(process.cwd());
|
|
2325
2497
|
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
2326
2498
|
const denyMsg = `Access Denied. You are not allowed to access files outside the current workspace. To enable this, ask the user to turn on "External Workspace Access" in /settings.`;
|
|
2327
2499
|
toolResults.push(`[TOOL_RESULT]: ERROR: ${denyMsg}`);
|
|
@@ -2366,11 +2538,11 @@ ${boxBottom}
|
|
|
2366
2538
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2367
2539
|
const isErr = result.startsWith("ERROR:");
|
|
2368
2540
|
const logStatus = isErr ? result.trim() : "SUCCESS";
|
|
2369
|
-
const toolHistDir =
|
|
2370
|
-
if (!
|
|
2371
|
-
|
|
2541
|
+
const toolHistDir = path16.join(LOGS_DIR, "tools");
|
|
2542
|
+
if (!fs16.existsSync(toolHistDir)) {
|
|
2543
|
+
fs16.mkdirSync(toolHistDir, { recursive: true });
|
|
2372
2544
|
}
|
|
2373
|
-
|
|
2545
|
+
fs16.appendFileSync(path16.join(toolHistDir, "history.log"), `HISTORY [${timestamp}]: ${toolCall.toolName} [${logStatus}]
|
|
2374
2546
|
`);
|
|
2375
2547
|
} catch (logErr) {
|
|
2376
2548
|
}
|
|
@@ -2432,11 +2604,11 @@ ${boxBottom}
|
|
|
2432
2604
|
if (parts && parts[1]?.text) {
|
|
2433
2605
|
finalSynthesis = parts[1].text;
|
|
2434
2606
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2435
|
-
const janitorLogDir =
|
|
2436
|
-
if (!
|
|
2437
|
-
|
|
2607
|
+
const janitorLogDir = path16.join(LOGS_DIR, "janitor");
|
|
2608
|
+
if (!fs16.existsSync(janitorLogDir)) {
|
|
2609
|
+
fs16.mkdirSync(janitorLogDir, { recursive: true });
|
|
2438
2610
|
}
|
|
2439
|
-
|
|
2611
|
+
fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: ${finalSynthesis}
|
|
2440
2612
|
`);
|
|
2441
2613
|
} else if (parts && parts[0]?.text) finalSynthesis = parts[0].text;
|
|
2442
2614
|
else if (janitorResult.response && janitorResult.response.text) finalSynthesis = janitorResult.response.text();
|
|
@@ -2448,8 +2620,8 @@ ${boxBottom}
|
|
|
2448
2620
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
2449
2621
|
const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
|
|
2450
2622
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2451
|
-
const janitorLogDir =
|
|
2452
|
-
|
|
2623
|
+
const janitorLogDir = path16.join(LOGS_DIR, "janitor");
|
|
2624
|
+
fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
|
|
2453
2625
|
`);
|
|
2454
2626
|
if (janitorToolCall.toolName === "memory" && !janitorToolCall.args.includes("action='temp'")) {
|
|
2455
2627
|
yield { type: "memory_updated" };
|
|
@@ -2457,11 +2629,11 @@ ${boxBottom}
|
|
|
2457
2629
|
}
|
|
2458
2630
|
} catch (janitorErr) {
|
|
2459
2631
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2460
|
-
const janitorErrDir =
|
|
2461
|
-
if (!
|
|
2462
|
-
|
|
2632
|
+
const janitorErrDir = path16.join(LOGS_DIR, "janitor");
|
|
2633
|
+
if (!fs16.existsSync(janitorErrDir)) {
|
|
2634
|
+
fs16.mkdirSync(janitorErrDir, { recursive: true });
|
|
2463
2635
|
}
|
|
2464
|
-
|
|
2636
|
+
fs16.appendFileSync(path16.join(janitorErrDir, "error.log"), `ERROR [${date}]: ${janitorErr.message}
|
|
2465
2637
|
`);
|
|
2466
2638
|
console.error("Janitor Background Tasks Failed:", janitorErr.message);
|
|
2467
2639
|
}
|
|
@@ -2490,8 +2662,8 @@ ${timestamp}`;
|
|
|
2490
2662
|
});
|
|
2491
2663
|
|
|
2492
2664
|
// src/utils/settings.js
|
|
2493
|
-
import
|
|
2494
|
-
import
|
|
2665
|
+
import fs17 from "fs-extra";
|
|
2666
|
+
import path17 from "path";
|
|
2495
2667
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
2496
2668
|
var init_settings = __esm({
|
|
2497
2669
|
"src/utils/settings.js"() {
|
|
@@ -2526,8 +2698,8 @@ var init_settings = __esm({
|
|
|
2526
2698
|
};
|
|
2527
2699
|
loadSettings = async () => {
|
|
2528
2700
|
try {
|
|
2529
|
-
if (await
|
|
2530
|
-
const saved = await
|
|
2701
|
+
if (await fs17.exists(SETTINGS_FILE)) {
|
|
2702
|
+
const saved = await fs17.readJson(SETTINGS_FILE);
|
|
2531
2703
|
return {
|
|
2532
2704
|
...DEFAULT_SETTINGS,
|
|
2533
2705
|
...saved,
|
|
@@ -2545,12 +2717,12 @@ var init_settings = __esm({
|
|
|
2545
2717
|
const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
2546
2718
|
const folders = ["logs", "secret"];
|
|
2547
2719
|
for (const folder of folders) {
|
|
2548
|
-
const src =
|
|
2549
|
-
const dest =
|
|
2720
|
+
const src = path17.join(FLUXFLOW_DIR2, folder);
|
|
2721
|
+
const dest = path17.join(newPath, folder);
|
|
2550
2722
|
try {
|
|
2551
|
-
if (await
|
|
2552
|
-
await
|
|
2553
|
-
await
|
|
2723
|
+
if (await fs17.exists(src)) {
|
|
2724
|
+
await fs17.ensureDir(dest);
|
|
2725
|
+
await fs17.copy(src, dest, { overwrite: true });
|
|
2554
2726
|
}
|
|
2555
2727
|
} catch (err) {
|
|
2556
2728
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -2564,8 +2736,8 @@ var init_settings = __esm({
|
|
|
2564
2736
|
await migrateToExternal(settings.systemSettings.externalDataPath);
|
|
2565
2737
|
}
|
|
2566
2738
|
const updated = { ...current, ...settings };
|
|
2567
|
-
await
|
|
2568
|
-
await
|
|
2739
|
+
await fs17.ensureDir(path17.dirname(SETTINGS_FILE));
|
|
2740
|
+
await fs17.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
|
|
2569
2741
|
return true;
|
|
2570
2742
|
} catch (err) {
|
|
2571
2743
|
console.error("Failed to save settings:", err);
|
|
@@ -2718,7 +2890,7 @@ var init_UpdateProcessor = __esm({
|
|
|
2718
2890
|
import puppeteer4 from "puppeteer";
|
|
2719
2891
|
import { exec as exec2 } from "child_process";
|
|
2720
2892
|
import { promisify } from "util";
|
|
2721
|
-
import
|
|
2893
|
+
import fs18 from "fs";
|
|
2722
2894
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
2723
2895
|
var init_setup = __esm({
|
|
2724
2896
|
"src/utils/setup.js"() {
|
|
@@ -2726,7 +2898,7 @@ var init_setup = __esm({
|
|
|
2726
2898
|
checkPuppeteerReady = () => {
|
|
2727
2899
|
try {
|
|
2728
2900
|
const exePath = puppeteer4.executablePath();
|
|
2729
|
-
const exists = exePath &&
|
|
2901
|
+
const exists = exePath && fs18.existsSync(exePath);
|
|
2730
2902
|
if (exists) return true;
|
|
2731
2903
|
} catch (e) {
|
|
2732
2904
|
return false;
|
|
@@ -2759,7 +2931,7 @@ __export(app_exports, {
|
|
|
2759
2931
|
import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
|
|
2760
2932
|
import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
|
|
2761
2933
|
import Spinner2 from "ink-spinner";
|
|
2762
|
-
import
|
|
2934
|
+
import fs19 from "fs-extra";
|
|
2763
2935
|
import { exec as exec3 } from "child_process";
|
|
2764
2936
|
import { MultilineInput } from "ink-multiline-input";
|
|
2765
2937
|
import TextInput3 from "ink-text-input";
|
|
@@ -3304,12 +3476,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
3304
3476
|
setCompletedIndex(prev.length + 1);
|
|
3305
3477
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
3306
3478
|
});
|
|
3307
|
-
if (
|
|
3308
|
-
if (
|
|
3309
|
-
if (
|
|
3479
|
+
if (fs19.existsSync(LOGS_DIR)) fs19.removeSync(LOGS_DIR);
|
|
3480
|
+
if (fs19.existsSync(SECRET_DIR)) fs19.removeSync(SECRET_DIR);
|
|
3481
|
+
if (fs19.existsSync(SETTINGS_FILE)) fs19.removeSync(SETTINGS_FILE);
|
|
3310
3482
|
try {
|
|
3311
|
-
const items =
|
|
3312
|
-
if (items.length === 0)
|
|
3483
|
+
const items = fs19.readdirSync(FLUXFLOW_DIR);
|
|
3484
|
+
if (items.length === 0) fs19.removeSync(FLUXFLOW_DIR);
|
|
3313
3485
|
} catch (e) {
|
|
3314
3486
|
}
|
|
3315
3487
|
setTimeout(() => {
|
|
@@ -4343,8 +4515,8 @@ var init_app = __esm({
|
|
|
4343
4515
|
init_setup();
|
|
4344
4516
|
SESSION_START_TIME = Date.now();
|
|
4345
4517
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
4346
|
-
versionFluxflow = "1.
|
|
4347
|
-
updatedOn = "2026-05-
|
|
4518
|
+
versionFluxflow = "1.7.0";
|
|
4519
|
+
updatedOn = "2026-05-03";
|
|
4348
4520
|
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "The agent already finished the task (turn: finish) before your hint was consumed."), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
|
|
4349
4521
|
CommandMenu,
|
|
4350
4522
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluxflow-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "A high-fidelity agentic terminal assistant for the Flux Era.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -34,13 +34,15 @@
|
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"start": "tsx ./src/cli.jsx",
|
|
37
|
-
"build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:ink-spinner --external:ink-multiline-input --external:@google/genai --external:zod --external:nanoid --external:puppeteer --external:pdf-lib --external:typescript"
|
|
37
|
+
"build": "esbuild ./src/cli.jsx --bundle --platform=node --format=esm --outfile=./dist/fluxflow.js --external:react --external:ink --external:chalk --external:fs-extra --external:gradient-string --external:ink-text-input --external:ink-select-input --external:ink-spinner --external:ink-multiline-input --external:@google/genai --external:zod --external:nanoid --external:puppeteer --external:pdf-lib --external:html-to-docx --external:pptxgenjs --external:html2pptxgenjs --external:typescript"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@google/genai": "^1.50.1",
|
|
41
41
|
"chalk": "^5.6.2",
|
|
42
42
|
"fs-extra": "^11.3.4",
|
|
43
43
|
"gradient-string": "^3.0.0",
|
|
44
|
+
"html-to-docx": "^1.8.0",
|
|
45
|
+
"html2pptxgenjs": "^0.0.3",
|
|
44
46
|
"ink": "^7.0.1",
|
|
45
47
|
"ink-multiline-input": "^0.1.0",
|
|
46
48
|
"ink-select-input": "^6.2.0",
|
|
@@ -48,6 +50,7 @@
|
|
|
48
50
|
"ink-text-input": "^6.0.0",
|
|
49
51
|
"nanoid": "^5.1.9",
|
|
50
52
|
"pdf-lib": "^1.17.1",
|
|
53
|
+
"pptxgenjs": "^4.0.1",
|
|
51
54
|
"puppeteer": "^24.42.0",
|
|
52
55
|
"react": "^19.2.5",
|
|
53
56
|
"zod": "^4.3.6"
|