fluxflow-cli 1.6.7 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/TOOLS.md +9 -0
- package/dist/fluxflow.js +353 -137
- 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
|
@@ -670,10 +670,12 @@ var init_main_tools = __esm({
|
|
|
670
670
|
You have access to internal tools. To call a tool, you MUST use the following exact syntax on a new line:
|
|
671
671
|
tool:functions.tool_name(arguments)
|
|
672
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
|
+
|
|
673
676
|
- WEB TOOLS (Available in Flux & Flow) -
|
|
674
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.
|
|
675
678
|
2. Web Scrape: tool:functions.web_scrape(url="<url>"). provides detail from a URL.
|
|
676
|
-
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. PREFER USING THIS TOOL RATHER THAN FINISHING THE LOOP FOR USER CLARIFICATION.
|
|
677
679
|
${mode === "Flux" ? `
|
|
678
680
|
- DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
|
|
679
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.
|
|
@@ -682,7 +684,14 @@ ${mode === "Flux" ? `
|
|
|
682
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.
|
|
683
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.
|
|
684
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.
|
|
685
|
-
7.
|
|
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.
|
|
686
695
|
|
|
687
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.
|
|
688
697
|
|
|
@@ -775,7 +784,7 @@ ${userMemories}
|
|
|
775
784
|
` : ""}${isMemoryEnabled ? `${tempMemoriesStr}
|
|
776
785
|
|
|
777
786
|
` : ""}--- START SYSTEM INSTRUCTION ---
|
|
778
|
-
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
|
|
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 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 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 only Web Tools & User Communication Tool in this mode."}
|
|
779
788
|
CURRENT_WORKING_DIRECTORY: ${cwdStr}.
|
|
780
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." : ""}
|
|
781
790
|
${nameStr}${nicknameStr}${userInstrStr}
|
|
@@ -968,7 +977,7 @@ var init_history = __esm({
|
|
|
968
977
|
// src/utils/usage.js
|
|
969
978
|
import fs5 from "fs-extra";
|
|
970
979
|
import path5 from "path";
|
|
971
|
-
var getDailyUsage, incrementUsage, checkQuota;
|
|
980
|
+
var getDailyUsage, incrementUsage, addToUsage, checkQuota;
|
|
972
981
|
var init_usage = __esm({
|
|
973
982
|
"src/utils/usage.js"() {
|
|
974
983
|
init_paths();
|
|
@@ -978,30 +987,55 @@ var init_usage = __esm({
|
|
|
978
987
|
if (await fs5.exists(USAGE_FILE)) {
|
|
979
988
|
const data = await fs5.readJson(USAGE_FILE);
|
|
980
989
|
if (data.date === today) {
|
|
981
|
-
|
|
990
|
+
const s = data.stats;
|
|
991
|
+
const normalized = {
|
|
992
|
+
agent: s.agent || 0,
|
|
993
|
+
background: s.background || 0,
|
|
994
|
+
search: s.search || 0,
|
|
995
|
+
toolSuccess: s.toolSuccess || 0,
|
|
996
|
+
toolFailure: s.toolFailure || 0,
|
|
997
|
+
duration: s.duration || 0,
|
|
998
|
+
tokens: s.tokens || 0
|
|
999
|
+
};
|
|
1000
|
+
return normalized;
|
|
982
1001
|
}
|
|
983
1002
|
}
|
|
984
1003
|
} catch (err) {
|
|
985
1004
|
console.error("Failed to read usage:", err);
|
|
986
1005
|
}
|
|
987
|
-
const defaultStats = {
|
|
1006
|
+
const defaultStats = {
|
|
1007
|
+
agent: 0,
|
|
1008
|
+
background: 0,
|
|
1009
|
+
search: 0,
|
|
1010
|
+
toolSuccess: 0,
|
|
1011
|
+
toolFailure: 0,
|
|
1012
|
+
duration: 0,
|
|
1013
|
+
tokens: 0
|
|
1014
|
+
};
|
|
988
1015
|
await fs5.ensureDir(path5.dirname(USAGE_FILE));
|
|
989
1016
|
await fs5.writeJson(USAGE_FILE, { date: today, stats: defaultStats }, { spaces: 2 });
|
|
990
1017
|
return defaultStats;
|
|
991
1018
|
};
|
|
992
1019
|
incrementUsage = async (key) => {
|
|
993
1020
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
data.date = today;
|
|
997
|
-
data.stats = { agent: 0, background: 0, search: 0 };
|
|
998
|
-
}
|
|
1021
|
+
const stats = await getDailyUsage();
|
|
1022
|
+
const data = { date: today, stats };
|
|
999
1023
|
if (data.stats[key] !== void 0) {
|
|
1000
1024
|
data.stats[key]++;
|
|
1001
1025
|
await fs5.ensureDir(path5.dirname(USAGE_FILE));
|
|
1002
1026
|
await fs5.writeJson(USAGE_FILE, data, { spaces: 2 });
|
|
1003
1027
|
}
|
|
1004
1028
|
};
|
|
1029
|
+
addToUsage = async (key, amount) => {
|
|
1030
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1031
|
+
const stats = await getDailyUsage();
|
|
1032
|
+
const data = { date: today, stats };
|
|
1033
|
+
if (data.stats[key] !== void 0) {
|
|
1034
|
+
data.stats[key] += Math.floor(amount);
|
|
1035
|
+
await fs5.ensureDir(path5.dirname(USAGE_FILE));
|
|
1036
|
+
await fs5.writeJson(USAGE_FILE, data, { spaces: 2 });
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1005
1039
|
checkQuota = async (key, settings) => {
|
|
1006
1040
|
const usage = await getDailyUsage();
|
|
1007
1041
|
const tier = settings.apiTier || "Free";
|
|
@@ -1080,6 +1114,40 @@ var init_arg_parser = __esm({
|
|
|
1080
1114
|
} catch (e) {
|
|
1081
1115
|
value = value.replace(/\\"/g, '"').replace(/\\'/g, "'").replace(/\\`/g, "`").replace(/\\\\/g, "\\");
|
|
1082
1116
|
}
|
|
1117
|
+
} else if (i < argsString.length && argsString[i] === "[") {
|
|
1118
|
+
let balance = 0;
|
|
1119
|
+
let inString = null;
|
|
1120
|
+
let start = i;
|
|
1121
|
+
let end = -1;
|
|
1122
|
+
for (let j = i; j < argsString.length; j++) {
|
|
1123
|
+
const char = argsString[j];
|
|
1124
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
1125
|
+
inString = char;
|
|
1126
|
+
} else if (inString && char === inString && argsString[j - 1] !== "\\") {
|
|
1127
|
+
inString = null;
|
|
1128
|
+
}
|
|
1129
|
+
if (!inString) {
|
|
1130
|
+
if (char === "[") balance++;
|
|
1131
|
+
else if (char === "]") balance--;
|
|
1132
|
+
if (balance === 0) {
|
|
1133
|
+
end = j;
|
|
1134
|
+
break;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
if (end !== -1) {
|
|
1139
|
+
value = argsString.substring(start, end + 1);
|
|
1140
|
+
i = end + 1;
|
|
1141
|
+
try {
|
|
1142
|
+
let normalized = value.trim();
|
|
1143
|
+
if (normalized.startsWith("'") || normalized.includes("'")) {
|
|
1144
|
+
}
|
|
1145
|
+
} catch (e) {
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
value = argsString.substring(start);
|
|
1149
|
+
i = argsString.length;
|
|
1150
|
+
}
|
|
1083
1151
|
} else {
|
|
1084
1152
|
let endMatch = argsString.substring(i).match(/([^,\s\)]+)/);
|
|
1085
1153
|
if (endMatch) {
|
|
@@ -1923,7 +1991,7 @@ var init_write_pdf = __esm({
|
|
|
1923
1991
|
});
|
|
1924
1992
|
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
1925
1993
|
const fileName = path13.basename(targetPath);
|
|
1926
|
-
pdfDoc.setTitle(`
|
|
1994
|
+
pdfDoc.setTitle(`FluxFlow_${fileName}`);
|
|
1927
1995
|
pdfDoc.setAuthor("FluxFlow CLI");
|
|
1928
1996
|
pdfDoc.setSubject("Generated with Agentic AI System");
|
|
1929
1997
|
pdfDoc.setKeywords(["FluxFlow", "AI", "Agentic", "Automated"]);
|
|
@@ -1942,6 +2010,121 @@ var init_write_pdf = __esm({
|
|
|
1942
2010
|
}
|
|
1943
2011
|
});
|
|
1944
2012
|
|
|
2013
|
+
// src/tools/write_docx.js
|
|
2014
|
+
import fs14 from "fs-extra";
|
|
2015
|
+
import path14 from "path";
|
|
2016
|
+
import HTMLtoDOCX from "html-to-docx";
|
|
2017
|
+
var write_docx;
|
|
2018
|
+
var init_write_docx = __esm({
|
|
2019
|
+
"src/tools/write_docx.js"() {
|
|
2020
|
+
init_arg_parser();
|
|
2021
|
+
write_docx = async (args) => {
|
|
2022
|
+
const {
|
|
2023
|
+
path: targetPath,
|
|
2024
|
+
content
|
|
2025
|
+
} = parseArgs(args);
|
|
2026
|
+
if (!targetPath) return 'ERROR: Missing "path" argument for write_docx.';
|
|
2027
|
+
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
2028
|
+
const absolutePath = path14.resolve(process.cwd(), targetPath);
|
|
2029
|
+
try {
|
|
2030
|
+
await fs14.ensureDir(path14.dirname(absolutePath));
|
|
2031
|
+
const fileName = path14.basename(targetPath);
|
|
2032
|
+
const fullHtml = content.includes("<html") ? content : `
|
|
2033
|
+
<!DOCTYPE html>
|
|
2034
|
+
<html lang="en">
|
|
2035
|
+
<head>
|
|
2036
|
+
<meta charset="UTF-8">
|
|
2037
|
+
<title>FluxFlow Document</title>
|
|
2038
|
+
</head>
|
|
2039
|
+
<body>
|
|
2040
|
+
${content}
|
|
2041
|
+
</body>
|
|
2042
|
+
</html>
|
|
2043
|
+
`;
|
|
2044
|
+
const docxBuffer = await HTMLtoDOCX(fullHtml, null, {
|
|
2045
|
+
title: `FluxFlow_${fileName}`,
|
|
2046
|
+
creator: "FluxFlow CLI",
|
|
2047
|
+
description: "Generated by Agentic AI System",
|
|
2048
|
+
table: { row: { cantSplit: true } },
|
|
2049
|
+
footer: true,
|
|
2050
|
+
pageNumber: true
|
|
2051
|
+
});
|
|
2052
|
+
await fs14.writeFile(absolutePath, docxBuffer);
|
|
2053
|
+
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
2054
|
+
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
2055
|
+
} catch (err) {
|
|
2056
|
+
return `ERROR: Failed to generate DOCX [${targetPath}]: ${err.message}`;
|
|
2057
|
+
}
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
});
|
|
2061
|
+
|
|
2062
|
+
// src/tools/write_pptx.js
|
|
2063
|
+
import fs15 from "fs-extra";
|
|
2064
|
+
import path15 from "path";
|
|
2065
|
+
import pptxgen from "pptxgenjs";
|
|
2066
|
+
import html2pptxgenjs from "html2pptxgenjs";
|
|
2067
|
+
var write_pptx;
|
|
2068
|
+
var init_write_pptx = __esm({
|
|
2069
|
+
"src/tools/write_pptx.js"() {
|
|
2070
|
+
init_arg_parser();
|
|
2071
|
+
write_pptx = async (args) => {
|
|
2072
|
+
let {
|
|
2073
|
+
path: targetPath,
|
|
2074
|
+
content = "",
|
|
2075
|
+
title = "Autonomous Agent Report"
|
|
2076
|
+
} = parseArgs(args);
|
|
2077
|
+
if (!targetPath) return 'ERROR: Missing "path" argument for write_pptx.';
|
|
2078
|
+
if (!content) return 'ERROR: No "content" (HTML) provided for write_pptx.';
|
|
2079
|
+
const absolutePath = path15.resolve(process.cwd(), targetPath);
|
|
2080
|
+
try {
|
|
2081
|
+
await fs15.ensureDir(path15.dirname(absolutePath));
|
|
2082
|
+
const PptxConstructor = typeof pptxgen === "function" ? pptxgen : pptxgen.default;
|
|
2083
|
+
if (!PptxConstructor) throw new Error("Could not find PptxGenJS constructor in module");
|
|
2084
|
+
const pres = new PptxConstructor();
|
|
2085
|
+
pres.layout = "LAYOUT_4x3";
|
|
2086
|
+
pres.title = title;
|
|
2087
|
+
pres.author = "FluxFlow CLI";
|
|
2088
|
+
pres.company = "Generated with Agentic AI System";
|
|
2089
|
+
const slideBlocks = content.split(/---/).filter((s) => s.trim().length > 0);
|
|
2090
|
+
if (slideBlocks.length === 0) {
|
|
2091
|
+
slideBlocks.push(content);
|
|
2092
|
+
}
|
|
2093
|
+
for (let i = 0; i < slideBlocks.length; i++) {
|
|
2094
|
+
const slide = pres.addSlide();
|
|
2095
|
+
const htmlSnippet = slideBlocks[i].trim();
|
|
2096
|
+
try {
|
|
2097
|
+
const items = html2pptxgenjs.htmlToPptxText(htmlSnippet);
|
|
2098
|
+
slide.addText(items, {
|
|
2099
|
+
x: 0.5,
|
|
2100
|
+
y: 0.5,
|
|
2101
|
+
w: "90%",
|
|
2102
|
+
h: "90%",
|
|
2103
|
+
valign: "top",
|
|
2104
|
+
fontSize: 18,
|
|
2105
|
+
color: "363636"
|
|
2106
|
+
});
|
|
2107
|
+
} catch (err) {
|
|
2108
|
+
slide.addText(htmlSnippet.replace(/<[^>]*>/g, ""), {
|
|
2109
|
+
x: 0.5,
|
|
2110
|
+
y: 0.5,
|
|
2111
|
+
w: "90%",
|
|
2112
|
+
h: "90%",
|
|
2113
|
+
fontSize: 14
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
const buffer = await pres.write({ outputType: "nodebuffer" });
|
|
2118
|
+
await fs15.writeFile(absolutePath, buffer);
|
|
2119
|
+
return `SUCCESS: Native HTML-to-PPTX [${targetPath}] generated with ${slideBlocks.length} slides.
|
|
2120
|
+
- Size: ${(buffer.length / 1024).toFixed(1)} KB`;
|
|
2121
|
+
} catch (err) {
|
|
2122
|
+
return `ERROR: Failed to generate native HTML-to-PPTX [${targetPath}]: ${err.message}`;
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
});
|
|
2127
|
+
|
|
1945
2128
|
// src/utils/tools.js
|
|
1946
2129
|
var TOOL_MAP, dispatchTool;
|
|
1947
2130
|
var init_tools = __esm({
|
|
@@ -1958,6 +2141,8 @@ var init_tools = __esm({
|
|
|
1958
2141
|
init_read_folder();
|
|
1959
2142
|
init_ask_user();
|
|
1960
2143
|
init_write_pdf();
|
|
2144
|
+
init_write_docx();
|
|
2145
|
+
init_write_pptx();
|
|
1961
2146
|
TOOL_MAP = {
|
|
1962
2147
|
web_search,
|
|
1963
2148
|
web_scrape,
|
|
@@ -1970,6 +2155,8 @@ var init_tools = __esm({
|
|
|
1970
2155
|
exec_command,
|
|
1971
2156
|
read_folder,
|
|
1972
2157
|
write_pdf,
|
|
2158
|
+
write_docx,
|
|
2159
|
+
write_pptx,
|
|
1973
2160
|
ask: ask_user
|
|
1974
2161
|
};
|
|
1975
2162
|
dispatchTool = async (toolName, args, context = {}) => {
|
|
@@ -2010,8 +2197,8 @@ var init_terminal = __esm({
|
|
|
2010
2197
|
|
|
2011
2198
|
// src/utils/ai.js
|
|
2012
2199
|
import { GoogleGenAI, ThinkingLevel } from "@google/genai";
|
|
2013
|
-
import
|
|
2014
|
-
import
|
|
2200
|
+
import path16 from "path";
|
|
2201
|
+
import fs16 from "fs";
|
|
2015
2202
|
var client, TERMINATION_SIGNAL, signalTermination, detectToolCalls, initAI, getAIStream;
|
|
2016
2203
|
var init_ai = __esm({
|
|
2017
2204
|
"src/utils/ai.js"() {
|
|
@@ -2177,9 +2364,9 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2177
2364
|
} catch (err) {
|
|
2178
2365
|
const errMsg = err.status || err.error && err.error.message || String(err);
|
|
2179
2366
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2180
|
-
const agentErrDir =
|
|
2181
|
-
if (!
|
|
2182
|
-
|
|
2367
|
+
const agentErrDir = path16.join(LOGS_DIR, "agent");
|
|
2368
|
+
if (!fs16.existsSync(agentErrDir)) fs16.mkdirSync(agentErrDir, { recursive: true });
|
|
2369
|
+
fs16.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errMsg}
|
|
2183
2370
|
`);
|
|
2184
2371
|
if (retryCount < MAX_RETRIES) {
|
|
2185
2372
|
retryCount++;
|
|
@@ -2214,6 +2401,7 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2214
2401
|
}
|
|
2215
2402
|
await incrementUsage("agent");
|
|
2216
2403
|
if (lastUsage) {
|
|
2404
|
+
await addToUsage("tokens", lastUsage.totalTokenCount || 0);
|
|
2217
2405
|
yield { type: "usage", content: lastUsage };
|
|
2218
2406
|
}
|
|
2219
2407
|
fullAgentResponseChunks.push(turnText);
|
|
@@ -2243,9 +2431,9 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2243
2431
|
let totalLines = "...";
|
|
2244
2432
|
let actualEndLine = end_line;
|
|
2245
2433
|
try {
|
|
2246
|
-
const absPath =
|
|
2247
|
-
if (
|
|
2248
|
-
const content =
|
|
2434
|
+
const absPath = path16.resolve(process.cwd(), targetPath2);
|
|
2435
|
+
if (fs16.existsSync(absPath)) {
|
|
2436
|
+
const content = fs16.readFileSync(absPath, "utf8");
|
|
2249
2437
|
const lines = content.split("\n").length;
|
|
2250
2438
|
totalLines = lines;
|
|
2251
2439
|
actualEndLine = Math.min(end_line, lines);
|
|
@@ -2258,7 +2446,7 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2258
2446
|
if (isPdf) {
|
|
2259
2447
|
label = `\u{1F4C4} ANALYZING PDF: ${targetPath2}`.toUpperCase();
|
|
2260
2448
|
} else if (isImage) {
|
|
2261
|
-
label = `\u{
|
|
2449
|
+
label = `\u{1F4F8} ANALYZING IMAGE: ${targetPath2}`.toUpperCase();
|
|
2262
2450
|
} else {
|
|
2263
2451
|
label = `\u{1F4C4} READING FILE: ${targetPath2}. LINES ${start_line} - ${actualEndLine} FROM ${totalLines}`.toUpperCase();
|
|
2264
2452
|
}
|
|
@@ -2270,6 +2458,10 @@ USER_PROMPT: ${agentText}`.trim();
|
|
|
2270
2458
|
label = `\u{1F4BE} ${action} FILE: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2271
2459
|
} else if (toolCall.toolName === "write_pdf") {
|
|
2272
2460
|
label = `\u{1F4D1} GENERATING PDF: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2461
|
+
} else if (toolCall.toolName === "write_docx") {
|
|
2462
|
+
label = `\u{1F4DD} GENERATING DOCX: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2463
|
+
} else if (toolCall.toolName === "write_pptx") {
|
|
2464
|
+
label = `\u{1F4CA} GENERATING PPTX: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
2273
2465
|
} else if (toolCall.toolName === "exec_command" || toolCall.toolName === "ask") {
|
|
2274
2466
|
label = "";
|
|
2275
2467
|
} else {
|
|
@@ -2304,7 +2496,7 @@ ${boxBottom}
|
|
|
2304
2496
|
/\/usr\//
|
|
2305
2497
|
// Sensitive Linux paths
|
|
2306
2498
|
];
|
|
2307
|
-
const currentDrive =
|
|
2499
|
+
const currentDrive = path16.resolve(process.cwd()).substring(0, 3).toLowerCase();
|
|
2308
2500
|
const isViolating = riskyPatterns.some((pattern) => {
|
|
2309
2501
|
if (pattern.source === "[a-zA-Z]:[\\\\\\/]") {
|
|
2310
2502
|
const driveMatch = command.match(/[a-zA-Z]:[\\\/]/i);
|
|
@@ -2326,8 +2518,8 @@ ${boxBottom}
|
|
|
2326
2518
|
const targetPath = parsedArgs.path || parsedArgs.targetPath || null;
|
|
2327
2519
|
if (targetPath) {
|
|
2328
2520
|
const isExternalOff = settings.systemSettings && settings.systemSettings.allowExternalAccess === false;
|
|
2329
|
-
const absoluteTarget =
|
|
2330
|
-
const absoluteCwd =
|
|
2521
|
+
const absoluteTarget = path16.resolve(targetPath);
|
|
2522
|
+
const absoluteCwd = path16.resolve(process.cwd());
|
|
2331
2523
|
if (isExternalOff && !absoluteTarget.startsWith(absoluteCwd)) {
|
|
2332
2524
|
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.`;
|
|
2333
2525
|
toolResults.push(`[TOOL_RESULT]: ERROR: ${denyMsg}`);
|
|
@@ -2353,12 +2545,15 @@ ${boxBottom}
|
|
|
2353
2545
|
}
|
|
2354
2546
|
}
|
|
2355
2547
|
}
|
|
2548
|
+
const toolStart = Date.now();
|
|
2356
2549
|
let result = await dispatchTool(toolCall.toolName, toolCall.args, {
|
|
2357
2550
|
chatId,
|
|
2358
2551
|
history,
|
|
2359
2552
|
onChunk: (chunk) => settings.onExecChunk ? settings.onExecChunk(chunk) : null,
|
|
2360
2553
|
onAskUser: settings.onAskUser
|
|
2361
2554
|
});
|
|
2555
|
+
const toolEnd = Date.now();
|
|
2556
|
+
yield { type: "tool_time", content: toolEnd - toolStart };
|
|
2362
2557
|
let binaryPart = null;
|
|
2363
2558
|
if (typeof result === "object" && result.binaryPart) {
|
|
2364
2559
|
binaryPart = result.binaryPart;
|
|
@@ -2368,15 +2563,23 @@ ${boxBottom}
|
|
|
2368
2563
|
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
2369
2564
|
settings.onExecEnd();
|
|
2370
2565
|
}
|
|
2566
|
+
const isSuccess = result && !result.startsWith("ERROR:");
|
|
2567
|
+
if (isSuccess) {
|
|
2568
|
+
await incrementUsage("toolSuccess");
|
|
2569
|
+
if (settings.onToolResult) settings.onToolResult("success");
|
|
2570
|
+
} else {
|
|
2571
|
+
await incrementUsage("toolFailure");
|
|
2572
|
+
if (settings.onToolResult) settings.onToolResult("failure");
|
|
2573
|
+
}
|
|
2371
2574
|
try {
|
|
2372
2575
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2373
2576
|
const isErr = result.startsWith("ERROR:");
|
|
2374
2577
|
const logStatus = isErr ? result.trim() : "SUCCESS";
|
|
2375
|
-
const toolHistDir =
|
|
2376
|
-
if (!
|
|
2377
|
-
|
|
2578
|
+
const toolHistDir = path16.join(LOGS_DIR, "tools");
|
|
2579
|
+
if (!fs16.existsSync(toolHistDir)) {
|
|
2580
|
+
fs16.mkdirSync(toolHistDir, { recursive: true });
|
|
2378
2581
|
}
|
|
2379
|
-
|
|
2582
|
+
fs16.appendFileSync(path16.join(toolHistDir, "history.log"), `HISTORY [${timestamp}]: ${toolCall.toolName} [${logStatus}]
|
|
2380
2583
|
`);
|
|
2381
2584
|
} catch (logErr) {
|
|
2382
2585
|
}
|
|
@@ -2438,24 +2641,27 @@ ${boxBottom}
|
|
|
2438
2641
|
if (parts && parts[1]?.text) {
|
|
2439
2642
|
finalSynthesis = parts[1].text;
|
|
2440
2643
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2441
|
-
const janitorLogDir =
|
|
2442
|
-
if (!
|
|
2443
|
-
|
|
2644
|
+
const janitorLogDir = path16.join(LOGS_DIR, "janitor");
|
|
2645
|
+
if (!fs16.existsSync(janitorLogDir)) {
|
|
2646
|
+
fs16.mkdirSync(janitorLogDir, { recursive: true });
|
|
2444
2647
|
}
|
|
2445
|
-
|
|
2648
|
+
fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: ${finalSynthesis}
|
|
2446
2649
|
`);
|
|
2447
2650
|
} else if (parts && parts[0]?.text) finalSynthesis = parts[0].text;
|
|
2448
2651
|
else if (janitorResult.response && janitorResult.response.text) finalSynthesis = janitorResult.response.text();
|
|
2449
2652
|
else throw new Error("No synthesis generated by Janitor.");
|
|
2450
2653
|
await incrementUsage("background");
|
|
2654
|
+
if (janitorResult.usageMetadata) {
|
|
2655
|
+
await addToUsage("tokens", janitorResult.usageMetadata.totalTokenCount || 0);
|
|
2656
|
+
}
|
|
2451
2657
|
yield { type: "background_increment" };
|
|
2452
2658
|
const janitorToolCalls = detectToolCalls(finalSynthesis);
|
|
2453
2659
|
for (const janitorToolCall of janitorToolCalls) {
|
|
2454
2660
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
2455
2661
|
const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
|
|
2456
2662
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2457
|
-
const janitorLogDir =
|
|
2458
|
-
|
|
2663
|
+
const janitorLogDir = path16.join(LOGS_DIR, "janitor");
|
|
2664
|
+
fs16.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
|
|
2459
2665
|
`);
|
|
2460
2666
|
if (janitorToolCall.toolName === "memory" && !janitorToolCall.args.includes("action='temp'")) {
|
|
2461
2667
|
yield { type: "memory_updated" };
|
|
@@ -2463,11 +2669,11 @@ ${boxBottom}
|
|
|
2463
2669
|
}
|
|
2464
2670
|
} catch (janitorErr) {
|
|
2465
2671
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
2466
|
-
const janitorErrDir =
|
|
2467
|
-
if (!
|
|
2468
|
-
|
|
2672
|
+
const janitorErrDir = path16.join(LOGS_DIR, "janitor");
|
|
2673
|
+
if (!fs16.existsSync(janitorErrDir)) {
|
|
2674
|
+
fs16.mkdirSync(janitorErrDir, { recursive: true });
|
|
2469
2675
|
}
|
|
2470
|
-
|
|
2676
|
+
fs16.appendFileSync(path16.join(janitorErrDir, "error.log"), `ERROR [${date}]: ${janitorErr.message}
|
|
2471
2677
|
`);
|
|
2472
2678
|
console.error("Janitor Background Tasks Failed:", janitorErr.message);
|
|
2473
2679
|
}
|
|
@@ -2496,8 +2702,8 @@ ${timestamp}`;
|
|
|
2496
2702
|
});
|
|
2497
2703
|
|
|
2498
2704
|
// src/utils/settings.js
|
|
2499
|
-
import
|
|
2500
|
-
import
|
|
2705
|
+
import fs17 from "fs-extra";
|
|
2706
|
+
import path17 from "path";
|
|
2501
2707
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
2502
2708
|
var init_settings = __esm({
|
|
2503
2709
|
"src/utils/settings.js"() {
|
|
@@ -2532,8 +2738,8 @@ var init_settings = __esm({
|
|
|
2532
2738
|
};
|
|
2533
2739
|
loadSettings = async () => {
|
|
2534
2740
|
try {
|
|
2535
|
-
if (await
|
|
2536
|
-
const saved = await
|
|
2741
|
+
if (await fs17.exists(SETTINGS_FILE)) {
|
|
2742
|
+
const saved = await fs17.readJson(SETTINGS_FILE);
|
|
2537
2743
|
return {
|
|
2538
2744
|
...DEFAULT_SETTINGS,
|
|
2539
2745
|
...saved,
|
|
@@ -2551,12 +2757,12 @@ var init_settings = __esm({
|
|
|
2551
2757
|
const { FLUXFLOW_DIR: FLUXFLOW_DIR2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
2552
2758
|
const folders = ["logs", "secret"];
|
|
2553
2759
|
for (const folder of folders) {
|
|
2554
|
-
const src =
|
|
2555
|
-
const dest =
|
|
2760
|
+
const src = path17.join(FLUXFLOW_DIR2, folder);
|
|
2761
|
+
const dest = path17.join(newPath, folder);
|
|
2556
2762
|
try {
|
|
2557
|
-
if (await
|
|
2558
|
-
await
|
|
2559
|
-
await
|
|
2763
|
+
if (await fs17.exists(src)) {
|
|
2764
|
+
await fs17.ensureDir(dest);
|
|
2765
|
+
await fs17.copy(src, dest, { overwrite: true });
|
|
2560
2766
|
}
|
|
2561
2767
|
} catch (err) {
|
|
2562
2768
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -2570,8 +2776,8 @@ var init_settings = __esm({
|
|
|
2570
2776
|
await migrateToExternal(settings.systemSettings.externalDataPath);
|
|
2571
2777
|
}
|
|
2572
2778
|
const updated = { ...current, ...settings };
|
|
2573
|
-
await
|
|
2574
|
-
await
|
|
2779
|
+
await fs17.ensureDir(path17.dirname(SETTINGS_FILE));
|
|
2780
|
+
await fs17.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
|
|
2575
2781
|
return true;
|
|
2576
2782
|
} catch (err) {
|
|
2577
2783
|
console.error("Failed to save settings:", err);
|
|
@@ -2724,7 +2930,7 @@ var init_UpdateProcessor = __esm({
|
|
|
2724
2930
|
import puppeteer4 from "puppeteer";
|
|
2725
2931
|
import { exec as exec2 } from "child_process";
|
|
2726
2932
|
import { promisify } from "util";
|
|
2727
|
-
import
|
|
2933
|
+
import fs18 from "fs";
|
|
2728
2934
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
2729
2935
|
var init_setup = __esm({
|
|
2730
2936
|
"src/utils/setup.js"() {
|
|
@@ -2732,7 +2938,7 @@ var init_setup = __esm({
|
|
|
2732
2938
|
checkPuppeteerReady = () => {
|
|
2733
2939
|
try {
|
|
2734
2940
|
const exePath = puppeteer4.executablePath();
|
|
2735
|
-
const exists = exePath &&
|
|
2941
|
+
const exists = exePath && fs18.existsSync(exePath);
|
|
2736
2942
|
if (exists) return true;
|
|
2737
2943
|
} catch (e) {
|
|
2738
2944
|
return false;
|
|
@@ -2765,7 +2971,7 @@ __export(app_exports, {
|
|
|
2765
2971
|
import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
|
|
2766
2972
|
import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
|
|
2767
2973
|
import Spinner2 from "ink-spinner";
|
|
2768
|
-
import
|
|
2974
|
+
import fs19 from "fs-extra";
|
|
2769
2975
|
import { exec as exec3 } from "child_process";
|
|
2770
2976
|
import { MultilineInput } from "ink-multiline-input";
|
|
2771
2977
|
import TextInput3 from "ink-text-input";
|
|
@@ -2857,6 +3063,10 @@ Check what's new using \`/changelog\` command.`,
|
|
|
2857
3063
|
const [sessionAgentCalls, setSessionAgentCalls] = useState7(0);
|
|
2858
3064
|
const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState7(0);
|
|
2859
3065
|
const [sessionTotalTokens, setSessionTotalTokens] = useState7(0);
|
|
3066
|
+
const [sessionToolSuccess, setSessionToolSuccess] = useState7(0);
|
|
3067
|
+
const [sessionToolFailure, setSessionToolFailure] = useState7(0);
|
|
3068
|
+
const [sessionApiTime, setSessionApiTime] = useState7(0);
|
|
3069
|
+
const [sessionToolTime, setSessionToolTime] = useState7(0);
|
|
2860
3070
|
const [dailyUsage, setDailyUsage] = useState7(null);
|
|
2861
3071
|
const [chatId, setChatId] = useState7(generateChatId());
|
|
2862
3072
|
const [activeCommand, setActiveCommand] = useState7(null);
|
|
@@ -2890,6 +3100,10 @@ Check what's new using \`/changelog\` command.`,
|
|
|
2890
3100
|
parts.push(`${s}s`);
|
|
2891
3101
|
return parts.join(" ");
|
|
2892
3102
|
};
|
|
3103
|
+
const formatMsDuration = (ms) => {
|
|
3104
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
3105
|
+
return formatDuration(Math.floor(ms / 1e3));
|
|
3106
|
+
};
|
|
2893
3107
|
const [statusText, setStatusText] = useState7(null);
|
|
2894
3108
|
const [isProcessing, setIsProcessing] = useState7(false);
|
|
2895
3109
|
const [escPressed, setEscPressed] = useState7(false);
|
|
@@ -3072,6 +3286,22 @@ Check what's new using \`/changelog\` command.`,
|
|
|
3072
3286
|
setTempKey("");
|
|
3073
3287
|
}
|
|
3074
3288
|
};
|
|
3289
|
+
useEffect5(() => {
|
|
3290
|
+
if (activeView === "exit") {
|
|
3291
|
+
const timer = setTimeout(() => {
|
|
3292
|
+
process.exit(0);
|
|
3293
|
+
}, 100);
|
|
3294
|
+
return () => clearTimeout(timer);
|
|
3295
|
+
}
|
|
3296
|
+
}, [activeView]);
|
|
3297
|
+
useEffect5(() => {
|
|
3298
|
+
const interval = setInterval(async () => {
|
|
3299
|
+
if (!isInitializing) {
|
|
3300
|
+
await addToUsage("duration", 5);
|
|
3301
|
+
}
|
|
3302
|
+
}, 5e3);
|
|
3303
|
+
return () => clearInterval(interval);
|
|
3304
|
+
}, [isInitializing]);
|
|
3075
3305
|
const COMMANDS = [
|
|
3076
3306
|
{ cmd: "/quit", desc: "Exit and shutdown Flux" },
|
|
3077
3307
|
{ cmd: "/help", desc: "Show all available commands" },
|
|
@@ -3079,24 +3309,36 @@ Check what's new using \`/changelog\` command.`,
|
|
|
3079
3309
|
{ cmd: "/resume", desc: "Load previous session" },
|
|
3080
3310
|
{ cmd: "/save", desc: "Force save current chat" },
|
|
3081
3311
|
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
3082
|
-
{
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3312
|
+
{
|
|
3313
|
+
cmd: "/mode",
|
|
3314
|
+
desc: "Toggle Flux/Flow modes",
|
|
3315
|
+
subs: [
|
|
3316
|
+
{ cmd: "flux", desc: "Enable Dev toolset" },
|
|
3317
|
+
{ cmd: "flow", desc: "Enable Chat mode" }
|
|
3318
|
+
]
|
|
3319
|
+
},
|
|
3320
|
+
{
|
|
3321
|
+
cmd: "/thinking",
|
|
3322
|
+
desc: "Set AI reasoning depth",
|
|
3323
|
+
subs: [
|
|
3324
|
+
{ cmd: "low", desc: "Fastest reasoning" },
|
|
3325
|
+
{ cmd: "medium", desc: "Balanced depth" },
|
|
3326
|
+
{ cmd: "high", desc: "Complex coding" },
|
|
3327
|
+
{ cmd: "max", desc: "Architectural depth" },
|
|
3328
|
+
{ cmd: "show", desc: "Show full thoughts" },
|
|
3329
|
+
{ cmd: "hide", desc: "Show concise thoughts" }
|
|
3330
|
+
]
|
|
3331
|
+
},
|
|
3332
|
+
{
|
|
3333
|
+
cmd: "/model",
|
|
3334
|
+
desc: "Switch AI model",
|
|
3335
|
+
subs: [
|
|
3336
|
+
{ cmd: "gemma-4-31b-it", desc: "Standard Default (Free, Recommended)" },
|
|
3337
|
+
{ cmd: "gemini-3.1-pro-preview", desc: "Most Capable (Paid)" },
|
|
3338
|
+
{ cmd: "gemini-3-flash-preview", desc: "Fast & Lightweight (Paid, Free limited quota)" },
|
|
3339
|
+
{ cmd: "gemini-3.1-flash-lite-preview", desc: "Ultra Fast (Paid, Free limited quota)" }
|
|
3340
|
+
]
|
|
3341
|
+
},
|
|
3100
3342
|
{ cmd: "/settings", desc: "Configure system prefs" },
|
|
3101
3343
|
{ cmd: "/key", desc: "Manage API keys" },
|
|
3102
3344
|
{ cmd: "/profile", desc: "Edit developer persona" },
|
|
@@ -3105,10 +3347,14 @@ Check what's new using \`/changelog\` command.`,
|
|
|
3105
3347
|
{ cmd: "/reset", desc: "Wipe all project data" },
|
|
3106
3348
|
{ cmd: "/about", desc: "Project info & credits" },
|
|
3107
3349
|
{ cmd: "/changelog", desc: "View latest updates" },
|
|
3108
|
-
{
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3350
|
+
{
|
|
3351
|
+
cmd: "/update",
|
|
3352
|
+
desc: "Check/Install updates",
|
|
3353
|
+
subs: [
|
|
3354
|
+
{ cmd: "check", desc: "Check for new version" },
|
|
3355
|
+
{ cmd: "latest", desc: "Install latest release" }
|
|
3356
|
+
]
|
|
3357
|
+
}
|
|
3112
3358
|
];
|
|
3113
3359
|
const handleSubmit = (value) => {
|
|
3114
3360
|
if (suggestions.length > 0) {
|
|
@@ -3310,12 +3556,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
3310
3556
|
setCompletedIndex(prev.length + 1);
|
|
3311
3557
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
3312
3558
|
});
|
|
3313
|
-
if (
|
|
3314
|
-
if (
|
|
3315
|
-
if (
|
|
3559
|
+
if (fs19.existsSync(LOGS_DIR)) fs19.removeSync(LOGS_DIR);
|
|
3560
|
+
if (fs19.existsSync(SECRET_DIR)) fs19.removeSync(SECRET_DIR);
|
|
3561
|
+
if (fs19.existsSync(SETTINGS_FILE)) fs19.removeSync(SETTINGS_FILE);
|
|
3316
3562
|
try {
|
|
3317
|
-
const items =
|
|
3318
|
-
if (items.length === 0)
|
|
3563
|
+
const items = fs19.readdirSync(FLUXFLOW_DIR);
|
|
3564
|
+
if (items.length === 0) fs19.removeSync(FLUXFLOW_DIR);
|
|
3319
3565
|
} catch (e) {
|
|
3320
3566
|
}
|
|
3321
3567
|
setTimeout(() => {
|
|
@@ -3390,6 +3636,7 @@ ${timestamp}` };
|
|
|
3390
3636
|
const streamChat = async () => {
|
|
3391
3637
|
setIsProcessing(true);
|
|
3392
3638
|
setIsExpanded(false);
|
|
3639
|
+
const apiStart = Date.now();
|
|
3393
3640
|
try {
|
|
3394
3641
|
const cleanHistoryForAI = [...messages, userMessage].filter(
|
|
3395
3642
|
(m) => m.role !== "think" && !m.isVisualFeedback && !String(m.id).startsWith("welcome")
|
|
@@ -3426,6 +3673,10 @@ OUTPUT: ${execOutputRef.current}`;
|
|
|
3426
3673
|
setIsTerminalFocused(false);
|
|
3427
3674
|
setExecOutput("");
|
|
3428
3675
|
},
|
|
3676
|
+
onToolResult: (status) => {
|
|
3677
|
+
if (status === "success") setSessionToolSuccess((prev) => prev + 1);
|
|
3678
|
+
else setSessionToolFailure((prev) => prev + 1);
|
|
3679
|
+
},
|
|
3429
3680
|
onToolApproval: async (tool, args) => {
|
|
3430
3681
|
const isAuto = autoAcceptWrites || systemSettings.autoExec;
|
|
3431
3682
|
if (tool === "exec_command") {
|
|
@@ -3556,6 +3807,10 @@ Selection: ${val}`,
|
|
|
3556
3807
|
setSessionBackgroundCalls((prev) => prev + 1);
|
|
3557
3808
|
continue;
|
|
3558
3809
|
}
|
|
3810
|
+
if (packet.type === "tool_time") {
|
|
3811
|
+
setSessionToolTime((prev) => prev + packet.content);
|
|
3812
|
+
continue;
|
|
3813
|
+
}
|
|
3559
3814
|
if (packet.type === "tool_result") {
|
|
3560
3815
|
setMessages((prev) => [...prev, {
|
|
3561
3816
|
id: "tool-" + Date.now(),
|
|
@@ -3655,6 +3910,8 @@ Selection: ${val}`,
|
|
|
3655
3910
|
}
|
|
3656
3911
|
}
|
|
3657
3912
|
}
|
|
3913
|
+
const apiEnd = Date.now();
|
|
3914
|
+
setSessionApiTime((prev) => prev + (apiEnd - apiStart));
|
|
3658
3915
|
} catch (err) {
|
|
3659
3916
|
setMessages((prev) => {
|
|
3660
3917
|
setCompletedIndex(prev.length + 1);
|
|
@@ -3843,9 +4100,8 @@ Selection: ${val}`,
|
|
|
3843
4100
|
{
|
|
3844
4101
|
title: `API Tier: ${apiTier}`,
|
|
3845
4102
|
items: [
|
|
3846
|
-
{ label: "Free Tier (
|
|
3847
|
-
{ label: `
|
|
3848
|
-
{ label: `Custom Model (Endpoint: ${quotas.customModelId || "None"})`, value: "Custom" },
|
|
4103
|
+
{ label: "Free Tier (Gemini API Free Tier - Optimized for Gemma 4 Model)", value: "Free" },
|
|
4104
|
+
{ label: `Custom (for using Paid API)`, value: "Custom" },
|
|
3849
4105
|
{ label: "Back", value: "settings" }
|
|
3850
4106
|
],
|
|
3851
4107
|
onSelect: (item) => {
|
|
@@ -3855,43 +4111,12 @@ Selection: ${val}`,
|
|
|
3855
4111
|
}
|
|
3856
4112
|
const newTier = item.value;
|
|
3857
4113
|
setApiTier(newTier);
|
|
3858
|
-
if (newTier === "
|
|
4114
|
+
if (newTier === "Custom") {
|
|
3859
4115
|
setInputConfig({
|
|
3860
|
-
label: "
|
|
3861
|
-
note: "NOTE: If you have your own Gemini API supported model, use Custom mode.",
|
|
4116
|
+
label: "Enter Agent daily limit (requests made):",
|
|
3862
4117
|
key: "quotas",
|
|
3863
4118
|
subKey: "agentLimit",
|
|
3864
|
-
value: String(quotas.agentLimit)
|
|
3865
|
-
next: (q) => ({
|
|
3866
|
-
label: "Daily default background model limit (Gemma 4 26B A4B):",
|
|
3867
|
-
key: "quotas",
|
|
3868
|
-
subKey: "backgroundLimit",
|
|
3869
|
-
value: String(q.backgroundLimit)
|
|
3870
|
-
})
|
|
3871
|
-
});
|
|
3872
|
-
setActiveView("input");
|
|
3873
|
-
} else if (newTier === "Custom") {
|
|
3874
|
-
setInputConfig({
|
|
3875
|
-
label: "Enter Agent Model ID:",
|
|
3876
|
-
key: "activeModel",
|
|
3877
|
-
value: activeModel,
|
|
3878
|
-
next: (val) => ({
|
|
3879
|
-
label: "Enter Background Model ID:",
|
|
3880
|
-
key: "janitorModel",
|
|
3881
|
-
value: janitorModel,
|
|
3882
|
-
next: (val2) => ({
|
|
3883
|
-
label: "Enter Agent daily limit (calls):",
|
|
3884
|
-
key: "quotas",
|
|
3885
|
-
subKey: "agentLimit",
|
|
3886
|
-
value: String(quotas.agentLimit),
|
|
3887
|
-
next: (q) => ({
|
|
3888
|
-
label: "Enter Background daily limit (calls):",
|
|
3889
|
-
key: "quotas",
|
|
3890
|
-
subKey: "backgroundLimit",
|
|
3891
|
-
value: String(quotas.backgroundLimit)
|
|
3892
|
-
})
|
|
3893
|
-
})
|
|
3894
|
-
})
|
|
4119
|
+
value: String(quotas.agentLimit)
|
|
3895
4120
|
});
|
|
3896
4121
|
setActiveView("input");
|
|
3897
4122
|
} else {
|
|
@@ -3940,7 +4165,7 @@ Selection: ${val}`,
|
|
|
3940
4165
|
}
|
|
3941
4166
|
)), /* @__PURE__ */ React10.createElement(Text10, { dimColor: true, marginTop: 1 }, "(Press Enter to confirm)"));
|
|
3942
4167
|
case "stats":
|
|
3943
|
-
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX:
|
|
4168
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, width: 100 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "SESSION TELEMETRY")), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Session Duration:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(Date.now() - SESSION_START_TIME))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionAgentCalls)), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 23 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionApiTime))), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 23 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionToolTime))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionBackgroundCalls)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Consumed:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, (sessionTotalTokens / 1e3).toFixed(2), "k")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls (Sess):")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, sessionToolSuccess + sessionToolFailure, " ( "), /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u221A ", sessionToolSuccess), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " "), /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", sessionToolFailure), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " )"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "DAILY USAGE TRACKER"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Wall Time Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatDuration(dailyUsage?.duration || 0))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Interactions:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, dailyUsage?.agent || 0)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Background Tasks:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, dailyUsage?.background || 0)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tokens Used Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, ((dailyUsage?.tokens || 0) / 1e3).toFixed(2), "k")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 25 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls Today:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, (dailyUsage?.toolSuccess || 0) + (dailyUsage?.toolFailure || 0), " ( "), /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u221A ", dailyUsage?.toolSuccess || 0), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " "), /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", dailyUsage?.toolFailure || 0), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, " )"))), /* @__PURE__ */ React10.createElement(Text10, { dimColor: true, marginTop: 1, italic: true }, "(Press ESC to return to chat)"));
|
|
3944
4169
|
case "autoExecDanger":
|
|
3945
4170
|
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true, underline: true }, "\u26A0\uFE0F SECURITY WARNING: AUTO-EXEC MODE"), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1 }, "Turning this ON allows the agent to execute terminal commands automatically without requiring your approval for each step."), /* @__PURE__ */ React10.createElement(Text10, { marginTop: 1, color: "yellow" }, "RISKS INVOLVED:"), /* @__PURE__ */ React10.createElement(Text10, null, "\u2022 The agent may execute destructive commands (rm -rf, etc.) by mistake."), /* @__PURE__ */ React10.createElement(Text10, null, "\u2022 Unintended system changes if the agent hallucinates a path or command."), /* @__PURE__ */ React10.createElement(Text10, null, "\u2022 Reduced control over the agent's step-by-step decision making."), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
|
|
3946
4171
|
CommandMenu,
|
|
@@ -4036,24 +4261,15 @@ Selection: ${val}`,
|
|
|
4036
4261
|
}
|
|
4037
4262
|
}
|
|
4038
4263
|
)));
|
|
4039
|
-
case "exit":
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
onSelect: (item) => {
|
|
4049
|
-
if (item.value === "yes") {
|
|
4050
|
-
process.exit(0);
|
|
4051
|
-
} else {
|
|
4052
|
-
setActiveView("chat");
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
}
|
|
4056
|
-
)));
|
|
4264
|
+
case "exit": {
|
|
4265
|
+
const wallTimeMs = Date.now() - SESSION_START_TIME;
|
|
4266
|
+
const totalTools = sessionToolSuccess + sessionToolFailure;
|
|
4267
|
+
const successRate = totalTools > 0 ? (sessionToolSuccess / totalTools * 100).toFixed(1) : "0.0";
|
|
4268
|
+
const agentActiveMs = sessionApiTime + sessionToolTime;
|
|
4269
|
+
const apiPercent = agentActiveMs > 0 ? (sessionApiTime / agentActiveMs * 100).toFixed(1) : "0.0";
|
|
4270
|
+
const toolPercent = agentActiveMs > 0 ? (sessionToolTime / agentActiveMs * 100).toFixed(1) : "0.0";
|
|
4271
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", paddingX: 3, paddingY: 1, borderColor: "red", width: 100 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan", bold: true }, "Agent powering down. ", /* @__PURE__ */ React10.createElement(Text10, { color: "magenta" }, "Goodbye!"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "Interaction Summary"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Session ID:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, chatId)), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Tool Calls:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, totalTools, " ( ", /* @__PURE__ */ React10.createElement(Text10, { color: "green" }, "\u221A ", sessionToolSuccess), " ", /* @__PURE__ */ React10.createElement(Text10, { color: "red" }, "x ", sessionToolFailure), " )")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Success Rate:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, successRate, "%"))), /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "white", bold: true, underline: true }, "Performance"), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Wall Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(wallTimeMs))), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Box10, { width: 20 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue" }, "Agent Active:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(agentActiveMs))), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 18 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB API Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionApiTime), " (", apiPercent, "%)")), /* @__PURE__ */ React10.createElement(Box10, { marginLeft: 2 }, /* @__PURE__ */ React10.createElement(Box10, { width: 18 }, /* @__PURE__ */ React10.createElement(Text10, { color: "blue", dimColor: true }, "\xBB Tool Time:")), /* @__PURE__ */ React10.createElement(Text10, { color: "white" }, formatMsDuration(sessionToolTime), " (", toolPercent, "%)"))));
|
|
4272
|
+
}
|
|
4057
4273
|
case "ask":
|
|
4058
4274
|
return /* @__PURE__ */ React10.createElement(Box10, { width: "100%" }, /* @__PURE__ */ React10.createElement(
|
|
4059
4275
|
AskUserModal_default,
|
|
@@ -4349,7 +4565,7 @@ var init_app = __esm({
|
|
|
4349
4565
|
init_setup();
|
|
4350
4566
|
SESSION_START_TIME = Date.now();
|
|
4351
4567
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
4352
|
-
versionFluxflow = "1.
|
|
4568
|
+
versionFluxflow = "1.7.1";
|
|
4353
4569
|
updatedOn = "2026-05-03";
|
|
4354
4570
|
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(
|
|
4355
4571
|
CommandMenu,
|
|
@@ -4412,5 +4628,5 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
|
|
|
4412
4628
|
console.warn = (...args) => !isNoise(args) && originalWarn(...args);
|
|
4413
4629
|
console.error = (...args) => !isNoise(args) && originalError(...args);
|
|
4414
4630
|
process.stdout.write("\x1Bc");
|
|
4415
|
-
render(/* @__PURE__ */ React11.createElement(App2, null));
|
|
4631
|
+
render(/* @__PURE__ */ React11.createElement(App2, null), { exitOnCtrlC: false });
|
|
4416
4632
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluxflow-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
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"
|