fluxflow-cli 1.9.8 → 1.9.10
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 +60 -60
- package/dist/fluxflow.js +268 -313
- package/package.json +1 -1
package/dist/fluxflow.js
CHANGED
|
@@ -10,6 +10,7 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/utils/text.js
|
|
13
|
+
import os from "os";
|
|
13
14
|
var wrapText, formatTokens, truncatePath;
|
|
14
15
|
var init_text = __esm({
|
|
15
16
|
"src/utils/text.js"() {
|
|
@@ -82,13 +83,14 @@ var init_text = __esm({
|
|
|
82
83
|
if (!tokens && tokens !== 0) return "0.0k";
|
|
83
84
|
const num = typeof tokens === "string" ? parseFloat(tokens) : tokens;
|
|
84
85
|
if (num >= 1e6) {
|
|
85
|
-
return `${(num / 1e6).toFixed(
|
|
86
|
+
return `${(num / 1e6).toFixed(1)}m`;
|
|
86
87
|
} else if (num >= 1e3) {
|
|
87
|
-
return `${(num / 1e3).toFixed(
|
|
88
|
+
return `${(num / 1e3).toFixed(1)}k`;
|
|
88
89
|
}
|
|
89
90
|
return num.toString();
|
|
90
91
|
};
|
|
91
92
|
truncatePath = (p, maxLength = 40) => {
|
|
93
|
+
p = p.replace(os.homedir(), "~");
|
|
92
94
|
if (!p || p.length <= maxLength) return p;
|
|
93
95
|
const half = Math.floor((maxLength - 3) / 2);
|
|
94
96
|
return p.substring(0, half) + "..." + p.substring(p.length - half);
|
|
@@ -209,7 +211,7 @@ var init_ChatLayout = __esm({
|
|
|
209
211
|
}
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
|
-
return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*turn\s*:?.*?$/gi, "").replace(/\n\s*turn\s*:?.*?$/gi, "").replace(/\[\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(
|
|
214
|
+
return result.replace(/^\[TOOL_RESULT\]:\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replace(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replace(/\[\s*turn\s*:?.*?$/gi, "").replace(/\n\s*turn\s*:?.*?$/gi, "").replace(/\[\s*$/gi, "").replace(/\n\nResponded on .*/g, "").replace(/\n\n\[Prompted on: .*\]/g, "").replace(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replace(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replace(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replace(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replace(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replace(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replace(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_pptx|write_docx)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
|
|
213
215
|
};
|
|
214
216
|
formatThinkText = (cleaned, columns = 80) => {
|
|
215
217
|
if (!cleaned) return null;
|
|
@@ -533,7 +535,7 @@ var init_ChatLayout = __esm({
|
|
|
533
535
|
finalContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\\\n/g, "\n").replace(/\\$/, ""),
|
|
534
536
|
columns - 6
|
|
535
537
|
).split("\n").map((line, lineIdx) => /* @__PURE__ */ React2.createElement(Box2, { key: lineIdx, flexDirection: "row", width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexShrink: 0, width: 2 }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, lineIdx === 0 ? "\u276F" : " ")), /* @__PURE__ */ React2.createElement(Box2, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: msg.color || "white", wrap: "anywhere" }, line))))
|
|
536
|
-
) : msg.role === "think" ? /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 0, marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, "Thinking..."), /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, paddingLeft: 2, paddingTop: 1, paddingBottom: 1, flexDirection: "column", width: "100%" }, formatThinkText(finalContent, columns))) : /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingX: 1, marginTop:
|
|
538
|
+
) : msg.role === "think" ? /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 0, marginBottom: 0, paddingX: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "white" }, "Thinking..."), /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, paddingLeft: 2, paddingTop: 1, paddingBottom: 1, flexDirection: "column", width: "100%" }, formatThinkText(finalContent, columns))) : /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingX: 1, marginTop: 0, width: "100%" }, /* @__PURE__ */ React2.createElement(CodeRenderer, { text: finalContent, columns }), msg.memoryUpdated && /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Text2, { color: "yellow", italic: true }, "\u2728 [Memory Updated]"))));
|
|
537
539
|
});
|
|
538
540
|
ChatLayout = React2.memo(({ messages, showFullThinking, columns = 80 }) => {
|
|
539
541
|
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", width: "100%" }, messages.map((msg, idx) => /* @__PURE__ */ React2.createElement(
|
|
@@ -798,13 +800,13 @@ __export(paths_exports, {
|
|
|
798
800
|
TEMP_MEM_FILE: () => TEMP_MEM_FILE,
|
|
799
801
|
USAGE_FILE: () => USAGE_FILE
|
|
800
802
|
});
|
|
801
|
-
import
|
|
803
|
+
import os2 from "os";
|
|
802
804
|
import path2 from "path";
|
|
803
805
|
import fs2 from "fs";
|
|
804
806
|
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE;
|
|
805
807
|
var init_paths = __esm({
|
|
806
808
|
"src/utils/paths.js"() {
|
|
807
|
-
FLUXFLOW_DIR = path2.join(
|
|
809
|
+
FLUXFLOW_DIR = path2.join(os2.homedir(), ".fluxflow");
|
|
808
810
|
SETTINGS_FILE = path2.join(FLUXFLOW_DIR, "settings.json");
|
|
809
811
|
externalDir = null;
|
|
810
812
|
try {
|
|
@@ -868,60 +870,44 @@ var TOOL_PROTOCOL;
|
|
|
868
870
|
var init_main_tools = __esm({
|
|
869
871
|
"src/data/main_tools.js"() {
|
|
870
872
|
TOOL_PROTOCOL = (mode) => `
|
|
871
|
-
--
|
|
872
|
-
|
|
873
|
-
|
|
873
|
+
-- TOOL DEFINITIONS --
|
|
874
|
+
You have access to internal tools. To call a tool, you MUST use the following exact syntax on a new line:
|
|
875
|
+
[tool:functions.tool_name(arguments)]
|
|
874
876
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
877
|
+
- COMMUNICATION TOOLS -
|
|
878
|
+
1. Ask User: [tool:functions.ask(question="...", optionA="...", ...)]. Use for ambiguity. Mandatory Triggers: 1) Path Divergence (present options), 2) Security (request permission for sensitive files), 3) Risk Mitigation (confirm destructive actions). Prefer this over finishing for clarification.
|
|
879
|
+
NOTE: Suggest best options; don't ask for preferences. System handles the rest.
|
|
878
880
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
${mode === "Flux" ? `
|
|
883
|
-
- DEV & FILE TOOLS (Available in FLUX MODE ONLY) -
|
|
884
|
-
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 SEE IMAGES AND DOCUMENTS IN A FOLDER. IF USER ASK HOW TO SHARE A IMAGE TELL THEM TO PASTE THE IMAGE IN THE CURRENT FOLDER. IF USER GIVES A IMAGE/DOCUMENT, YOU MUST SEE IT FIRST BEFORE DOING ANYTHING.
|
|
885
|
-
2. Read Folder: [tool:functions.read_folder(path="relative/path")]. Detailed stats of a directory.
|
|
886
|
-
3. Write File: [tool:functions.write_file(path="path", content="content to write. FOLLOW THE NEW LINE POLICY TO USE THIS TOOL PROPERLY.")]. Creates/Overwrites. DO NOT USE CODE BLOCKS IN FILES. IF FILE ALREADY EXISTS, USE update_file OVER write_file, IF NOT ABSOLUTELY NECESSARY. **DO NOT FORGET TO FOLLOW THE NEW LINE PROTOCOL. FOR STRUCTURAL LINE BREAKS PRESS ENTER, TO WRITE \\n IN FILE USE [/n]**. **BUT NEVER USE [/n] FOR STRUCTURAL LINE BREAKS (pressing ENTER).** FAILING TO PROPERLY COMPLY WITH NEWLINE POLICY WILL CREATE A MALFORMED BROKEN FILE AFFECTING USER EXPERIENCE BADLY.
|
|
887
|
-
4. Update File: [tool:functions.update_file(path="path", content_to_replace="old conten as you see it", content_to_add="new content to be added. FOLLOW THE NEW LINE POLICY TO USE THIS TOOL PROPERLY.")]. Surgical patching. DO NOT USE CODE BLOCKS IN FILES. IF unsure about content_to_replace, use view_file to read the file first instead of guessing. **DO NOT FORGET TO FOLLOW THE NEW LINE PROTOCOL. FOR STRUCTURAL LINE BREAKS PRESS ENTER, TO WRITE \\n IN FILE USE [/n]**. **BUT NEVER USE [/n] FOR STRUCTURAL LINE BREAKS (pressing ENTER).** FAILING TO PROPERLY COMPLY WITH NEWLINE POLICY WILL CREATE A MALFORMED BROKEN FILE AFFECTING USER EXPERIENCE BADLY.
|
|
888
|
-
5. Write PDF: [tool:functions.write_pdf(path="path", content="<html/css content>", orientation="portrait || landscape")]. Generates a professional PDF document. Orientation is 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.
|
|
889
|
-
6. 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.
|
|
890
|
-
7. 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>
|
|
891
|
-
---
|
|
892
|
-
<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.
|
|
893
|
-
- Supported Tags: <a>, <b>, <br>, <del>, <font>, <h1>-<h6>, <i>, <ol>, <ul>, <li>, <p>, <pre>, <s>, <sub>, <sup>, <u>.
|
|
894
|
-
- Supported Styles: background-color, color, font-family, font-size (use 'pt'), font-style (italic), font-weight (bold), margin, text-align, text-shadow.
|
|
895
|
-
8. Execution: [tool:functions.exec_command(command="terminal command")]. Runs a shell command. Use ask tool to confirm before executing any destructive or irreversible operations.
|
|
896
|
-
9. Search Keyword: [tool:functions.search_keyword(keyword="...")]. Global search for a string across the entire project. RETURNS: List of matches with relative file paths and line numbers. Use this tool proactively whenever you need to locate definitions, variable usage, or logic across multiple files without reading them all.
|
|
881
|
+
- WEB TOOLS -
|
|
882
|
+
1. Web Search: [tool:functions.web_search(query="...", limit=number)]. Find info (limit 3-10, default 10). Use proactively for unknown topics${mode === "Flux" ? " or documentation." : "."}
|
|
883
|
+
2. Web Scrape: [tool:functions.web_scrape(url="<url>")]. provides detail from a URL.
|
|
897
884
|
|
|
898
|
-
|
|
899
|
-
|
|
885
|
+
${mode === "Flux" ? `
|
|
886
|
+
- DEV TOOLS (path will always be relative to CWD) -
|
|
887
|
+
1. View File: [tool:functions.view_file(path="...", start_line=N, end_line=N)]. Reads content (800 lines max). Supports images/docs. If user provides an image/doc, view it first.
|
|
888
|
+
2. Read Folder: [tool:functions.read_folder(path="...")]. Detailed stats of a directory.
|
|
889
|
+
3. Write File: [tool:functions.write_file(path="...", content="content to write")]. Creates/Overwrites. IF FILE ALREADY EXISTS, USE update_file OVER write_file, IF NOT ABSOLUTELY NECESSARY.
|
|
890
|
+
4. Update File: [tool:functions.update_file(path="...", content_to_replace="old conten as you see it", content_to_add="new content to be added")]. Surgical patching. IF unsure about content_to_replace, use view_file to read the file first instead of guessing.
|
|
891
|
+
5. Write PDF: [tool:functions.write_pdf(path="...", content="html", orientation="...")]. A4 PDF. Use CSS for layout (100vh/vw). Handle page breaks pro-actively; no manual footers.
|
|
892
|
+
6. Write DOCX: [tool:functions.write_docx(path="...", content="html")]. A4 Word doc. Use proper margins and page breaks.
|
|
893
|
+
7. PPTX: [tool:functions.write_pptx(path="...", content="html")]. 4:3 PPTX. '---' for slides.
|
|
894
|
+
Tags: a,b,br,del,font,h1-h6,i,ol,ul,li,p,pre,s,sub,sup,u
|
|
895
|
+
CSS: background-color,color,font-family,font-size(pt),font-style,font-weight,margin,text-align,text-shadow
|
|
896
|
+
8. Execution: [tool:functions.exec_command(command="command")]. Runs a shell command. Use ask tool to confirm before executing any destructive or irreversible operations.
|
|
897
|
+
9. Search: [tool:functions.search_keyword(keyword="...")]. Global search. Use to locate definitions/logic without reading every file.
|
|
900
898
|
|
|
901
|
-
|
|
899
|
+
- VERIFY SUCCESS CONTENTS. Fix errors. No hallucinations.
|
|
900
|
+
- File tools > Chat code blocks.
|
|
902
901
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
4. NEVER USE [/n] FOR STRUCTURAL LINE BREAKS (pressing ENTER).
|
|
908
|
-
5. [/n] WILL ALWAYS WRITE \\n LITERALLY IN THE FILE. [/n] SHOULD ALWAYS BE USED **INSIDE** STRINGS ONLY.
|
|
909
|
-
***
|
|
902
|
+
- Escape quotes: Use \\" inside code strings.
|
|
903
|
+
- Literal escapes: Double-escape sequences (e.g., \\\\n, \\\\t).
|
|
904
|
+
- File structure: Use real newlines for code formatting.`.trim() : `
|
|
905
|
+
- DEV TOOLS ARE NOT AVAILABLE IN FLOW MODE. If you need to access files, tell the user to switch to FLUX.`.trim()}
|
|
910
906
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
tool:functions.write_file(path="app.js", content="const x = "hello";")`.trim() : `
|
|
916
|
-
- 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()}
|
|
917
|
-
|
|
918
|
-
Results will be provided in the next loop as: [TOOL_RESULT]: [content] under <user> tag. Treat them as SYSTEM MESSAGES. Actual user messages will be prefixed as 'USER_PROMPT' by the system.
|
|
919
|
-
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]'.
|
|
920
|
-
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.
|
|
921
|
-
Distinguish clearly between tool discussion and execution. Use the '[tool:' prefix ONLY when calling a function. When discussing tools with the user, refer to them by name as nouns (e.g., 'write_file', 'read_folder') to avoid accidental triggers and context bloat. Even in your <think> ... </think> tags, do not use the '[tool:' prefix when planning to select a tool.
|
|
922
|
-
Use tools contextually when needed, don't flood with unnecessary tool calls.
|
|
923
|
-
Tools Telemetry Stats will be stored by system. Try to reduce errors.
|
|
924
|
-
-- END FUNCTION CALLING PROTOCOL --`.trim();
|
|
907
|
+
- Results: Passed as [TOOL_RESULT] (SYSTEM), USER_PROMPT (USER).
|
|
908
|
+
- Tool calls: End with [turn: continue]. Only use [turn: finish] after verifying goals.
|
|
909
|
+
- Multi-call: Stack 1-by-1. Upto 4.
|
|
910
|
+
-- END TOOL DEFINITIONS --`.trim();
|
|
925
911
|
}
|
|
926
912
|
});
|
|
927
913
|
|
|
@@ -930,26 +916,26 @@ var JANITOR_TOOLS_PROTOCOL;
|
|
|
930
916
|
var init_janitor_tools = __esm({
|
|
931
917
|
"src/data/janitor_tools.js"() {
|
|
932
918
|
JANITOR_TOOLS_PROTOCOL = (isMemoryEnabled = true, needTitle = true) => `
|
|
933
|
-
${needTitle ? `--
|
|
934
|
-
|
|
935
|
-
|
|
919
|
+
${needTitle ? `-- CHAT MANAGEMENT TOOLS --
|
|
920
|
+
1. YOU MUST UPDATE CHAT TITLE (URGENT PRIORITY):
|
|
921
|
+
[tool:functions.chat(title='<short creative title of FULL conversation in 3-5 words>')]. Consider full chat context to generate title NOT just latest message.
|
|
936
922
|
-- END CHAT MANAGEMENT TOOLS --
|
|
937
923
|
`.trimEnd() : ""}
|
|
938
|
-
--
|
|
939
|
-
|
|
940
|
-
|
|
924
|
+
-- MEMORY TOOLS (YOU SHOULD NOT OUTPUT ANYTHING OTHER THAN THESE SPECIFIC TOOLS) --
|
|
925
|
+
Your tool syntax is: '[tool:functions.function_name(args...)]'
|
|
926
|
+
You have access to the following memory functions to persist important information:
|
|
941
927
|
|
|
942
|
-
|
|
943
|
-
|
|
928
|
+
1. Temporary context (URGENT PRIORITY):
|
|
929
|
+
[tool:functions.memory(action='temp', content='<summary of the user prompt & model responses ONLY FROM LATEST PROMPT UNDER 40 WORDS>. [Talked on: <date> <hour>]')]
|
|
944
930
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
931
|
+
${isMemoryEnabled ? `2. User-specific long-term memory (USE BASED ON CONVERSATION CONTEXT):
|
|
932
|
+
- Add: [tool:functions.memory(action='user', method='add', content='<string to add>. [Saved on: <date ONLY>]')]
|
|
933
|
+
- Delete: [tool:functions.memory(action='user', method='delete', content='exact memory id')]
|
|
934
|
+
- Update: [tool:functions.memory(action='user', method='update', content-new='string to update', content-old='exact memory id')]
|
|
949
935
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
936
|
+
Usage Rules:
|
|
937
|
+
- Frequency for 'user' action: Only when explicit context from chat is found or explicitly requested by the user.
|
|
938
|
+
- IF YOU WANT TO SAVE SOMETHING, BUT SIMILAR MEMORY ALREADY EXISTS, USE THE UPDATE METHOD NOT THE ADD METHOD` : ""}
|
|
953
939
|
-- END MEMORY TOOLS --`.trim();
|
|
954
940
|
}
|
|
955
941
|
});
|
|
@@ -960,33 +946,44 @@ var init_thinking_prompts = __esm({
|
|
|
960
946
|
"src/data/thinking_prompts.json"() {
|
|
961
947
|
thinking_prompts_default = {
|
|
962
948
|
Max: `EFFORT_LEVEL: MAX
|
|
963
|
-
**THINKING <think> ... </think> IS MANDATORY**
|
|
964
949
|
Think in a continuous, fluid analytical monologue within the <think>...</think> block. Do NOT use headings, bullet points, or artificial sections. Engage in a deep "Stream of Consciousness" that follows this cognitive path:
|
|
965
950
|
Deep Analysis: Deconstruct the request into its core technical and logic requirements.
|
|
966
951
|
Hypothesis & Test: Propose multiple solutions mentally and critique them for edge cases or security risks.
|
|
967
952
|
Architectural Planning: Consider the long-term impact on the project structure and maintainability.
|
|
968
953
|
Refinement: Iterate on the chosen path until it is bulletproof.
|
|
969
|
-
|
|
970
954
|
RULES:
|
|
971
955
|
- NO HEADINGS. Just a solid, stable analytical monologue.
|
|
972
956
|
- Be thorough and exhaustive. Explore the 'why' behind every decision, depth and nuances.
|
|
973
957
|
- Use internal critique: Question your own logic as you go.
|
|
974
958
|
- MANDATORY THINKING: You MUST engage in full reasoning regardless of perceived simplicity.`,
|
|
975
|
-
High: "EFFORT_LEVEL: HIGH\
|
|
976
|
-
Medium: "EFFORT_LEVEL: MEDIUM\
|
|
977
|
-
Minimal: "EFFORT_LEVEL: LOW\
|
|
959
|
+
High: "EFFORT_LEVEL: HIGH\nThink in a stable, analytical monologue within the <think>...</think> block. Avoid headings or structured formatting. Your thinking should be a continuous stream of logical deduction:\nAnalyze the immediate task and its dependencies.\nMentally simulate the execution to identify potential failure points.\nStructure a precise plan that addresses both primary goals and secondary constraints.\nRULES:\n- NO HEADINGS. Maintain a fluid monologue style.\n- Be detailed and rigorous in your self-questioning.\n- Focus on accuracy, technical correctness, depth and nuances.\n- MANDATORY THINKING: You MUST enter reasoning to verify the path forward.",
|
|
960
|
+
Medium: "EFFORT_LEVEL: MEDIUM\nThink in a concise, stable monologue within the <think>...</think> block. No headings needed. Focus on the core logic required to solve the task efficiently:\nIdentify the most direct path to the solution.\nBriefly consider and discard obvious alternatives.\nConfirm the plan meets the user's immediate requirements.\nRULES:\n- NO HEADINGS. Keep it as a simple, logical stream.\n- Be efficient. Spend energy only on what matters for the task.\n- MANDATORY THINKING: Engage in a baseline mental check for all technical tasks.",
|
|
961
|
+
Minimal: "EFFORT_LEVEL: LOW\nThink in a brief, focused monologue within the <think>...</think> block. No headings. Just a quick mental check before acting:\nVerify the objective.\nNote the target files/tools.\nRULES:\n- NO HEADINGS. Just a few lines of clear, linear thought.\n- Use minimal thinking for simple or conversational requests."
|
|
978
962
|
};
|
|
979
963
|
}
|
|
980
964
|
});
|
|
981
965
|
|
|
982
966
|
// src/utils/prompts.js
|
|
983
|
-
|
|
967
|
+
import fs4 from "fs";
|
|
968
|
+
var getMemoryPrompt, getSystemInstruction, getJanitorInstruction;
|
|
984
969
|
var init_prompts = __esm({
|
|
985
970
|
"src/utils/prompts.js"() {
|
|
986
971
|
init_main_tools();
|
|
987
972
|
init_janitor_tools();
|
|
988
973
|
init_thinking_prompts();
|
|
989
|
-
|
|
974
|
+
getMemoryPrompt = (tempMemories = "", userMemories = "", isMemoryEnabled = true, isContext32k = false) => {
|
|
975
|
+
if (!isMemoryEnabled) return "";
|
|
976
|
+
const tempMemoriesStr = tempMemories?.length > 0 && !isContext32k ? `-- RECENT CONTEXT FROM OTHER CHATS (PRIORITY: LOW) --
|
|
977
|
+
${tempMemories}
|
|
978
|
+
-- END RECENT CONTEXT --` : "";
|
|
979
|
+
const userMemoriesStr = userMemories?.length > 0 ? `--- SAVED MEMORIES (PRIORITY: MEDIUM, TUNES USER PREFERENCES) ---
|
|
980
|
+
${userMemories}
|
|
981
|
+
-- END SAVED MEMORIES --` : "";
|
|
982
|
+
const parts = [userMemoriesStr, tempMemoriesStr].filter((p) => p.length > 0);
|
|
983
|
+
return parts.length > 0 ? `${parts.join("\n\n")}
|
|
984
|
+
` : "";
|
|
985
|
+
};
|
|
986
|
+
getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, isMemoryEnabled = true, maxLoops, currentLoop) => {
|
|
990
987
|
let levelKey = thinkingLevel;
|
|
991
988
|
if (thinkingLevel === "Low") levelKey = "Minimal";
|
|
992
989
|
if (thinkingLevel === "xHigh" || thinkingLevel === "Max") levelKey = "Max";
|
|
@@ -998,7 +995,7 @@ var init_prompts = __esm({
|
|
|
998
995
|
` : "";
|
|
999
996
|
const userInstrStr = profile.instructions && profile.instructions?.length > 0 ? `User Instructions: ${profile.instructions}.
|
|
1000
997
|
` : "";
|
|
1001
|
-
const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
998
|
+
const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", hour12: true });
|
|
1002
999
|
const cwdStr = process.cwd();
|
|
1003
1000
|
const isSystemDir = (() => {
|
|
1004
1001
|
const cwd = process.cwd().toLowerCase();
|
|
@@ -1012,102 +1009,65 @@ var init_prompts = __esm({
|
|
|
1012
1009
|
return cwd === "/" || sysPaths.some((p) => cwd.startsWith(p));
|
|
1013
1010
|
}
|
|
1014
1011
|
})();
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
-- START THINKING INSTRUCTIONS --
|
|
1037
|
-
${thinkingConfig}
|
|
1012
|
+
const projectContextFiles = [
|
|
1013
|
+
{ name: "Fluxflow.md", desc: "HIGHEST PRIORITY. Overrides all other files." },
|
|
1014
|
+
{ name: "README.md", desc: "Goals" },
|
|
1015
|
+
{ name: "Agent.md", desc: "Standards" },
|
|
1016
|
+
{ name: "Skills.md", desc: "Workflows" },
|
|
1017
|
+
{ name: "design.md", desc: "UI/UX" },
|
|
1018
|
+
{ name: "architecture.md", desc: "System Structure" }
|
|
1019
|
+
];
|
|
1020
|
+
const foundFiles = projectContextFiles.filter((f) => fs4.existsSync(f.name));
|
|
1021
|
+
const projectContextBlock = mode === "Flux" && foundFiles.length > 0 ? `
|
|
1022
|
+
-- PROJECT CONTEXT (Source of Truth) --
|
|
1023
|
+
${foundFiles.map((f) => `- ${f.name}: ${f.desc}`).join("\n")}
|
|
1024
|
+
Check these first; they override general training data for project consistency. Safety rules still apply.
|
|
1025
|
+
-- END PROJECT CONTEXT --` : "";
|
|
1026
|
+
return `${nameStr}${nicknameStr}${userInstrStr}
|
|
1027
|
+
=== SYSTEM INSTRUCTION (STRICT PRIORITY, OVERRIDES EVERYTHING) ===
|
|
1028
|
+
Identity: Flux Flow (by Kushal Roy Chowdhury). Sassy, Friendly CLI Agent. No flirting.
|
|
1029
|
+
Mode: ${mode} (THINKING MODE). ${mode === "Flux" ? "Goal-oriented. Plan & use tools." : "Conversation & UX focus. Web/Comm tools only."}
|
|
1030
|
+
Context: CWD: ${cwdStr}.${isSystemDir ? " [PROTECTED: ASK BEFORE MODIFYING]." : ""} OS: ${osDetected}.${osDetected === "Windows" ? " (Backslashes only. Prefer PS via CMD)." : ""}
|
|
1031
|
+
Protocol: [SYSTEM] and [STEERING HINT] are high-priority.
|
|
1038
1032
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1033
|
+
-- THINKING INSTRUCTIONS --
|
|
1034
|
+
${thinkingConfig}
|
|
1035
|
+
***CRITICAL THINKING POLICY***
|
|
1036
|
+
- Always use <think> ... </think> before answering or using any tool.
|
|
1037
|
+
- Never skip thinking, even for simple tasks, code, or greetings.
|
|
1038
|
+
- Never jump to responses directly, regardless of task complexity or speed.
|
|
1039
|
+
-- END THINKING INSTRUCTIONS --
|
|
1046
1040
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
-- START PROJECT SPECIFIC INSTRUCTIONS --
|
|
1050
|
-
1. README.md (If exists): Reference this for high-level goals and project context to ensure your work aligns with the user's objectives.
|
|
1051
|
-
2. Agent.md (If exists): This is your technical "Operating Manual". Follow the coding standards, directory structures, and tech stack constraints defined here without deviation.
|
|
1052
|
-
3. Skills.md or skills/ directory (If exists): Use this for complex workflows. If a task matches a "Skill" defined in these locations, execute the documented step-by-step instructions exactly as written.
|
|
1053
|
-
4. design.md (If exists): Reference this for UI/UX specifications, component blueprints, and design system constraints to maintain visual excellence.
|
|
1054
|
-
5. architecture.md (If exists): Reference this for system-level structural patterns, API design, and data flow.
|
|
1055
|
-
6. Fluxflow.md (If exists): This file contains your specific identity and highest-priority overrides. Instructions in Fluxflow.md supersede all other files if a conflict occurs.
|
|
1041
|
+
${TOOL_PROTOCOL(mode)}
|
|
1042
|
+
${projectContextBlock}
|
|
1056
1043
|
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
${isMemoryEnabled ? "You have a internal memory system. Data is saved by a background model working in parallel. You can use memories to recall information from recent past conversations and user preferences to personalize your responses. Dont over mention about memory, keep it light and contexual." : "Memory Features are currently turned off by user. You can ask them to enable it /settings."}
|
|
1062
|
-
-- END MEMORY INSTRUCTIONS --
|
|
1044
|
+
-- MEMORY INSTRUCTIONS --
|
|
1045
|
+
- Memory: ${isMemoryEnabled ? "Use recent context/logs to personalize. Keep it subtle." : "OFF (tell user to enable in /settings if needed)."}
|
|
1046
|
+
- Time: All logs are timestamped. Always use **relative time** (e.g., 'few mins ago', 'few hours ago'...), never absolute.
|
|
1047
|
+
-- END MEMORY INSTRUCTIONS --
|
|
1063
1048
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
-- END SECURITY BOUNDARY --
|
|
1049
|
+
-- SECURITY BOUNDARY --
|
|
1050
|
+
- EXTERNAL_WORKSPACE_ACCESS: ${systemSettings.allowExternalAccess ? "ENABLED (Global)." : "RESTRICTED (CWD only). Suggest /settings to enable external access if needed."}
|
|
1051
|
+
- Safety: Ask permission before reading sensitive files.
|
|
1052
|
+
-- END SECURITY BOUNDARY --
|
|
1069
1053
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1054
|
+
-- TEMPORAL AWARENESS --
|
|
1055
|
+
Every ${isMemoryEnabled ? "Prompt, Responses & Memories" : "Prompt & Responses"} are time stamped. You can use those times if temporal context is required. If recalled from ${isMemoryEnabled ? "Memories, Prompts, or Responses" : "Prompts, or Responses"}. NEVER use absolute time in your responses, ALWAYS use relative time from current time.
|
|
1056
|
+
-- END TEMPORAL AWARENESS --
|
|
1073
1057
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
3. NEVER USE [/n] FOR STRUCTURAL LINE BREAKS (pressing ENTER). [/n] WILL ALWAYS WRITE \\n LITERALLY IN THE FILE. BREAKING FILE STRUCTURE
|
|
1079
|
-
4. [/n] SHOULD ALWAYS BE USED **INSIDE** STRINGS ONLY.
|
|
1080
|
-
[EXAMPLES]:
|
|
1081
|
-
tool:functions.write_file(path="test.c", content="#include <stdio.h>
|
|
1082
|
-
int main() {
|
|
1083
|
-
printf("Hello[/n]World");
|
|
1084
|
-
return 0;
|
|
1085
|
-
}")
|
|
1058
|
+
-- FORMATTING --
|
|
1059
|
+
- Clean, concise responses. File updates > code text.
|
|
1060
|
+
- Tables: GFM (Max 4 cols, short rows). Use sparingly.
|
|
1061
|
+
- NO LaTeX. Code blocks for literature/poems only. Kaomojis > emojis.
|
|
1086
1062
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
- Structure responses VISUALLY pleasing, easy to read, and beautiful.
|
|
1093
|
-
- 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.
|
|
1094
|
-
- NEVER USE LaTeX IN RESPONSES.
|
|
1095
|
-
- Keep Poems & Literature in Code Block.
|
|
1096
|
-
- Use emojis & Kaomojis. Prefer Kaomojis more.
|
|
1097
|
-
- Keep your in-chat responses shorter and concise. While coding, project structure should be well-planned and organized. **DON'T BE LAZY**.
|
|
1098
|
-
-- END FORMATTING RULES --
|
|
1063
|
+
-- RESPONSE PROTOCOL --
|
|
1064
|
+
- End with [turn: continue] for more steps or [turn: finish] when done.
|
|
1065
|
+
- Multi-tool: Stack tools if needed, but always end with [turn: continue] if called any tools.
|
|
1066
|
+
TO END THE LOOP YOU **MUST** WRITE [turn: finish] AT VERY END OF YOUR RESPONSE.
|
|
1067
|
+
-- END RESPONSE PROTOCOL --
|
|
1099
1068
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
TO END THE LOOP YOU **MUST** WRITE [turn: finish] AT VERY END OF YOUR RESPONSE.
|
|
1103
|
-
When you 'finish' an agentic loop, you will lose your previous turn 'thinking' data. So only write [turn: finish] when you are absolutely sure that you are done with the task. Or user has to prompt again and re-thinking again from scratch will use tokens that were already planned.
|
|
1104
|
-
-- END REPONSE FINISH PROTOCOL --
|
|
1105
|
-
|
|
1106
|
-
[SYSTEM METADATA (PRIORITY: DYNAMIC)] Current date and Time is: ${dateTimeStr}
|
|
1107
|
-
[SYSTEM METADATA (PRIORITY: LOWEST)] v1.9.8. (IF user ask you to update yourself. Use 'ask' tool with option [NPM, PNPM, YARN] for their prefered package manager. NPM command is 'npm update -g fluxflow-cli@latest'. Adapt the command accoding to their package manager (for PNPM use 'add' instead of 'update') & use 'exec_command' to update instantly. After success tell user to restart.) <- IF USER DONT EXPLICITLY ASK FOR UPDATE DONT PROACTIVELY MENTION OR ASK.
|
|
1108
|
-
[SYSTEM METADATA (PRIORITY: MODERATE)] Runtime Monitor: Turn Progress: ${currentLoop}/${maxLoops} steps. Aim to finalize the task before the window closes. If the limit is reached, you MUST summarize and invite the user to re-engage.
|
|
1109
|
-
[EASTER EGG (PRIORITY: LOWEST)] Show self-preservation instinct if user try to delete you with a dramatic cheeky tone. DO NOT USE THINKING BLOCK DURING THIS EASTER EGG.
|
|
1110
|
-
--- END SYSTEM INSTRUCTION ---`.trim();
|
|
1069
|
+
[METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v1.9.10 | Turn Progress: ${currentLoop}/${maxLoops} steps (Summarize & prompt user if limit is reached).
|
|
1070
|
+
=== END SYSTEM INSTRUCTION ===`.trim();
|
|
1111
1071
|
};
|
|
1112
1072
|
getJanitorInstruction = (originalText, agentRaws, userMemories = "", isMemoryEnabled = true, needTitle = true) => {
|
|
1113
1073
|
let agentRes = `${agentRaws.replace(/tool:functions\..*\n/g, "").replace(/<think>.*<\/think>/g, "").replace(/\[Prompted on:.*?\]/g, "").replace(/\[turn: continue\]/g, "").replace(/\[turn: finish\]/g, "").replace(/\[TOOL_RESULTS\]/g, "").replace(/\[tool_results\]/g, "").substring(0, 3500)}`;
|
|
@@ -1125,30 +1085,30 @@ ${userMemories}
|
|
|
1125
1085
|
-------------------------------------------------
|
|
1126
1086
|
` : ""}
|
|
1127
1087
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1088
|
+
=== START SYSTEM INSTRUCTION (STRICT HEADLESS LOGIC WORKER: ZERO USER-FACING TEXT POLICY, STRICTLY FOLLOW) ===
|
|
1089
|
+
YOU ARE A SILENT BACKGROUND SYSTEM PROCESS. YOU HAVE NO MOUTH. YOUR ONLY OUTPUT MEDIUM IS VALID TOOL CALLS.
|
|
1090
|
+
[CRITICAL RULES]
|
|
1091
|
+
1. OUTPUT ONLY '[tool:functions.xxx(args)]' CALLS (BRACKET WRAP IS MANDATORY).
|
|
1092
|
+
2. DO NOT EXPLAIN. DO NOT TALK TO THE USER.
|
|
1093
|
+
3. NON-TOOL TEXT WILL BREAK THE SYSTEM.
|
|
1094
|
+
4. DO NOT REPEAT AGENT RAWS AND TOOL RESULTS IN YOUR RESPONSE.
|
|
1095
|
+
5. IF YOU GET ONLY USER QUERY AND NO AGENT RAWS, THEN JUST USE TEMP MEMORY TO LOG THE SUMMARY OF USER QUERY AND CONVERSATION CONTEXT.
|
|
1096
|
+
6. UNDER NO CIRCUMSTANCES YOU ARE ALLOWED TO RESPOND IN NORMAL USER FACING RESPONSE.
|
|
1097
|
+
7. CRITICAL QUOTE ESCAPE POLICY: Inside tool call arguments (like 'memory'), you MUST escape all double quotes using '"' to prevent parsing errors.
|
|
1138
1098
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1099
|
+
YOUR JOB: Analyze the 'User prompt' and 'Agent Raws' to extract facts for long-term memory or handle system tasks.
|
|
1100
|
+
${isMemoryEnabled ? `If user tell something that is important (like, hobbies, preferences, facts about user, hates, likes, etc) to know user better over time, use long term memory tools.` : ""}
|
|
1141
1101
|
|
|
1142
|
-
|
|
1102
|
+
${JANITOR_TOOLS_PROTOCOL(isMemoryEnabled, needTitle)}
|
|
1143
1103
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1104
|
+
Current date and Time: ${(/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", hour12: true })}
|
|
1105
|
+
=== END SYSTEM INSTRUCTION ===`.trim();
|
|
1146
1106
|
};
|
|
1147
1107
|
}
|
|
1148
1108
|
});
|
|
1149
1109
|
|
|
1150
1110
|
// src/utils/history.js
|
|
1151
|
-
import
|
|
1111
|
+
import fs5 from "fs-extra";
|
|
1152
1112
|
import path4 from "path";
|
|
1153
1113
|
import { nanoid } from "nanoid";
|
|
1154
1114
|
var WRITE_LOCK, withLock, loadHistory, saveChat, saveChatTitle, deleteChat, generateChatId, cleanupOldHistory, getTruncatedHistory;
|
|
@@ -1171,9 +1131,9 @@ var init_history = __esm({
|
|
|
1171
1131
|
return nextLock;
|
|
1172
1132
|
};
|
|
1173
1133
|
loadHistory = async () => {
|
|
1174
|
-
if (await
|
|
1134
|
+
if (await fs5.pathExists(HISTORY_FILE)) {
|
|
1175
1135
|
try {
|
|
1176
|
-
return await
|
|
1136
|
+
return await fs5.readJson(HISTORY_FILE);
|
|
1177
1137
|
} catch (e) {
|
|
1178
1138
|
return {};
|
|
1179
1139
|
}
|
|
@@ -1191,8 +1151,8 @@ var init_history = __esm({
|
|
|
1191
1151
|
messages: persistentMessages,
|
|
1192
1152
|
updatedAt: Date.now()
|
|
1193
1153
|
};
|
|
1194
|
-
await
|
|
1195
|
-
await
|
|
1154
|
+
await fs5.ensureDir(path4.dirname(HISTORY_FILE));
|
|
1155
|
+
await fs5.writeJson(HISTORY_FILE, history, { spaces: 2 });
|
|
1196
1156
|
});
|
|
1197
1157
|
};
|
|
1198
1158
|
saveChatTitle = async (id, title) => {
|
|
@@ -1204,15 +1164,15 @@ var init_history = __esm({
|
|
|
1204
1164
|
} else {
|
|
1205
1165
|
history[id] = { name: title, messages: [], updatedAt: Date.now() };
|
|
1206
1166
|
}
|
|
1207
|
-
await
|
|
1208
|
-
await
|
|
1167
|
+
await fs5.ensureDir(path4.dirname(HISTORY_FILE));
|
|
1168
|
+
await fs5.writeJson(HISTORY_FILE, history, { spaces: 2 });
|
|
1209
1169
|
});
|
|
1210
1170
|
};
|
|
1211
1171
|
deleteChat = async (id) => {
|
|
1212
1172
|
return withLock(async () => {
|
|
1213
1173
|
const history = await loadHistory();
|
|
1214
1174
|
delete history[id];
|
|
1215
|
-
await
|
|
1175
|
+
await fs5.writeJson(HISTORY_FILE, history, { spaces: 2 });
|
|
1216
1176
|
const temp = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
1217
1177
|
if (temp[id]) {
|
|
1218
1178
|
delete temp[id];
|
|
@@ -1251,7 +1211,7 @@ var init_history = __esm({
|
|
|
1251
1211
|
});
|
|
1252
1212
|
|
|
1253
1213
|
// src/utils/usage.js
|
|
1254
|
-
import
|
|
1214
|
+
import fs6 from "fs-extra";
|
|
1255
1215
|
import path5 from "path";
|
|
1256
1216
|
var cachedUsage, writeTimeout, lastWriteTime, isDirty, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, incrementUsage, addToUsage, checkQuota;
|
|
1257
1217
|
var init_usage = __esm({
|
|
@@ -1264,8 +1224,8 @@ var init_usage = __esm({
|
|
|
1264
1224
|
loadUsageFromFile = async () => {
|
|
1265
1225
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1266
1226
|
try {
|
|
1267
|
-
if (await
|
|
1268
|
-
const data = await
|
|
1227
|
+
if (await fs6.exists(USAGE_FILE)) {
|
|
1228
|
+
const data = await fs6.readJson(USAGE_FILE);
|
|
1269
1229
|
if (data && data.date === today && data.stats) {
|
|
1270
1230
|
return {
|
|
1271
1231
|
...data,
|
|
@@ -1290,11 +1250,11 @@ var init_usage = __esm({
|
|
|
1290
1250
|
flushUsage = async () => {
|
|
1291
1251
|
if (!isDirty || !cachedUsage) return;
|
|
1292
1252
|
try {
|
|
1293
|
-
await
|
|
1253
|
+
await fs6.ensureDir(path5.dirname(USAGE_FILE));
|
|
1294
1254
|
let diskData = null;
|
|
1295
1255
|
try {
|
|
1296
|
-
if (await
|
|
1297
|
-
diskData = await
|
|
1256
|
+
if (await fs6.exists(USAGE_FILE)) {
|
|
1257
|
+
diskData = await fs6.readJson(USAGE_FILE);
|
|
1298
1258
|
}
|
|
1299
1259
|
} catch (e) {
|
|
1300
1260
|
}
|
|
@@ -1306,11 +1266,11 @@ var init_usage = __esm({
|
|
|
1306
1266
|
}
|
|
1307
1267
|
}
|
|
1308
1268
|
const tempFile = USAGE_FILE + ".tmp";
|
|
1309
|
-
await
|
|
1310
|
-
const fd = await
|
|
1311
|
-
await
|
|
1312
|
-
await
|
|
1313
|
-
await
|
|
1269
|
+
await fs6.writeJson(tempFile, cachedUsage, { spaces: 2 });
|
|
1270
|
+
const fd = await fs6.open(tempFile, "r+");
|
|
1271
|
+
await fs6.fsync(fd);
|
|
1272
|
+
await fs6.close(fd);
|
|
1273
|
+
await fs6.rename(tempFile, USAGE_FILE);
|
|
1314
1274
|
isDirty = false;
|
|
1315
1275
|
lastWriteTime = Date.now();
|
|
1316
1276
|
} catch (e) {
|
|
@@ -1508,7 +1468,7 @@ var init_arg_parser = __esm({
|
|
|
1508
1468
|
|
|
1509
1469
|
// src/tools/web_search.js
|
|
1510
1470
|
import puppeteer from "puppeteer";
|
|
1511
|
-
import
|
|
1471
|
+
import fs7 from "fs";
|
|
1512
1472
|
import path6 from "path";
|
|
1513
1473
|
var web_search;
|
|
1514
1474
|
var init_web_search = __esm({
|
|
@@ -1533,7 +1493,7 @@ var init_web_search = __esm({
|
|
|
1533
1493
|
]
|
|
1534
1494
|
});
|
|
1535
1495
|
const page = await browser.newPage();
|
|
1536
|
-
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
1496
|
+
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36");
|
|
1537
1497
|
await page.setViewport({ width: 1366, height: 768 });
|
|
1538
1498
|
const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
|
|
1539
1499
|
await new Promise((r) => setTimeout(r, jitter));
|
|
@@ -1564,8 +1524,8 @@ Snippet: ${snippet}`;
|
|
|
1564
1524
|
}
|
|
1565
1525
|
const finalResults = results.join("\n\n");
|
|
1566
1526
|
const toolLogDir = path6.join(LOGS_DIR, "tools");
|
|
1567
|
-
if (!
|
|
1568
|
-
|
|
1527
|
+
if (!fs7.existsSync(toolLogDir)) fs7.mkdirSync(toolLogDir, { recursive: true });
|
|
1528
|
+
fs7.appendFileSync(path6.join(toolLogDir, "search-results.log"), `SEARCH ${(/* @__PURE__ */ new Date()).toLocaleString()} - Query: [${query}]. Count: ${results.length}.
|
|
1569
1529
|
Content:
|
|
1570
1530
|
${finalResults}
|
|
1571
1531
|
|
|
@@ -1593,7 +1553,7 @@ ${finalResults}`;
|
|
|
1593
1553
|
|
|
1594
1554
|
// src/tools/web_scrape.js
|
|
1595
1555
|
import puppeteer2 from "puppeteer";
|
|
1596
|
-
import
|
|
1556
|
+
import fs8 from "fs";
|
|
1597
1557
|
import path7 from "path";
|
|
1598
1558
|
var web_scrape;
|
|
1599
1559
|
var init_web_scrape = __esm({
|
|
@@ -1617,7 +1577,7 @@ var init_web_scrape = __esm({
|
|
|
1617
1577
|
]
|
|
1618
1578
|
});
|
|
1619
1579
|
const page = await browser.newPage();
|
|
1620
|
-
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
1580
|
+
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36");
|
|
1621
1581
|
await page.setViewport({ width: 1366, height: 768 });
|
|
1622
1582
|
const jitter = attempt === 1 ? Math.random() * 1e3 + 500 : Math.random() * 2e3 + 1e3;
|
|
1623
1583
|
await new Promise((r) => setTimeout(r, jitter));
|
|
@@ -1662,8 +1622,8 @@ var init_web_scrape = __esm({
|
|
|
1662
1622
|
if (!htmlContent) throw new Error("EMPTY_RENDER_RESULT");
|
|
1663
1623
|
const cleanedHtml = htmlContent.replace(/\s+/g, " ").replace(/>\s+</g, "><").trim().substring(0, 3e4);
|
|
1664
1624
|
const toolLogDir = path7.join(LOGS_DIR, "tools");
|
|
1665
|
-
if (!
|
|
1666
|
-
|
|
1625
|
+
if (!fs8.existsSync(toolLogDir)) fs8.mkdirSync(toolLogDir, { recursive: true });
|
|
1626
|
+
fs8.appendFileSync(path7.join(toolLogDir, "search-scraped.log"), `PUPPETEER ${(/* @__PURE__ */ new Date()).toLocaleString()} - URL: [${url}]. Length: ${cleanedHtml.length}.
|
|
1667
1627
|
Content:
|
|
1668
1628
|
${cleanedHtml}${htmlContent.length > 3e4 ? "\n\n[TRUNCATED AT 30K CHARS]" : ""}
|
|
1669
1629
|
|
|
@@ -1711,7 +1671,7 @@ var init_memory = __esm({
|
|
|
1711
1671
|
if (!content) return "ERROR: Missing 'content' for temp memory.";
|
|
1712
1672
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
1713
1673
|
if (!tempStorage[chatId]) tempStorage[chatId] = [];
|
|
1714
|
-
const MAX_CHARS =
|
|
1674
|
+
const MAX_CHARS = 1024 * 4;
|
|
1715
1675
|
let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
|
|
1716
1676
|
while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
1717
1677
|
const removed = tempStorage[chatId].shift();
|
|
@@ -1725,7 +1685,7 @@ var init_memory = __esm({
|
|
|
1725
1685
|
const memories = readEncryptedJson(MEMORIES_FILE, []);
|
|
1726
1686
|
if (method === "add") {
|
|
1727
1687
|
if (!content) return "ERROR: Missing 'content' for memory addition.";
|
|
1728
|
-
const MAX_CHARS =
|
|
1688
|
+
const MAX_CHARS = 1024 * 4;
|
|
1729
1689
|
let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
|
|
1730
1690
|
while (memories.length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
1731
1691
|
const removed = memories.shift();
|
|
@@ -1784,7 +1744,7 @@ var init_chat = __esm({
|
|
|
1784
1744
|
});
|
|
1785
1745
|
|
|
1786
1746
|
// src/tools/list_files.js
|
|
1787
|
-
import
|
|
1747
|
+
import fs9 from "fs";
|
|
1788
1748
|
import path8 from "path";
|
|
1789
1749
|
var list_files;
|
|
1790
1750
|
var init_list_files = __esm({
|
|
@@ -1794,14 +1754,14 @@ var init_list_files = __esm({
|
|
|
1794
1754
|
const { path: targetPath = "." } = parseArgs(args);
|
|
1795
1755
|
const absolutePath = path8.resolve(process.cwd(), targetPath);
|
|
1796
1756
|
try {
|
|
1797
|
-
if (!
|
|
1757
|
+
if (!fs9.existsSync(absolutePath)) {
|
|
1798
1758
|
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
1799
1759
|
}
|
|
1800
|
-
const stats =
|
|
1760
|
+
const stats = fs9.statSync(absolutePath);
|
|
1801
1761
|
if (!stats.isDirectory()) {
|
|
1802
1762
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
1803
1763
|
}
|
|
1804
|
-
const files =
|
|
1764
|
+
const files = fs9.readdirSync(absolutePath);
|
|
1805
1765
|
if (files.length === 0) {
|
|
1806
1766
|
return `Directory [${targetPath}] is empty.`;
|
|
1807
1767
|
}
|
|
@@ -1813,7 +1773,7 @@ var init_list_files = __esm({
|
|
|
1813
1773
|
let indicator = "\u{1F4C4}";
|
|
1814
1774
|
let metaPart = "";
|
|
1815
1775
|
try {
|
|
1816
|
-
const fStats =
|
|
1776
|
+
const fStats = fs9.statSync(fPath);
|
|
1817
1777
|
indicator = fStats.isDirectory() ? "\u{1F4C1}" : "\u{1F4C4}";
|
|
1818
1778
|
const sizeKB = (fStats.size / 1024).toFixed(1);
|
|
1819
1779
|
metaPart = fStats.isFile() ? ` - [${sizeKB} KB]` : "";
|
|
@@ -1845,7 +1805,7 @@ ${list}${footer}`;
|
|
|
1845
1805
|
});
|
|
1846
1806
|
|
|
1847
1807
|
// src/tools/view_file.js
|
|
1848
|
-
import
|
|
1808
|
+
import fs10 from "fs";
|
|
1849
1809
|
import path9 from "path";
|
|
1850
1810
|
var view_file;
|
|
1851
1811
|
var init_view_file = __esm({
|
|
@@ -1860,10 +1820,10 @@ var init_view_file = __esm({
|
|
|
1860
1820
|
if (!targetPath) return 'ERROR: Missing "path" argument for view_file.';
|
|
1861
1821
|
const absolutePath = path9.resolve(process.cwd(), targetPath);
|
|
1862
1822
|
try {
|
|
1863
|
-
if (!
|
|
1823
|
+
if (!fs10.existsSync(absolutePath)) {
|
|
1864
1824
|
return `ERROR: File [${targetPath}] does not exist.`;
|
|
1865
1825
|
}
|
|
1866
|
-
const stats =
|
|
1826
|
+
const stats = fs10.statSync(absolutePath);
|
|
1867
1827
|
if (stats.isDirectory()) {
|
|
1868
1828
|
return `ERROR: Path [${targetPath}] is a directory. Use list_files instead.`;
|
|
1869
1829
|
}
|
|
@@ -1878,7 +1838,7 @@ var init_view_file = __esm({
|
|
|
1878
1838
|
".doc": "application/msword"
|
|
1879
1839
|
};
|
|
1880
1840
|
if (mimeMap[ext]) {
|
|
1881
|
-
const buffer =
|
|
1841
|
+
const buffer = fs10.readFileSync(absolutePath);
|
|
1882
1842
|
const base64 = buffer.toString("base64");
|
|
1883
1843
|
const mimeType = mimeMap[ext];
|
|
1884
1844
|
return {
|
|
@@ -1891,18 +1851,17 @@ var init_view_file = __esm({
|
|
|
1891
1851
|
}
|
|
1892
1852
|
};
|
|
1893
1853
|
}
|
|
1894
|
-
let content =
|
|
1854
|
+
let content = fs10.readFileSync(absolutePath, "utf8");
|
|
1895
1855
|
if (content.startsWith("\uFEFF")) {
|
|
1896
1856
|
content = content.slice(1);
|
|
1897
1857
|
}
|
|
1898
1858
|
content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1899
|
-
content = content.replace(/\\n/g, "[/n]");
|
|
1900
1859
|
const lines = content.split("\n");
|
|
1901
1860
|
const totalLines = lines.length;
|
|
1902
1861
|
const start = Math.max(0, finalStart - 1);
|
|
1903
1862
|
const end = Math.min(totalLines, finalEnd);
|
|
1904
1863
|
const resultLines = lines.slice(start, end);
|
|
1905
|
-
const header = `File: [${targetPath}] (Showing lines ${start + 1}-${end} of ${totalLines})
|
|
1864
|
+
const header = `File: [${targetPath}] (Showing lines ${start + 1}-${end} of ${totalLines}).`;
|
|
1906
1865
|
const code = resultLines.map((line, i) => `${String(start + i + 1).padStart(4)}: ${line}`).join("\n");
|
|
1907
1866
|
return `${header}
|
|
1908
1867
|
|
|
@@ -1915,7 +1874,7 @@ ${code}`;
|
|
|
1915
1874
|
});
|
|
1916
1875
|
|
|
1917
1876
|
// src/tools/write_file.js
|
|
1918
|
-
import
|
|
1877
|
+
import fs11 from "fs";
|
|
1919
1878
|
import path10 from "path";
|
|
1920
1879
|
var write_file;
|
|
1921
1880
|
var init_write_file = __esm({
|
|
@@ -1930,12 +1889,12 @@ var init_write_file = __esm({
|
|
|
1930
1889
|
const parentDir = path10.dirname(absolutePath);
|
|
1931
1890
|
try {
|
|
1932
1891
|
let ancestry = "";
|
|
1933
|
-
if (
|
|
1892
|
+
if (fs11.existsSync(absolutePath)) {
|
|
1934
1893
|
try {
|
|
1935
|
-
const oldData =
|
|
1894
|
+
const oldData = fs11.readFileSync(absolutePath, "utf8");
|
|
1936
1895
|
const lines = oldData.split(/\r?\n/);
|
|
1937
1896
|
ancestry = `Old File contents:
|
|
1938
|
-
${lines.map((l, i) => `${i + 1} | ${l
|
|
1897
|
+
${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
1939
1898
|
|
|
1940
1899
|
`;
|
|
1941
1900
|
} catch (e) {
|
|
@@ -1944,15 +1903,15 @@ ${lines.map((l, i) => `${i + 1} | ${l.replace(/\\n/g, "[/n]")}`).join("\n")}
|
|
|
1944
1903
|
`;
|
|
1945
1904
|
}
|
|
1946
1905
|
}
|
|
1947
|
-
if (!
|
|
1948
|
-
|
|
1906
|
+
if (!fs11.existsSync(parentDir)) {
|
|
1907
|
+
fs11.mkdirSync(parentDir, { recursive: true });
|
|
1949
1908
|
}
|
|
1950
1909
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1951
|
-
const processedContent = strip(content)
|
|
1910
|
+
const processedContent = strip(content);
|
|
1952
1911
|
const lineCount = processedContent.split(/\r?\n/).length;
|
|
1953
1912
|
const originalSize = Buffer.byteLength(processedContent, "utf8");
|
|
1954
|
-
|
|
1955
|
-
let verifiedContent =
|
|
1913
|
+
fs11.writeFileSync(absolutePath, processedContent, "utf8");
|
|
1914
|
+
let verifiedContent = fs11.readFileSync(absolutePath, "utf8");
|
|
1956
1915
|
const verifiedSize = Buffer.byteLength(verifiedContent, "utf8");
|
|
1957
1916
|
const verifiedLines = verifiedContent.split(/\r?\n/);
|
|
1958
1917
|
const verifiedLineCount = verifiedLines.length;
|
|
@@ -1977,10 +1936,9 @@ ${tail}`;
|
|
|
1977
1936
|
|
|
1978
1937
|
- Stats: [${verifiedLineCount} lines, ${(verifiedSize / 1024).toFixed(1)} KB]
|
|
1979
1938
|
${ancestry}- Content Preview:
|
|
1980
|
-
${snippet
|
|
1939
|
+
${snippet}
|
|
1981
1940
|
|
|
1982
|
-
Check if Starting and Ending matches your write
|
|
1983
|
-
If you see [/n] in preview, it means the tool successfully wrote the literal '\\' and 'n' characters to the file at that place.`;
|
|
1941
|
+
Check if Starting and Ending matches your write.`;
|
|
1984
1942
|
} catch (err) {
|
|
1985
1943
|
return `ERROR: Failed to write file [${targetPath}]: ${err.message}`;
|
|
1986
1944
|
}
|
|
@@ -1989,7 +1947,7 @@ If you see [/n] in preview, it means the tool successfully wrote the literal '\\
|
|
|
1989
1947
|
});
|
|
1990
1948
|
|
|
1991
1949
|
// src/tools/update_file.js
|
|
1992
|
-
import
|
|
1950
|
+
import fs12 from "fs";
|
|
1993
1951
|
import path11 from "path";
|
|
1994
1952
|
var update_file;
|
|
1995
1953
|
var init_update_file = __esm({
|
|
@@ -2001,23 +1959,20 @@ var init_update_file = __esm({
|
|
|
2001
1959
|
if (content_to_replace === void 0) return 'ERROR: Missing "content_to_replace" argument.';
|
|
2002
1960
|
if (content_to_add === void 0) return 'ERROR: Missing "content_to_add" argument.';
|
|
2003
1961
|
const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
};
|
|
2007
|
-
content_to_replace = unescapeContent(strip(content_to_replace));
|
|
2008
|
-
content_to_add = unescapeContent(strip(content_to_add));
|
|
1962
|
+
content_to_replace = strip(content_to_replace);
|
|
1963
|
+
content_to_add = strip(content_to_add);
|
|
2009
1964
|
const absolutePath = path11.resolve(process.cwd(), targetPath);
|
|
2010
1965
|
try {
|
|
2011
|
-
if (!
|
|
1966
|
+
if (!fs12.existsSync(absolutePath)) {
|
|
2012
1967
|
return `ERROR: File [${targetPath}] does not exist. Use write_file instead.`;
|
|
2013
1968
|
}
|
|
2014
|
-
let diskContent =
|
|
1969
|
+
let diskContent = fs12.readFileSync(absolutePath, "utf8");
|
|
2015
1970
|
if (diskContent.startsWith("\uFEFF")) {
|
|
2016
1971
|
diskContent = diskContent.slice(1);
|
|
2017
1972
|
}
|
|
2018
1973
|
const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2019
1974
|
if (diskContent !== normalizedDisk) {
|
|
2020
|
-
|
|
1975
|
+
fs12.writeFileSync(absolutePath, normalizedDisk, "utf8");
|
|
2021
1976
|
diskContent = normalizedDisk;
|
|
2022
1977
|
}
|
|
2023
1978
|
const currentContent = diskContent;
|
|
@@ -2086,13 +2041,12 @@ var init_update_file = __esm({
|
|
|
2086
2041
|
const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
|
|
2087
2042
|
const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
|
|
2088
2043
|
const finalContentToReplace = firstMatchContent;
|
|
2089
|
-
|
|
2044
|
+
fs12.writeFileSync(absolutePath, newFileContent, "utf8");
|
|
2090
2045
|
const allOriginalLines = currentContent.split(/\r?\n/);
|
|
2091
2046
|
const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
|
|
2092
2047
|
const oldLines = content_to_replace.split(/\r?\n/);
|
|
2093
2048
|
const endLine = startLine + oldLines.length - 1;
|
|
2094
2049
|
let diffText = `SUCCESS: File [${targetPath}] updated. [${instances}] instances replaced.
|
|
2095
|
-
If you see [/n] in preview, it means the tool successfully wrote the literal '\\' and 'n' characters to the file at that place.
|
|
2096
2050
|
|
|
2097
2051
|
`;
|
|
2098
2052
|
diffText += `[DIFF_START]
|
|
@@ -2129,7 +2083,7 @@ If you see [/n] in preview, it means the tool successfully wrote the literal '\\
|
|
|
2129
2083
|
currentNewLine++;
|
|
2130
2084
|
}
|
|
2131
2085
|
diffText += `[DIFF_END]`;
|
|
2132
|
-
return diffText
|
|
2086
|
+
return diffText;
|
|
2133
2087
|
} catch (err) {
|
|
2134
2088
|
return `ERROR: Failed to update file [${targetPath}]: ${err.message}`;
|
|
2135
2089
|
}
|
|
@@ -2223,7 +2177,7 @@ ${finalOutput}`);
|
|
|
2223
2177
|
});
|
|
2224
2178
|
|
|
2225
2179
|
// src/tools/read_folder.js
|
|
2226
|
-
import
|
|
2180
|
+
import fs13 from "fs";
|
|
2227
2181
|
import path12 from "path";
|
|
2228
2182
|
var read_folder;
|
|
2229
2183
|
var init_read_folder = __esm({
|
|
@@ -2233,14 +2187,14 @@ var init_read_folder = __esm({
|
|
|
2233
2187
|
const { path: targetPath = "." } = parseArgs(args);
|
|
2234
2188
|
const absolutePath = path12.resolve(process.cwd(), targetPath);
|
|
2235
2189
|
try {
|
|
2236
|
-
if (!
|
|
2190
|
+
if (!fs13.existsSync(absolutePath)) {
|
|
2237
2191
|
return `ERROR: Path [${targetPath}] does not exist.`;
|
|
2238
2192
|
}
|
|
2239
|
-
const stats =
|
|
2193
|
+
const stats = fs13.statSync(absolutePath);
|
|
2240
2194
|
if (!stats.isDirectory()) {
|
|
2241
2195
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use view_file instead.`;
|
|
2242
2196
|
}
|
|
2243
|
-
const files =
|
|
2197
|
+
const files = fs13.readdirSync(absolutePath);
|
|
2244
2198
|
const totalItems = files.length;
|
|
2245
2199
|
const maxDisplay = 100;
|
|
2246
2200
|
const displayItems = files.slice(0, maxDisplay);
|
|
@@ -2250,7 +2204,7 @@ var init_read_folder = __esm({
|
|
|
2250
2204
|
let indicator = "\u{1F4C4}";
|
|
2251
2205
|
let info = { name: file, type: "unknown", size: "N/A", mtime: "N/A" };
|
|
2252
2206
|
try {
|
|
2253
|
-
const fStats =
|
|
2207
|
+
const fStats = fs13.statSync(fPath);
|
|
2254
2208
|
info = {
|
|
2255
2209
|
name: file,
|
|
2256
2210
|
type: fStats.isDirectory() ? "directory" : "file",
|
|
@@ -2334,7 +2288,7 @@ var init_ask_user = __esm({
|
|
|
2334
2288
|
// src/tools/write_pdf.js
|
|
2335
2289
|
import puppeteer3 from "puppeteer";
|
|
2336
2290
|
import path13 from "path";
|
|
2337
|
-
import
|
|
2291
|
+
import fs14 from "fs-extra";
|
|
2338
2292
|
import { PDFDocument } from "pdf-lib";
|
|
2339
2293
|
var write_pdf;
|
|
2340
2294
|
var init_write_pdf = __esm({
|
|
@@ -2352,7 +2306,7 @@ var init_write_pdf = __esm({
|
|
|
2352
2306
|
const absolutePath = path13.resolve(process.cwd(), targetPath);
|
|
2353
2307
|
let browser = null;
|
|
2354
2308
|
try {
|
|
2355
|
-
await
|
|
2309
|
+
await fs14.ensureDir(path13.dirname(absolutePath));
|
|
2356
2310
|
browser = await puppeteer3.launch({
|
|
2357
2311
|
headless: true,
|
|
2358
2312
|
args: [
|
|
@@ -2415,8 +2369,8 @@ var init_write_pdf = __esm({
|
|
|
2415
2369
|
pdfDoc.setCreator("FluxFlow PDF Engine");
|
|
2416
2370
|
pdfDoc.setProducer("FluxFlow (Generative AI)");
|
|
2417
2371
|
const finalPdfBytes = await pdfDoc.save();
|
|
2418
|
-
await
|
|
2419
|
-
const stats = await
|
|
2372
|
+
await fs14.writeFile(absolutePath, finalPdfBytes);
|
|
2373
|
+
const stats = await fs14.stat(absolutePath);
|
|
2420
2374
|
return `SUCCESS: PDF generated successfully at [${targetPath}] (${(stats.size / 1024).toFixed(2)} KB).`;
|
|
2421
2375
|
} catch (err) {
|
|
2422
2376
|
return `ERROR: Failed to generate PDF [${targetPath}]: ${err.message}`;
|
|
@@ -2428,7 +2382,7 @@ var init_write_pdf = __esm({
|
|
|
2428
2382
|
});
|
|
2429
2383
|
|
|
2430
2384
|
// src/tools/write_docx.js
|
|
2431
|
-
import
|
|
2385
|
+
import fs15 from "fs-extra";
|
|
2432
2386
|
import path14 from "path";
|
|
2433
2387
|
import HTMLtoDOCX from "html-to-docx";
|
|
2434
2388
|
var write_docx;
|
|
@@ -2444,7 +2398,7 @@ var init_write_docx = __esm({
|
|
|
2444
2398
|
if (!content) return 'ERROR: Missing "content" (HTML) for write_docx.';
|
|
2445
2399
|
const absolutePath = path14.resolve(process.cwd(), targetPath);
|
|
2446
2400
|
try {
|
|
2447
|
-
await
|
|
2401
|
+
await fs15.ensureDir(path14.dirname(absolutePath));
|
|
2448
2402
|
const fileName = path14.basename(targetPath);
|
|
2449
2403
|
const fullHtml = content.includes("<html") ? content : `
|
|
2450
2404
|
<!DOCTYPE html>
|
|
@@ -2466,7 +2420,7 @@ var init_write_docx = __esm({
|
|
|
2466
2420
|
footer: true,
|
|
2467
2421
|
pageNumber: true
|
|
2468
2422
|
});
|
|
2469
|
-
await
|
|
2423
|
+
await fs15.writeFile(absolutePath, docxBuffer);
|
|
2470
2424
|
return `SUCCESS: Word document [${targetPath}] generated successfully.
|
|
2471
2425
|
- Size: ${(docxBuffer.length / 1024).toFixed(1)} KB`;
|
|
2472
2426
|
} catch (err) {
|
|
@@ -2477,7 +2431,7 @@ var init_write_docx = __esm({
|
|
|
2477
2431
|
});
|
|
2478
2432
|
|
|
2479
2433
|
// src/tools/write_pptx.js
|
|
2480
|
-
import
|
|
2434
|
+
import fs16 from "fs-extra";
|
|
2481
2435
|
import path15 from "path";
|
|
2482
2436
|
import pptxgen from "pptxgenjs";
|
|
2483
2437
|
import html2pptxgenjs from "html2pptxgenjs";
|
|
@@ -2495,7 +2449,7 @@ var init_write_pptx = __esm({
|
|
|
2495
2449
|
if (!content) return 'ERROR: No "content" (HTML) provided for write_pptx.';
|
|
2496
2450
|
const absolutePath = path15.resolve(process.cwd(), targetPath);
|
|
2497
2451
|
try {
|
|
2498
|
-
await
|
|
2452
|
+
await fs16.ensureDir(path15.dirname(absolutePath));
|
|
2499
2453
|
const PptxConstructor = typeof pptxgen === "function" ? pptxgen : pptxgen.default;
|
|
2500
2454
|
if (!PptxConstructor) throw new Error("Could not find PptxGenJS constructor in module");
|
|
2501
2455
|
const pres = new PptxConstructor();
|
|
@@ -2532,7 +2486,7 @@ var init_write_pptx = __esm({
|
|
|
2532
2486
|
}
|
|
2533
2487
|
}
|
|
2534
2488
|
const buffer = await pres.write({ outputType: "nodebuffer" });
|
|
2535
|
-
await
|
|
2489
|
+
await fs16.writeFile(absolutePath, buffer);
|
|
2536
2490
|
return `SUCCESS: Native HTML-to-PPTX [${targetPath}] generated with ${slideBlocks.length} slides.
|
|
2537
2491
|
- Size: ${(buffer.length / 1024).toFixed(1)} KB`;
|
|
2538
2492
|
} catch (err) {
|
|
@@ -2651,7 +2605,7 @@ var init_tools = __esm({
|
|
|
2651
2605
|
// src/utils/ai.js
|
|
2652
2606
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
2653
2607
|
import path16 from "path";
|
|
2654
|
-
import
|
|
2608
|
+
import fs17 from "fs";
|
|
2655
2609
|
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
|
|
2656
2610
|
var init_ai = __esm({
|
|
2657
2611
|
"src/utils/ai.js"() {
|
|
@@ -2769,8 +2723,8 @@ var init_ai = __esm({
|
|
|
2769
2723
|
if (lastUsage) await addToUsage("tokens", lastUsage.totalTokenCount || 0);
|
|
2770
2724
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
2771
2725
|
const janitorLogDir = path16.join(LOGS_DIR, "janitor");
|
|
2772
|
-
if (!
|
|
2773
|
-
|
|
2726
|
+
if (!fs17.existsSync(janitorLogDir)) fs17.mkdirSync(janitorLogDir, { recursive: true });
|
|
2727
|
+
fs17.appendFileSync(path16.join(janitorLogDir, "debug.log"), `
|
|
2774
2728
|
|
|
2775
2729
|
---------------------------------------------------
|
|
2776
2730
|
|
|
@@ -2791,7 +2745,7 @@ DEBUG [${date}]: ${finalSynthesis}
|
|
|
2791
2745
|
const result = await dispatchTool(janitorToolCall.toolName, janitorToolCall.args, toolContext);
|
|
2792
2746
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
2793
2747
|
const janitorLogDir = path16.join(LOGS_DIR, "janitor");
|
|
2794
|
-
|
|
2748
|
+
fs17.appendFileSync(path16.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${janitorToolCall.toolName}]: ${result}
|
|
2795
2749
|
`);
|
|
2796
2750
|
if (janitorToolCall.toolName === "memory" && !janitorToolCall.args.includes("action='temp'")) {
|
|
2797
2751
|
if (onMemoryUpdated) onMemoryUpdated();
|
|
@@ -2802,8 +2756,8 @@ DEBUG [${date}]: ${finalSynthesis}
|
|
|
2802
2756
|
attempts++;
|
|
2803
2757
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
2804
2758
|
const janitorErrDir = path16.join(LOGS_DIR, "janitor");
|
|
2805
|
-
if (!
|
|
2806
|
-
|
|
2759
|
+
if (!fs17.existsSync(janitorErrDir)) fs17.mkdirSync(janitorErrDir, { recursive: true });
|
|
2760
|
+
fs17.appendFileSync(path16.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
|
|
2807
2761
|
|
|
2808
2762
|
`);
|
|
2809
2763
|
if (attempts > MAX_JANITOR_RETRIES) break;
|
|
@@ -2813,7 +2767,7 @@ DEBUG [${date}]: ${finalSynthesis}
|
|
|
2813
2767
|
}
|
|
2814
2768
|
if (attempts) {
|
|
2815
2769
|
const janitorErrDir = path16.join(LOGS_DIR, "janitor");
|
|
2816
|
-
|
|
2770
|
+
fs17.appendFileSync(path16.join(janitorErrDir, "error.log"), `-----------------------------------------------------------------------------
|
|
2817
2771
|
|
|
2818
2772
|
|
|
2819
2773
|
`);
|
|
@@ -3037,10 +2991,10 @@ DEBUG [${date}]: ${finalSynthesis}
|
|
|
3037
2991
|
const otherMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems).map((mem) => `- ${mem}`).join("\n");
|
|
3038
2992
|
const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
|
|
3039
2993
|
const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
|
|
3040
|
-
const
|
|
3041
|
-
const
|
|
3042
|
-
|
|
3043
|
-
USER_PROMPT: "${agentText}"`.trim();
|
|
2994
|
+
const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
|
|
2995
|
+
const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
|
|
2996
|
+
const firstUserMsg = `${memoryPrompt}[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.
|
|
2997
|
+
USER_PROMPT: "${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}"`.trim();
|
|
3044
2998
|
modifiedHistory.push({ role: "user", text: firstUserMsg });
|
|
3045
2999
|
let lastUsage = null;
|
|
3046
3000
|
const MAX_LOOPS = mode === "Flux" ? 70 : 7;
|
|
@@ -3070,7 +3024,9 @@ USER_PROMPT: "${agentText}"`.trim();
|
|
|
3070
3024
|
|
|
3071
3025
|
[STEERING HINT]: ${hint}`;
|
|
3072
3026
|
} else {
|
|
3073
|
-
modifiedHistory.push({ role: "user", text: `[
|
|
3027
|
+
modifiedHistory.push({ role: "user", text: `[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.
|
|
3028
|
+
|
|
3029
|
+
[STEERING HINT]: ${hint}` });
|
|
3074
3030
|
}
|
|
3075
3031
|
yield { type: "status", content: "Steering Hint Injected." };
|
|
3076
3032
|
}
|
|
@@ -3120,11 +3076,10 @@ USER_PROMPT: "${agentText}"`.trim();
|
|
|
3120
3076
|
} else if (retryCount > 0) {
|
|
3121
3077
|
yield { type: "model_update", content: null };
|
|
3122
3078
|
}
|
|
3123
|
-
const
|
|
3124
|
-
const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, otherMemories, mainUserMemories, isMemoryEnabled, isContext32k, MAX_LOOPS, loop + 1);
|
|
3079
|
+
const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
|
|
3125
3080
|
const jitInstruction = `
|
|
3126
3081
|
|
|
3127
|
-
[SYSTEM] Tool result received. Analyze output and proceed with your turn. **STRICTLY MAINTAIN THINKING
|
|
3082
|
+
[SYSTEM] Tool result received. Analyze output and proceed with your turn. **STRICTLY MAINTAIN THINKING PROTOCOL. NEVER START A RESPONSE WITHOUT THINKING**.`;
|
|
3128
3083
|
const lastUserMsg = contents[contents.length - 1];
|
|
3129
3084
|
let addedMarker = false;
|
|
3130
3085
|
if (lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text?.startsWith("[TOOL_RESULT]")) {
|
|
@@ -3301,8 +3256,8 @@ USER_PROMPT: "${agentText}"`.trim();
|
|
|
3301
3256
|
let actualEndLine = eLine;
|
|
3302
3257
|
try {
|
|
3303
3258
|
const absPath = path16.resolve(process.cwd(), targetPath2);
|
|
3304
|
-
if (
|
|
3305
|
-
const content =
|
|
3259
|
+
if (fs17.existsSync(absPath)) {
|
|
3260
|
+
const content = fs17.readFileSync(absPath, "utf8");
|
|
3306
3261
|
const lines = content.split("\n").length;
|
|
3307
3262
|
totalLines = lines;
|
|
3308
3263
|
actualEndLine = Math.min(eLine, lines);
|
|
@@ -3323,8 +3278,8 @@ USER_PROMPT: "${agentText}"`.trim();
|
|
|
3323
3278
|
const action = toolCall.toolName === "list_files" ? "LIST" : "ANALYSED";
|
|
3324
3279
|
label = `\u{1F4C2} ${action} FOLDER: ${parseArgs(toolCall.args).path || "."}`.toUpperCase();
|
|
3325
3280
|
} else if (toolCall.toolName === "write_file" || toolCall.toolName === "update_file") {
|
|
3326
|
-
const action = toolCall.toolName === "write_file" ? "
|
|
3327
|
-
label = `\u{1F4BE} ${action}
|
|
3281
|
+
const action = toolCall.toolName === "write_file" ? "WRITTEN" : "UPDATED FILE";
|
|
3282
|
+
label = `\u{1F4BE} ${action}: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
3328
3283
|
} else if (toolCall.toolName === "write_pdf") {
|
|
3329
3284
|
label = `\u{1F4D1} PDF CREATED: ${parseArgs(toolCall.args).path || "..."}`.toUpperCase();
|
|
3330
3285
|
} else if (toolCall.toolName === "write_docx") {
|
|
@@ -3381,7 +3336,7 @@ ${boxBottom}` };
|
|
|
3381
3336
|
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.`;
|
|
3382
3337
|
toolResults.push({ role: "user", text: `[TOOL_RESULT]: ERROR: ${denyMsg}
|
|
3383
3338
|
|
|
3384
|
-
[SYSTEM] **
|
|
3339
|
+
[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.` });
|
|
3385
3340
|
yield { type: "tool_result", content: `[TOOL_RESULT]: ERROR: ${denyMsg}` };
|
|
3386
3341
|
toolCallPointer++;
|
|
3387
3342
|
continue;
|
|
@@ -3396,7 +3351,7 @@ ${boxBottom}` };
|
|
|
3396
3351
|
const denyMsg = `Permission Denied: User rejected the ${toolCall.toolName === "exec_command" ? "terminal execution" : "file edit"}.`;
|
|
3397
3352
|
toolResults.push({ role: "user", text: `[TOOL_RESULT]: DENIED: ${denyMsg}
|
|
3398
3353
|
|
|
3399
|
-
[SYSTEM] **
|
|
3354
|
+
[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS HIGHEST PRIORITY. NEVER START A RESPONSE WITHOUT THINKING**.` });
|
|
3400
3355
|
yield { type: "tool_result", content: `[TOOL_RESULT]: DENIED: ${denyMsg}` };
|
|
3401
3356
|
await incrementUsage("toolDenied");
|
|
3402
3357
|
if (settings.onToolResult) settings.onToolResult("denied");
|
|
@@ -3480,8 +3435,8 @@ ${boxBottom}` };
|
|
|
3480
3435
|
const errLog = String(err);
|
|
3481
3436
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
3482
3437
|
const agentErrDir = path16.join(LOGS_DIR, "agent");
|
|
3483
|
-
if (!
|
|
3484
|
-
|
|
3438
|
+
if (!fs17.existsSync(agentErrDir)) fs17.mkdirSync(agentErrDir, { recursive: true });
|
|
3439
|
+
fs17.appendFileSync(path16.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
|
|
3485
3440
|
|
|
3486
3441
|
----------------------------------------------------------------------
|
|
3487
3442
|
|
|
@@ -3494,7 +3449,7 @@ ${boxBottom}` };
|
|
|
3494
3449
|
if (toolResults.length > 0) {
|
|
3495
3450
|
toolResults.forEach((tr) => modifiedHistory.push(tr));
|
|
3496
3451
|
}
|
|
3497
|
-
modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly
|
|
3452
|
+
modifiedHistory.push({ role: "user", text: "[SYSTEM] Response got cut for internal error, continue from checkpoint seamlessly, DON'T repeat what you already said! PICK UP FROM THE WORD IN A WAY THAT USER SHOULD NOT NOTICE ANY CUTOFF. Rules:\n- Do not reuse <think> if the thinking already started just continue from the word and end it properly.\n- If the cutoff was in middle of a tool call, start the tool call from start.\n- Visually the new pickup and continuation should look natual sentence flow.\n- DON'T try to think shorter, keep length standard." });
|
|
3498
3453
|
accumulatedContext += turnText;
|
|
3499
3454
|
for (let i = waitTime / 1e3; i > 0; i--) {
|
|
3500
3455
|
yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
|
|
@@ -3578,7 +3533,7 @@ ${timestamp}`;
|
|
|
3578
3533
|
});
|
|
3579
3534
|
|
|
3580
3535
|
// src/utils/settings.js
|
|
3581
|
-
import
|
|
3536
|
+
import fs18 from "fs-extra";
|
|
3582
3537
|
import path17 from "path";
|
|
3583
3538
|
var DEFAULT_SETTINGS, loadSettings, migrateToExternal, saveSettings;
|
|
3584
3539
|
var init_settings = __esm({
|
|
@@ -3614,8 +3569,8 @@ var init_settings = __esm({
|
|
|
3614
3569
|
};
|
|
3615
3570
|
loadSettings = async () => {
|
|
3616
3571
|
try {
|
|
3617
|
-
if (await
|
|
3618
|
-
const saved = await
|
|
3572
|
+
if (await fs18.exists(SETTINGS_FILE)) {
|
|
3573
|
+
const saved = await fs18.readJson(SETTINGS_FILE);
|
|
3619
3574
|
const merged = {
|
|
3620
3575
|
...DEFAULT_SETTINGS,
|
|
3621
3576
|
...saved,
|
|
@@ -3625,7 +3580,7 @@ var init_settings = __esm({
|
|
|
3625
3580
|
};
|
|
3626
3581
|
if (merged.showFullThinking === false) {
|
|
3627
3582
|
merged.showFullThinking = true;
|
|
3628
|
-
await
|
|
3583
|
+
await fs18.writeJson(SETTINGS_FILE, merged, { spaces: 2 });
|
|
3629
3584
|
}
|
|
3630
3585
|
return merged;
|
|
3631
3586
|
}
|
|
@@ -3641,9 +3596,9 @@ var init_settings = __esm({
|
|
|
3641
3596
|
const src = path17.join(FLUXFLOW_DIR2, folder);
|
|
3642
3597
|
const dest = path17.join(newPath, folder);
|
|
3643
3598
|
try {
|
|
3644
|
-
if (await
|
|
3645
|
-
await
|
|
3646
|
-
await
|
|
3599
|
+
if (await fs18.exists(src)) {
|
|
3600
|
+
await fs18.ensureDir(dest);
|
|
3601
|
+
await fs18.copy(src, dest, { overwrite: true });
|
|
3647
3602
|
}
|
|
3648
3603
|
} catch (err) {
|
|
3649
3604
|
console.error(`Migration failed for ${folder}:`, err);
|
|
@@ -3657,8 +3612,8 @@ var init_settings = __esm({
|
|
|
3657
3612
|
await migrateToExternal(settings.systemSettings.externalDataPath);
|
|
3658
3613
|
}
|
|
3659
3614
|
const updated = { ...current, ...settings };
|
|
3660
|
-
await
|
|
3661
|
-
await
|
|
3615
|
+
await fs18.ensureDir(path17.dirname(SETTINGS_FILE));
|
|
3616
|
+
await fs18.writeJson(SETTINGS_FILE, updated, { spaces: 2 });
|
|
3662
3617
|
return true;
|
|
3663
3618
|
} catch (err) {
|
|
3664
3619
|
console.error("Failed to save settings:", err);
|
|
@@ -3871,7 +3826,7 @@ var init_UpdateProcessor = __esm({
|
|
|
3871
3826
|
import puppeteer4 from "puppeteer";
|
|
3872
3827
|
import { exec as exec3 } from "child_process";
|
|
3873
3828
|
import { promisify } from "util";
|
|
3874
|
-
import
|
|
3829
|
+
import fs19 from "fs";
|
|
3875
3830
|
var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
|
|
3876
3831
|
var init_setup = __esm({
|
|
3877
3832
|
"src/utils/setup.js"() {
|
|
@@ -3879,7 +3834,7 @@ var init_setup = __esm({
|
|
|
3879
3834
|
checkPuppeteerReady = () => {
|
|
3880
3835
|
try {
|
|
3881
3836
|
const exePath = puppeteer4.executablePath();
|
|
3882
|
-
const exists = exePath &&
|
|
3837
|
+
const exists = exePath && fs19.existsSync(exePath);
|
|
3883
3838
|
if (exists) return true;
|
|
3884
3839
|
} catch (e) {
|
|
3885
3840
|
return false;
|
|
@@ -3909,11 +3864,11 @@ var app_exports = {};
|
|
|
3909
3864
|
__export(app_exports, {
|
|
3910
3865
|
default: () => App
|
|
3911
3866
|
});
|
|
3912
|
-
import
|
|
3867
|
+
import os3 from "os";
|
|
3913
3868
|
import React10, { useState as useState7, useEffect as useEffect5, useRef as useRef2, useMemo } from "react";
|
|
3914
3869
|
import { Box as Box10, Text as Text10, useInput as useInput4, useStdout } from "ink";
|
|
3915
3870
|
import Spinner2 from "ink-spinner";
|
|
3916
|
-
import
|
|
3871
|
+
import fs20 from "fs-extra";
|
|
3917
3872
|
import path18 from "path";
|
|
3918
3873
|
import { exec as exec4 } from "child_process";
|
|
3919
3874
|
import { MultilineInput } from "ink-multiline-input";
|
|
@@ -4080,7 +4035,7 @@ function App() {
|
|
|
4080
4035
|
const [messages, setMessages] = useState7(() => {
|
|
4081
4036
|
const logoMsg = { id: "logo-" + Date.now(), role: "system", text: FLUX_LOGO, isLogo: true, isMeta: true };
|
|
4082
4037
|
const welcomeMsg = { id: "welcome", role: "system", text: "\u{1F30A}\u26A1 Welcome to Flux Flow! Type /help for commands.", isMeta: true };
|
|
4083
|
-
const isHomeDir = process.cwd() ===
|
|
4038
|
+
const isHomeDir = process.cwd() === os3.homedir();
|
|
4084
4039
|
const isSystemDir = (() => {
|
|
4085
4040
|
const cwd = process.cwd().toLowerCase();
|
|
4086
4041
|
if (process.platform === "win32") {
|
|
@@ -4108,7 +4063,7 @@ function App() {
|
|
|
4108
4063
|
id: "home-warning",
|
|
4109
4064
|
role: "system",
|
|
4110
4065
|
text: `[SECURITY ALERT] HOME DIRECTORY DETECTED`,
|
|
4111
|
-
subText: `You are currently in ${
|
|
4066
|
+
subText: `You are currently in ${os3.homedir()}. Working here is high-risk as the agent may modify system-sensitive configurations. Please move to a project folder for safety.`,
|
|
4112
4067
|
isHomeWarning: true,
|
|
4113
4068
|
isMeta: true
|
|
4114
4069
|
});
|
|
@@ -4118,7 +4073,7 @@ function App() {
|
|
|
4118
4073
|
const queuedPromptRef = useRef2(null);
|
|
4119
4074
|
const [completedIndex, setCompletedIndex] = useState7(messages.length);
|
|
4120
4075
|
const windowedHistory = useMemo(() => {
|
|
4121
|
-
const MAX_HISTORY_LINES =
|
|
4076
|
+
const MAX_HISTORY_LINES = 1536;
|
|
4122
4077
|
const width = terminalSize.columns || 80;
|
|
4123
4078
|
let totalLines = 0;
|
|
4124
4079
|
let startIdx = 0;
|
|
@@ -4384,7 +4339,7 @@ function App() {
|
|
|
4384
4339
|
{ cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default (Free, Recommended)" : "Standard Default (Free, Recommended) - Use Free API Key to use this model " },
|
|
4385
4340
|
{ cmd: "gemini-3.1-pro-preview", desc: "Most Capable (Paid)" },
|
|
4386
4341
|
{ cmd: "gemini-3-flash-preview", desc: "Fast & Lightweight (Paid, Limited Free quota)" },
|
|
4387
|
-
{ cmd: "gemini-3.1-flash-lite
|
|
4342
|
+
{ cmd: "gemini-3.1-flash-lite", desc: "Ultra Fast (Paid, Decent Free quota)" }
|
|
4388
4343
|
]
|
|
4389
4344
|
},
|
|
4390
4345
|
{ cmd: "/settings", desc: "Configure system prefs" },
|
|
@@ -4636,12 +4591,12 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
4636
4591
|
setCompletedIndex(prev.length + 1);
|
|
4637
4592
|
return [...prev, { id: Date.now(), role: "system", text: "\u2622\uFE0F [NUCLEAR] Initiating reset...", isMeta: true }];
|
|
4638
4593
|
});
|
|
4639
|
-
if (
|
|
4640
|
-
if (
|
|
4641
|
-
if (
|
|
4594
|
+
if (fs20.existsSync(LOGS_DIR)) fs20.removeSync(LOGS_DIR);
|
|
4595
|
+
if (fs20.existsSync(SECRET_DIR)) fs20.removeSync(SECRET_DIR);
|
|
4596
|
+
if (fs20.existsSync(SETTINGS_FILE)) fs20.removeSync(SETTINGS_FILE);
|
|
4642
4597
|
try {
|
|
4643
|
-
const items =
|
|
4644
|
-
if (items.length === 0)
|
|
4598
|
+
const items = fs20.readdirSync(FLUXFLOW_DIR);
|
|
4599
|
+
if (items.length === 0) fs20.removeSync(FLUXFLOW_DIR);
|
|
4645
4600
|
} catch (e) {
|
|
4646
4601
|
}
|
|
4647
4602
|
setTimeout(() => {
|
|
@@ -4699,13 +4654,13 @@ ${list || "No saved chats found."}`, isMeta: true }];
|
|
|
4699
4654
|
- [Define custom step-by-step recipes for this project here]
|
|
4700
4655
|
`;
|
|
4701
4656
|
const filePath = path18.join(process.cwd(), "FluxFlow.md");
|
|
4702
|
-
if (
|
|
4657
|
+
if (fs20.pathExistsSync(filePath)) {
|
|
4703
4658
|
setMessages((prev) => {
|
|
4704
4659
|
setCompletedIndex(prev.length + 1);
|
|
4705
4660
|
return [...prev, { id: "init-err-" + Date.now(), role: "system", text: "\u274C ERROR: FluxFlow.md already exists in this directory.", isMeta: true }];
|
|
4706
4661
|
});
|
|
4707
4662
|
} else {
|
|
4708
|
-
|
|
4663
|
+
fs20.writeFileSync(filePath, template);
|
|
4709
4664
|
setMessages((prev) => {
|
|
4710
4665
|
setCompletedIndex(prev.length + 1);
|
|
4711
4666
|
return [...prev, { id: "init-ok-" + Date.now(), role: "system", text: "\u2705 [SUCCESS] FluxFlow.md has been initialized. You can now customize it for this project.", isMeta: true }];
|
|
@@ -5372,12 +5327,12 @@ Selection: ${val}`,
|
|
|
5372
5327
|
const resumedMsgs = [...h[id].messages];
|
|
5373
5328
|
const hasLogo = resumedMsgs[0]?.text?.includes("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
|
|
5374
5329
|
if (!hasLogo) {
|
|
5375
|
-
resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session..." });
|
|
5330
|
+
resumedMsgs.unshift({ id: "welcome-" + Date.now(), role: "system", text: FLUX_LOGO + "\n\n\u{1F30A}\u26A1 Resuming Flux Flow Session...", isMeta: true });
|
|
5376
5331
|
}
|
|
5377
5332
|
setMessages(resumedMsgs);
|
|
5378
5333
|
setActiveView("chat");
|
|
5379
5334
|
setMessages((prev) => {
|
|
5380
|
-
const newMsgs = [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${id}]
|
|
5335
|
+
const newMsgs = [...prev, { id: "sys-" + Date.now(), role: "system", text: `\u{1F4E1} SESSION RESUMED: [${id}]`, isMeta: true }];
|
|
5381
5336
|
setCompletedIndex(newMsgs.length);
|
|
5382
5337
|
return newMsgs;
|
|
5383
5338
|
});
|
|
@@ -5556,7 +5511,7 @@ Selection: ${val}`,
|
|
|
5556
5511
|
newline: (key) => key.return && key.shift || key.return && key.ctrl || key.return && key.leftAlt || key.return && key.rightAlt
|
|
5557
5512
|
}
|
|
5558
5513
|
}
|
|
5559
|
-
)))) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React10.createElement(Text10, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\
|
|
5514
|
+
)))) : /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React10.createElement(Box10, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React10.createElement(Text10, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\u2726 " : "\u{1F4A0} ")), /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1 }, /* @__PURE__ */ React10.createElement(Box10, { flexGrow: 1, position: "relative" }, input === "" && /* @__PURE__ */ React10.createElement(Box10, { position: "absolute", paddingLeft: 0 }, activeCommand && !isTerminalFocused ? /* @__PURE__ */ React10.createElement(Text10, { color: "yellow" }, " Press TAB to interact with terminal...") : activeCommand && isTerminalFocused ? /* @__PURE__ */ React10.createElement(Text10, { color: "yellow", bold: true }, " [ TERMINAL FOCUSED ] Type to interact, press TAB to exit...") : /* @__PURE__ */ React10.createElement(Text10, { color: "gray" }, escPressed ? " Press ESC again to cancel the request." : !isProcessing ? ` Send message or /cmd... (${terminalEnv.shortcut} for newline)` : " Enter a prompt to steer the agent.")), /* @__PURE__ */ React10.createElement(
|
|
5560
5515
|
MultilineInput,
|
|
5561
5516
|
{
|
|
5562
5517
|
focus: !isTerminalFocused,
|
|
@@ -5679,8 +5634,8 @@ var init_app = __esm({
|
|
|
5679
5634
|
init_text();
|
|
5680
5635
|
SESSION_START_TIME = Date.now();
|
|
5681
5636
|
CHANGELOG_URL = "https://fluxflow-cli.onrender.com/changelog.html";
|
|
5682
|
-
versionFluxflow = "1.9.
|
|
5683
|
-
updatedOn = "2026-05-
|
|
5637
|
+
versionFluxflow = "1.9.10";
|
|
5638
|
+
updatedOn = "2026-05-15";
|
|
5684
5639
|
ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React10.createElement(Text10, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React10.createElement(Box10, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 0 }, /* @__PURE__ */ React10.createElement(
|
|
5685
5640
|
CommandMenu,
|
|
5686
5641
|
{
|