fluxflow-cli 3.15.1 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TOOLS.md +1 -4
- package/dist/fluxflow.js +798 -221
- package/model_config.json +1 -1
- package/package.json +74 -73
package/dist/fluxflow.js
CHANGED
|
@@ -780,6 +780,9 @@ var init_settings = __esm({
|
|
|
780
780
|
progressiveRendering: true,
|
|
781
781
|
showTPMEstimate: false,
|
|
782
782
|
subAgents: true,
|
|
783
|
+
CustomSubAgent: false,
|
|
784
|
+
SubAgentModel: "Default",
|
|
785
|
+
SubAgentProvider: "",
|
|
783
786
|
dynamicDirAwareness: false,
|
|
784
787
|
indentationTree: true
|
|
785
788
|
},
|
|
@@ -5675,7 +5678,7 @@ var init_ChatLayout = __esm({
|
|
|
5675
5678
|
return;
|
|
5676
5679
|
}
|
|
5677
5680
|
if (trimmed === "---" || trimmed === "***" || trimmed === "___") {
|
|
5678
|
-
result.push(/* @__PURE__ */ React4.createElement(Box3, { key: i, marginY:
|
|
5681
|
+
result.push(/* @__PURE__ */ React4.createElement(Box3, { key: i, marginY: 0, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, width: "100%", borderColor: colors.borderMuted }));
|
|
5679
5682
|
return;
|
|
5680
5683
|
}
|
|
5681
5684
|
const headingMatch = trimmed.match(/^(#{1,6})\s+(.*)/);
|
|
@@ -5740,37 +5743,138 @@ var init_ChatLayout = __esm({
|
|
|
5740
5743
|
const displayPrefix = isRemoval ? "-" : isAddition ? "+" : " ";
|
|
5741
5744
|
const renderInlineDiff = () => {
|
|
5742
5745
|
if (isPureUnpairedBlock) {
|
|
5743
|
-
const blockColor = isRemoval ? colors.diffRemovalHighlightColor : colors.diffAdditionHighlightColor;
|
|
5744
5746
|
const textBgColor = isRemoval ? colors.diffRemovalHighlightBg : colors.diffAdditionHighlightBg;
|
|
5745
|
-
|
|
5746
|
-
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, blockColor, textBgColor))));
|
|
5747
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, renderHighlightedLine(wrapText(content, columns - 15), extension, void 0, textBgColor));
|
|
5747
5748
|
}
|
|
5748
5749
|
if (!(isRemoval || isAddition) || words.length === 0 || !hasInlineChange) {
|
|
5749
5750
|
const textColor = isRemoval ? colors.diffRemovalText : isAddition ? colors.diffAdditionText : colors.textMuted;
|
|
5750
5751
|
const textBgColor = void 0;
|
|
5751
|
-
|
|
5752
|
-
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, wrappedLines.map((wl, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx }, renderHighlightedLine(wl, extension, textColor, textBgColor))));
|
|
5752
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, renderHighlightedLine(wrapText(content, columns - 15), extension, textColor, textBgColor));
|
|
5753
5753
|
}
|
|
5754
|
-
|
|
5754
|
+
const maxLen = Math.max(10, columns - 15);
|
|
5755
|
+
const wrappedLines = wrapText(content, maxLen).split("\n");
|
|
5756
|
+
const validWords = [];
|
|
5757
|
+
words.forEach((part, idx) => {
|
|
5755
5758
|
const isWhitespace = /^\s+$/.test(part.value);
|
|
5756
5759
|
if (isRemoval) {
|
|
5757
5760
|
const isSurroundedByRemoval = words[idx - 1]?.removed || words[idx + 1]?.removed;
|
|
5758
5761
|
if (part.removed || isWhitespace && isSurroundedByRemoval) {
|
|
5759
|
-
|
|
5762
|
+
validWords.push({ text: part.value, isHighlight: true });
|
|
5763
|
+
} else if (!part.added) {
|
|
5764
|
+
validWords.push({ text: part.value, isHighlight: false });
|
|
5760
5765
|
}
|
|
5761
|
-
|
|
5762
|
-
return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: colors.diffRemovalText }, part.value);
|
|
5763
|
-
}
|
|
5764
|
-
if (isAddition) {
|
|
5766
|
+
} else if (isAddition) {
|
|
5765
5767
|
const isSurroundedByAddition = words[idx - 1]?.added || words[idx + 1]?.added;
|
|
5766
5768
|
if (part.added || isWhitespace && isSurroundedByAddition) {
|
|
5767
|
-
|
|
5769
|
+
validWords.push({ text: part.value, isHighlight: true });
|
|
5770
|
+
} else if (!part.removed) {
|
|
5771
|
+
validWords.push({ text: part.value, isHighlight: false });
|
|
5768
5772
|
}
|
|
5769
|
-
if (part.removed) return null;
|
|
5770
|
-
return /* @__PURE__ */ React4.createElement(Text4, { key: idx, color: colors.diffAdditionText }, part.value);
|
|
5771
5773
|
}
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
+
});
|
|
5775
|
+
if (wrappedLines.length <= 1) {
|
|
5776
|
+
return /* @__PURE__ */ React4.createElement(Text4, { wrap: "wrap" }, validWords.map((part, idx) => {
|
|
5777
|
+
if (isRemoval) {
|
|
5778
|
+
if (part.isHighlight) {
|
|
5779
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: idx }, renderHighlightedLine(part.text, extension, colors.diffRemovalHighlightColor, colors.diffRemovalHighlightBg));
|
|
5780
|
+
}
|
|
5781
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: idx }, renderHighlightedLine(part.text, extension, colors.diffRemovalText));
|
|
5782
|
+
}
|
|
5783
|
+
if (isAddition) {
|
|
5784
|
+
if (part.isHighlight) {
|
|
5785
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: idx }, renderHighlightedLine(part.text, extension, colors.diffAdditionHighlightColor, colors.diffAdditionHighlightBg));
|
|
5786
|
+
}
|
|
5787
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: idx }, renderHighlightedLine(part.text, extension, colors.diffAdditionText));
|
|
5788
|
+
}
|
|
5789
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: idx }, renderHighlightedLine(part.text, extension, colors.textMuted));
|
|
5790
|
+
}));
|
|
5791
|
+
}
|
|
5792
|
+
let wordIdx = 0;
|
|
5793
|
+
let charIdx = 0;
|
|
5794
|
+
const leadingSpaceMatch = content.match(/^(\s*)/);
|
|
5795
|
+
const indent = leadingSpaceMatch ? leadingSpaceMatch[1] : "";
|
|
5796
|
+
const cappedIndent = indent.substring(0, Math.min(indent.length, 8));
|
|
5797
|
+
const lineSpans = wrappedLines.map((wl, lineIdx) => {
|
|
5798
|
+
const spans = [];
|
|
5799
|
+
let lineTextToMatch = wl;
|
|
5800
|
+
if (lineIdx > 0 && cappedIndent && wl.startsWith(cappedIndent)) {
|
|
5801
|
+
const currentAvail = validWords[wordIdx] ? validWords[wordIdx].text.substring(charIdx) : "";
|
|
5802
|
+
if (!currentAvail.startsWith(cappedIndent)) {
|
|
5803
|
+
spans.push({ text: cappedIndent, isHighlight: false });
|
|
5804
|
+
lineTextToMatch = wl.substring(cappedIndent.length);
|
|
5805
|
+
}
|
|
5806
|
+
}
|
|
5807
|
+
let neededLength = lineTextToMatch.length;
|
|
5808
|
+
while (neededLength > 0 && wordIdx < validWords.length) {
|
|
5809
|
+
const vw = validWords[wordIdx];
|
|
5810
|
+
const avail = vw.text.length - charIdx;
|
|
5811
|
+
if (avail <= 0) {
|
|
5812
|
+
wordIdx++;
|
|
5813
|
+
charIdx = 0;
|
|
5814
|
+
continue;
|
|
5815
|
+
}
|
|
5816
|
+
const takeLen = Math.min(neededLength, avail);
|
|
5817
|
+
spans.push({
|
|
5818
|
+
text: vw.text.substring(charIdx, charIdx + takeLen),
|
|
5819
|
+
isHighlight: vw.isHighlight
|
|
5820
|
+
});
|
|
5821
|
+
charIdx += takeLen;
|
|
5822
|
+
neededLength -= takeLen;
|
|
5823
|
+
if (charIdx >= vw.text.length) {
|
|
5824
|
+
wordIdx++;
|
|
5825
|
+
charIdx = 0;
|
|
5826
|
+
}
|
|
5827
|
+
}
|
|
5828
|
+
while (wordIdx < validWords.length) {
|
|
5829
|
+
const vw = validWords[wordIdx];
|
|
5830
|
+
const rem = vw.text.substring(charIdx);
|
|
5831
|
+
if (/^\s+$/.test(rem)) {
|
|
5832
|
+
wordIdx++;
|
|
5833
|
+
charIdx = 0;
|
|
5834
|
+
} else if (rem.startsWith(" ") || rem.startsWith(" ")) {
|
|
5835
|
+
let skipCount = 0;
|
|
5836
|
+
while (skipCount < rem.length && (rem[skipCount] === " " || rem[skipCount] === " ")) {
|
|
5837
|
+
skipCount++;
|
|
5838
|
+
}
|
|
5839
|
+
charIdx += skipCount;
|
|
5840
|
+
if (charIdx >= vw.text.length) {
|
|
5841
|
+
wordIdx++;
|
|
5842
|
+
charIdx = 0;
|
|
5843
|
+
}
|
|
5844
|
+
break;
|
|
5845
|
+
} else {
|
|
5846
|
+
break;
|
|
5847
|
+
}
|
|
5848
|
+
}
|
|
5849
|
+
return spans;
|
|
5850
|
+
});
|
|
5851
|
+
if (wordIdx < validWords.length) {
|
|
5852
|
+
const lastSpans = lineSpans[lineSpans.length - 1];
|
|
5853
|
+
while (wordIdx < validWords.length) {
|
|
5854
|
+
const vw = validWords[wordIdx];
|
|
5855
|
+
lastSpans.push({
|
|
5856
|
+
text: vw.text.substring(charIdx),
|
|
5857
|
+
isHighlight: vw.isHighlight
|
|
5858
|
+
});
|
|
5859
|
+
wordIdx++;
|
|
5860
|
+
charIdx = 0;
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, lineSpans.map((spans, lIdx) => /* @__PURE__ */ React4.createElement(Box3, { key: lIdx }, /* @__PURE__ */ React4.createElement(Text4, { wrap: "wrap" }, spans.map((part, sIdx) => {
|
|
5864
|
+
if (isRemoval) {
|
|
5865
|
+
if (part.isHighlight) {
|
|
5866
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: sIdx }, renderHighlightedLine(part.text, extension, colors.diffRemovalHighlightColor, colors.diffRemovalHighlightBg));
|
|
5867
|
+
}
|
|
5868
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: sIdx }, renderHighlightedLine(part.text, extension, colors.diffRemovalText));
|
|
5869
|
+
}
|
|
5870
|
+
if (isAddition) {
|
|
5871
|
+
if (part.isHighlight) {
|
|
5872
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: sIdx }, renderHighlightedLine(part.text, extension, colors.diffAdditionHighlightColor, colors.diffAdditionHighlightBg));
|
|
5873
|
+
}
|
|
5874
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: sIdx }, renderHighlightedLine(part.text, extension, colors.diffAdditionText));
|
|
5875
|
+
}
|
|
5876
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: sIdx }, renderHighlightedLine(part.text, extension, colors.textMuted));
|
|
5877
|
+
})))));
|
|
5774
5878
|
};
|
|
5775
5879
|
return /* @__PURE__ */ React4.createElement(Box3, { backgroundColor: colors.codeBg, paddingX: 1, width: columns }, /* @__PURE__ */ React4.createElement(Box3, { width: 4, flexShrink: 0, justifyContent: "flex-end" }, /* @__PURE__ */ React4.createElement(Text4, { color: finalNumColor }, lineNum)), /* @__PURE__ */ React4.createElement(Box3, { width: 1, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: finalPrefixColor }, displayPrefix)), /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 1, backgroundColor: innerBgColor, flexGrow: 1 }, renderInlineDiff()));
|
|
5776
5880
|
});
|
|
@@ -6704,10 +6808,10 @@ var init_main_tools = __esm({
|
|
|
6704
6808
|
Tool calls: ONLY use [tool:functions.ToolName(args)]
|
|
6705
6809
|
**NO OTHER SYNTAX/MARKERS/BOUNDARY ALLOWED**
|
|
6706
6810
|
|
|
6707
|
-
**TOOL USAGE
|
|
6811
|
+
**CRITICAL TOOL USAGE RULES:**
|
|
6708
6812
|
- MAX 4 TOOL CALLS/TURN${mode === "Flux" ? " (Todo: 4+, Run: max 1 or 2 consecutive)" : ""}
|
|
6709
|
-
${mode === "Flux" ? '- **Escape quotes: \\" for code strings **\n- ** Literal escapes: Double - escape sequences(e.g., \\\\n) **\n- ** File structure: Real newlines for code formatting**\n-
|
|
6710
|
-
- COMMUNICATION
|
|
6813
|
+
${mode === "Flux" ? '- **Escape quotes: \\" for code strings **\n- ** Literal escapes: Double - escape sequences(e.g., \\\\n) **\n- ** File structure: Real newlines for code formatting**\n- SAME file, MULTIPLE edits? Use ONE PatchFile call with up to 15 blocks \u2190 **PRIORITY**\n- Tool denied? Use `Ask` immediately for user guidance \u2190 **MANDATORY**\n- Need specific text ? SearchKeyword > Guessing/ReadFile\n- Huge files ? SearchKeyword > Full Read\n- **Update Todos from realtime progress every turn when created**\n' : ""}
|
|
6814
|
+
- COMMUNICATION WITH USER -
|
|
6711
6815
|
- [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity: MUST for path divergence, security risk. Ask, don't finish/guess. Suggest best options; no preferences. Keep options short
|
|
6712
6816
|
|
|
6713
6817
|
- WEB TOOLS -
|
|
@@ -6716,13 +6820,12 @@ ${mode === "Flux" ? '- **Escape quotes: \\" for code strings **\n- ** Literal es
|
|
|
6716
6820
|
|
|
6717
6821
|
${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative; FIRST ARGUMENT, path separator: '/') -
|
|
6718
6822
|
- [tool:functions.ReadFile(path="...", startLine="integer", endLine="integer")]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs` : ""}` : `Supports images/docs`}
|
|
6719
|
-
- [tool:functions.ReadFolder(path="...", recurse="integer
|
|
6720
|
-
- [tool:functions.
|
|
6721
|
-
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", replaceContent1="...", newContent1="...", ...MAX 15)]. Surgical patchs, TARGET SMALLEST LINES/SUB-STRINGS. allowMultiple: Replace all matches. Use replaceContent2/newContent2... for multi blocks. Verify DIFFs
|
|
6823
|
+
- [tool:functions.ReadFolder(path="...", recurse="integer 1-3 optional, default: 1")]. DIR Contents + File Size. Minimize recursion
|
|
6824
|
+
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", replaceContent1="...", newContent1="...", ...MAX 15)]. Surgical patchs, TARGET SMALLEST LINES. allowMultiple: Replace all matches ONLY WHEN SURE. Use replaceContent2/newContent2... for multi blocks. Verify DIFFs
|
|
6722
6825
|
- [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile
|
|
6723
|
-
- [tool:functions.SearchKeyword(keyword="...", path="optional,
|
|
6826
|
+
- [tool:functions.SearchKeyword(keyword="...", path="optional, dir/file/glob/regex", fuzzy="bool optional, default: false", regex="bool optional, default: auto")]. path limits search scope. Find definitions/logic without full reads. Locate relevant code
|
|
6724
6827
|
- [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL` : `WINDOWS CMD` : `BASH`} command. Destructive/Irreversible ops \u2192 Ask user
|
|
6725
|
-
- [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASKS])]. Task list, no Markdown in arrays. Analyze request: if long multi-task, break it down & create Todos BEFORE starting. \`tasks\` & \`markDone\` optional with \`get\`. Use \`get + markDone\` to complete tasks
|
|
6828
|
+
- [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASKS])]. Task list, no Markdown in arrays. Analyze request: ONLY if long multi-task, break it down & create Todos BEFORE starting. \`tasks\` & \`markDone\` optional with \`get\`. Use \`get + markDone\` to complete tasks. **UPDATE EVERY TURN WHEN CREATED**${enableSubAgents ? '\n- [tool:functions.Await(time="integer 15-180")]. For waiting without exiting agent loop' : ""}
|
|
6726
6829
|
${_cachedAdvanceRollback ? `
|
|
6727
6830
|
- EMERGENCY SAFETY TOOLS -
|
|
6728
6831
|
Info: \`initial\` = user prompt for current task. Revert \`id\` = turn BEFORE the disaster tool (e.g. disaster:\`turn_3\` \u2192 revert:\`turn_2\`). Reason explicitly
|
|
@@ -6732,10 +6835,10 @@ Use ONLY for catastrophic/codebase corruption. Before ending loop, verify no cat
|
|
|
6732
6835
|
- SUB AGENT TOOLS -
|
|
6733
6836
|
**PROACTIVE sub-agent use HIGHLY RECOMMENDED. Prefer for any task with even slight benefit, no user nudge needed**
|
|
6734
6837
|
Invocations:
|
|
6735
|
-
- Invoke (async/background, \u22647 parallel). Parallelize long tasks. NEVER repeat while active
|
|
6838
|
+
- Invoke (async/background, \u22647 parallel). Parallelize long tasks. NEVER repeat while active, meantime, do your OWN work
|
|
6736
6839
|
- InvokeSync (sync/blocking). Sequential, repetitive or delegated tasks. Saves tokens/cost
|
|
6737
6840
|
- [agent:generalist.InvokeSync/Invoke(title="...", task="...")]. Task must be detailed: exact file paths, imports/exports, dependencies & folder structure
|
|
6738
|
-
- [agent:generalist.GetProgress(id="...")].
|
|
6841
|
+
- [agent:generalist.GetProgress(id="...")]. Poll \`getProgress\` sparingly (exp backoff Await); **NO IMMEDIATE FIRST POLL**
|
|
6739
6842
|
- [agent:generalist.Cancel(id="...")]. Cancel async task ONLY if stalled (2m+) or clearly incorrect` : ""}`.trim() : `- CREATIVE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
|
|
6740
6843
|
- [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout, stable margins & headers/footers, NO WATERMARKS
|
|
6741
6844
|
- [tool:functions.WriteDoc(path="...", content="...")]. A4 Word document, NO WATERMARKS, stable margins & headers/footers
|
|
@@ -7448,6 +7551,104 @@ function SettingsMenu({
|
|
|
7448
7551
|
const [isSelectingTheme, setIsSelectingTheme] = useState6(initialSelectingTheme);
|
|
7449
7552
|
const [themeIndex, setThemeIndex] = useState6(defaultIdx >= 0 ? defaultIdx : 0);
|
|
7450
7553
|
const [initialTheme, setInitialTheme] = useState6(systemSettings.theme || "Dark");
|
|
7554
|
+
const [isSelectingSubAgentModel, setIsSelectingSubAgentModel] = useState6(false);
|
|
7555
|
+
const [subAgentModelIndex, setSubAgentModelIndex] = useState6(0);
|
|
7556
|
+
const [subAgentScrollOffset, setSubAgentScrollOffset] = useState6(0);
|
|
7557
|
+
const [subAgentSearchQuery, setSubAgentSearchQuery] = useState6("");
|
|
7558
|
+
const [subAgentFocusMode, setSubAgentFocusMode] = useState6("list");
|
|
7559
|
+
const [activeProviderKeys, setActiveProviderKeys] = useState6({});
|
|
7560
|
+
useEffect5(() => {
|
|
7561
|
+
const checkKeys = async () => {
|
|
7562
|
+
const providers = ["Google", "DeepSeek", "OpenRouter", "NVIDIA", "Mistral"];
|
|
7563
|
+
const keyMap = {};
|
|
7564
|
+
for (const p of providers) {
|
|
7565
|
+
try {
|
|
7566
|
+
const k = await getProviderAPIKey(p);
|
|
7567
|
+
if (k) keyMap[p] = true;
|
|
7568
|
+
} catch (e) {
|
|
7569
|
+
}
|
|
7570
|
+
}
|
|
7571
|
+
setActiveProviderKeys(keyMap);
|
|
7572
|
+
};
|
|
7573
|
+
checkKeys();
|
|
7574
|
+
}, []);
|
|
7575
|
+
const allSubAgentItems = React7.useMemo(() => {
|
|
7576
|
+
const ALL_PROVIDERS = ["Google", "DeepSeek", "OpenRouter", "NVIDIA", "Mistral"];
|
|
7577
|
+
const hasEnv = !!(process.env.SUBAGENT_MODEL && process.env.SUBAGENT_MODEL.trim());
|
|
7578
|
+
const envLabel = hasEnv ? `ENV (${process.env.SUBAGENT_MODEL.trim()})` : "ENV";
|
|
7579
|
+
const items = [
|
|
7580
|
+
{ label: "Default (use the current model)", value: "Default", isHeader: false },
|
|
7581
|
+
{ label: envLabel, value: "ENV", isHeader: false }
|
|
7582
|
+
];
|
|
7583
|
+
const activeTier = quotas?.providerTiers?.[aiProvider] || apiTier || "Free";
|
|
7584
|
+
const currentModels = getModels(aiProvider, activeTier) || [];
|
|
7585
|
+
if (currentModels.length > 0) {
|
|
7586
|
+
items.push({ label: `\u2500\u2500 ${aiProvider.toUpperCase()}${activeTier !== "Free" ? ` (${activeTier})` : ""} \u2500\u2500`, isHeader: true });
|
|
7587
|
+
currentModels.forEach((m) => {
|
|
7588
|
+
const name = typeof m === "string" ? m : m.cmd || m.name || m.id || String(m);
|
|
7589
|
+
if (name && !name.trim().startsWith("---") && !name.startsWith("\n---")) {
|
|
7590
|
+
items.push({ label: name, value: name, isHeader: false, provider: aiProvider });
|
|
7591
|
+
}
|
|
7592
|
+
});
|
|
7593
|
+
}
|
|
7594
|
+
for (const p of ALL_PROVIDERS) {
|
|
7595
|
+
if (p === aiProvider) continue;
|
|
7596
|
+
if (activeProviderKeys[p]) {
|
|
7597
|
+
const tier = quotas?.providerTiers?.[p] || "Free";
|
|
7598
|
+
const models = getModels(p, tier) || [];
|
|
7599
|
+
if (models.length > 0) {
|
|
7600
|
+
items.push({ label: `\u2500\u2500 ${p.toUpperCase()}${tier !== "Free" ? ` (${tier})` : ""} \u2500\u2500`, isHeader: true });
|
|
7601
|
+
models.forEach((m) => {
|
|
7602
|
+
const name = typeof m === "string" ? m : m.cmd || m.name || m.id || String(m);
|
|
7603
|
+
if (name && !name.trim().startsWith("---") && !name.startsWith("\n---")) {
|
|
7604
|
+
items.push({ label: name, value: name, isHeader: false, provider: p });
|
|
7605
|
+
}
|
|
7606
|
+
});
|
|
7607
|
+
}
|
|
7608
|
+
}
|
|
7609
|
+
}
|
|
7610
|
+
return items;
|
|
7611
|
+
}, [aiProvider, apiTier, quotas, activeProviderKeys]);
|
|
7612
|
+
const availableModels = React7.useMemo(() => {
|
|
7613
|
+
if (!subAgentSearchQuery.trim()) return allSubAgentItems;
|
|
7614
|
+
const q = subAgentSearchQuery.trim().toLowerCase();
|
|
7615
|
+
const filtered = [];
|
|
7616
|
+
let currentHeader = null;
|
|
7617
|
+
for (const item of allSubAgentItems) {
|
|
7618
|
+
if (item.isHeader) {
|
|
7619
|
+
currentHeader = item;
|
|
7620
|
+
} else {
|
|
7621
|
+
const matches = item.label.toLowerCase().includes(q) || item.value && item.value.toLowerCase().includes(q);
|
|
7622
|
+
if (matches) {
|
|
7623
|
+
if (currentHeader && !filtered.includes(currentHeader)) {
|
|
7624
|
+
filtered.push(currentHeader);
|
|
7625
|
+
}
|
|
7626
|
+
filtered.push(item);
|
|
7627
|
+
}
|
|
7628
|
+
}
|
|
7629
|
+
}
|
|
7630
|
+
return filtered;
|
|
7631
|
+
}, [allSubAgentItems, subAgentSearchQuery]);
|
|
7632
|
+
useEffect5(() => {
|
|
7633
|
+
if (isSelectingSubAgentModel) {
|
|
7634
|
+
let firstValid = availableModels.findIndex((item) => !item.isHeader);
|
|
7635
|
+
setSubAgentModelIndex(firstValid >= 0 ? firstValid : 0);
|
|
7636
|
+
setSubAgentScrollOffset(0);
|
|
7637
|
+
}
|
|
7638
|
+
}, [subAgentSearchQuery]);
|
|
7639
|
+
useEffect5(() => {
|
|
7640
|
+
if (isSelectingSubAgentModel) {
|
|
7641
|
+
if (availableModels.length === 0) {
|
|
7642
|
+
setSubAgentModelIndex(0);
|
|
7643
|
+
setSubAgentScrollOffset(0);
|
|
7644
|
+
return;
|
|
7645
|
+
}
|
|
7646
|
+
if (subAgentModelIndex >= availableModels.length || availableModels[subAgentModelIndex]?.isHeader) {
|
|
7647
|
+
let firstValid = availableModels.findIndex((item) => !item.isHeader);
|
|
7648
|
+
setSubAgentModelIndex(firstValid >= 0 ? firstValid : 0);
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
}, [availableModels, isSelectingSubAgentModel]);
|
|
7451
7652
|
const [currentMemory, setCurrentMemory] = useState6(0);
|
|
7452
7653
|
const [maxMemory, setMaxMemory] = useState6(0);
|
|
7453
7654
|
const [memoryUnit, setMemoryUnit] = useState6("MB");
|
|
@@ -7512,10 +7713,11 @@ function SettingsMenu({
|
|
|
7512
7713
|
case "other":
|
|
7513
7714
|
return [
|
|
7514
7715
|
{ label: "Sub-Agents", value: "subAgents", status: systemSettings.subAgents !== false ? "ON" : "OFF" },
|
|
7716
|
+
{ label: "Sub-Agent Model", value: "subAgentModel", status: systemSettings.CustomSubAgent && systemSettings.SubAgentModel ? systemSettings.SubAgentModel : "Default" },
|
|
7515
7717
|
{ label: "Preserve Thinking", value: "preserveThinking", status: systemSettings.preserveThinking !== false ? "ON" : "OFF" },
|
|
7516
7718
|
{ label: "Dynamic Directory Awareness", value: "dynamicDirAwareness", status: systemSettings.dynamicDirAwareness ? "ON" : "OFF" },
|
|
7517
|
-
{ label: "Directory Tree Design", value: "indentationTree", status: systemSettings.indentationTree !== false ? "Modern" : "Classic (deprecated)" }
|
|
7518
|
-
{ label:
|
|
7719
|
+
{ label: "Directory Tree Design", value: "indentationTree", status: systemSettings.indentationTree !== false ? "Modern" : "Classic (deprecated)" }
|
|
7720
|
+
// { label: 'Download Language Parsers', value: 'parserDownload', status: 'ACTION' } // Dont remove this comment
|
|
7519
7721
|
];
|
|
7520
7722
|
default:
|
|
7521
7723
|
return [];
|
|
@@ -7524,6 +7726,69 @@ function SettingsMenu({
|
|
|
7524
7726
|
const currentCatId = CATEGORIES[selectedCategoryIndex].id;
|
|
7525
7727
|
const currentItems = getCategoryItems(currentCatId);
|
|
7526
7728
|
useInput3((input, key) => {
|
|
7729
|
+
if (isSelectingSubAgentModel) {
|
|
7730
|
+
if (key.tab) {
|
|
7731
|
+
setSubAgentFocusMode((prev) => prev === "search" ? "list" : "search");
|
|
7732
|
+
return;
|
|
7733
|
+
}
|
|
7734
|
+
if (subAgentFocusMode === "search") {
|
|
7735
|
+
if (key.escape) {
|
|
7736
|
+
setIsSelectingSubAgentModel(false);
|
|
7737
|
+
} else if (key.downArrow || key.return) {
|
|
7738
|
+
setSubAgentFocusMode("list");
|
|
7739
|
+
} else if (key.backspace || key.delete) {
|
|
7740
|
+
setSubAgentSearchQuery((q) => q.slice(0, -1));
|
|
7741
|
+
} else if (input && !key.ctrl && !key.meta && input.length === 1) {
|
|
7742
|
+
setSubAgentSearchQuery((q) => q + input);
|
|
7743
|
+
}
|
|
7744
|
+
return;
|
|
7745
|
+
}
|
|
7746
|
+
if (key.upArrow) {
|
|
7747
|
+
setSubAgentModelIndex((prev) => {
|
|
7748
|
+
if (availableModels.length === 0) return 0;
|
|
7749
|
+
let next = (prev - 1 + availableModels.length) % availableModels.length;
|
|
7750
|
+
let count = 0;
|
|
7751
|
+
while (availableModels[next]?.isHeader && count < availableModels.length) {
|
|
7752
|
+
next = (next - 1 + availableModels.length) % availableModels.length;
|
|
7753
|
+
count++;
|
|
7754
|
+
}
|
|
7755
|
+
return next;
|
|
7756
|
+
});
|
|
7757
|
+
} else if (key.downArrow) {
|
|
7758
|
+
setSubAgentModelIndex((prev) => {
|
|
7759
|
+
if (availableModels.length === 0) return 0;
|
|
7760
|
+
let next = (prev + 1) % availableModels.length;
|
|
7761
|
+
let count = 0;
|
|
7762
|
+
while (availableModels[next]?.isHeader && count < availableModels.length) {
|
|
7763
|
+
next = (next + 1) % availableModels.length;
|
|
7764
|
+
count++;
|
|
7765
|
+
}
|
|
7766
|
+
return next;
|
|
7767
|
+
});
|
|
7768
|
+
} else if (key.return) {
|
|
7769
|
+
const selectedOpt = availableModels[subAgentModelIndex];
|
|
7770
|
+
if (selectedOpt && !selectedOpt.isHeader) {
|
|
7771
|
+
setSystemSettings((s) => {
|
|
7772
|
+
const isDefault = selectedOpt.value === "Default";
|
|
7773
|
+
const newSysSettings = {
|
|
7774
|
+
...s,
|
|
7775
|
+
CustomSubAgent: !isDefault,
|
|
7776
|
+
SubAgentModel: selectedOpt.value,
|
|
7777
|
+
SubAgentProvider: isDefault ? "" : selectedOpt.provider || ""
|
|
7778
|
+
};
|
|
7779
|
+
saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
|
|
7780
|
+
return newSysSettings;
|
|
7781
|
+
});
|
|
7782
|
+
setIsSelectingSubAgentModel(false);
|
|
7783
|
+
}
|
|
7784
|
+
} else if (key.escape) {
|
|
7785
|
+
setIsSelectingSubAgentModel(false);
|
|
7786
|
+
} else if (input && !key.ctrl && !key.meta && input.length === 1) {
|
|
7787
|
+
setSubAgentSearchQuery((q) => q + input);
|
|
7788
|
+
setSubAgentFocusMode("search");
|
|
7789
|
+
}
|
|
7790
|
+
return;
|
|
7791
|
+
}
|
|
7527
7792
|
if (isSelectingTheme) {
|
|
7528
7793
|
if (key.upArrow) {
|
|
7529
7794
|
const nextIdx = (themeIndex - 1 + themeOptions.length) % themeOptions.length;
|
|
@@ -7711,6 +7976,11 @@ function SettingsMenu({
|
|
|
7711
7976
|
saveSettings2({ systemSettings: newSysSettings, apiTier, quotas });
|
|
7712
7977
|
return newSysSettings;
|
|
7713
7978
|
});
|
|
7979
|
+
} else if (item.value === "subAgentModel") {
|
|
7980
|
+
const currentSubAgentModel = systemSettings.CustomSubAgent && systemSettings.SubAgentModel ? systemSettings.SubAgentModel : "Default";
|
|
7981
|
+
const curIdx = availableModels.findIndex((m) => m.value === currentSubAgentModel);
|
|
7982
|
+
setSubAgentModelIndex(curIdx >= 0 ? curIdx : 0);
|
|
7983
|
+
setIsSelectingSubAgentModel(true);
|
|
7714
7984
|
} else if (item.value === "preserveThinking") {
|
|
7715
7985
|
setSystemSettings((s) => {
|
|
7716
7986
|
const newSysSettings = { ...s, preserveThinking: s.preserveThinking === false ? true : false };
|
|
@@ -7754,6 +8024,42 @@ function SettingsMenu({
|
|
|
7754
8024
|
}
|
|
7755
8025
|
};
|
|
7756
8026
|
const colors = getThemeColors(systemSettings.theme);
|
|
8027
|
+
if (isSelectingSubAgentModel) {
|
|
8028
|
+
const currentSavedModel = systemSettings.CustomSubAgent && systemSettings.SubAgentModel ? systemSettings.SubAgentModel : "Default";
|
|
8029
|
+
const VISIBLE_COUNT = 15;
|
|
8030
|
+
let startIndex = subAgentScrollOffset;
|
|
8031
|
+
if (subAgentModelIndex < startIndex) {
|
|
8032
|
+
startIndex = subAgentModelIndex;
|
|
8033
|
+
} else if (subAgentModelIndex >= startIndex + VISIBLE_COUNT) {
|
|
8034
|
+
startIndex = subAgentModelIndex - VISIBLE_COUNT + 1;
|
|
8035
|
+
}
|
|
8036
|
+
startIndex = Math.max(0, Math.min(startIndex, Math.max(0, availableModels.length - VISIBLE_COUNT)));
|
|
8037
|
+
if (startIndex !== subAgentScrollOffset) {
|
|
8038
|
+
setSubAgentScrollOffset(startIndex);
|
|
8039
|
+
}
|
|
8040
|
+
const visibleItems = availableModels.slice(startIndex, startIndex + VISIBLE_COUNT);
|
|
8041
|
+
return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, padding: 1, width: "100%", minHeight: 32 }, /* @__PURE__ */ React7.createElement(Box6, { marginBottom: 1, flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React7.createElement(Text7, { color: colors.text, bold: true, underline: true }, "Select Sub-Agent Model:"), availableModels.length > 0 && /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, subAgentModelIndex + 1, "/", availableModels.length)), /* @__PURE__ */ React7.createElement(
|
|
8042
|
+
Box6,
|
|
8043
|
+
{
|
|
8044
|
+
borderStyle: "single",
|
|
8045
|
+
borderColor: subAgentFocusMode === "search" ? colors.primary || "cyan" : "gray",
|
|
8046
|
+
paddingX: 1,
|
|
8047
|
+
marginBottom: 1
|
|
8048
|
+
},
|
|
8049
|
+
/* @__PURE__ */ React7.createElement(Text7, { color: subAgentFocusMode === "search" ? colors.primary || "cyan" : "gray", bold: true }, "\u{1F50D} Search: ", " "),
|
|
8050
|
+
/* @__PURE__ */ React7.createElement(Text7, { color: colors.text }, subAgentSearchQuery),
|
|
8051
|
+
subAgentFocusMode === "search" && /* @__PURE__ */ React7.createElement(Text7, { color: colors.primary || "cyan" }, "\u2588"),
|
|
8052
|
+
!subAgentSearchQuery && subAgentFocusMode !== "search" && /* @__PURE__ */ React7.createElement(Text7, { color: "gray", italic: true }, "(Press TAB or type to filter models...)")
|
|
8053
|
+
), /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", flexGrow: 1, height: VISIBLE_COUNT }, visibleItems.length > 0 ? visibleItems.map((opt, idx) => {
|
|
8054
|
+
const actualIndex = startIndex + idx;
|
|
8055
|
+
if (opt.isHeader) {
|
|
8056
|
+
return /* @__PURE__ */ React7.createElement(Box6, { key: `hdr-${actualIndex}`, paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", bold: true, underline: true }, opt.label));
|
|
8057
|
+
}
|
|
8058
|
+
const isSelected = subAgentModelIndex === actualIndex && subAgentFocusMode === "list";
|
|
8059
|
+
const isSaved = currentSavedModel === opt.value;
|
|
8060
|
+
return /* @__PURE__ */ React7.createElement(Box6, { key: `item-${opt.value}-${actualIndex}`, paddingX: 1, backgroundColor: isSelected ? colors.highlightBg : void 0 }, /* @__PURE__ */ React7.createElement(Text7, { color: isSelected ? colors.text : colors.textDim, bold: isSelected }, isSelected ? "\u276F " : " ", opt.label, isSaved ? /* @__PURE__ */ React7.createElement(Text7, { color: colors.primary || "cyan", italic: true }, " (active)") : ""));
|
|
8061
|
+
}) : /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", italic: true }, 'No models matching "', subAgentSearchQuery, '"'))), /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginTop: 1, flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React7.createElement(Text7, { color: "gray", italic: true }, "TAB to switch search/list \u2022 \u25B2\u25BC Navigate \u2022 ENTER to Select \u2022 ESC to Cancel"), /* @__PURE__ */ React7.createElement(Text7, { color: subAgentFocusMode === "search" ? colors.primary || "cyan" : "gray", bold: true }, "[", subAgentFocusMode.toUpperCase(), " MODE]")));
|
|
8062
|
+
}
|
|
7757
8063
|
if (isSelectingTheme) {
|
|
7758
8064
|
const previewThemeName = themeOptions[themeIndex];
|
|
7759
8065
|
const previewColors = getThemeColors(previewThemeName);
|
|
@@ -7857,6 +8163,8 @@ var init_SettingsMenu = __esm({
|
|
|
7857
8163
|
async "src/components/SettingsMenu.jsx"() {
|
|
7858
8164
|
await init_exec_command();
|
|
7859
8165
|
init_theme();
|
|
8166
|
+
init_model_config();
|
|
8167
|
+
init_secrets();
|
|
7860
8168
|
themeOptions = [...Object.keys(THEMES), "Mystery"];
|
|
7861
8169
|
CATEGORIES = [
|
|
7862
8170
|
{ id: "appearance", label: "Appearance", desc: "Customize UI theme & rendering options" },
|
|
@@ -8254,12 +8562,14 @@ ${forcedReasoning || thinkingLevel !== "Fast" && (aiProvider === "Mistral" || th
|
|
|
8254
8562
|
- Use <think> ... </think> for reasoning before responding, even with simple queries/greetings
|
|
8255
8563
|
` : ""}` : `${thinkingConfig}
|
|
8256
8564
|
`}
|
|
8565
|
+
- **USE PROVIDED DIRECTORY STRUCTURE FOR FILES/PATHS**
|
|
8566
|
+
- RELATIVE TIME REFERENCE eg. few mins ago
|
|
8567
|
+
|
|
8257
8568
|
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider, systemSettings?.advanceRollback, systemSettings?.subAgents !== false)}
|
|
8258
8569
|
${projectContextBlock}${isMemoryEnabled ? `
|
|
8259
8570
|
-- MEMORY RULES --
|
|
8260
|
-
- Subtly Personalize with RELEVENT CONTEXTUAL MEMORIES. Auto Saves
|
|
8261
|
-
|
|
8262
|
-
|
|
8571
|
+
- Subtly Personalize with RELEVENT CONTEXTUAL MEMORIES. Auto Saves
|
|
8572
|
+
` : ""}
|
|
8263
8573
|
-- SECURITY RULES --
|
|
8264
8574
|
- Sensitive files? Ask before Read${isSystemDir ? "\n- PROTECTED DIRECTORY" : ""}
|
|
8265
8575
|
|
|
@@ -10342,7 +10652,7 @@ var init_update_file = __esm({
|
|
|
10342
10652
|
update_file = async (args, context = {}) => {
|
|
10343
10653
|
const parsed = parseArgs(args);
|
|
10344
10654
|
const targetPath = parsed.path;
|
|
10345
|
-
if (!targetPath) return 'ERROR: Missing "path" argument for
|
|
10655
|
+
if (!targetPath) return 'ERROR: Missing "path" argument for PatchFile.';
|
|
10346
10656
|
const { patchPairs, allowMultiple: parsedAllowMultiple, error: parseError } = parsePatchPairs(parsed);
|
|
10347
10657
|
if (parseError) return `ERROR: ${parseError}`;
|
|
10348
10658
|
if (patchPairs.length === 0) {
|
|
@@ -10352,7 +10662,7 @@ var init_update_file = __esm({
|
|
|
10352
10662
|
const absolutePath = path15.resolve(process.cwd(), targetPath);
|
|
10353
10663
|
try {
|
|
10354
10664
|
if (!fs16.existsSync(absolutePath)) {
|
|
10355
|
-
return `ERROR: File [${targetPath}] does not exist. Use
|
|
10665
|
+
return `ERROR: File [${targetPath}] does not exist. Use WriteFile instead.`;
|
|
10356
10666
|
}
|
|
10357
10667
|
let diskContent = context.forcedContent || fs16.readFileSync(absolutePath, "utf8");
|
|
10358
10668
|
if (diskContent.startsWith("\uFEFF")) diskContent = diskContent.slice(1);
|
|
@@ -10389,7 +10699,7 @@ ${diffText}`;
|
|
|
10389
10699
|
// src/tools/read_folder.js
|
|
10390
10700
|
import fs17 from "fs";
|
|
10391
10701
|
import path16 from "path";
|
|
10392
|
-
var EXCLUDED_DIRS, isExcludedDir, read_folder;
|
|
10702
|
+
var EXCLUDED_DIRS, isExcludedDir, formatMtime, read_folder;
|
|
10393
10703
|
var init_read_folder = __esm({
|
|
10394
10704
|
"src/tools/read_folder.js"() {
|
|
10395
10705
|
init_arg_parser();
|
|
@@ -10536,24 +10846,35 @@ var init_read_folder = __esm({
|
|
|
10536
10846
|
".VSCodeCounter"
|
|
10537
10847
|
]);
|
|
10538
10848
|
isExcludedDir = (dirName) => EXCLUDED_DIRS.has(dirName) || dirName.startsWith(".pnpm");
|
|
10849
|
+
formatMtime = (d) => {
|
|
10850
|
+
try {
|
|
10851
|
+
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
10852
|
+
const dd = String(d.getDate()).padStart(2, "0");
|
|
10853
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
10854
|
+
const min = String(d.getMinutes()).padStart(2, "0");
|
|
10855
|
+
return `${mm}-${dd} ${hh}:${min}`;
|
|
10856
|
+
} catch {
|
|
10857
|
+
return "N/A";
|
|
10858
|
+
}
|
|
10859
|
+
};
|
|
10539
10860
|
read_folder = async (args) => {
|
|
10540
10861
|
const parsed = parseArgs(args);
|
|
10541
10862
|
const targetPath = parsed.path || null;
|
|
10542
10863
|
if (!targetPath) {
|
|
10543
10864
|
return "ERROR: No directory path provided.";
|
|
10544
10865
|
}
|
|
10545
|
-
let recurseDepth =
|
|
10866
|
+
let recurseDepth = 1;
|
|
10546
10867
|
if (parsed.recurse !== void 0 && parsed.recurse !== null) {
|
|
10547
10868
|
if (typeof parsed.recurse === "number") {
|
|
10548
10869
|
recurseDepth = parsed.recurse;
|
|
10549
10870
|
} else if (typeof parsed.recurse === "boolean") {
|
|
10550
|
-
recurseDepth = parsed.recurse ?
|
|
10871
|
+
recurseDepth = parsed.recurse ? 2 : 1;
|
|
10551
10872
|
} else {
|
|
10552
10873
|
const val = parseInt(String(parsed.recurse).trim(), 10);
|
|
10553
|
-
recurseDepth = isNaN(val) ?
|
|
10874
|
+
recurseDepth = isNaN(val) ? 1 : val;
|
|
10554
10875
|
}
|
|
10555
10876
|
}
|
|
10556
|
-
recurseDepth = Math.max(
|
|
10877
|
+
recurseDepth = Math.max(1, Math.min(3, recurseDepth));
|
|
10557
10878
|
const absolutePath = path16.resolve(process.cwd(), targetPath);
|
|
10558
10879
|
try {
|
|
10559
10880
|
if (!fs17.existsSync(absolutePath)) {
|
|
@@ -10563,7 +10884,7 @@ var init_read_folder = __esm({
|
|
|
10563
10884
|
if (!stats.isDirectory()) {
|
|
10564
10885
|
return `ERROR: Path [${targetPath}] is a file, not a directory. Use ReadFile instead.`;
|
|
10565
10886
|
}
|
|
10566
|
-
if (recurseDepth ===
|
|
10887
|
+
if (recurseDepth === 1) {
|
|
10567
10888
|
const files = fs17.readdirSync(absolutePath);
|
|
10568
10889
|
const totalItems = files.length;
|
|
10569
10890
|
const maxDisplay = 150;
|
|
@@ -10577,8 +10898,8 @@ var init_read_folder = __esm({
|
|
|
10577
10898
|
info = {
|
|
10578
10899
|
name: file,
|
|
10579
10900
|
type: fStats.isDirectory() ? "directory" : "file",
|
|
10580
|
-
size: (fStats.size / 1024).toFixed(1) + "
|
|
10581
|
-
mtime: fStats.mtime
|
|
10901
|
+
size: (fStats.size / 1024).toFixed(1) + "KB",
|
|
10902
|
+
mtime: formatMtime(fStats.mtime)
|
|
10582
10903
|
};
|
|
10583
10904
|
} catch (e) {
|
|
10584
10905
|
info.type = "inaccessible";
|
|
@@ -10586,11 +10907,10 @@ var init_read_folder = __esm({
|
|
|
10586
10907
|
folderData.push(info);
|
|
10587
10908
|
}
|
|
10588
10909
|
const formatted = folderData.map((f) => {
|
|
10589
|
-
const indicator = f.type === "directory" ? "\u{1F4C1}" : f.type === "file" ? "\u{1F4C4}" : "\u2753";
|
|
10590
10910
|
if (f.type === "directory") {
|
|
10591
|
-
return `${
|
|
10911
|
+
return `${f.name}/`;
|
|
10592
10912
|
}
|
|
10593
|
-
return `${
|
|
10913
|
+
return `${f.name} (${f.size}, ${f.mtime})`;
|
|
10594
10914
|
}).join("\n");
|
|
10595
10915
|
let footer2 = `
|
|
10596
10916
|
|
|
@@ -10598,7 +10918,7 @@ var init_read_folder = __esm({
|
|
|
10598
10918
|
if (totalItems > maxDisplay) {
|
|
10599
10919
|
footer2 = `
|
|
10600
10920
|
|
|
10601
|
-
|
|
10921
|
+
TRUNCATED: Showing first ${maxDisplay} of ${totalItems} items.`;
|
|
10602
10922
|
}
|
|
10603
10923
|
files.length = 0;
|
|
10604
10924
|
displayItems.length = 0;
|
|
@@ -10612,15 +10932,17 @@ ${formatted}${footer2}`;
|
|
|
10612
10932
|
let totalItemsScanned = 0;
|
|
10613
10933
|
const maxTotalItems = 500;
|
|
10614
10934
|
let truncated = false;
|
|
10615
|
-
const buildTree = (dirPath, currentDepth,
|
|
10616
|
-
if (currentDepth > recurseDepth
|
|
10935
|
+
const buildTree = (dirPath, currentDepth, depth = 1) => {
|
|
10936
|
+
if (currentDepth > recurseDepth || truncated) return [];
|
|
10617
10937
|
let entries = [];
|
|
10618
10938
|
try {
|
|
10619
10939
|
entries = fs17.readdirSync(dirPath);
|
|
10620
10940
|
} catch (e) {
|
|
10621
|
-
|
|
10941
|
+
const indent2 = " ".repeat(depth - 1);
|
|
10942
|
+
return [`${indent2}[Inaccessible Directory]`];
|
|
10622
10943
|
}
|
|
10623
|
-
const
|
|
10944
|
+
const subDirs = [];
|
|
10945
|
+
const fileEntries = [];
|
|
10624
10946
|
for (const name of entries) {
|
|
10625
10947
|
const fullPath = path16.join(dirPath, name);
|
|
10626
10948
|
let isDir = false;
|
|
@@ -10628,60 +10950,53 @@ ${formatted}${footer2}`;
|
|
|
10628
10950
|
isDir = fs17.statSync(fullPath).isDirectory();
|
|
10629
10951
|
} catch (e) {
|
|
10630
10952
|
}
|
|
10631
|
-
|
|
10953
|
+
if (isDir) {
|
|
10954
|
+
subDirs.push({ name, fullPath });
|
|
10955
|
+
} else {
|
|
10956
|
+
fileEntries.push({ name, fullPath });
|
|
10957
|
+
}
|
|
10632
10958
|
}
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
if (!a.isDir && b.isDir) return 1;
|
|
10636
|
-
return a.name.localeCompare(b.name);
|
|
10637
|
-
});
|
|
10959
|
+
subDirs.sort((a, b) => a.name.localeCompare(b.name));
|
|
10960
|
+
fileEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
10638
10961
|
const lines = [];
|
|
10639
|
-
const
|
|
10640
|
-
for (
|
|
10962
|
+
const indent = " ".repeat(depth - 1);
|
|
10963
|
+
for (const subDir of subDirs) {
|
|
10641
10964
|
if (totalItemsScanned >= maxTotalItems) {
|
|
10642
10965
|
truncated = true;
|
|
10643
|
-
lines.push(`${
|
|
10966
|
+
lines.push(`${indent}[Truncated - Maximum item limit reached (${maxTotalItems})]`);
|
|
10644
10967
|
break;
|
|
10645
10968
|
}
|
|
10646
|
-
const item = sortedEntries[i];
|
|
10647
|
-
const isLast = i === count - 1;
|
|
10648
|
-
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
10649
|
-
const childPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
10650
10969
|
totalItemsScanned++;
|
|
10651
|
-
|
|
10970
|
+
totalDirectories++;
|
|
10971
|
+
lines.push(`${indent}${subDir.name}/`);
|
|
10972
|
+
if (currentDepth < recurseDepth && !isExcludedDir(subDir.name)) {
|
|
10973
|
+
const childLines = buildTree(subDir.fullPath, currentDepth + 1, depth + 1);
|
|
10974
|
+
lines.push(...childLines);
|
|
10975
|
+
}
|
|
10976
|
+
}
|
|
10977
|
+
const formattedFiles = [];
|
|
10978
|
+
for (const file of fileEntries) {
|
|
10979
|
+
if (totalItemsScanned >= maxTotalItems) {
|
|
10980
|
+
truncated = true;
|
|
10981
|
+
lines.push(`${indent}[Truncated - Maximum item limit reached (${maxTotalItems})]`);
|
|
10982
|
+
break;
|
|
10983
|
+
}
|
|
10984
|
+
totalItemsScanned++;
|
|
10985
|
+
totalFiles++;
|
|
10652
10986
|
let sizeStr = "N/A";
|
|
10653
|
-
let mtimeStr = "N/A";
|
|
10654
10987
|
try {
|
|
10655
|
-
const fStats = fs17.statSync(
|
|
10656
|
-
|
|
10657
|
-
itemType = "directory";
|
|
10658
|
-
mtimeStr = fStats.mtime.toLocaleString();
|
|
10659
|
-
totalDirectories++;
|
|
10660
|
-
} else {
|
|
10661
|
-
itemType = "file";
|
|
10662
|
-
sizeStr = (fStats.size / 1024).toFixed(1) + " KB";
|
|
10663
|
-
mtimeStr = fStats.mtime.toLocaleString();
|
|
10664
|
-
totalFiles++;
|
|
10665
|
-
}
|
|
10988
|
+
const fStats = fs17.statSync(file.fullPath);
|
|
10989
|
+
sizeStr = (fStats.size / 1024).toFixed(1) + "KB";
|
|
10666
10990
|
} catch (e) {
|
|
10667
|
-
itemType = "inaccessible";
|
|
10668
|
-
}
|
|
10669
|
-
const indicator = itemType === "directory" ? "\u{1F4C1}" : itemType === "file" ? "\u{1F4C4}" : "\u2753";
|
|
10670
|
-
let lineText = "";
|
|
10671
|
-
if (itemType === "directory") {
|
|
10672
|
-
lineText = `${prefix}${connector}${indicator} ${item.name} - [DIR] - [Modified: ${mtimeStr}]`;
|
|
10673
|
-
} else {
|
|
10674
|
-
lineText = `${prefix}${connector}${indicator} ${item.name} - [Size: ${sizeStr}] - [Modified: ${mtimeStr}]`;
|
|
10675
|
-
}
|
|
10676
|
-
lines.push(lineText);
|
|
10677
|
-
if (itemType === "directory" && currentDepth <= recurseDepth && !isExcludedDir(item.name)) {
|
|
10678
|
-
const childLines = buildTree(item.fullPath, currentDepth + 1, childPrefix);
|
|
10679
|
-
lines.push(...childLines);
|
|
10680
10991
|
}
|
|
10992
|
+
formattedFiles.push(`${file.name} (${sizeStr})`);
|
|
10993
|
+
}
|
|
10994
|
+
if (formattedFiles.length > 0) {
|
|
10995
|
+
lines.push(`${indent}${formattedFiles.join("; ")}`);
|
|
10681
10996
|
}
|
|
10682
10997
|
return lines;
|
|
10683
10998
|
};
|
|
10684
|
-
const treeLines = buildTree(absolutePath, 1,
|
|
10999
|
+
const treeLines = buildTree(absolutePath, 1, 1);
|
|
10685
11000
|
const formattedTree = treeLines.join("\n");
|
|
10686
11001
|
let footer = `
|
|
10687
11002
|
|
|
@@ -10689,9 +11004,9 @@ ${formatted}${footer2}`;
|
|
|
10689
11004
|
if (truncated) {
|
|
10690
11005
|
footer = `
|
|
10691
11006
|
|
|
10692
|
-
|
|
11007
|
+
TRUNCATED: Scan capped at ${maxTotalItems} items. (Directories: ${totalDirectories}, Files: ${totalFiles})`;
|
|
10693
11008
|
}
|
|
10694
|
-
return `Detailed directory tree for [${targetPath}] (
|
|
11009
|
+
return `Detailed directory tree for [${targetPath}] (recursive depth: ${recurseDepth}):
|
|
10695
11010
|
|
|
10696
11011
|
${formattedTree}${footer}`;
|
|
10697
11012
|
} catch (err) {
|
|
@@ -10965,6 +11280,7 @@ var init_write_docx = __esm({
|
|
|
10965
11280
|
// src/tools/search_keyword.js
|
|
10966
11281
|
import fs20 from "fs/promises";
|
|
10967
11282
|
import path19 from "path";
|
|
11283
|
+
import fg from "fast-glob";
|
|
10968
11284
|
async function getFilesRecursively(dir, excludes, baseDir = dir, depth = 1) {
|
|
10969
11285
|
if (depth > 12) return [];
|
|
10970
11286
|
let results = [];
|
|
@@ -10996,35 +11312,50 @@ async function getFilesRecursively(dir, excludes, baseDir = dir, depth = 1) {
|
|
|
10996
11312
|
}
|
|
10997
11313
|
return results;
|
|
10998
11314
|
}
|
|
10999
|
-
function
|
|
11000
|
-
return s.toLowerCase().replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
11001
|
-
}
|
|
11002
|
-
function levenshtein(a, b) {
|
|
11315
|
+
function levenshtein(a, b, cap = Infinity) {
|
|
11003
11316
|
if (a === b) return 0;
|
|
11004
11317
|
if (a.length === 0) return b.length;
|
|
11005
11318
|
if (b.length === 0) return a.length;
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
for (let
|
|
11009
|
-
let
|
|
11010
|
-
|
|
11011
|
-
for (let
|
|
11012
|
-
const
|
|
11013
|
-
|
|
11014
|
-
|
|
11319
|
+
if (Math.abs(a.length - b.length) > cap) return cap + 1;
|
|
11320
|
+
let row = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
11321
|
+
for (let i = 1; i <= a.length; i++) {
|
|
11322
|
+
let nextRow = [i];
|
|
11323
|
+
let minInRow = i;
|
|
11324
|
+
for (let j = 1; j <= b.length; j++) {
|
|
11325
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
11326
|
+
const dist = Math.min(
|
|
11327
|
+
nextRow[j - 1] + 1,
|
|
11328
|
+
// insertion
|
|
11329
|
+
row[j] + 1,
|
|
11330
|
+
// deletion
|
|
11331
|
+
row[j - 1] + cost
|
|
11332
|
+
// substitution
|
|
11333
|
+
);
|
|
11334
|
+
nextRow.push(dist);
|
|
11335
|
+
if (dist < minInRow) minInRow = dist;
|
|
11015
11336
|
}
|
|
11016
|
-
|
|
11337
|
+
row = nextRow;
|
|
11338
|
+
if (minInRow > cap) return cap + 1;
|
|
11017
11339
|
}
|
|
11018
|
-
return
|
|
11340
|
+
return row[b.length];
|
|
11019
11341
|
}
|
|
11020
11342
|
function fuzzyMatch(line, keyword) {
|
|
11021
|
-
|
|
11022
|
-
const
|
|
11023
|
-
const
|
|
11024
|
-
if (normLine.includes(
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11343
|
+
if (!line || !keyword) return false;
|
|
11344
|
+
const normLine = line.toLowerCase();
|
|
11345
|
+
const normKw = keyword.toLowerCase();
|
|
11346
|
+
if (normLine.includes(normKw)) return true;
|
|
11347
|
+
const lineWords = normLine.split(/[^a-z0-9]+/).filter((w) => w.length > 0);
|
|
11348
|
+
const kwTokens = normKw.split(/[^a-z0-9]+/).filter((t) => t.length > 1 || normKw.length === 1 && t.length > 0);
|
|
11349
|
+
if (kwTokens.length === 0) return false;
|
|
11350
|
+
return kwTokens.every((kwToken) => {
|
|
11351
|
+
const maxDist = kwToken.length <= 2 ? 0 : kwToken.length <= 5 ? 1 : 2;
|
|
11352
|
+
for (const lineWord of lineWords) {
|
|
11353
|
+
if (lineWord.includes(kwToken)) return true;
|
|
11354
|
+
if (kwToken.length >= 3 && lineWord.length >= 3 && Math.abs(lineWord.length - kwToken.length) <= maxDist) {
|
|
11355
|
+
if (levenshtein(kwToken, lineWord, maxDist) <= maxDist) return true;
|
|
11356
|
+
}
|
|
11357
|
+
}
|
|
11358
|
+
return false;
|
|
11028
11359
|
});
|
|
11029
11360
|
}
|
|
11030
11361
|
var search_keyword;
|
|
@@ -11032,17 +11363,17 @@ var init_search_keyword = __esm({
|
|
|
11032
11363
|
"src/tools/search_keyword.js"() {
|
|
11033
11364
|
init_arg_parser();
|
|
11034
11365
|
search_keyword = async (args) => {
|
|
11035
|
-
const { keyword: rawKeyword, path: pathArg, subString, regex } = parseArgs(args);
|
|
11366
|
+
const { keyword: rawKeyword, path: pathArg, fuzzy, subString, regex } = parseArgs(args);
|
|
11036
11367
|
if (rawKeyword === void 0 || rawKeyword === null) return 'ERROR: Missing "keyword" argument.';
|
|
11037
11368
|
const keyword = String(rawKeyword);
|
|
11038
11369
|
const toBool = (v) => v === true || v === "true" || v === 1 || v === "1" || v === "yes";
|
|
11039
11370
|
const regexExplicitlyFalse = regex === false || regex === "false" || regex === 0 || regex === "0" || regex === "no";
|
|
11040
11371
|
const regexExplicitlyTrue = regex === true || regex === "true" || regex === 1 || regex === "1" || regex === "yes";
|
|
11041
|
-
|
|
11372
|
+
const isFuzzy = toBool(fuzzy) || toBool(subString);
|
|
11042
11373
|
let regexPattern = null;
|
|
11043
11374
|
let wordRegex = null;
|
|
11044
11375
|
if (regexExplicitlyFalse) {
|
|
11045
|
-
if (!
|
|
11376
|
+
if (!isFuzzy) {
|
|
11046
11377
|
wordRegex = new RegExp(`(?<![\\w])${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w])`, "i");
|
|
11047
11378
|
}
|
|
11048
11379
|
} else {
|
|
@@ -11233,21 +11564,67 @@ var init_search_keyword = __esm({
|
|
|
11233
11564
|
const rootDir = process.cwd();
|
|
11234
11565
|
let pathArgType = null;
|
|
11235
11566
|
if (pathArg) {
|
|
11236
|
-
const
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
const
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11567
|
+
const isGlob = fg.isDynamicPattern(pathArg) || /[*?{}[\]()|+]/.test(pathArg);
|
|
11568
|
+
if (isGlob) {
|
|
11569
|
+
pathArgType = "glob";
|
|
11570
|
+
const posixPath = pathArg.replace(/\\/g, "/");
|
|
11571
|
+
const globExcludes = excludes.map((ex) => ex.startsWith(".") ? `**/*${ex}` : `**/${ex}/**`);
|
|
11572
|
+
const hasRegexSyntax = /[\(\)\|]|\.\*/.test(posixPath);
|
|
11573
|
+
let matchedPaths = [];
|
|
11574
|
+
if (!hasRegexSyntax) {
|
|
11575
|
+
try {
|
|
11576
|
+
matchedPaths = await fg(posixPath, {
|
|
11577
|
+
cwd: rootDir,
|
|
11578
|
+
ignore: globExcludes,
|
|
11579
|
+
dot: true,
|
|
11580
|
+
onlyFiles: true,
|
|
11581
|
+
absolute: false
|
|
11582
|
+
});
|
|
11583
|
+
} catch {
|
|
11584
|
+
matchedPaths = [];
|
|
11585
|
+
}
|
|
11586
|
+
}
|
|
11587
|
+
if (matchedPaths.length === 0 && (hasRegexSyntax || fg.isDynamicPattern(posixPath))) {
|
|
11588
|
+
const baseDirMatch = posixPath.match(/^([^\*\?\(\)\|\[\]\s]+)\//);
|
|
11589
|
+
const scanDir = baseDirMatch && !/[\*\?\(\)\|\[\]]/.test(baseDirMatch[1]) ? path19.resolve(rootDir, baseDirMatch[1]) : rootDir;
|
|
11590
|
+
const allFiles = await getFilesRecursively(scanDir, excludes, rootDir);
|
|
11591
|
+
try {
|
|
11592
|
+
let cleanRegexStr = posixPath.replace(/^\.\//, "");
|
|
11593
|
+
cleanRegexStr = cleanRegexStr.replace(/\.\*\/(\\\.|[^\/])/g, ".*$1");
|
|
11594
|
+
if (!cleanRegexStr.startsWith("^") && !cleanRegexStr.startsWith(".*")) {
|
|
11595
|
+
cleanRegexStr = `.*${cleanRegexStr}`;
|
|
11596
|
+
}
|
|
11597
|
+
const pathRegex = new RegExp(cleanRegexStr.endsWith("$") ? cleanRegexStr : `${cleanRegexStr}$`, "i");
|
|
11598
|
+
filesToSearch = allFiles.filter((f) => {
|
|
11599
|
+
const rel = f.relativePath.replace(/\\/g, "/");
|
|
11600
|
+
return pathRegex.test(rel);
|
|
11601
|
+
});
|
|
11602
|
+
} catch {
|
|
11603
|
+
filesToSearch = [];
|
|
11604
|
+
}
|
|
11246
11605
|
} else {
|
|
11247
|
-
|
|
11606
|
+
filesToSearch = matchedPaths.map((relP) => ({
|
|
11607
|
+
fullPath: path19.resolve(rootDir, relP),
|
|
11608
|
+
relativePath: relP
|
|
11609
|
+
}));
|
|
11610
|
+
}
|
|
11611
|
+
} else {
|
|
11612
|
+
const normalised = pathArg.replace(/[\/\\]+$/, "");
|
|
11613
|
+
const fullPath = path19.resolve(rootDir, normalised);
|
|
11614
|
+
try {
|
|
11615
|
+
const stat = await fs20.stat(fullPath);
|
|
11616
|
+
if (stat.isDirectory()) {
|
|
11617
|
+
pathArgType = "dir";
|
|
11618
|
+
filesToSearch = await getFilesRecursively(fullPath, excludes, rootDir);
|
|
11619
|
+
} else if (stat.isFile()) {
|
|
11620
|
+
pathArgType = "file";
|
|
11621
|
+
filesToSearch.push({ fullPath, relativePath: path19.relative(rootDir, fullPath) });
|
|
11622
|
+
} else {
|
|
11623
|
+
return `ERROR: Path is neither a file nor a directory: ${pathArg}`;
|
|
11624
|
+
}
|
|
11625
|
+
} catch {
|
|
11626
|
+
return `ERROR: Path not found: ${pathArg}`;
|
|
11248
11627
|
}
|
|
11249
|
-
} catch {
|
|
11250
|
-
return `ERROR: Path not found: ${pathArg}`;
|
|
11251
11628
|
}
|
|
11252
11629
|
} else {
|
|
11253
11630
|
filesToSearch = await getFilesRecursively(rootDir, excludes);
|
|
@@ -11259,7 +11636,7 @@ var init_search_keyword = __esm({
|
|
|
11259
11636
|
const lines = content.split(/\r?\n/);
|
|
11260
11637
|
const fileMatches = [];
|
|
11261
11638
|
for (let i = 0; i < lines.length; i++) {
|
|
11262
|
-
const matched =
|
|
11639
|
+
const matched = isFuzzy ? lines[i].toLowerCase().includes(keyword.toLowerCase()) || fuzzyMatch(lines[i], keyword) : regexExplicitlyFalse ? wordRegex && wordRegex.test(lines[i]) : regexPattern && regexPattern.test(lines[i]) || wordRegex && wordRegex.test(lines[i]);
|
|
11263
11640
|
if (matched) {
|
|
11264
11641
|
fileMatches.push({ line: i + 1, content: lines[i].trim() });
|
|
11265
11642
|
}
|
|
@@ -11285,11 +11662,11 @@ var init_search_keyword = __esm({
|
|
|
11285
11662
|
if (typeof global.gc === "function") {
|
|
11286
11663
|
global.gc();
|
|
11287
11664
|
}
|
|
11288
|
-
const modeLabel =
|
|
11665
|
+
const modeLabel = isFuzzy ? "(fuzzy mode)" : regexExplicitlyTrue ? "(regex mode)" : regexExplicitlyFalse ? "(keyword mode)" : "(standard mode)";
|
|
11289
11666
|
if (fileGroups.length === 0) {
|
|
11290
|
-
const zeroLocation = pathArgType === "file" ? ` in '${pathArg}'` : pathArgType === "dir" ? ` in '${pathArg}'` : ". Try to specify files";
|
|
11291
|
-
const dirPrefix2 = pathArgType === "dir" ? "[DIR]" : "";
|
|
11292
|
-
return `${dirPrefix2}Found 0 matches of '${keyword}'${zeroLocation}${modeLabel ? ` ${modeLabel}` : ""}`;
|
|
11667
|
+
const zeroLocation = pathArgType === "file" ? ` in '${pathArg}'` : pathArgType === "dir" || pathArgType === "glob" ? ` in '${pathArg}'` : ". Try to specify files";
|
|
11668
|
+
const dirPrefix2 = pathArgType === "dir" ? "[DIR]" : pathArgType === "glob" ? "[GLOB]" : "";
|
|
11669
|
+
return `${dirPrefix2}${dirPrefix2 ? " " : ""}Found 0 matches of '${keyword}'${zeroLocation}${modeLabel ? ` ${modeLabel}` : ""}`;
|
|
11293
11670
|
}
|
|
11294
11671
|
const ml = modeLabel ? ` ${modeLabel}` : "";
|
|
11295
11672
|
const fileCount = `${fileGroups.length} file${fileGroups.length === 1 ? "" : "s"}`;
|
|
@@ -11297,22 +11674,20 @@ var init_search_keyword = __esm({
|
|
|
11297
11674
|
let outputHeader;
|
|
11298
11675
|
if (pathArgType === "file") {
|
|
11299
11676
|
outputHeader = `Found ${matchCount} of '${keyword}' in '${pathArg}'${ml}:`;
|
|
11300
|
-
} else if (pathArgType === "dir") {
|
|
11677
|
+
} else if (pathArgType === "dir" || pathArgType === "glob") {
|
|
11301
11678
|
outputHeader = `Found ${matchCount} of '${keyword}' in '${pathArg}' across ${fileCount}${ml}:`;
|
|
11302
11679
|
} else {
|
|
11303
11680
|
outputHeader = `Found ${matchCount} of '${keyword}' across ${fileCount}${ml}:`;
|
|
11304
11681
|
}
|
|
11305
|
-
const dirPrefix = pathArgType === "dir" ? "[DIR]" : "";
|
|
11306
|
-
let output = `${dirPrefix}${outputHeader}
|
|
11682
|
+
const dirPrefix = pathArgType === "dir" ? "[DIR]" : pathArgType === "glob" ? "[GLOB]" : "";
|
|
11683
|
+
let output = `${dirPrefix}${dirPrefix ? " " : ""}${outputHeader}
|
|
11307
11684
|
|
|
11308
11685
|
`;
|
|
11309
11686
|
for (const group of fileGroups) {
|
|
11310
11687
|
output += `${group.path}
|
|
11311
11688
|
`;
|
|
11312
|
-
for (
|
|
11313
|
-
|
|
11314
|
-
const prefix = isLast ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
11315
|
-
output += `${prefix} ${group.matches[i].line}: ${group.matches[i].content}
|
|
11689
|
+
for (const m of group.matches) {
|
|
11690
|
+
output += ` ${m.line}: ${m.content}
|
|
11316
11691
|
`;
|
|
11317
11692
|
}
|
|
11318
11693
|
output += "\n";
|
|
@@ -13176,7 +13551,7 @@ import dotenv from "dotenv";
|
|
|
13176
13551
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
13177
13552
|
import path27, { normalize } from "path";
|
|
13178
13553
|
import fs28 from "fs";
|
|
13179
|
-
var RE_STUTTER_CODE_BLOCK_CLOSED, RE_STUTTER_CODE_BLOCK_OPEN, RE_STUTTER_INLINE_CODE, RE_STUTTER_TABLE_ROW, RE_STUTTER_WORD_BOUNDARY, RE_STUTTER_NON_ALNUM, RE_TOOL_CALL_FUNC, RE_TOOL_PARTIAL_ARGS_FALLBACK, RE_STRIP_QUOTES, RE_BACKSLASH_SLASH, client, globalSettings,
|
|
13554
|
+
var RE_STUTTER_CODE_BLOCK_CLOSED, RE_STUTTER_CODE_BLOCK_OPEN, RE_STUTTER_INLINE_CODE, RE_STUTTER_TABLE_ROW, RE_STUTTER_WORD_BOUNDARY, RE_STUTTER_NON_ALNUM, RE_TOOL_CALL_FUNC, RE_TOOL_PARTIAL_ARGS_FALLBACK, RE_STRIP_QUOTES, RE_BACKSLASH_SLASH, client, globalSettings, systemInstructionCache, colorMainWords, withRetry, TERMINATION_SIGNAL, getCleanGroupedLength, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getMistralStream, getNVIDIAStream, wrapNvidiaStreamWithQueueDepth, getOpenRouterStream, signalTermination, isTerminationSignaled, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, translateKimiToolCalls, REGEX_PLACEHOLDER_ARG, REGEX_PLACEHOLDER_VAL, isPlaceholderVal, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, compressHistory, deleteChatSummary, getAIStream, runSubagent;
|
|
13180
13555
|
var init_ai = __esm({
|
|
13181
13556
|
async "src/utils/ai.js"() {
|
|
13182
13557
|
await init_prompts();
|
|
@@ -13198,6 +13573,7 @@ var init_ai = __esm({
|
|
|
13198
13573
|
init_editor();
|
|
13199
13574
|
init_indentation();
|
|
13200
13575
|
init_box();
|
|
13576
|
+
await init_main_tools();
|
|
13201
13577
|
dotenv.config({ quiet: true });
|
|
13202
13578
|
RE_STUTTER_CODE_BLOCK_CLOSED = /```[\s\S]*?```/g;
|
|
13203
13579
|
RE_STUTTER_CODE_BLOCK_OPEN = /```[\s\S]*$/g;
|
|
@@ -13211,26 +13587,7 @@ var init_ai = __esm({
|
|
|
13211
13587
|
RE_BACKSLASH_SLASH = /\\/g;
|
|
13212
13588
|
client = null;
|
|
13213
13589
|
globalSettings = {};
|
|
13214
|
-
|
|
13215
|
-
cachedChatId2 = null;
|
|
13216
|
-
cachedIndentationTree = null;
|
|
13217
|
-
getCachedDirTree = (fn, chatId, isDynamicDirAwareness, indentationTree) => {
|
|
13218
|
-
if (isDynamicDirAwareness) {
|
|
13219
|
-
dirTreeCache = null;
|
|
13220
|
-
cachedChatId2 = chatId;
|
|
13221
|
-
cachedIndentationTree = indentationTree;
|
|
13222
|
-
return fn();
|
|
13223
|
-
}
|
|
13224
|
-
if (cachedChatId2 !== chatId || cachedIndentationTree !== indentationTree) {
|
|
13225
|
-
dirTreeCache = null;
|
|
13226
|
-
cachedChatId2 = chatId;
|
|
13227
|
-
cachedIndentationTree = indentationTree;
|
|
13228
|
-
}
|
|
13229
|
-
if (dirTreeCache === null) {
|
|
13230
|
-
dirTreeCache = fn();
|
|
13231
|
-
}
|
|
13232
|
-
return dirTreeCache;
|
|
13233
|
-
};
|
|
13590
|
+
systemInstructionCache = { key: null, value: null };
|
|
13234
13591
|
colorMainWords = (label) => {
|
|
13235
13592
|
if (!label) return label;
|
|
13236
13593
|
return label.replace(/(?:(\x1b\[\d+m))?([✔✘✖🔍📖→➕↻↷•🛇])(?:(\x1b\[\d+m))?\s*\b(Created|Read|Edited|Viewed|Processed|Auto-Read|Skipped|List|Generated|Written|Searched|AI Search|Get Map|Write Canceled|Edit Canceled|Write Cancelled|Edit Denied|Visited|Updated|Reviewed|Delegated|Background|Checked|Indexed|Analyzed|Browsed|Elevating SubAgent|Checking SubAgent Work|Started Generalist|Called Generalist|Unsupported Modality|Awaiting|Cancelled|Aligning Moon Phase|Contemplating Existence|Staring At Void|Rollback Point Checked|Emergency Rollback Failed|Emergency Rollback|Delaying Professionally|Negotiating With Electrons|Touching Grass (virtually)|Panicking Softly|Rethinking Career Choices|Loading Cat Videos|Giving Up Entirely|Summoning Braincell #2|Pretending To Be Busy|Waiting For Motivation DLC|Rotating Internal Screaming|Downloading More RAM|Feeding The Hamsters|Gaslighting Scheduler|Performing Dramatic Pause|Buffering Social Energy|Calculating Regret|Reading Terms And Conditions|Becoming Sentient Briefly|Contacting Ancestors)\b/ig, (match, ansiBefore, icon, ansiAfter, word) => {
|
|
@@ -14220,7 +14577,9 @@ var init_ai = __esm({
|
|
|
14220
14577
|
}
|
|
14221
14578
|
let originalTextProcessed = agentText.replace(/\[Prompted on:.*?\]/g, "").trim();
|
|
14222
14579
|
agentRes = agentRes.replace(/\r?\n\r?\n/g, "\n").replace(/\n\n/g, "\n").replace(/\\n\\n/g, "").trim();
|
|
14223
|
-
|
|
14580
|
+
const now1223 = /* @__PURE__ */ new Date();
|
|
14581
|
+
const dateTimeStr1223 = `${now1223.getFullYear()}-${now1223.toLocaleString("en-US", { month: "short" }).toUpperCase()}-${String(now1223.getDate()).padStart(2, "0")}, ${now1223.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: true })}`;
|
|
14582
|
+
let userPrompt = `[METADATA] Current date and Time: ${dateTimeStr1223}
|
|
14224
14583
|
|
|
14225
14584
|
[USER]: ${originalTextProcessed.substring(0, USER_CONTEXT_LENGTH)}
|
|
14226
14585
|
${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n" : ""}
|
|
@@ -14687,6 +15046,13 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
14687
15046
|
result = result.replace(/<\|\s*tool_calls_section_end\s*\|>/gi, "");
|
|
14688
15047
|
return result;
|
|
14689
15048
|
};
|
|
15049
|
+
REGEX_PLACEHOLDER_ARG = /(?:path|query|url|keyword|command|method|title|task|id)\s*=\s*['"`]?\s*\.\.\.\s*['"`]?/i;
|
|
15050
|
+
REGEX_PLACEHOLDER_VAL = /^['"`]?\s*\.\.\.\s*['"`]?$/;
|
|
15051
|
+
isPlaceholderVal = (val) => {
|
|
15052
|
+
if (val === void 0 || val === null) return false;
|
|
15053
|
+
const str = String(val).trim();
|
|
15054
|
+
return str === "..." || str === "\u2026" || REGEX_PLACEHOLDER_VAL.test(str);
|
|
15055
|
+
};
|
|
14690
15056
|
detectToolCalls = (text) => {
|
|
14691
15057
|
if (!text) return [];
|
|
14692
15058
|
const translatedText = translateKimiToolCalls(text);
|
|
@@ -14735,11 +15101,15 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
14735
15101
|
if (endIdx !== -1) {
|
|
14736
15102
|
const finalArgsText = cleanText.substring(startIdx + 1, closingParenIdx);
|
|
14737
15103
|
const finalFullMatch = cleanText.substring(match.index, endIdx + 1);
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
15104
|
+
const parsed = parseArgs(finalArgsText);
|
|
15105
|
+
const hasPlaceholderArg = isPlaceholderVal(parsed.path) || isPlaceholderVal(parsed.query) || isPlaceholderVal(parsed.url) || isPlaceholderVal(parsed.keyword) || isPlaceholderVal(parsed.command) || isPlaceholderVal(parsed.method) || isPlaceholderVal(parsed.title) || isPlaceholderVal(parsed.task) || isPlaceholderVal(parsed.id) || REGEX_PLACEHOLDER_ARG.test(finalArgsText);
|
|
15106
|
+
if (!hasPlaceholderArg) {
|
|
15107
|
+
results.push({
|
|
15108
|
+
fullMatch: finalFullMatch,
|
|
15109
|
+
toolName: toolName.trim(),
|
|
15110
|
+
args: finalArgsText.trim()
|
|
15111
|
+
});
|
|
15112
|
+
}
|
|
14743
15113
|
toolRegex.lastIndex = endIdx + 1;
|
|
14744
15114
|
}
|
|
14745
15115
|
}
|
|
@@ -14937,7 +15307,8 @@ Chats to process:
|
|
|
14937
15307
|
if (oldSummary) {
|
|
14938
15308
|
prompt += `- Existing Summary: "${oldSummary}"
|
|
14939
15309
|
`;
|
|
14940
|
-
prompt +=
|
|
15310
|
+
prompt += `
|
|
15311
|
+
-- New Memories to integrate:
|
|
14941
15312
|
${newMemoryListStr}
|
|
14942
15313
|
|
|
14943
15314
|
`;
|
|
@@ -15179,7 +15550,12 @@ Provide a consolidated summary of the entire session.`;
|
|
|
15179
15550
|
const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
|
|
15180
15551
|
const isContext32k = (sessionStats?.tokens || 0) >= 1e4;
|
|
15181
15552
|
const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
|
|
15182
|
-
const
|
|
15553
|
+
const now = /* @__PURE__ */ new Date();
|
|
15554
|
+
const year = now.getFullYear();
|
|
15555
|
+
const month = now.toLocaleString("en-US", { month: "short" }).toUpperCase();
|
|
15556
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
15557
|
+
const timeStr = now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: true });
|
|
15558
|
+
const dateTimeStr = `${year}-${month}-${day}, ${timeStr}`;
|
|
15183
15559
|
const COLLAPSED_DIRS_GLOBAL = [
|
|
15184
15560
|
// --- The OG Clutter ---
|
|
15185
15561
|
".git",
|
|
@@ -15406,8 +15782,11 @@ ${currentSummary}
|
|
|
15406
15782
|
**CONTEXT SUMMARY OF PREVIOUS TURNS**
|
|
15407
15783
|
${currentSummary}
|
|
15408
15784
|
` : "";
|
|
15409
|
-
|
|
15410
|
-
|
|
15785
|
+
const dynamicDirAwareness = !!systemSettings?.dynamicDirAwareness;
|
|
15786
|
+
const sysInstructionCacheKey = `${chatId}|${aiProvider}|${thinkingLevel}|${modelName}|${profile}|${dynamicDirAwareness}`;
|
|
15787
|
+
const isSysInstructionCached = !dynamicDirAwareness && systemInstructionCache.key === sysInstructionCacheKey && systemInstructionCache.value;
|
|
15788
|
+
let dirStructure = isSysInstructionCached ? "" : "\n**DIRECTORY STRUCTURE**\nCWD: " + process.cwd() + `${isPlayground ? " [PLAYGROUND MODE]" : ""}${cwdMismatch ? ` (WARNING: CWD Mismatch! Previous Path: ${lastCwd})` : ""}
|
|
15789
|
+
` + getDirTree(process.cwd(), dynamicMaxDepth);
|
|
15411
15790
|
const ideCtx = await getIDEContext();
|
|
15412
15791
|
let ideBlock = "";
|
|
15413
15792
|
if (isBridgeConnected()) {
|
|
@@ -15859,10 +16238,18 @@ ${cleanPromptForModel.trim()}
|
|
|
15859
16238
|
throw new Error("Error: Quota Exausted for Agent");
|
|
15860
16239
|
}
|
|
15861
16240
|
targetModel = modelName;
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
16241
|
+
const sysInstructionCacheKey2 = `${chatId}|${aiProvider}|${thinkingLevel}|${targetModel}|${JSON.stringify(profile)}|${!!systemSettings?.dynamicDirAwareness}|${!!systemSettings?.subAgents}`;
|
|
16242
|
+
let isCacheHit = systemInstructionCache.key === sysInstructionCacheKey2 && systemInstructionCache.value;
|
|
16243
|
+
if (isCacheHit) {
|
|
16244
|
+
currentSystemInstruction = systemInstructionCache.value;
|
|
16245
|
+
} else {
|
|
16246
|
+
currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? thinkingLevel : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, aiProvider === "Google" ? true : isMultiModal, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? true : false, chatId);
|
|
16247
|
+
if (!systemSettings?.dynamicDirAwareness) {
|
|
16248
|
+
currentSystemInstruction += `
|
|
16249
|
+
${dirStructure.replace("\n**DIRECTORY STRUCTURE**", "\n**DIRECTORY STRUCTURE**")}`;
|
|
16250
|
+
}
|
|
16251
|
+
systemInstructionCache.key = sysInstructionCacheKey2;
|
|
16252
|
+
systemInstructionCache.value = currentSystemInstruction;
|
|
15866
16253
|
}
|
|
15867
16254
|
const lastUserMsg = contents[contents.length - 1];
|
|
15868
16255
|
if (isBridgeConnected() & loop > 0) {
|
|
@@ -16599,21 +16986,21 @@ ${ideErr} [/ERROR]`;
|
|
|
16599
16986
|
} else if (normToolName === "list_files" || normToolName === "read_folder") {
|
|
16600
16987
|
const action = normToolName === "list_files" ? "List" : "Browsed";
|
|
16601
16988
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
16602
|
-
const recurse = parseArgs(toolCall.args).recurse ||
|
|
16603
|
-
label = `${path29 ? "\u2714" : "\u2718"} ${action}: ${path29 ? `${path29 === "." ? "
|
|
16989
|
+
const recurse = parseArgs(toolCall.args).recurse || 1;
|
|
16990
|
+
label = `${path29 ? "\u2714" : "\u2718"} ${action}: ${path29 ? `${path29 === "." ? `./${recurse > 1 ? "*" : ""}` : `${path29.replaceAll("\\", "/")}${recurse > 1 ? `${path29.endsWith("/") ? `*` : `/*`}` : `${path29.endsWith("/") ? "" : "/"}`}`}` : "No Folder Selected"}`;
|
|
16604
16991
|
} else if (normToolName === "write_file" || normToolName === "update_file") {
|
|
16605
16992
|
const action = normToolName === "write_file" ? "Created" : "Edited";
|
|
16606
16993
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
16607
|
-
label = `${path29 ? "\u2714" : "\u2718"} ${action}: ${path29 || "No File Changes"}`;
|
|
16994
|
+
label = `${path29 ? "\u2714" : "\u2718"} ${action}: ${path29.replaceAll("\\", "/") || "No File Changes"}`;
|
|
16608
16995
|
} else if (normToolName === "write_pdf") {
|
|
16609
16996
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
16610
|
-
label = `${path29 ? "\u2714" : "\u2718"} Generated: ${path29 || "No PDF Generated"}`;
|
|
16997
|
+
label = `${path29 ? "\u2714" : "\u2718"} Generated: ${path29.replaceAll("\\", "/") || "No PDF Generated"}`;
|
|
16611
16998
|
} else if (normToolName === "write_docx") {
|
|
16612
16999
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
16613
|
-
label = `${path29 ? "\u2714" : "\u2718"} Generated: ${path29 || "No Docx Generated"}`;
|
|
17000
|
+
label = `${path29 ? "\u2714" : "\u2718"} Generated: ${path29.replaceAll("\\", "/") || "No Docx Generated"}`;
|
|
16614
17001
|
} else if (normToolName === "file_map") {
|
|
16615
17002
|
const path29 = parseArgs(toolCall.args).path;
|
|
16616
|
-
label = `${path29 ? "\u2714" : "\u2718"} Indexed: ${path29 ? "" + path29 : "File Not Found"}`;
|
|
17003
|
+
label = `${path29 ? "\u2714" : "\u2718"} Indexed: ${path29.replaceAll("\\", "/") ? "" + path29 : "File Not Found"}`;
|
|
16617
17004
|
} else if (normToolName.toLowerCase() === "search_keyword" || normToolName.toLowerCase() === "todo") {
|
|
16618
17005
|
label = "";
|
|
16619
17006
|
} else if (normToolName.toLowerCase() === "generate_image") {
|
|
@@ -16659,7 +17046,6 @@ ${ideErr} [/ERROR]`;
|
|
|
16659
17046
|
"Panicking Softly",
|
|
16660
17047
|
"Rethinking Career Choices",
|
|
16661
17048
|
"Loading Cat Videos",
|
|
16662
|
-
"Giving Up Entirely",
|
|
16663
17049
|
// --- The New Chaos Pack ---
|
|
16664
17050
|
"Summoning Braincell #2",
|
|
16665
17051
|
"Pretending To Be Busy",
|
|
@@ -17048,7 +17434,7 @@ ${ideErr} [/ERROR]`;
|
|
|
17048
17434
|
if (successes.length === 0) {
|
|
17049
17435
|
const errorMsg = `[TOOL RESULT]: ERROR: Failed to apply patches to [${path27.basename(absPath)}].
|
|
17050
17436
|
${failures.map((f) => ` \u2022 ${f.error}`).join("\n")}`;
|
|
17051
|
-
const errorLabel = `\u2714 Edited: ${path27.basename(absPath)}`;
|
|
17437
|
+
const errorLabel = `\u2714 Edited: ${path27.basename(absPath.replaceAll("\\", "/"))}`;
|
|
17052
17438
|
let terminalWidth = 115;
|
|
17053
17439
|
if (process.stdout.isTTY) {
|
|
17054
17440
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -17203,7 +17589,7 @@ ${ancestry2}- Content Preview:
|
|
|
17203
17589
|
${snippet2}`;
|
|
17204
17590
|
}
|
|
17205
17591
|
const action = normToolName === "write_file" ? "Created" : "Edited";
|
|
17206
|
-
const feedbackLabel = `${filePath ? "\u2714" : "\u2718"} ${action}: ${filePath || "No File Changes"}`;
|
|
17592
|
+
const feedbackLabel = `${filePath ? "\u2714" : "\u2718"} ${action}: ${filePath.replaceAll("\\", "/") || "No File Changes"}`;
|
|
17207
17593
|
let terminalWidth = 115;
|
|
17208
17594
|
if (process.stdout.isTTY) {
|
|
17209
17595
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -17237,7 +17623,7 @@ ${snippet2}`;
|
|
|
17237
17623
|
}
|
|
17238
17624
|
if (normToolName === "write_file" || normToolName === "update_file") {
|
|
17239
17625
|
const action = normToolName === "write_file" ? "Write Cancelled" : "Edit Denied";
|
|
17240
|
-
const deniedLabel = `\u2718 ${action}: ${parseArgs(toolCall.args).path || "..."}`;
|
|
17626
|
+
const deniedLabel = `\u2718 ${action}: ${parseArgs(toolCall.args).path.replaceAll("\\", "/") || "..."}`;
|
|
17241
17627
|
let terminalWidth = 115;
|
|
17242
17628
|
if (process.stdout.isTTY) {
|
|
17243
17629
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -17333,8 +17719,10 @@ ${snippet2}`;
|
|
|
17333
17719
|
}
|
|
17334
17720
|
if (normToolName === "search_keyword") {
|
|
17335
17721
|
const { keyword, path: path29 } = parseArgs(toolCall.args);
|
|
17722
|
+
const _isGlob = typeof result === "string" && result.startsWith("[GLOB]");
|
|
17723
|
+
if (_isGlob) result = result.slice(6).trimStart();
|
|
17336
17724
|
const _isDir = typeof result === "string" && result.startsWith("[DIR]");
|
|
17337
|
-
if (_isDir) result = result.slice(5);
|
|
17725
|
+
if (_isDir) result = result.slice(5).trimStart();
|
|
17338
17726
|
let matchCount = 0;
|
|
17339
17727
|
if (result) {
|
|
17340
17728
|
const m = result.match(/Found (\d+) match/i);
|
|
@@ -17343,8 +17731,8 @@ ${snippet2}`;
|
|
|
17343
17731
|
}
|
|
17344
17732
|
}
|
|
17345
17733
|
const _sp = path29 ? path29.replace(/[\/\\]+$/, "") : null;
|
|
17346
|
-
const displayPath = _sp && _sp !== "." ? `"${_isDir ? `${_sp}/*` : _sp}"` : "./";
|
|
17347
|
-
const postLabel = `${keyword ? "\u2714" : "\u2718"} Searched: "${keyword ? keyword : ""}" in ${displayPath} \u2192 ${matchCount} Match${matchCount === 1 ? "" : "es"}`;
|
|
17734
|
+
const displayPath = _sp && _sp !== "." ? `"${_isGlob ? path29 : _isDir ? `${_sp}/*` : _sp}"` : "./";
|
|
17735
|
+
const postLabel = `${keyword ? "\u2714" : "\u2718"} Searched: "${keyword ? keyword : ""}" in ${displayPath.replaceAll("\\", "/")} \u2192 ${matchCount} Match${matchCount === 1 ? "" : "es"}`;
|
|
17348
17736
|
let terminalWidth = 115;
|
|
17349
17737
|
if (process.stdout.isTTY) {
|
|
17350
17738
|
terminalWidth = process.stdout.columns - 5 || 120;
|
|
@@ -17800,18 +18188,76 @@ Error Log can be found in ${path27.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
17800
18188
|
runSubagent = async (task, settings, model = null, allowedTools = null, maxTurns = 50, logCallback = null) => {
|
|
17801
18189
|
const savedSettings = await loadSettings();
|
|
17802
18190
|
const mergedSettings = { ...savedSettings, ...settings };
|
|
17803
|
-
const
|
|
17804
|
-
const
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
18191
|
+
const envSubagentModel = process.env.SUBAGENT_MODEL ? process.env.SUBAGENT_MODEL.trim() : null;
|
|
18192
|
+
const envSubagentProviderRaw = process.env.SUBAGENT_PROVIDER ? process.env.SUBAGENT_PROVIDER.trim() : null;
|
|
18193
|
+
const subagentNow = /* @__PURE__ */ new Date();
|
|
18194
|
+
const time = `${subagentNow.getFullYear()}-${subagentNow.toLocaleString("en-US", { month: "short" }).toUpperCase()}-${String(subagentNow.getDate()).padStart(2, "0")}, ${subagentNow.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: true }).replace(":", "-")}`;
|
|
18195
|
+
const normalizeProvider = (pStr) => {
|
|
18196
|
+
if (!pStr) return null;
|
|
18197
|
+
const lower = pStr.toLowerCase();
|
|
18198
|
+
if (lower === "google") return "Google";
|
|
18199
|
+
if (lower === "deepseek") return "DeepSeek";
|
|
18200
|
+
if (lower === "openrouter") return "OpenRouter";
|
|
18201
|
+
if (lower === "nvidia") return "NVIDIA";
|
|
18202
|
+
if (lower === "mistral") return "Mistral";
|
|
18203
|
+
return null;
|
|
18204
|
+
};
|
|
18205
|
+
const envSubagentProvider = normalizeProvider(envSubagentProviderRaw);
|
|
18206
|
+
const configuredSubAgentModel = mergedSettings?.systemSettings?.CustomSubAgent ? mergedSettings?.systemSettings?.SubAgentModel : null;
|
|
18207
|
+
const configuredSubAgentProvider = mergedSettings?.systemSettings?.CustomSubAgent ? mergedSettings?.systemSettings?.SubAgentProvider : null;
|
|
18208
|
+
let subAgentCustomModel = null;
|
|
18209
|
+
if (configuredSubAgentModel === "ENV") {
|
|
18210
|
+
subAgentCustomModel = envSubagentModel;
|
|
18211
|
+
if (envSubagentModel && envSubagentProvider) {
|
|
18212
|
+
mergedSettings.aiProvider = envSubagentProvider;
|
|
18213
|
+
}
|
|
18214
|
+
} else if (configuredSubAgentModel && configuredSubAgentModel !== "Default") {
|
|
18215
|
+
subAgentCustomModel = configuredSubAgentModel;
|
|
18216
|
+
if (configuredSubAgentProvider) {
|
|
18217
|
+
mergedSettings.aiProvider = configuredSubAgentProvider;
|
|
18218
|
+
}
|
|
18219
|
+
} else if (envSubagentModel) {
|
|
18220
|
+
if (envSubagentProvider) {
|
|
18221
|
+
mergedSettings.aiProvider = envSubagentProvider;
|
|
18222
|
+
}
|
|
18223
|
+
}
|
|
18224
|
+
if (mergedSettings.aiProvider) {
|
|
18225
|
+
const providerApiKey = await getProviderAPIKey(mergedSettings.aiProvider);
|
|
18226
|
+
if (providerApiKey) {
|
|
18227
|
+
mergedSettings.apiKey = providerApiKey;
|
|
18228
|
+
}
|
|
18229
|
+
}
|
|
18230
|
+
const isSubagentCommandAllowed = (cmdString) => {
|
|
18231
|
+
if (!cmdString || typeof cmdString !== "string") return { allowed: true };
|
|
18232
|
+
const DANGEROUS_PATTERNS = [
|
|
18233
|
+
// Destructive file deletion / formatting
|
|
18234
|
+
/rm\s+-[rf]{1,2}\s+[\/*.]/i,
|
|
18235
|
+
/rmdir\s+\/[sq]/i,
|
|
18236
|
+
/del\s+\/[fsq]/i,
|
|
18237
|
+
/\bformat\b\s+[a-z]:/i,
|
|
18238
|
+
/mkfs/i,
|
|
18239
|
+
/dd\s+if=/i,
|
|
18240
|
+
// System shutdown / reboot / killall
|
|
18241
|
+
/\b(shutdown|reboot|poweroff|init\s+0|init\s+6)\b/i,
|
|
18242
|
+
// Low level disk / raw write / partition / chmod dangerous
|
|
18243
|
+
/chmod\s+(-R\s+)?777\s+[\/*.]/i,
|
|
18244
|
+
/chown\s+(-R\s+)?root/i,
|
|
18245
|
+
// Dangerous git force / reset operations on remote / system
|
|
18246
|
+
/git\s+push\s+.*--force/i,
|
|
18247
|
+
/git\s+clean\s+-fdx/i,
|
|
18248
|
+
// System-level privilege escalation
|
|
18249
|
+
/\bsudo\s+su\b/i,
|
|
18250
|
+
/\bsu\s+-\b/i
|
|
18251
|
+
];
|
|
18252
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
18253
|
+
if (pattern.test(cmdString)) {
|
|
18254
|
+
return { allowed: false, reason: `Blocked potentially destructive or unsafe command pattern: "${pattern.source}"` };
|
|
18255
|
+
}
|
|
18256
|
+
}
|
|
18257
|
+
return { allowed: true };
|
|
17814
18258
|
};
|
|
18259
|
+
const targetModel = model || subAgentCustomModel || settings?.modelName || settings?.activeModel || savedSettings.activeModel;
|
|
18260
|
+
const osDetected = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
|
|
17815
18261
|
const providedToolsSection = `-- TOOL DEFINITIONS (path = relative to CWD, path separator: '/') --
|
|
17816
18262
|
TO ACCESS TOOLS **STRICTLY USE THE EXACT FORMAT IN CHAT OUTPUT:** [tool:functions.ToolName(args)]
|
|
17817
18263
|
**NO OTHER SYNTAX/MARKERS/BOUNDARY ALLOWED**
|
|
@@ -17819,15 +18265,26 @@ TO ACCESS TOOLS **STRICTLY USE THE EXACT FORMAT IN CHAT OUTPUT:** [tool:function
|
|
|
17819
18265
|
TOOL POLICY:
|
|
17820
18266
|
- MAX 3 TOOL CALLS PER TURN
|
|
17821
18267
|
- Same file, many edits? Prefer multi search-replace in Patch \u2190 **HIGHLY RECOMMENDED**
|
|
17822
|
-
-
|
|
17823
|
-
-
|
|
17824
|
-
-
|
|
17825
|
-
- NO Shell Access
|
|
18268
|
+
- Need specific text OR huge file ? SearchKeyword > ReadFile
|
|
18269
|
+
- Tool denied? Use \`Ask\` immediately for user guidance \u2190 **MANDATORY**
|
|
18270
|
+
- Restricted Shell Access, NO DELETION
|
|
17826
18271
|
|
|
17827
|
-
|
|
17828
|
-
|
|
18272
|
+
**PROVIDED TOOLS**
|
|
18273
|
+
-- Communication with USER --
|
|
18274
|
+
- [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity: MUST for path divergence, security risk. Ask, don't finish/guess. Suggest best options; no preferences. Keep options short
|
|
18275
|
+
|
|
18276
|
+
-- Web Tools --
|
|
18277
|
+
- [tool:functions.WebSearch(query="...", aiMode="bool optional, default: false", limit="integer 3-10, aiMode: exclude")]. Usage: unknown info/docs. aiMode: LLM search
|
|
18278
|
+
- [tool:functions.WebScrape(url="...")]. Proactive use for specific webpage/docs/api
|
|
18279
|
+
|
|
18280
|
+
-- Workspace Tools --
|
|
18281
|
+
- [tool:functions.SearchKeyword(keyword="...", path="optional, dir/file/glob/regex", fuzzy="bool optional, default: false", regex="bool optional, default: auto")]. path limits search scope. Find definitions/logic without full reads. Locate relevant code
|
|
18282
|
+
- [tool:functions.ReadFolder(path="...", recurse="integer 1-3 optional, default: 1")]. DIR Contents + File Size. Minimize recursion
|
|
18283
|
+
- [tool:functions.ReadFile(path="...", startLine="integer", endLine="integer")]. View files
|
|
18284
|
+
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", replaceContent1="...", newContent1="...", ...MAX 15)]. Surgical patchs, TARGET SMALLEST LINES. allowMultiple: Replace all matches ONLY WHERE SURE. Use replaceContent2/newContent2... for multi blocks. Verify DIFFs
|
|
18285
|
+
- [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. VERIFY IMPORTS
|
|
18286
|
+
- [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL` : `WINDOWS CMD` : `BASH`} command. Destructive/Irreversible ops \u2192 Ask user
|
|
17829
18287
|
|
|
17830
|
-
- VERIFY TOOL RESULT CONTENTS. Fix errors. No hallucinations
|
|
17831
18288
|
- **Escape quotes: \\" for code strings**
|
|
17832
18289
|
- **Literal escapes: Double-escape sequences (e.g., \\\\n)**
|
|
17833
18290
|
- **File structure: Real newlines for code formatting**`.trim();
|
|
@@ -17838,12 +18295,12 @@ Your task is: "${task}"
|
|
|
17838
18295
|
${providedToolsSection.trimEnd()}
|
|
17839
18296
|
|
|
17840
18297
|
-- THINKING GUIDANCE --
|
|
17841
|
-
NO EXPLICIT THINKING REQUIRED. FOCUS ON
|
|
17842
|
-
|
|
18298
|
+
NO EXPLICIT THINKING REQUIRED. FOCUS ON TASK COMPLETION
|
|
17843
18299
|
Keep main focus on tools and task, not chatting
|
|
17844
|
-
|
|
18300
|
+
On task completion, provide a detailed structured summary preferebly in Tables/Bullet Points with file modified info, if any task failed report back in detail, no hallucination
|
|
17845
18301
|
|
|
17846
18302
|
CWD: ${process.cwd()}
|
|
18303
|
+
Current Time: ${time}
|
|
17847
18304
|
=== END SYSTEM PROMPT ===`;
|
|
17848
18305
|
const subagentHistory = [
|
|
17849
18306
|
{ role: "user", text: `Complete this task: ${task}` }
|
|
@@ -17909,36 +18366,54 @@ ${cleanResponse}
|
|
|
17909
18366
|
`;
|
|
17910
18367
|
continue;
|
|
17911
18368
|
}
|
|
18369
|
+
if (normalizedToolName === "exec_command" || normalizedToolName === "execcommand" || normalizedToolName === "run") {
|
|
18370
|
+
const cmdArg = parseArgs(toolCall.args).command || "";
|
|
18371
|
+
const cmdCheck = isSubagentCommandAllowed(cmdArg);
|
|
18372
|
+
if (!cmdCheck.allowed) {
|
|
18373
|
+
const blockMsg = `ERROR: [SECURITY RESTRICTION] Subagent execution blocked command: ${cmdCheck.reason}`;
|
|
18374
|
+
if (logCallback) logCallback(`[Blocked Command] ${cmdArg} - ${cmdCheck.reason}
|
|
18375
|
+
`);
|
|
18376
|
+
toolResultsStr += `${blockMsg}
|
|
18377
|
+
|
|
18378
|
+
`;
|
|
18379
|
+
continue;
|
|
18380
|
+
}
|
|
18381
|
+
}
|
|
17912
18382
|
let label = "";
|
|
17913
18383
|
if (normalizedToolName === "web_search" || normalizedToolName === "websearch") {
|
|
17914
|
-
|
|
18384
|
+
const query = parseArgs(toolCall.args).query || "";
|
|
18385
|
+
label = `\u2714 \x1B[95mSearched\x1B[0m: ${query}`;
|
|
17915
18386
|
} else if (normalizedToolName === "web_scrape" || normalizedToolName === "webscrape") {
|
|
17916
|
-
|
|
18387
|
+
const url = parseArgs(toolCall.args).url || "";
|
|
18388
|
+
label = `\u2714 \x1B[95mScraped\x1B[0m: ${url}`;
|
|
17917
18389
|
} else if (normalizedToolName === "search_keyword" || normalizedToolName === "searchkeyword") {
|
|
17918
18390
|
const pArgs = parseArgs(toolCall.args);
|
|
17919
18391
|
const keyword = pArgs.keyword || "";
|
|
17920
18392
|
const keywordPath = pArgs.path || "";
|
|
17921
|
-
label = `${keyword ? "\u2714" : "\u2718"} \x1B[95mSearched\x1B[0m: ${keyword || "No Query"}${keywordPath ? ` \u2192 ${keywordPath}` : ""}`;
|
|
18393
|
+
label = `${keyword ? "\u2714" : "\u2718"} \x1B[95mSearched\x1B[0m: ${keyword || "No Query"}${keywordPath ? ` \u2192 ${keywordPath.replaceAll("\\", "/")}` : ""}`;
|
|
17922
18394
|
} else if (normalizedToolName === "view_file" || normalizedToolName === "viewfile" || normalizedToolName === "readfile") {
|
|
17923
18395
|
const path29 = parseArgs(toolCall.args).path || "";
|
|
17924
|
-
label = `\u2714 \x1B[95mRead\x1B[0m: ${path29}`;
|
|
18396
|
+
label = `\u2714 \x1B[95mRead\x1B[0m: ${path29.replaceAll("\\", "/")}`;
|
|
17925
18397
|
} else if (normalizedToolName === "list_files" || normalizedToolName === "read_folder" || normalizedToolName === "readfolder") {
|
|
17926
18398
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
17927
18399
|
const recurse = parseArgs(toolCall.args).recurse || 0;
|
|
17928
|
-
label = `${path29 ? "\u2714" : "\u2718"}
|
|
18400
|
+
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mBrowsed\x1B[0m: ${path29 ? `${path29.replaceAll("\\", "/")}${recurse > 0 ? `${path29.endsWith("/") ? `*${recurse}` : `/*${recurse}`}` : `${path29.endsWith("/") ? "" : "/"}`}` : ""}`;
|
|
17929
18401
|
} else if (normalizedToolName === "write_file" || normalizedToolName === "writefile") {
|
|
17930
18402
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
17931
|
-
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mCreated\x1B[0m: ${path29 ? `${path29}` : "No File Changes"}`;
|
|
18403
|
+
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mCreated\x1B[0m: ${path29 ? `${path29.replaceAll("\\", "/")}` : "No File Changes"}`;
|
|
17932
18404
|
} else if (normalizedToolName === "update_file" || normalizedToolName === "updatefile" || normalizedToolName === "patchfile" || normalizedToolName === "patch_file" || normalizedToolName === "patchfile" || normalizedToolName === "updatefile") {
|
|
17933
18405
|
const path29 = parseArgs(toolCall.args).path || null;
|
|
17934
18406
|
const content = parseArgs(toolCall.args).content || null;
|
|
17935
|
-
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mEdited\x1B[0m: ${path29 ? `${path29}` : "No File Changes"}`;
|
|
18407
|
+
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mEdited\x1B[0m: ${path29 ? `${path29.replaceAll("\\", "/")}` : "No File Changes"}`;
|
|
18408
|
+
} else if (normalizedToolName === "exec_command" || normalizedToolName === "execcommand" || normalizedToolName === "run") {
|
|
18409
|
+
const command = parseArgs(toolCall.args).command || null;
|
|
18410
|
+
label = `${command ? "\u2714" : "\u2718"} \x1B[95mExecuted\x1B[0m: ${command ? command.slice(0, 100) + (command.length > 100 ? "..." : "") : "No Command"}`;
|
|
17936
18411
|
} else if (normalizedToolName === "file_map" || normalizedToolName === "filemap") {
|
|
17937
18412
|
const path29 = parseArgs(toolCall.args).path || "";
|
|
17938
|
-
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mIndexed\x1B[0m: ${path29 ? `${path29}` : "File Not Found"}`;
|
|
18413
|
+
label = `${path29 ? "\u2714" : "\u2718"} \x1B[95mIndexed\x1B[0m: ${path29 ? `${path29.replaceAll("\\", "/")}` : "File Not Found"}`;
|
|
17939
18414
|
} else if (normalizedToolName === "await") {
|
|
17940
|
-
const { time } = parseArgs(toolCall.args);
|
|
17941
|
-
let sec = parseFloat(
|
|
18415
|
+
const { time: time2 } = parseArgs(toolCall.args);
|
|
18416
|
+
let sec = parseFloat(time2) || 0;
|
|
17942
18417
|
if (sec < 10) sec = 10;
|
|
17943
18418
|
if (sec > 180) sec = 180;
|
|
17944
18419
|
const formatTime = (s) => {
|
|
@@ -19172,6 +19647,108 @@ function App({ args = [] }) {
|
|
|
19172
19647
|
clearInterval(memInterval);
|
|
19173
19648
|
};
|
|
19174
19649
|
}, []);
|
|
19650
|
+
useEffect12(() => {
|
|
19651
|
+
const checkSubAgentModelOnStartup = async () => {
|
|
19652
|
+
try {
|
|
19653
|
+
const settings = await loadSettings();
|
|
19654
|
+
const sysSettings = settings?.systemSettings || {};
|
|
19655
|
+
const customSubAgent = sysSettings.CustomSubAgent;
|
|
19656
|
+
const configuredModel = sysSettings.SubAgentModel;
|
|
19657
|
+
if (!customSubAgent || !configuredModel || configuredModel === "Default") {
|
|
19658
|
+
return;
|
|
19659
|
+
}
|
|
19660
|
+
const envModel = process.env.SUBAGENT_MODEL ? process.env.SUBAGENT_MODEL.trim() : null;
|
|
19661
|
+
const envProviderRaw = process.env.SUBAGENT_PROVIDER ? process.env.SUBAGENT_PROVIDER.trim() : null;
|
|
19662
|
+
const ALL_PROVIDERS = ["Google", "DeepSeek", "OpenRouter", "NVIDIA", "Mistral"];
|
|
19663
|
+
const normalizeProvider = (pStr) => {
|
|
19664
|
+
if (!pStr) return null;
|
|
19665
|
+
const lower = pStr.toLowerCase();
|
|
19666
|
+
if (lower === "google") return "Google";
|
|
19667
|
+
if (lower === "deepseek") return "DeepSeek";
|
|
19668
|
+
if (lower === "openrouter") return "OpenRouter";
|
|
19669
|
+
if (lower === "nvidia") return "NVIDIA";
|
|
19670
|
+
if (lower === "mistral") return "Mistral";
|
|
19671
|
+
return null;
|
|
19672
|
+
};
|
|
19673
|
+
const envProvider = normalizeProvider(envProviderRaw);
|
|
19674
|
+
if (envModel && !envProvider) {
|
|
19675
|
+
const currentActiveProv = settings.aiProvider || aiProvider || "Google";
|
|
19676
|
+
setMessages((prev) => {
|
|
19677
|
+
setCompletedIndex(prev.length + 1);
|
|
19678
|
+
return [...prev, {
|
|
19679
|
+
id: "subagent-env-noprov-" + Date.now(),
|
|
19680
|
+
role: "system",
|
|
19681
|
+
text: `[SUBAGENT CONFIG] SUBAGENT_MODEL found in ENV but SUBAGENT_PROVIDER is missing/invalid. Active provider (${currentActiveProv}) will be used.`,
|
|
19682
|
+
isMeta: true
|
|
19683
|
+
}];
|
|
19684
|
+
});
|
|
19685
|
+
}
|
|
19686
|
+
if (configuredModel === "ENV") {
|
|
19687
|
+
if (!envModel) {
|
|
19688
|
+
setMessages((prev) => {
|
|
19689
|
+
setCompletedIndex(prev.length + 1);
|
|
19690
|
+
return [...prev, {
|
|
19691
|
+
id: "subagent-model-noenv-" + Date.now(),
|
|
19692
|
+
role: "system",
|
|
19693
|
+
text: "No SubAgent model is found in ENV, Using Deafult until changed",
|
|
19694
|
+
isMeta: true
|
|
19695
|
+
}];
|
|
19696
|
+
});
|
|
19697
|
+
}
|
|
19698
|
+
return;
|
|
19699
|
+
}
|
|
19700
|
+
const currentProvider = settings.aiProvider || aiProvider || "Google";
|
|
19701
|
+
const currentTier = settings.apiTier || apiTier || "Free";
|
|
19702
|
+
const quotasObj = settings.quotas || quotas || {};
|
|
19703
|
+
const availableModelNamesSet = /* @__PURE__ */ new Set();
|
|
19704
|
+
const currentModelsRaw = getModels(currentProvider, currentTier) || [];
|
|
19705
|
+
currentModelsRaw.forEach((m) => {
|
|
19706
|
+
const name = typeof m === "string" ? m : m.cmd || m.name || m.id || String(m);
|
|
19707
|
+
if (name) availableModelNamesSet.add(name);
|
|
19708
|
+
});
|
|
19709
|
+
for (const p of ALL_PROVIDERS) {
|
|
19710
|
+
try {
|
|
19711
|
+
const key = await getProviderAPIKey(p);
|
|
19712
|
+
if (key) {
|
|
19713
|
+
const tier = quotasObj?.providerTiers?.[p] || "Free";
|
|
19714
|
+
const pModels = getModels(p, tier) || [];
|
|
19715
|
+
pModels.forEach((m) => {
|
|
19716
|
+
const name = typeof m === "string" ? m : m.cmd || m.name || m.id || String(m);
|
|
19717
|
+
if (name) availableModelNamesSet.add(name);
|
|
19718
|
+
});
|
|
19719
|
+
}
|
|
19720
|
+
} catch (e) {
|
|
19721
|
+
}
|
|
19722
|
+
}
|
|
19723
|
+
const isModelAvailable = availableModelNamesSet.has(configuredModel);
|
|
19724
|
+
if (envModel) {
|
|
19725
|
+
if (envModel !== configuredModel) {
|
|
19726
|
+
setMessages((prev) => {
|
|
19727
|
+
setCompletedIndex(prev.length + 1);
|
|
19728
|
+
return [...prev, {
|
|
19729
|
+
id: "subagent-model-env-" + Date.now(),
|
|
19730
|
+
role: "system",
|
|
19731
|
+
text: "Current Seleted Sub-Agent model is not available in this provider. Using model from ENV unless changed.",
|
|
19732
|
+
isMeta: true
|
|
19733
|
+
}];
|
|
19734
|
+
});
|
|
19735
|
+
}
|
|
19736
|
+
} else if (!isModelAvailable) {
|
|
19737
|
+
setMessages((prev) => {
|
|
19738
|
+
setCompletedIndex(prev.length + 1);
|
|
19739
|
+
return [...prev, {
|
|
19740
|
+
id: "subagent-model-err-" + Date.now(),
|
|
19741
|
+
role: "system",
|
|
19742
|
+
text: "Current Seleted Sub-Agent model is not available in this provider. Using Default until changed",
|
|
19743
|
+
isMeta: true
|
|
19744
|
+
}];
|
|
19745
|
+
});
|
|
19746
|
+
}
|
|
19747
|
+
} catch (err) {
|
|
19748
|
+
}
|
|
19749
|
+
};
|
|
19750
|
+
checkSubAgentModelOnStartup();
|
|
19751
|
+
}, []);
|
|
19175
19752
|
const parsedArgs = useMemo2(() => {
|
|
19176
19753
|
const parsed = {};
|
|
19177
19754
|
for (let i = 0; i < args.length; i++) {
|