@bike4mind/cli 0.2.8-fix-cli-type-error.17148 → 0.2.10-dowgrade-mcp-sdk.17228
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/dist/{artifactExtractor-DNE5C6DY.js → artifactExtractor-JAGU7QRL.js} +1 -1
- package/dist/{chunk-YXHQN7SK.js → chunk-AQBZVAYO.js} +2 -2
- package/dist/{chunk-H6SHASMZ.js → chunk-DJPXSSP4.js} +13 -1
- package/dist/{chunk-DNSBC3LO.js → chunk-GCVIRGIN.js} +1 -1
- package/dist/{chunk-3CCBDIFR.js → chunk-GO75FMLY.js} +2 -2
- package/dist/{chunk-LIRY24M5.js → chunk-VZU4Z7WI.js} +2 -2
- package/dist/{create-PNU64QSF.js → create-ZDOTF7XD.js} +3 -3
- package/dist/index.js +760 -88
- package/dist/{llmMarkdownGenerator-UQXKK2AS.js → llmMarkdownGenerator-LXUGJ7QH.js} +1 -1
- package/dist/{markdownGenerator-FLLZFXMT.js → markdownGenerator-IMDG6OX6.js} +1 -1
- package/dist/{mementoService-LVFQ5XAW.js → mementoService-TURUS3OH.js} +3 -3
- package/dist/{src-OH5AAQEW.js → src-6ZRXGE5J.js} +2 -2
- package/dist/{src-OYQXRLTM.js → src-YNY32ELR.js} +3 -1
- package/dist/{subtractCredits-75VT7HP2.js → subtractCredits-GOVKM3IR.js} +3 -3
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
getEffectiveApiKey,
|
|
5
5
|
getOpenWeatherKey,
|
|
6
6
|
getSerperKey
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-GO75FMLY.js";
|
|
8
|
+
import "./chunk-VZU4Z7WI.js";
|
|
9
|
+
import "./chunk-AQBZVAYO.js";
|
|
10
10
|
import {
|
|
11
11
|
BFLImageService,
|
|
12
12
|
BaseStorage,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
OpenAIBackend,
|
|
16
16
|
OpenAIImageService,
|
|
17
17
|
XAIImageService
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GCVIRGIN.js";
|
|
19
19
|
import {
|
|
20
20
|
Logger
|
|
21
21
|
} from "./chunk-AMDXHL6S.js";
|
|
@@ -73,19 +73,19 @@ import {
|
|
|
73
73
|
XAI_IMAGE_MODELS,
|
|
74
74
|
b4mLLMTools,
|
|
75
75
|
getMcpProviderMetadata
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-DJPXSSP4.js";
|
|
77
77
|
import {
|
|
78
78
|
__require
|
|
79
79
|
} from "./chunk-PDX44BCA.js";
|
|
80
80
|
|
|
81
81
|
// src/index.tsx
|
|
82
|
-
import
|
|
83
|
-
import { render, Box as
|
|
82
|
+
import React16, { useState as useState7, useEffect as useEffect3, useCallback, useRef } from "react";
|
|
83
|
+
import { render, Box as Box15, Text as Text15, useApp, useInput as useInput6 } from "ink";
|
|
84
84
|
import { v4 as uuidv49 } from "uuid";
|
|
85
85
|
|
|
86
86
|
// src/components/App.tsx
|
|
87
87
|
import React10 from "react";
|
|
88
|
-
import { Box as Box9, Text as Text9
|
|
88
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
89
89
|
|
|
90
90
|
// src/components/StatusBar.tsx
|
|
91
91
|
import React from "react";
|
|
@@ -742,6 +742,7 @@ function InputPrompt({
|
|
|
742
742
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
743
743
|
const [historyIndex, setHistoryIndex] = useState2(-1);
|
|
744
744
|
const [tempInput, setTempInput] = useState2("");
|
|
745
|
+
const [inputKey, setInputKey] = useState2(0);
|
|
745
746
|
useEffect(() => {
|
|
746
747
|
if (prefillInput) {
|
|
747
748
|
setValue(prefillInput);
|
|
@@ -889,10 +890,11 @@ function InputPrompt({
|
|
|
889
890
|
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(
|
|
890
891
|
CustomTextInput,
|
|
891
892
|
{
|
|
893
|
+
key: inputKey,
|
|
892
894
|
value,
|
|
893
895
|
onChange: handleChange,
|
|
894
896
|
onSubmit: handleSubmit,
|
|
895
|
-
placeholder: disabled ? "
|
|
897
|
+
placeholder: disabled ? "" : "Type your message, /help for commands, or @file to reference",
|
|
896
898
|
showCursor: !disabled
|
|
897
899
|
}
|
|
898
900
|
)), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
|
|
@@ -923,6 +925,7 @@ var useCliStore = create((set) => ({
|
|
|
923
925
|
addAgentStep: (step) => set((state) => ({
|
|
924
926
|
agentSteps: [...state.agentSteps, step]
|
|
925
927
|
})),
|
|
928
|
+
setAgentSteps: (steps) => set({ agentSteps: steps }),
|
|
926
929
|
clearAgentSteps: () => set({ agentSteps: [] }),
|
|
927
930
|
// Permission prompt
|
|
928
931
|
permissionPrompt: null,
|
|
@@ -942,7 +945,7 @@ var AgentThinking = React7.memo(function AgentThinking2() {
|
|
|
942
945
|
if (!isThinking) {
|
|
943
946
|
return null;
|
|
944
947
|
}
|
|
945
|
-
return /* @__PURE__ */ React7.createElement(Box6, {
|
|
948
|
+
return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
|
|
946
949
|
});
|
|
947
950
|
|
|
948
951
|
// src/components/PermissionPrompt.tsx
|
|
@@ -1397,7 +1400,7 @@ ${errorBlock}`;
|
|
|
1397
1400
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
1398
1401
|
onResponse: onPermissionResponse
|
|
1399
1402
|
}
|
|
1400
|
-
)) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
1403
|
+
)) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column" }, messages.map((message, index) => /* @__PURE__ */ React10.createElement(Box9, { key: `${message.timestamp}-${message.role}-${index}`, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(MessageItem, { message })))), /* @__PURE__ */ React10.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React10.createElement(Box9, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
|
|
1401
1404
|
InputPrompt,
|
|
1402
1405
|
{
|
|
1403
1406
|
onSubmit: handleSubmit,
|
|
@@ -1410,7 +1413,8 @@ ${errorBlock}`;
|
|
|
1410
1413
|
))));
|
|
1411
1414
|
}
|
|
1412
1415
|
function MessageItem({ message }) {
|
|
1413
|
-
|
|
1416
|
+
const isUser = message.role === "user";
|
|
1417
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: isUser ? "cyan" : "green" }, isUser ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), isUser && message.content && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { backgroundColor: "whiteBright", color: "black" }, " ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " ", "tools used, ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
1414
1418
|
if (step.type === "thought") {
|
|
1415
1419
|
return /* @__PURE__ */ React10.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${step.content.slice(0, 200)}${step.content.length > 200 ? "..." : ""}`));
|
|
1416
1420
|
}
|
|
@@ -1422,7 +1426,7 @@ function MessageItem({ message }) {
|
|
|
1422
1426
|
return /* @__PURE__ */ React10.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` Result: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result).slice(0, 200)}${(typeof result === "string" ? result.length : JSON.stringify(result).length) > 200 ? "..." : ""}`));
|
|
1423
1427
|
}
|
|
1424
1428
|
return null;
|
|
1425
|
-
}).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
|
|
1429
|
+
}).filter(Boolean)), !isUser && message.content !== "..." && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, marginTop: message.metadata?.steps?.length ? 1 : 0 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React10.createElement(Text9, null, message.content)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
|
|
1426
1430
|
}
|
|
1427
1431
|
|
|
1428
1432
|
// src/components/MessageList.tsx
|
|
@@ -1566,9 +1570,72 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
1566
1570
|
), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
|
|
1567
1571
|
}
|
|
1568
1572
|
|
|
1573
|
+
// src/components/SessionSelector.tsx
|
|
1574
|
+
import React14, { useState as useState5 } from "react";
|
|
1575
|
+
import { Box as Box13, Text as Text13, useInput as useInput5 } from "ink";
|
|
1576
|
+
import SelectInput4 from "ink-select-input";
|
|
1577
|
+
function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
|
|
1578
|
+
const [step, setStep] = useState5("selection");
|
|
1579
|
+
const [selectedSession, setSelectedSession] = useState5(null);
|
|
1580
|
+
useInput5((input, key) => {
|
|
1581
|
+
if (key.escape) {
|
|
1582
|
+
if (step === "confirmation") {
|
|
1583
|
+
setStep("selection");
|
|
1584
|
+
setSelectedSession(null);
|
|
1585
|
+
} else {
|
|
1586
|
+
onCancel();
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1590
|
+
const hasUnsavedWork = currentSession && currentSession.messages.length > 0;
|
|
1591
|
+
const items = sessions.map((session, index) => {
|
|
1592
|
+
const messageCount = session.messages.length;
|
|
1593
|
+
const lastUpdated = new Date(session.updatedAt).toLocaleString();
|
|
1594
|
+
return {
|
|
1595
|
+
label: `[${index + 1}] ${session.name} (${messageCount} msg, ${session.model})
|
|
1596
|
+
Last updated: ${lastUpdated}`,
|
|
1597
|
+
value: session
|
|
1598
|
+
};
|
|
1599
|
+
});
|
|
1600
|
+
const handleSelectionSelect = (item) => {
|
|
1601
|
+
setSelectedSession(item.value);
|
|
1602
|
+
setStep("confirmation");
|
|
1603
|
+
};
|
|
1604
|
+
const handleConfirmationSelect = (item) => {
|
|
1605
|
+
if (item.value === "confirm" && selectedSession) {
|
|
1606
|
+
onSelect(selectedSession);
|
|
1607
|
+
} else {
|
|
1608
|
+
setStep("selection");
|
|
1609
|
+
setSelectedSession(null);
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
if (step === "selection") {
|
|
1613
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { bold: true }, "Select a session to resume:")), /* @__PURE__ */ React14.createElement(
|
|
1614
|
+
SelectInput4,
|
|
1615
|
+
{
|
|
1616
|
+
items,
|
|
1617
|
+
onSelect: handleSelectionSelect,
|
|
1618
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1619
|
+
}
|
|
1620
|
+
), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
|
|
1621
|
+
}
|
|
1622
|
+
const confirmationItems = [
|
|
1623
|
+
{ label: "Yes, resume this session", value: "confirm" },
|
|
1624
|
+
{ label: "No, go back to selection", value: "cancel" }
|
|
1625
|
+
];
|
|
1626
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text13, { bold: true }, 'Resume session: "', selectedSession?.name, '"'), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, selectedSession?.messages.length, " messages | ", selectedSession?.model, " |", " ", selectedSession?.metadata?.totalTokens?.toLocaleString() ?? 0, " tokens"), hasUnsavedWork && /* @__PURE__ */ React14.createElement(Text13, { color: "yellow" }, "Warning: Your current session has unsaved messages. Use /save first if needed.")), /* @__PURE__ */ React14.createElement(
|
|
1627
|
+
SelectInput4,
|
|
1628
|
+
{
|
|
1629
|
+
items: confirmationItems,
|
|
1630
|
+
onSelect: handleConfirmationSelect,
|
|
1631
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1632
|
+
}
|
|
1633
|
+
), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1569
1636
|
// src/components/LoginFlow.tsx
|
|
1570
|
-
import
|
|
1571
|
-
import { Box as
|
|
1637
|
+
import React15, { useState as useState6, useEffect as useEffect2 } from "react";
|
|
1638
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1572
1639
|
import Spinner2 from "ink-spinner";
|
|
1573
1640
|
import jwt from "jsonwebtoken";
|
|
1574
1641
|
import open from "open";
|
|
@@ -1684,10 +1751,10 @@ var OAuthClient = class {
|
|
|
1684
1751
|
|
|
1685
1752
|
// src/components/LoginFlow.tsx
|
|
1686
1753
|
function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, onError }) {
|
|
1687
|
-
const [status, setStatus] =
|
|
1688
|
-
const [deviceFlow, setDeviceFlow] =
|
|
1689
|
-
const [statusMessage, setStatusMessage] =
|
|
1690
|
-
const [error, setError] =
|
|
1754
|
+
const [status, setStatus] = useState6("initiating");
|
|
1755
|
+
const [deviceFlow, setDeviceFlow] = useState6(null);
|
|
1756
|
+
const [statusMessage, setStatusMessage] = useState6("Initiating device authorization...");
|
|
1757
|
+
const [error, setError] = useState6(null);
|
|
1691
1758
|
useEffect2(() => {
|
|
1692
1759
|
const runLoginFlow = async () => {
|
|
1693
1760
|
const oauth = new OAuthClient(apiUrl);
|
|
@@ -1731,15 +1798,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
1731
1798
|
}
|
|
1732
1799
|
}, [deviceFlow, status]);
|
|
1733
1800
|
if (status === "initiating") {
|
|
1734
|
-
return /* @__PURE__ */
|
|
1801
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Text14, { color: "cyan" }, /* @__PURE__ */ React15.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
|
|
1735
1802
|
}
|
|
1736
1803
|
if (status === "error") {
|
|
1737
|
-
return /* @__PURE__ */
|
|
1804
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Text14, { color: "red" }, error)));
|
|
1738
1805
|
}
|
|
1739
1806
|
if (status === "success") {
|
|
1740
|
-
return /* @__PURE__ */
|
|
1807
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "You can now use B4M CLI with your account.")));
|
|
1741
1808
|
}
|
|
1742
|
-
return /* @__PURE__ */
|
|
1809
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React15.createElement(Text14, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "And enter this code when prompted:")), /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React15.createElement(Text14, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "cyan" }, /* @__PURE__ */ React15.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
|
|
1743
1810
|
}
|
|
1744
1811
|
|
|
1745
1812
|
// src/storage/SessionStore.ts
|
|
@@ -2625,10 +2692,9 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
2625
2692
|
content: query
|
|
2626
2693
|
}
|
|
2627
2694
|
];
|
|
2628
|
-
console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
|
|
2629
2695
|
messages.forEach((msg, i) => {
|
|
2630
2696
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
2631
|
-
|
|
2697
|
+
this.context.logger.debug(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
|
|
2632
2698
|
});
|
|
2633
2699
|
let finalAnswer = "";
|
|
2634
2700
|
let reachedMaxIterations = false;
|
|
@@ -5021,8 +5087,8 @@ async function processAndStoreImages(images, context) {
|
|
|
5021
5087
|
const buffer = await downloadImage(image);
|
|
5022
5088
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
5023
5089
|
const filename = `${uuidv45()}.${fileType?.ext}`;
|
|
5024
|
-
const
|
|
5025
|
-
return
|
|
5090
|
+
const path15 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
5091
|
+
return path15;
|
|
5026
5092
|
}));
|
|
5027
5093
|
}
|
|
5028
5094
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -6234,8 +6300,8 @@ async function processAndStoreImage(imageUrl, context) {
|
|
|
6234
6300
|
const buffer = await downloadImage2(imageUrl);
|
|
6235
6301
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
6236
6302
|
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
6237
|
-
const
|
|
6238
|
-
return
|
|
6303
|
+
const path15 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
6304
|
+
return path15;
|
|
6239
6305
|
}
|
|
6240
6306
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
6241
6307
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -8647,6 +8713,381 @@ var deleteFileTool = {
|
|
|
8647
8713
|
})
|
|
8648
8714
|
};
|
|
8649
8715
|
|
|
8716
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
8717
|
+
import { spawn } from "child_process";
|
|
8718
|
+
import path11 from "path";
|
|
8719
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
8720
|
+
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
8721
|
+
var DANGEROUS_PATTERNS = [
|
|
8722
|
+
// Destructive file operations
|
|
8723
|
+
{
|
|
8724
|
+
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
8725
|
+
reason: "Recursive delete with path",
|
|
8726
|
+
block: true
|
|
8727
|
+
},
|
|
8728
|
+
{
|
|
8729
|
+
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
8730
|
+
reason: "Force delete without preserve root",
|
|
8731
|
+
block: true
|
|
8732
|
+
},
|
|
8733
|
+
{
|
|
8734
|
+
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
8735
|
+
reason: "Recursive force delete on root paths",
|
|
8736
|
+
block: true
|
|
8737
|
+
},
|
|
8738
|
+
{
|
|
8739
|
+
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
8740
|
+
reason: "Force recursive delete on root paths",
|
|
8741
|
+
block: true
|
|
8742
|
+
},
|
|
8743
|
+
// System-level dangerous commands
|
|
8744
|
+
{ pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
|
|
8745
|
+
{ pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
|
|
8746
|
+
{ pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
|
|
8747
|
+
{ pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
|
|
8748
|
+
// Disk/partition operations
|
|
8749
|
+
{ pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
|
|
8750
|
+
{ pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
|
|
8751
|
+
{ pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
|
|
8752
|
+
// Network attacks
|
|
8753
|
+
{ pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
|
|
8754
|
+
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8755
|
+
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8756
|
+
// Fork bombs and resource exhaustion
|
|
8757
|
+
{ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
|
|
8758
|
+
{ pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
|
|
8759
|
+
// Credential/sensitive data access
|
|
8760
|
+
{ pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
|
|
8761
|
+
{ pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
|
|
8762
|
+
{ pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
|
|
8763
|
+
// History/log manipulation
|
|
8764
|
+
{ pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
|
|
8765
|
+
{ pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
|
|
8766
|
+
// Dangerous redirects
|
|
8767
|
+
{ pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
|
|
8768
|
+
{ pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
|
|
8769
|
+
// Environment manipulation
|
|
8770
|
+
{ pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
|
|
8771
|
+
{ pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
|
|
8772
|
+
// Process/system control
|
|
8773
|
+
{ pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
|
|
8774
|
+
{ pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
|
|
8775
|
+
{ pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
|
|
8776
|
+
{ pattern: /\breboot\b/i, reason: "System reboot", block: true },
|
|
8777
|
+
{ pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
|
|
8778
|
+
];
|
|
8779
|
+
var SAFE_COMMAND_PREFIXES = [
|
|
8780
|
+
"ls",
|
|
8781
|
+
"cat",
|
|
8782
|
+
"head",
|
|
8783
|
+
"tail",
|
|
8784
|
+
"grep",
|
|
8785
|
+
"find",
|
|
8786
|
+
"echo",
|
|
8787
|
+
"pwd",
|
|
8788
|
+
"whoami",
|
|
8789
|
+
"date",
|
|
8790
|
+
"cal",
|
|
8791
|
+
"wc",
|
|
8792
|
+
"sort",
|
|
8793
|
+
"uniq",
|
|
8794
|
+
"cut",
|
|
8795
|
+
"tr",
|
|
8796
|
+
"sed",
|
|
8797
|
+
"awk",
|
|
8798
|
+
"git",
|
|
8799
|
+
"npm",
|
|
8800
|
+
"pnpm",
|
|
8801
|
+
"yarn",
|
|
8802
|
+
"node",
|
|
8803
|
+
"npx",
|
|
8804
|
+
"tsx",
|
|
8805
|
+
"ts-node",
|
|
8806
|
+
"python",
|
|
8807
|
+
"python3",
|
|
8808
|
+
"pip",
|
|
8809
|
+
"pip3",
|
|
8810
|
+
"docker",
|
|
8811
|
+
"docker-compose",
|
|
8812
|
+
"curl",
|
|
8813
|
+
"wget",
|
|
8814
|
+
// These are safe for fetching, blocked when piped to shell
|
|
8815
|
+
"mkdir",
|
|
8816
|
+
"touch",
|
|
8817
|
+
"cp",
|
|
8818
|
+
"mv",
|
|
8819
|
+
// File operations (still require permission)
|
|
8820
|
+
"which",
|
|
8821
|
+
"whereis",
|
|
8822
|
+
"type",
|
|
8823
|
+
"file",
|
|
8824
|
+
"stat",
|
|
8825
|
+
"env",
|
|
8826
|
+
"printenv",
|
|
8827
|
+
"set",
|
|
8828
|
+
"man",
|
|
8829
|
+
"help",
|
|
8830
|
+
"info",
|
|
8831
|
+
"diff",
|
|
8832
|
+
"comm",
|
|
8833
|
+
"cmp",
|
|
8834
|
+
"tar",
|
|
8835
|
+
"zip",
|
|
8836
|
+
"unzip",
|
|
8837
|
+
"gzip",
|
|
8838
|
+
"gunzip",
|
|
8839
|
+
"ssh",
|
|
8840
|
+
"scp",
|
|
8841
|
+
"rsync",
|
|
8842
|
+
// Network tools
|
|
8843
|
+
"make",
|
|
8844
|
+
"cmake",
|
|
8845
|
+
"cargo",
|
|
8846
|
+
"go",
|
|
8847
|
+
"rustc",
|
|
8848
|
+
"gcc",
|
|
8849
|
+
"g++",
|
|
8850
|
+
// Build tools
|
|
8851
|
+
"jest",
|
|
8852
|
+
"vitest",
|
|
8853
|
+
"mocha",
|
|
8854
|
+
"pytest",
|
|
8855
|
+
// Test runners
|
|
8856
|
+
"eslint",
|
|
8857
|
+
"prettier",
|
|
8858
|
+
"tsc"
|
|
8859
|
+
// Linters/formatters
|
|
8860
|
+
];
|
|
8861
|
+
function checkDangerousPatterns(command) {
|
|
8862
|
+
for (const { pattern, reason, block } of DANGEROUS_PATTERNS) {
|
|
8863
|
+
if (pattern.test(command)) {
|
|
8864
|
+
return { blocked: block, reason };
|
|
8865
|
+
}
|
|
8866
|
+
}
|
|
8867
|
+
return { blocked: false };
|
|
8868
|
+
}
|
|
8869
|
+
function getBaseCommand(command) {
|
|
8870
|
+
const trimmed = command.trim();
|
|
8871
|
+
const match = trimmed.match(/^(\S+)/);
|
|
8872
|
+
return match ? match[1] : "";
|
|
8873
|
+
}
|
|
8874
|
+
function isSafeCommandPrefix(command) {
|
|
8875
|
+
const baseCommand = getBaseCommand(command);
|
|
8876
|
+
return SAFE_COMMAND_PREFIXES.some((safe) => baseCommand === safe || baseCommand.endsWith(`/${safe}`));
|
|
8877
|
+
}
|
|
8878
|
+
async function executeBashCommand(params) {
|
|
8879
|
+
const { command, cwd: relativeCwd, timeout = DEFAULT_TIMEOUT_MS } = params;
|
|
8880
|
+
if (!command || command.trim().length === 0) {
|
|
8881
|
+
return {
|
|
8882
|
+
stdout: "",
|
|
8883
|
+
stderr: "Error: Command cannot be empty",
|
|
8884
|
+
exitCode: 1,
|
|
8885
|
+
timedOut: false,
|
|
8886
|
+
blocked: true,
|
|
8887
|
+
blockedReason: "Empty command"
|
|
8888
|
+
};
|
|
8889
|
+
}
|
|
8890
|
+
const dangerCheck = checkDangerousPatterns(command);
|
|
8891
|
+
if (dangerCheck.blocked) {
|
|
8892
|
+
return {
|
|
8893
|
+
stdout: "",
|
|
8894
|
+
stderr: `Command blocked for safety: ${dangerCheck.reason}`,
|
|
8895
|
+
exitCode: 1,
|
|
8896
|
+
timedOut: false,
|
|
8897
|
+
blocked: true,
|
|
8898
|
+
blockedReason: dangerCheck.reason
|
|
8899
|
+
};
|
|
8900
|
+
}
|
|
8901
|
+
const baseCwd = process.cwd();
|
|
8902
|
+
const targetCwd = relativeCwd ? path11.resolve(baseCwd, relativeCwd) : baseCwd;
|
|
8903
|
+
const effectiveTimeout = Math.min(timeout, 5 * 60 * 1e3);
|
|
8904
|
+
return new Promise((resolve3) => {
|
|
8905
|
+
let stdout = "";
|
|
8906
|
+
let stderr = "";
|
|
8907
|
+
let timedOut = false;
|
|
8908
|
+
const proc = spawn("bash", ["-c", command], {
|
|
8909
|
+
cwd: targetCwd,
|
|
8910
|
+
env: {
|
|
8911
|
+
...process.env,
|
|
8912
|
+
// Prevent color codes that might be hard to read
|
|
8913
|
+
NO_COLOR: "1",
|
|
8914
|
+
FORCE_COLOR: "0"
|
|
8915
|
+
},
|
|
8916
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
8917
|
+
});
|
|
8918
|
+
const timeoutId = setTimeout(() => {
|
|
8919
|
+
timedOut = true;
|
|
8920
|
+
proc.kill("SIGTERM");
|
|
8921
|
+
setTimeout(() => {
|
|
8922
|
+
if (!proc.killed) {
|
|
8923
|
+
proc.kill("SIGKILL");
|
|
8924
|
+
}
|
|
8925
|
+
}, 5e3);
|
|
8926
|
+
}, effectiveTimeout);
|
|
8927
|
+
proc.stdout.on("data", (data) => {
|
|
8928
|
+
if (stdout.length < MAX_OUTPUT_SIZE) {
|
|
8929
|
+
stdout += data.toString();
|
|
8930
|
+
if (stdout.length > MAX_OUTPUT_SIZE) {
|
|
8931
|
+
stdout = stdout.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8932
|
+
}
|
|
8933
|
+
}
|
|
8934
|
+
});
|
|
8935
|
+
proc.stderr.on("data", (data) => {
|
|
8936
|
+
if (stderr.length < MAX_OUTPUT_SIZE) {
|
|
8937
|
+
stderr += data.toString();
|
|
8938
|
+
if (stderr.length > MAX_OUTPUT_SIZE) {
|
|
8939
|
+
stderr = stderr.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8940
|
+
}
|
|
8941
|
+
}
|
|
8942
|
+
});
|
|
8943
|
+
proc.on("close", (exitCode) => {
|
|
8944
|
+
clearTimeout(timeoutId);
|
|
8945
|
+
resolve3({
|
|
8946
|
+
stdout: stdout.trim(),
|
|
8947
|
+
stderr: stderr.trim(),
|
|
8948
|
+
exitCode,
|
|
8949
|
+
timedOut,
|
|
8950
|
+
blocked: false
|
|
8951
|
+
});
|
|
8952
|
+
});
|
|
8953
|
+
proc.on("error", (error) => {
|
|
8954
|
+
clearTimeout(timeoutId);
|
|
8955
|
+
resolve3({
|
|
8956
|
+
stdout: "",
|
|
8957
|
+
stderr: `Failed to execute command: ${error.message}`,
|
|
8958
|
+
exitCode: 1,
|
|
8959
|
+
timedOut: false,
|
|
8960
|
+
blocked: false
|
|
8961
|
+
});
|
|
8962
|
+
});
|
|
8963
|
+
});
|
|
8964
|
+
}
|
|
8965
|
+
function formatResult(result, command) {
|
|
8966
|
+
const parts = [];
|
|
8967
|
+
parts.push(`$ ${command}`);
|
|
8968
|
+
parts.push("");
|
|
8969
|
+
if (result.blocked) {
|
|
8970
|
+
parts.push(`BLOCKED: ${result.blockedReason}`);
|
|
8971
|
+
parts.push("");
|
|
8972
|
+
parts.push("This command was blocked for safety reasons.");
|
|
8973
|
+
parts.push("If you believe this is a false positive, please run the command manually.");
|
|
8974
|
+
return parts.join("\n");
|
|
8975
|
+
}
|
|
8976
|
+
if (result.timedOut) {
|
|
8977
|
+
parts.push("WARNING: Command timed out and was terminated.");
|
|
8978
|
+
parts.push("");
|
|
8979
|
+
}
|
|
8980
|
+
if (result.stdout) {
|
|
8981
|
+
parts.push(result.stdout);
|
|
8982
|
+
}
|
|
8983
|
+
if (result.stderr) {
|
|
8984
|
+
if (result.stdout) {
|
|
8985
|
+
parts.push("");
|
|
8986
|
+
}
|
|
8987
|
+
parts.push("STDERR:");
|
|
8988
|
+
parts.push(result.stderr);
|
|
8989
|
+
}
|
|
8990
|
+
if (result.exitCode !== 0 && result.exitCode !== null) {
|
|
8991
|
+
parts.push("");
|
|
8992
|
+
parts.push(`Exit code: ${result.exitCode}`);
|
|
8993
|
+
}
|
|
8994
|
+
if (!result.stdout && !result.stderr && !result.timedOut) {
|
|
8995
|
+
parts.push("(command completed with no output)");
|
|
8996
|
+
}
|
|
8997
|
+
return parts.join("\n");
|
|
8998
|
+
}
|
|
8999
|
+
var bashExecuteTool = {
|
|
9000
|
+
name: "bash_execute",
|
|
9001
|
+
implementation: (context) => ({
|
|
9002
|
+
toolFn: async (value) => {
|
|
9003
|
+
const params = value;
|
|
9004
|
+
const isSafe = isSafeCommandPrefix(params.command);
|
|
9005
|
+
context.logger.info("Bash: Executing command", {
|
|
9006
|
+
command: params.command,
|
|
9007
|
+
cwd: params.cwd || ".",
|
|
9008
|
+
timeout: params.timeout || DEFAULT_TIMEOUT_MS,
|
|
9009
|
+
isSafeCommand: isSafe
|
|
9010
|
+
});
|
|
9011
|
+
if (context.onStart) {
|
|
9012
|
+
await context.onStart("bash_execute", {
|
|
9013
|
+
command: params.command,
|
|
9014
|
+
cwd: params.cwd
|
|
9015
|
+
});
|
|
9016
|
+
}
|
|
9017
|
+
try {
|
|
9018
|
+
const result = await executeBashCommand(params);
|
|
9019
|
+
const formattedResult = formatResult(result, params.command);
|
|
9020
|
+
context.logger.info("Bash: Command completed", {
|
|
9021
|
+
exitCode: result.exitCode,
|
|
9022
|
+
timedOut: result.timedOut,
|
|
9023
|
+
blocked: result.blocked
|
|
9024
|
+
});
|
|
9025
|
+
if (context.onFinish) {
|
|
9026
|
+
await context.onFinish("bash_execute", {
|
|
9027
|
+
command: params.command,
|
|
9028
|
+
exitCode: result.exitCode,
|
|
9029
|
+
blocked: result.blocked
|
|
9030
|
+
});
|
|
9031
|
+
}
|
|
9032
|
+
return formattedResult;
|
|
9033
|
+
} catch (error) {
|
|
9034
|
+
context.logger.error("Bash: Command failed", error);
|
|
9035
|
+
if (context.onFinish) {
|
|
9036
|
+
await context.onFinish("bash_execute", {
|
|
9037
|
+
command: params.command,
|
|
9038
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
9039
|
+
});
|
|
9040
|
+
}
|
|
9041
|
+
throw error;
|
|
9042
|
+
}
|
|
9043
|
+
},
|
|
9044
|
+
toolSchema: {
|
|
9045
|
+
name: "bash_execute",
|
|
9046
|
+
description: `Execute a bash command in the terminal. Use this for running shell commands, scripts, build tools, git operations, and other CLI tasks.
|
|
9047
|
+
|
|
9048
|
+
SAFETY NOTES:
|
|
9049
|
+
- Commands are executed in the current working directory (or specified cwd)
|
|
9050
|
+
- Dangerous commands (sudo, rm -rf /, etc.) are automatically blocked
|
|
9051
|
+
- Commands have a default timeout of 60 seconds (max 5 minutes)
|
|
9052
|
+
- Output is limited to prevent overwhelming responses
|
|
9053
|
+
- This tool ALWAYS requires user permission before execution
|
|
9054
|
+
|
|
9055
|
+
COMMON USE CASES:
|
|
9056
|
+
- Running build commands: npm run build, make, cargo build
|
|
9057
|
+
- Git operations: git status, git log, git diff
|
|
9058
|
+
- Viewing system info: ls, pwd, cat, head, tail
|
|
9059
|
+
- Running tests: npm test, pytest, cargo test
|
|
9060
|
+
- Package management: npm install, pip install
|
|
9061
|
+
- File operations: mkdir, cp, mv (with permission)
|
|
9062
|
+
|
|
9063
|
+
BLOCKED OPERATIONS:
|
|
9064
|
+
- sudo and privilege escalation
|
|
9065
|
+
- Recursive deletes on system paths
|
|
9066
|
+
- Direct disk operations
|
|
9067
|
+
- Fork bombs and resource exhaustion
|
|
9068
|
+
- Piping remote scripts to shell`,
|
|
9069
|
+
parameters: {
|
|
9070
|
+
type: "object",
|
|
9071
|
+
properties: {
|
|
9072
|
+
command: {
|
|
9073
|
+
type: "string",
|
|
9074
|
+
description: "The bash command to execute. Can include pipes, redirects, and chained commands."
|
|
9075
|
+
},
|
|
9076
|
+
cwd: {
|
|
9077
|
+
type: "string",
|
|
9078
|
+
description: "Working directory for the command (optional). Can be relative or absolute path. Defaults to current directory."
|
|
9079
|
+
},
|
|
9080
|
+
timeout: {
|
|
9081
|
+
type: "number",
|
|
9082
|
+
description: "Timeout in milliseconds (optional, default: 60000, max: 300000). Command will be terminated if it exceeds this time."
|
|
9083
|
+
}
|
|
9084
|
+
},
|
|
9085
|
+
required: ["command"]
|
|
9086
|
+
}
|
|
9087
|
+
}
|
|
9088
|
+
})
|
|
9089
|
+
};
|
|
9090
|
+
|
|
8650
9091
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
8651
9092
|
var tools = {
|
|
8652
9093
|
dice_roll: diceRollTool,
|
|
@@ -8674,7 +9115,9 @@ var tools = {
|
|
|
8674
9115
|
create_file: createFileTool,
|
|
8675
9116
|
glob_files: globFilesTool,
|
|
8676
9117
|
grep_search: grepSearchTool,
|
|
8677
|
-
delete_file: deleteFileTool
|
|
9118
|
+
delete_file: deleteFileTool,
|
|
9119
|
+
// Shell execution
|
|
9120
|
+
bash_execute: bashExecuteTool
|
|
8678
9121
|
};
|
|
8679
9122
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
8680
9123
|
const context = {
|
|
@@ -8949,7 +9392,7 @@ async function generateFileDeletePreview(args) {
|
|
|
8949
9392
|
if (!existsSync7(args.path)) {
|
|
8950
9393
|
return `[File does not exist: ${args.path}]`;
|
|
8951
9394
|
}
|
|
8952
|
-
const stats = await import("fs/promises").then((
|
|
9395
|
+
const stats = await import("fs/promises").then((fs12) => fs12.stat(args.path));
|
|
8953
9396
|
return `[File will be deleted]
|
|
8954
9397
|
|
|
8955
9398
|
Path: ${args.path}
|
|
@@ -8962,7 +9405,7 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
8962
9405
|
|
|
8963
9406
|
// src/utils/Logger.ts
|
|
8964
9407
|
import fs10 from "fs/promises";
|
|
8965
|
-
import
|
|
9408
|
+
import path12 from "path";
|
|
8966
9409
|
import os from "os";
|
|
8967
9410
|
var Logger2 = class _Logger {
|
|
8968
9411
|
constructor() {
|
|
@@ -8985,9 +9428,9 @@ var Logger2 = class _Logger {
|
|
|
8985
9428
|
*/
|
|
8986
9429
|
async initialize(sessionId) {
|
|
8987
9430
|
this.sessionId = sessionId;
|
|
8988
|
-
const debugDir =
|
|
9431
|
+
const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
|
|
8989
9432
|
await fs10.mkdir(debugDir, { recursive: true });
|
|
8990
|
-
this.logFilePath =
|
|
9433
|
+
this.logFilePath = path12.join(debugDir, `${sessionId}.txt`);
|
|
8991
9434
|
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
8992
9435
|
}
|
|
8993
9436
|
/**
|
|
@@ -9197,12 +9640,12 @@ var Logger2 = class _Logger {
|
|
|
9197
9640
|
async cleanupOldLogs() {
|
|
9198
9641
|
if (!this.fileLoggingEnabled) return;
|
|
9199
9642
|
try {
|
|
9200
|
-
const debugDir =
|
|
9643
|
+
const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
|
|
9201
9644
|
const files = await fs10.readdir(debugDir);
|
|
9202
9645
|
const now = Date.now();
|
|
9203
9646
|
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9204
9647
|
for (const file of files) {
|
|
9205
|
-
const filePath =
|
|
9648
|
+
const filePath = path12.join(debugDir, file);
|
|
9206
9649
|
const stats = await fs10.stat(filePath);
|
|
9207
9650
|
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9208
9651
|
await fs10.unlink(filePath);
|
|
@@ -9267,7 +9710,8 @@ var LOCAL_TOOLS = [
|
|
|
9267
9710
|
"edit_file",
|
|
9268
9711
|
"dice_roll",
|
|
9269
9712
|
"math_evaluate",
|
|
9270
|
-
"current_datetime"
|
|
9713
|
+
"current_datetime",
|
|
9714
|
+
"bash_execute"
|
|
9271
9715
|
];
|
|
9272
9716
|
function isServerTool(toolName) {
|
|
9273
9717
|
return SERVER_TOOLS.includes(toolName);
|
|
@@ -9297,21 +9741,21 @@ var NoOpStorage = class extends BaseStorage {
|
|
|
9297
9741
|
async upload(input, destination, options) {
|
|
9298
9742
|
return `/tmp/${destination}`;
|
|
9299
9743
|
}
|
|
9300
|
-
async download(
|
|
9744
|
+
async download(path15) {
|
|
9301
9745
|
throw new Error("Download not supported in CLI");
|
|
9302
9746
|
}
|
|
9303
|
-
async delete(
|
|
9747
|
+
async delete(path15) {
|
|
9304
9748
|
}
|
|
9305
|
-
async getSignedUrl(
|
|
9306
|
-
return `/tmp/${
|
|
9749
|
+
async getSignedUrl(path15) {
|
|
9750
|
+
return `/tmp/${path15}`;
|
|
9307
9751
|
}
|
|
9308
|
-
getPublicUrl(
|
|
9309
|
-
return `/tmp/${
|
|
9752
|
+
getPublicUrl(path15) {
|
|
9753
|
+
return `/tmp/${path15}`;
|
|
9310
9754
|
}
|
|
9311
|
-
async getPreview(
|
|
9312
|
-
return `/tmp/${
|
|
9755
|
+
async getPreview(path15) {
|
|
9756
|
+
return `/tmp/${path15}`;
|
|
9313
9757
|
}
|
|
9314
|
-
async getMetadata(
|
|
9758
|
+
async getMetadata(path15) {
|
|
9315
9759
|
return { size: 0, contentType: "application/octet-stream" };
|
|
9316
9760
|
}
|
|
9317
9761
|
};
|
|
@@ -9369,6 +9813,10 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9369
9813
|
} catch (error) {
|
|
9370
9814
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9371
9815
|
}
|
|
9816
|
+
} else if (toolName === "bash_execute" && args?.command) {
|
|
9817
|
+
const cwd = args.cwd ? ` (in ${args.cwd})` : "";
|
|
9818
|
+
const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
|
|
9819
|
+
preview = `$ ${args.command}${cwd}${timeout}`;
|
|
9372
9820
|
}
|
|
9373
9821
|
const response = await showPermissionPrompt(toolName, args, preview);
|
|
9374
9822
|
if (response.action === "deny") {
|
|
@@ -9439,6 +9887,8 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9439
9887
|
glob_files: {},
|
|
9440
9888
|
grep_search: {},
|
|
9441
9889
|
delete_file: {},
|
|
9890
|
+
// Shell execution (always requires permission)
|
|
9891
|
+
bash_execute: {},
|
|
9442
9892
|
// Server-side tools (executed via /api/ai/v1/tools Lambda)
|
|
9443
9893
|
// Routed by ToolRouter to use B4M company API keys
|
|
9444
9894
|
weather_info: {},
|
|
@@ -9504,6 +9954,7 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
9504
9954
|
create_file: "prompt_always",
|
|
9505
9955
|
delete_file: "prompt_always",
|
|
9506
9956
|
shell_execute: "prompt_always",
|
|
9957
|
+
bash_execute: "prompt_always",
|
|
9507
9958
|
git_commit: "prompt_always",
|
|
9508
9959
|
git_push: "prompt_always",
|
|
9509
9960
|
// ===== PROMPT DEFAULT (Repository read tools) =====
|
|
@@ -9665,10 +10116,122 @@ function getEnvironmentName(configApiConfig) {
|
|
|
9665
10116
|
return "Bike4Mind";
|
|
9666
10117
|
}
|
|
9667
10118
|
|
|
10119
|
+
// src/utils/contextLoader.ts
|
|
10120
|
+
import * as fs11 from "fs";
|
|
10121
|
+
import * as path13 from "path";
|
|
10122
|
+
import { homedir as homedir4 } from "os";
|
|
10123
|
+
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
10124
|
+
var PROJECT_CONTEXT_FILES = [
|
|
10125
|
+
"CLAUDE.local.md",
|
|
10126
|
+
// gitignored, highest priority
|
|
10127
|
+
"CLAUDE.md",
|
|
10128
|
+
"AGENTS.md",
|
|
10129
|
+
// cross-tool standard
|
|
10130
|
+
"AI.local.md",
|
|
10131
|
+
// gitignored
|
|
10132
|
+
"AI.md",
|
|
10133
|
+
"INSTRUCTIONS.md"
|
|
10134
|
+
];
|
|
10135
|
+
var GLOBAL_CONTEXT_FILES = ["AI.local.md", "AI.md"];
|
|
10136
|
+
function formatFileSize2(bytes) {
|
|
10137
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
10138
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
10139
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
10140
|
+
}
|
|
10141
|
+
function tryReadContextFile(dir, filename, source) {
|
|
10142
|
+
const filePath = path13.join(dir, filename);
|
|
10143
|
+
try {
|
|
10144
|
+
const stats = fs11.lstatSync(filePath);
|
|
10145
|
+
if (stats.isDirectory()) {
|
|
10146
|
+
return null;
|
|
10147
|
+
}
|
|
10148
|
+
if (stats.isSymbolicLink()) {
|
|
10149
|
+
return {
|
|
10150
|
+
error: `${source === "global" ? "Global" : "Project"} ${filename} is a symlink (not allowed for security)`
|
|
10151
|
+
};
|
|
10152
|
+
}
|
|
10153
|
+
if (stats.size > CONTEXT_FILE_SIZE_LIMIT) {
|
|
10154
|
+
return {
|
|
10155
|
+
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
10156
|
+
};
|
|
10157
|
+
}
|
|
10158
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
10159
|
+
return {
|
|
10160
|
+
filename,
|
|
10161
|
+
content,
|
|
10162
|
+
source,
|
|
10163
|
+
path: filePath
|
|
10164
|
+
};
|
|
10165
|
+
} catch (err) {
|
|
10166
|
+
if (err.code === "ENOENT") {
|
|
10167
|
+
return null;
|
|
10168
|
+
}
|
|
10169
|
+
if (err.code === "EACCES") {
|
|
10170
|
+
return {
|
|
10171
|
+
error: `Cannot read ${source} ${filename}: permission denied`
|
|
10172
|
+
};
|
|
10173
|
+
}
|
|
10174
|
+
return {
|
|
10175
|
+
error: `Cannot read ${source} ${filename}: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
10176
|
+
};
|
|
10177
|
+
}
|
|
10178
|
+
}
|
|
10179
|
+
function findContextFile(dir, candidates, source) {
|
|
10180
|
+
for (const filename of candidates) {
|
|
10181
|
+
const result = tryReadContextFile(dir, filename, source);
|
|
10182
|
+
if (result === null) {
|
|
10183
|
+
continue;
|
|
10184
|
+
}
|
|
10185
|
+
if ("error" in result) {
|
|
10186
|
+
return { result: null, error: result.error };
|
|
10187
|
+
}
|
|
10188
|
+
return { result, error: null };
|
|
10189
|
+
}
|
|
10190
|
+
return { result: null, error: null };
|
|
10191
|
+
}
|
|
10192
|
+
function mergeContextContent(global, project) {
|
|
10193
|
+
if (global && project) {
|
|
10194
|
+
return `${global.content}
|
|
10195
|
+
|
|
10196
|
+
---
|
|
10197
|
+
|
|
10198
|
+
${project.content}`;
|
|
10199
|
+
}
|
|
10200
|
+
if (global) {
|
|
10201
|
+
return global.content;
|
|
10202
|
+
}
|
|
10203
|
+
if (project) {
|
|
10204
|
+
return project.content;
|
|
10205
|
+
}
|
|
10206
|
+
return "";
|
|
10207
|
+
}
|
|
10208
|
+
async function loadContextFiles(projectDir) {
|
|
10209
|
+
const errors = [];
|
|
10210
|
+
const globalDir = path13.join(homedir4(), ".bike4mind");
|
|
10211
|
+
const projectDirectory = projectDir || process.cwd();
|
|
10212
|
+
const [globalResult, projectResult] = await Promise.all([
|
|
10213
|
+
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
10214
|
+
Promise.resolve(findContextFile(projectDirectory, PROJECT_CONTEXT_FILES, "project"))
|
|
10215
|
+
]);
|
|
10216
|
+
if (globalResult.error) {
|
|
10217
|
+
errors.push(globalResult.error);
|
|
10218
|
+
}
|
|
10219
|
+
if (projectResult.error) {
|
|
10220
|
+
errors.push(projectResult.error);
|
|
10221
|
+
}
|
|
10222
|
+
const mergedContent = mergeContextContent(globalResult.result, projectResult.result);
|
|
10223
|
+
return {
|
|
10224
|
+
globalContext: globalResult.result,
|
|
10225
|
+
projectContext: projectResult.result,
|
|
10226
|
+
mergedContent,
|
|
10227
|
+
errors
|
|
10228
|
+
};
|
|
10229
|
+
}
|
|
10230
|
+
|
|
9668
10231
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
9669
10232
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
9670
10233
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9671
|
-
import
|
|
10234
|
+
import path14 from "path";
|
|
9672
10235
|
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
9673
10236
|
var MCPClient = class {
|
|
9674
10237
|
// Note: This class handles MCP server communication with repository filtering
|
|
@@ -9709,16 +10272,16 @@ var MCPClient = class {
|
|
|
9709
10272
|
const root = process.env.INIT_CWD || process.cwd();
|
|
9710
10273
|
const candidatePaths = [
|
|
9711
10274
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
9712
|
-
|
|
10275
|
+
path14.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
9713
10276
|
// When running from SST Lambda deployed environment (/var/task)
|
|
9714
|
-
|
|
10277
|
+
path14.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9715
10278
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
9716
|
-
|
|
10279
|
+
path14.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9717
10280
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
9718
|
-
|
|
10281
|
+
path14.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9719
10282
|
// Original paths (backward compatibility)
|
|
9720
|
-
|
|
9721
|
-
|
|
10283
|
+
path14.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10284
|
+
path14.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
9722
10285
|
];
|
|
9723
10286
|
const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
|
|
9724
10287
|
if (!serverScriptPath) {
|
|
@@ -10522,7 +11085,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
10522
11085
|
// package.json
|
|
10523
11086
|
var package_default = {
|
|
10524
11087
|
name: "@bike4mind/cli",
|
|
10525
|
-
version: "0.2.
|
|
11088
|
+
version: "0.2.10-dowgrade-mcp-sdk.17228+eeed70576",
|
|
10526
11089
|
type: "module",
|
|
10527
11090
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
10528
11091
|
license: "UNLICENSED",
|
|
@@ -10577,7 +11140,7 @@ var package_default = {
|
|
|
10577
11140
|
"@google/generative-ai": "^0.21.0",
|
|
10578
11141
|
"@joplin/turndown-plugin-gfm": "^1.0.62",
|
|
10579
11142
|
"@mendable/firecrawl-js": "^1.29.3",
|
|
10580
|
-
"@modelcontextprotocol/sdk": "
|
|
11143
|
+
"@modelcontextprotocol/sdk": "1.20.1",
|
|
10581
11144
|
"@octokit/rest": "^22.0.0",
|
|
10582
11145
|
"@opensearch-project/opensearch": "2.11.0",
|
|
10583
11146
|
"async-mutex": "^0.5.0",
|
|
@@ -10625,11 +11188,11 @@ var package_default = {
|
|
|
10625
11188
|
},
|
|
10626
11189
|
devDependencies: {
|
|
10627
11190
|
"@bike4mind/agents": "0.1.0",
|
|
10628
|
-
"@bike4mind/common": "2.
|
|
10629
|
-
"@bike4mind/mcp": "1.20.
|
|
10630
|
-
"@bike4mind/services": "2.
|
|
10631
|
-
"@bike4mind/utils": "2.1.
|
|
10632
|
-
"@types/better-sqlite3": "^7.6.
|
|
11191
|
+
"@bike4mind/common": "2.39.1-dowgrade-mcp-sdk.17228+eeed70576",
|
|
11192
|
+
"@bike4mind/mcp": "1.20.4-dowgrade-mcp-sdk.17228+eeed70576",
|
|
11193
|
+
"@bike4mind/services": "2.34.2-dowgrade-mcp-sdk.17228+eeed70576",
|
|
11194
|
+
"@bike4mind/utils": "2.1.4-dowgrade-mcp-sdk.17228+eeed70576",
|
|
11195
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
10633
11196
|
"@types/diff": "^5.0.9",
|
|
10634
11197
|
"@types/jsonwebtoken": "^9.0.4",
|
|
10635
11198
|
"@types/node": "^22.9.0",
|
|
@@ -10641,7 +11204,7 @@ var package_default = {
|
|
|
10641
11204
|
typescript: "^5.9.3",
|
|
10642
11205
|
vitest: "^3.2.4"
|
|
10643
11206
|
},
|
|
10644
|
-
gitHead: "
|
|
11207
|
+
gitHead: "eeed70576ada327d03166880bbd1d1d32f7d4e7c"
|
|
10645
11208
|
};
|
|
10646
11209
|
|
|
10647
11210
|
// src/config/constants.ts
|
|
@@ -10663,7 +11226,7 @@ var usageCache = null;
|
|
|
10663
11226
|
function CliApp() {
|
|
10664
11227
|
const { exit } = useApp();
|
|
10665
11228
|
const imageRenderer = new ImageRenderer();
|
|
10666
|
-
const [state, setState] =
|
|
11229
|
+
const [state, setState] = useState7({
|
|
10667
11230
|
session: null,
|
|
10668
11231
|
sessionStore: new SessionStore(),
|
|
10669
11232
|
configStore: new ConfigStore(),
|
|
@@ -10677,11 +11240,12 @@ function CliApp() {
|
|
|
10677
11240
|
permissionManager: null,
|
|
10678
11241
|
permissionPrompt: null,
|
|
10679
11242
|
trustLocationSelector: null,
|
|
10680
|
-
rewindSelector: null
|
|
11243
|
+
rewindSelector: null,
|
|
11244
|
+
sessionSelector: null
|
|
10681
11245
|
});
|
|
10682
|
-
const [isInitialized, setIsInitialized] =
|
|
10683
|
-
const [initError, setInitError] =
|
|
10684
|
-
const [commandHistory, setCommandHistory] =
|
|
11246
|
+
const [isInitialized, setIsInitialized] = useState7(false);
|
|
11247
|
+
const [initError, setInitError] = useState7(null);
|
|
11248
|
+
const [commandHistory, setCommandHistory] = useState7([]);
|
|
10685
11249
|
const imageStoreInitPromise = useRef(null);
|
|
10686
11250
|
const setStoreSession = useCliStore((state2) => state2.setSession);
|
|
10687
11251
|
const setPermissionPrompt = useCliStore((state2) => state2.setPermissionPrompt);
|
|
@@ -10722,7 +11286,7 @@ function CliApp() {
|
|
|
10722
11286
|
process.exit(0);
|
|
10723
11287
|
}, 100);
|
|
10724
11288
|
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
10725
|
-
|
|
11289
|
+
useInput6((input, key) => {
|
|
10726
11290
|
if (key.ctrl && input === "c") {
|
|
10727
11291
|
const now = Date.now();
|
|
10728
11292
|
if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
|
|
@@ -10892,6 +11456,24 @@ function CliApp() {
|
|
|
10892
11456
|
}
|
|
10893
11457
|
const allTools = [...b4mTools, ...mcpTools];
|
|
10894
11458
|
console.log(`\u2705 Total: ${allTools.length} tool(s) available`);
|
|
11459
|
+
const projectDir = state.configStore.getProjectConfigDir();
|
|
11460
|
+
const contextResult = await loadContextFiles(projectDir);
|
|
11461
|
+
if (contextResult.globalContext) {
|
|
11462
|
+
console.log(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
|
|
11463
|
+
}
|
|
11464
|
+
if (contextResult.projectContext) {
|
|
11465
|
+
console.log(`\u{1F4C4} Project context: ${contextResult.projectContext.filename}`);
|
|
11466
|
+
}
|
|
11467
|
+
for (const error of contextResult.errors) {
|
|
11468
|
+
console.log(`\u26A0\uFE0F Context file error: ${error}`);
|
|
11469
|
+
}
|
|
11470
|
+
const contextSection = contextResult.mergedContent ? `
|
|
11471
|
+
|
|
11472
|
+
## Project Context
|
|
11473
|
+
|
|
11474
|
+
Follow these project-specific instructions:
|
|
11475
|
+
|
|
11476
|
+
${contextResult.mergedContent}` : "";
|
|
10895
11477
|
const cliSystemPrompt = `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
10896
11478
|
|
|
10897
11479
|
CORE BEHAVIOR:
|
|
@@ -10921,7 +11503,7 @@ EXAMPLES:
|
|
|
10921
11503
|
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
10922
11504
|
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
10923
11505
|
|
|
10924
|
-
Remember: Use context from previous messages to understand follow-up questions
|
|
11506
|
+
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
10925
11507
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
10926
11508
|
const agent = new ReActAgent({
|
|
10927
11509
|
userId: config.userId,
|
|
@@ -10976,6 +11558,29 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
10976
11558
|
console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
|
|
10977
11559
|
return;
|
|
10978
11560
|
}
|
|
11561
|
+
const currentSteps = [];
|
|
11562
|
+
const stepHandler = (step) => {
|
|
11563
|
+
currentSteps.push(step);
|
|
11564
|
+
const currentSession = useCliStore.getState().session;
|
|
11565
|
+
if (currentSession) {
|
|
11566
|
+
const messages = [...currentSession.messages];
|
|
11567
|
+
const lastMessage = messages[messages.length - 1];
|
|
11568
|
+
if (lastMessage && lastMessage.role === "assistant") {
|
|
11569
|
+
messages[messages.length - 1] = {
|
|
11570
|
+
...lastMessage,
|
|
11571
|
+
metadata: {
|
|
11572
|
+
...lastMessage.metadata,
|
|
11573
|
+
steps: [...currentSteps]
|
|
11574
|
+
}
|
|
11575
|
+
};
|
|
11576
|
+
setStoreSession({
|
|
11577
|
+
...currentSession,
|
|
11578
|
+
messages
|
|
11579
|
+
});
|
|
11580
|
+
}
|
|
11581
|
+
}
|
|
11582
|
+
};
|
|
11583
|
+
state.agent.on("action", stepHandler);
|
|
10979
11584
|
try {
|
|
10980
11585
|
let messageContent = message;
|
|
10981
11586
|
let userMessageContent = message;
|
|
@@ -10989,6 +11594,21 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
10989
11594
|
content: userMessageContent,
|
|
10990
11595
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10991
11596
|
};
|
|
11597
|
+
const pendingAssistantMessage = {
|
|
11598
|
+
role: "assistant",
|
|
11599
|
+
content: "...",
|
|
11600
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11601
|
+
metadata: {
|
|
11602
|
+
steps: []
|
|
11603
|
+
}
|
|
11604
|
+
};
|
|
11605
|
+
const sessionWithMessages = {
|
|
11606
|
+
...state.session,
|
|
11607
|
+
messages: [...state.session.messages, userMessage, pendingAssistantMessage],
|
|
11608
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11609
|
+
};
|
|
11610
|
+
setState((prev) => ({ ...prev, session: sessionWithMessages }));
|
|
11611
|
+
setStoreSession(sessionWithMessages);
|
|
10992
11612
|
const recentMessages = state.session.messages.slice(-20);
|
|
10993
11613
|
const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
|
|
10994
11614
|
role: msg.role,
|
|
@@ -11002,26 +11622,28 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11002
11622
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
11003
11623
|
}
|
|
11004
11624
|
const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
|
|
11005
|
-
const
|
|
11625
|
+
const currentSession = useCliStore.getState().session;
|
|
11626
|
+
if (!currentSession) return;
|
|
11627
|
+
const finalMessages = [...currentSession.messages];
|
|
11628
|
+
const finalAssistantMessage = {
|
|
11006
11629
|
role: "assistant",
|
|
11007
11630
|
content: result.finalAnswer,
|
|
11008
|
-
timestamp:
|
|
11631
|
+
timestamp: pendingAssistantMessage.timestamp,
|
|
11009
11632
|
metadata: {
|
|
11010
11633
|
tokenUsage: {
|
|
11011
11634
|
prompt: 0,
|
|
11012
|
-
// TODO: Extract from result
|
|
11013
11635
|
completion: 0,
|
|
11014
11636
|
total: result.completionInfo.totalTokens
|
|
11015
11637
|
},
|
|
11016
11638
|
steps: result.steps,
|
|
11017
11639
|
// Complete history: thoughts, actions, observations
|
|
11018
11640
|
permissionDenied
|
|
11019
|
-
// Mark if this ended due to permission denial
|
|
11020
11641
|
}
|
|
11021
11642
|
};
|
|
11643
|
+
finalMessages[finalMessages.length - 1] = finalAssistantMessage;
|
|
11022
11644
|
const updatedSession = {
|
|
11023
|
-
...
|
|
11024
|
-
messages:
|
|
11645
|
+
...currentSession,
|
|
11646
|
+
messages: finalMessages,
|
|
11025
11647
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11026
11648
|
metadata: {
|
|
11027
11649
|
...state.session.metadata,
|
|
@@ -11041,6 +11663,8 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11041
11663
|
}
|
|
11042
11664
|
}
|
|
11043
11665
|
console.error("Error processing message:", error);
|
|
11666
|
+
} finally {
|
|
11667
|
+
state.agent.off("action", stepHandler);
|
|
11044
11668
|
}
|
|
11045
11669
|
};
|
|
11046
11670
|
const handleImageDetected = async (imageData) => {
|
|
@@ -11143,15 +11767,44 @@ Project Configuration:
|
|
|
11143
11767
|
await state.sessionStore.save(state.session);
|
|
11144
11768
|
console.log(`\u2705 Session saved as "${sessionName}"`);
|
|
11145
11769
|
break;
|
|
11146
|
-
case "sessions":
|
|
11770
|
+
case "sessions": {
|
|
11147
11771
|
const sessions = await state.sessionStore.list();
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
console.log(
|
|
11151
|
-
|
|
11152
|
-
}
|
|
11153
|
-
|
|
11772
|
+
if (sessions.length === 0) {
|
|
11773
|
+
console.log("\n\u{1F4DA} No saved sessions found.");
|
|
11774
|
+
console.log("\u{1F4A1} Use /save <name> to save your current session.\n");
|
|
11775
|
+
break;
|
|
11776
|
+
}
|
|
11777
|
+
const handleSessionSelect = async (selectedSession) => {
|
|
11778
|
+
setState((prev) => ({ ...prev, sessionSelector: null }));
|
|
11779
|
+
if (!selectedSession) {
|
|
11780
|
+
console.log("\u274C Session selection cancelled");
|
|
11781
|
+
return;
|
|
11782
|
+
}
|
|
11783
|
+
const loadedSession = await state.sessionStore.load(selectedSession.id);
|
|
11784
|
+
if (!loadedSession) {
|
|
11785
|
+
console.log(`\u274C Failed to load session: ${selectedSession.name}`);
|
|
11786
|
+
console.log(" The session file may be corrupted or deleted.");
|
|
11787
|
+
return;
|
|
11788
|
+
}
|
|
11789
|
+
await logger.initialize(loadedSession.id);
|
|
11790
|
+
logger.debug("=== Session Resumed ===");
|
|
11791
|
+
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
11792
|
+
setStoreSession(loadedSession);
|
|
11793
|
+
useCliStore.getState().clearAgentSteps();
|
|
11794
|
+
usageCache = null;
|
|
11795
|
+
console.log(`
|
|
11796
|
+
\u2705 Session resumed: "${loadedSession.name}"`);
|
|
11797
|
+
console.log(
|
|
11798
|
+
`\u{1F4DD} ${loadedSession.messages.length} messages | \u{1F916} ${loadedSession.model} | \u{1F4CA} ${loadedSession.metadata.totalTokens.toLocaleString()} tokens
|
|
11799
|
+
`
|
|
11800
|
+
);
|
|
11801
|
+
};
|
|
11802
|
+
setState((prev) => ({
|
|
11803
|
+
...prev,
|
|
11804
|
+
sessionSelector: { sessions, resolve: handleSessionSelect }
|
|
11805
|
+
}));
|
|
11154
11806
|
break;
|
|
11807
|
+
}
|
|
11155
11808
|
case "config": {
|
|
11156
11809
|
setShowConfigEditor(true);
|
|
11157
11810
|
break;
|
|
@@ -11592,12 +12245,12 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11592
12245
|
setState((prev) => ({ ...prev, config: updatedConfig }));
|
|
11593
12246
|
};
|
|
11594
12247
|
if (initError) {
|
|
11595
|
-
return /* @__PURE__ */
|
|
12248
|
+
return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React16.createElement(Text15, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React16.createElement(Text15, null, initError), /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
|
|
11596
12249
|
}
|
|
11597
12250
|
if (state.trustLocationSelector) {
|
|
11598
12251
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
11599
12252
|
const inProject = projectDir !== null;
|
|
11600
|
-
return /* @__PURE__ */
|
|
12253
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11601
12254
|
TrustLocationSelector,
|
|
11602
12255
|
{
|
|
11603
12256
|
inProject,
|
|
@@ -11615,7 +12268,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11615
12268
|
);
|
|
11616
12269
|
}
|
|
11617
12270
|
if (state.rewindSelector && state.session) {
|
|
11618
|
-
return /* @__PURE__ */
|
|
12271
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11619
12272
|
RewindSelector,
|
|
11620
12273
|
{
|
|
11621
12274
|
messages: state.session.messages,
|
|
@@ -11632,9 +12285,28 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11632
12285
|
}
|
|
11633
12286
|
);
|
|
11634
12287
|
}
|
|
12288
|
+
if (state.sessionSelector) {
|
|
12289
|
+
return /* @__PURE__ */ React16.createElement(
|
|
12290
|
+
SessionSelector,
|
|
12291
|
+
{
|
|
12292
|
+
sessions: state.sessionSelector.sessions,
|
|
12293
|
+
currentSession: state.session,
|
|
12294
|
+
onSelect: (session) => {
|
|
12295
|
+
if (state.sessionSelector) {
|
|
12296
|
+
state.sessionSelector.resolve(session);
|
|
12297
|
+
}
|
|
12298
|
+
},
|
|
12299
|
+
onCancel: () => {
|
|
12300
|
+
if (state.sessionSelector) {
|
|
12301
|
+
state.sessionSelector.resolve(null);
|
|
12302
|
+
}
|
|
12303
|
+
}
|
|
12304
|
+
}
|
|
12305
|
+
);
|
|
12306
|
+
}
|
|
11635
12307
|
if (state.showLoginFlow) {
|
|
11636
12308
|
const loginApiUrl = getApiUrl(state.config?.apiConfig);
|
|
11637
|
-
return /* @__PURE__ */
|
|
12309
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11638
12310
|
LoginFlow,
|
|
11639
12311
|
{
|
|
11640
12312
|
apiUrl: loginApiUrl,
|
|
@@ -11657,9 +12329,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11657
12329
|
);
|
|
11658
12330
|
}
|
|
11659
12331
|
if (!isInitialized) {
|
|
11660
|
-
return /* @__PURE__ */
|
|
12332
|
+
return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React16.createElement(Text15, null, "\u{1F680} Initializing..."));
|
|
11661
12333
|
}
|
|
11662
|
-
return /* @__PURE__ */
|
|
12334
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11663
12335
|
App,
|
|
11664
12336
|
{
|
|
11665
12337
|
onMessage: handleMessage,
|
|
@@ -11698,6 +12370,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
|
|
|
11698
12370
|
if (isDevMode) {
|
|
11699
12371
|
console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
|
|
11700
12372
|
}
|
|
11701
|
-
render(/* @__PURE__ */
|
|
12373
|
+
render(/* @__PURE__ */ React16.createElement(CliApp, null), {
|
|
11702
12374
|
exitOnCtrlC: false
|
|
11703
12375
|
});
|