@bike4mind/cli 0.2.8-fix-cli-type-error.17148 → 0.2.10-cli-fix-model-change.17240
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 +866 -96
- 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,20 @@ 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 useState8, useEffect as useEffect3, useCallback, useRef } from "react";
|
|
83
|
+
import { render, Box as Box15, Text as Text15, useApp, useInput as useInput6 } from "ink";
|
|
84
|
+
import { execSync } from "child_process";
|
|
84
85
|
import { v4 as uuidv49 } from "uuid";
|
|
85
86
|
|
|
86
87
|
// src/components/App.tsx
|
|
87
|
-
import React10 from "react";
|
|
88
|
-
import { Box as Box9, Text as Text9
|
|
88
|
+
import React10, { useState as useState4 } from "react";
|
|
89
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
89
90
|
|
|
90
91
|
// src/components/StatusBar.tsx
|
|
91
92
|
import React from "react";
|
|
@@ -732,16 +733,19 @@ function findAtTrigger(value) {
|
|
|
732
733
|
}
|
|
733
734
|
function InputPrompt({
|
|
734
735
|
onSubmit,
|
|
736
|
+
onBashCommand,
|
|
735
737
|
onImageDetected,
|
|
736
738
|
disabled = false,
|
|
737
739
|
history = [],
|
|
738
740
|
prefillInput,
|
|
739
|
-
onPrefillConsumed
|
|
741
|
+
onPrefillConsumed,
|
|
742
|
+
onBashModeChange
|
|
740
743
|
}) {
|
|
741
744
|
const [value, setValue] = useState2("");
|
|
742
745
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
743
746
|
const [historyIndex, setHistoryIndex] = useState2(-1);
|
|
744
747
|
const [tempInput, setTempInput] = useState2("");
|
|
748
|
+
const [inputKey, setInputKey] = useState2(0);
|
|
745
749
|
useEffect(() => {
|
|
746
750
|
if (prefillInput) {
|
|
747
751
|
setValue(prefillInput);
|
|
@@ -750,6 +754,10 @@ function InputPrompt({
|
|
|
750
754
|
}, [prefillInput, onPrefillConsumed]);
|
|
751
755
|
const [fileAutocomplete, setFileAutocomplete] = useState2(null);
|
|
752
756
|
const [fileSelectedIndex, setFileSelectedIndex] = useState2(0);
|
|
757
|
+
const isBashMode = value.startsWith("!");
|
|
758
|
+
useEffect(() => {
|
|
759
|
+
onBashModeChange?.(isBashMode);
|
|
760
|
+
}, [isBashMode, onBashModeChange]);
|
|
753
761
|
const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
|
|
754
762
|
const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
|
|
755
763
|
const filteredCommands = useMemo(() => {
|
|
@@ -856,6 +864,16 @@ function InputPrompt({
|
|
|
856
864
|
onSubmit(commandText);
|
|
857
865
|
return;
|
|
858
866
|
}
|
|
867
|
+
if (isBashMode && onBashCommand) {
|
|
868
|
+
const command = input.slice(1).trim();
|
|
869
|
+
if (command) {
|
|
870
|
+
onBashCommand(command);
|
|
871
|
+
setValue("");
|
|
872
|
+
setHistoryIndex(-1);
|
|
873
|
+
setFileAutocomplete(null);
|
|
874
|
+
}
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
859
877
|
onSubmit(input);
|
|
860
878
|
setValue("");
|
|
861
879
|
setHistoryIndex(-1);
|
|
@@ -886,13 +904,19 @@ function InputPrompt({
|
|
|
886
904
|
setFileAutocomplete(null);
|
|
887
905
|
}
|
|
888
906
|
};
|
|
889
|
-
|
|
907
|
+
const getPlaceholder = () => {
|
|
908
|
+
if (disabled) return "Thinking...";
|
|
909
|
+
if (isBashMode) return "Enter shell command to execute...";
|
|
910
|
+
return "Type your message, /help for commands, @file to reference, or ! for bash";
|
|
911
|
+
};
|
|
912
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: isBashMode ? "yellow" : "cyan" }, isBashMode ? "$ " : "> "), /* @__PURE__ */ React5.createElement(
|
|
890
913
|
CustomTextInput,
|
|
891
914
|
{
|
|
915
|
+
key: inputKey,
|
|
892
916
|
value,
|
|
893
917
|
onChange: handleChange,
|
|
894
918
|
onSubmit: handleSubmit,
|
|
895
|
-
placeholder:
|
|
919
|
+
placeholder: getPlaceholder(),
|
|
896
920
|
showCursor: !disabled
|
|
897
921
|
}
|
|
898
922
|
)), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
|
|
@@ -916,6 +940,16 @@ var useCliStore = create((set) => ({
|
|
|
916
940
|
// Session state
|
|
917
941
|
session: null,
|
|
918
942
|
setSession: (session) => set({ session }),
|
|
943
|
+
addMessage: (message) => set((state) => {
|
|
944
|
+
if (!state.session) return state;
|
|
945
|
+
return {
|
|
946
|
+
session: {
|
|
947
|
+
...state.session,
|
|
948
|
+
messages: [...state.session.messages, message],
|
|
949
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
}),
|
|
919
953
|
// UI state
|
|
920
954
|
isThinking: false,
|
|
921
955
|
setIsThinking: (thinking) => set({ isThinking: thinking }),
|
|
@@ -923,6 +957,7 @@ var useCliStore = create((set) => ({
|
|
|
923
957
|
addAgentStep: (step) => set((state) => ({
|
|
924
958
|
agentSteps: [...state.agentSteps, step]
|
|
925
959
|
})),
|
|
960
|
+
setAgentSteps: (steps) => set({ agentSteps: steps }),
|
|
926
961
|
clearAgentSteps: () => set({ agentSteps: [] }),
|
|
927
962
|
// Permission prompt
|
|
928
963
|
permissionPrompt: null,
|
|
@@ -942,7 +977,7 @@ var AgentThinking = React7.memo(function AgentThinking2() {
|
|
|
942
977
|
if (!isThinking) {
|
|
943
978
|
return null;
|
|
944
979
|
}
|
|
945
|
-
return /* @__PURE__ */ React7.createElement(Box6, {
|
|
980
|
+
return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
|
|
946
981
|
});
|
|
947
982
|
|
|
948
983
|
// src/components/PermissionPrompt.tsx
|
|
@@ -1332,6 +1367,7 @@ function hasFileReferences(message) {
|
|
|
1332
1367
|
function App({
|
|
1333
1368
|
onMessage,
|
|
1334
1369
|
onCommand,
|
|
1370
|
+
onBashCommand,
|
|
1335
1371
|
onPermissionResponse,
|
|
1336
1372
|
onImageDetected,
|
|
1337
1373
|
commandHistory = [],
|
|
@@ -1351,6 +1387,7 @@ function App({
|
|
|
1351
1387
|
const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
|
|
1352
1388
|
const exitRequested = useCliStore((state) => state.exitRequested);
|
|
1353
1389
|
const setIsThinking = useCliStore((state) => state.setIsThinking);
|
|
1390
|
+
const [isBashMode, setIsBashMode] = useState4(false);
|
|
1354
1391
|
const handleSubmit = React10.useCallback(
|
|
1355
1392
|
async (input) => {
|
|
1356
1393
|
const trimmed = input.trim();
|
|
@@ -1397,20 +1434,23 @@ ${errorBlock}`;
|
|
|
1397
1434
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
1398
1435
|
onResponse: onPermissionResponse
|
|
1399
1436
|
}
|
|
1400
|
-
)) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
1437
|
+
)) : /* @__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: isBashMode ? "yellow" : "cyan", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
|
|
1401
1438
|
InputPrompt,
|
|
1402
1439
|
{
|
|
1403
1440
|
onSubmit: handleSubmit,
|
|
1441
|
+
onBashCommand,
|
|
1404
1442
|
onImageDetected,
|
|
1405
1443
|
disabled: isThinking,
|
|
1406
1444
|
history: commandHistory,
|
|
1407
1445
|
prefillInput,
|
|
1408
|
-
onPrefillConsumed
|
|
1446
|
+
onPrefillConsumed,
|
|
1447
|
+
onBashModeChange: setIsBashMode
|
|
1409
1448
|
}
|
|
1410
1449
|
))));
|
|
1411
1450
|
}
|
|
1412
1451
|
function MessageItem({ message }) {
|
|
1413
|
-
|
|
1452
|
+
const isUser = message.role === "user";
|
|
1453
|
+
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
1454
|
if (step.type === "thought") {
|
|
1415
1455
|
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
1456
|
}
|
|
@@ -1422,7 +1462,7 @@ function MessageItem({ message }) {
|
|
|
1422
1462
|
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
1463
|
}
|
|
1424
1464
|
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`)));
|
|
1465
|
+
}).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
1466
|
}
|
|
1427
1467
|
|
|
1428
1468
|
// src/components/MessageList.tsx
|
|
@@ -1498,12 +1538,12 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
|
1498
1538
|
}
|
|
1499
1539
|
|
|
1500
1540
|
// src/components/RewindSelector.tsx
|
|
1501
|
-
import React13, { useState as
|
|
1541
|
+
import React13, { useState as useState5 } from "react";
|
|
1502
1542
|
import { Box as Box12, Text as Text12, useInput as useInput4 } from "ink";
|
|
1503
1543
|
import SelectInput3 from "ink-select-input";
|
|
1504
1544
|
function RewindSelector({ messages, onSelect, onCancel }) {
|
|
1505
|
-
const [step, setStep] =
|
|
1506
|
-
const [selectedMessageIndex, setSelectedMessageIndex] =
|
|
1545
|
+
const [step, setStep] = useState5("selection");
|
|
1546
|
+
const [selectedMessageIndex, setSelectedMessageIndex] = useState5(null);
|
|
1507
1547
|
useInput4((input, key) => {
|
|
1508
1548
|
if (key.escape) {
|
|
1509
1549
|
if (step === "confirmation") {
|
|
@@ -1566,9 +1606,72 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
1566
1606
|
), /* @__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
1607
|
}
|
|
1568
1608
|
|
|
1609
|
+
// src/components/SessionSelector.tsx
|
|
1610
|
+
import React14, { useState as useState6 } from "react";
|
|
1611
|
+
import { Box as Box13, Text as Text13, useInput as useInput5 } from "ink";
|
|
1612
|
+
import SelectInput4 from "ink-select-input";
|
|
1613
|
+
function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
|
|
1614
|
+
const [step, setStep] = useState6("selection");
|
|
1615
|
+
const [selectedSession, setSelectedSession] = useState6(null);
|
|
1616
|
+
useInput5((input, key) => {
|
|
1617
|
+
if (key.escape) {
|
|
1618
|
+
if (step === "confirmation") {
|
|
1619
|
+
setStep("selection");
|
|
1620
|
+
setSelectedSession(null);
|
|
1621
|
+
} else {
|
|
1622
|
+
onCancel();
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
});
|
|
1626
|
+
const hasUnsavedWork = currentSession && currentSession.messages.length > 0;
|
|
1627
|
+
const items = sessions.map((session, index) => {
|
|
1628
|
+
const messageCount = session.messages.length;
|
|
1629
|
+
const lastUpdated = new Date(session.updatedAt).toLocaleString();
|
|
1630
|
+
return {
|
|
1631
|
+
label: `[${index + 1}] ${session.name} (${messageCount} msg, ${session.model})
|
|
1632
|
+
Last updated: ${lastUpdated}`,
|
|
1633
|
+
value: session
|
|
1634
|
+
};
|
|
1635
|
+
});
|
|
1636
|
+
const handleSelectionSelect = (item) => {
|
|
1637
|
+
setSelectedSession(item.value);
|
|
1638
|
+
setStep("confirmation");
|
|
1639
|
+
};
|
|
1640
|
+
const handleConfirmationSelect = (item) => {
|
|
1641
|
+
if (item.value === "confirm" && selectedSession) {
|
|
1642
|
+
onSelect(selectedSession);
|
|
1643
|
+
} else {
|
|
1644
|
+
setStep("selection");
|
|
1645
|
+
setSelectedSession(null);
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
if (step === "selection") {
|
|
1649
|
+
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(
|
|
1650
|
+
SelectInput4,
|
|
1651
|
+
{
|
|
1652
|
+
items,
|
|
1653
|
+
onSelect: handleSelectionSelect,
|
|
1654
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1655
|
+
}
|
|
1656
|
+
), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
|
|
1657
|
+
}
|
|
1658
|
+
const confirmationItems = [
|
|
1659
|
+
{ label: "Yes, resume this session", value: "confirm" },
|
|
1660
|
+
{ label: "No, go back to selection", value: "cancel" }
|
|
1661
|
+
];
|
|
1662
|
+
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(
|
|
1663
|
+
SelectInput4,
|
|
1664
|
+
{
|
|
1665
|
+
items: confirmationItems,
|
|
1666
|
+
onSelect: handleConfirmationSelect,
|
|
1667
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1668
|
+
}
|
|
1669
|
+
), /* @__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")));
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1569
1672
|
// src/components/LoginFlow.tsx
|
|
1570
|
-
import
|
|
1571
|
-
import { Box as
|
|
1673
|
+
import React15, { useState as useState7, useEffect as useEffect2 } from "react";
|
|
1674
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1572
1675
|
import Spinner2 from "ink-spinner";
|
|
1573
1676
|
import jwt from "jsonwebtoken";
|
|
1574
1677
|
import open from "open";
|
|
@@ -1684,10 +1787,10 @@ var OAuthClient = class {
|
|
|
1684
1787
|
|
|
1685
1788
|
// src/components/LoginFlow.tsx
|
|
1686
1789
|
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] =
|
|
1790
|
+
const [status, setStatus] = useState7("initiating");
|
|
1791
|
+
const [deviceFlow, setDeviceFlow] = useState7(null);
|
|
1792
|
+
const [statusMessage, setStatusMessage] = useState7("Initiating device authorization...");
|
|
1793
|
+
const [error, setError] = useState7(null);
|
|
1691
1794
|
useEffect2(() => {
|
|
1692
1795
|
const runLoginFlow = async () => {
|
|
1693
1796
|
const oauth = new OAuthClient(apiUrl);
|
|
@@ -1731,15 +1834,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
1731
1834
|
}
|
|
1732
1835
|
}, [deviceFlow, status]);
|
|
1733
1836
|
if (status === "initiating") {
|
|
1734
|
-
return /* @__PURE__ */
|
|
1837
|
+
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
1838
|
}
|
|
1736
1839
|
if (status === "error") {
|
|
1737
|
-
return /* @__PURE__ */
|
|
1840
|
+
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
1841
|
}
|
|
1739
1842
|
if (status === "success") {
|
|
1740
|
-
return /* @__PURE__ */
|
|
1843
|
+
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
1844
|
}
|
|
1742
|
-
return /* @__PURE__ */
|
|
1845
|
+
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
1846
|
}
|
|
1744
1847
|
|
|
1745
1848
|
// src/storage/SessionStore.ts
|
|
@@ -2625,10 +2728,9 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
2625
2728
|
content: query
|
|
2626
2729
|
}
|
|
2627
2730
|
];
|
|
2628
|
-
console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
|
|
2629
2731
|
messages.forEach((msg, i) => {
|
|
2630
2732
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
2631
|
-
|
|
2733
|
+
this.context.logger.debug(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
|
|
2632
2734
|
});
|
|
2633
2735
|
let finalAnswer = "";
|
|
2634
2736
|
let reachedMaxIterations = false;
|
|
@@ -5021,8 +5123,8 @@ async function processAndStoreImages(images, context) {
|
|
|
5021
5123
|
const buffer = await downloadImage(image);
|
|
5022
5124
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
5023
5125
|
const filename = `${uuidv45()}.${fileType?.ext}`;
|
|
5024
|
-
const
|
|
5025
|
-
return
|
|
5126
|
+
const path15 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
5127
|
+
return path15;
|
|
5026
5128
|
}));
|
|
5027
5129
|
}
|
|
5028
5130
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -6234,8 +6336,8 @@ async function processAndStoreImage(imageUrl, context) {
|
|
|
6234
6336
|
const buffer = await downloadImage2(imageUrl);
|
|
6235
6337
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
6236
6338
|
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
6237
|
-
const
|
|
6238
|
-
return
|
|
6339
|
+
const path15 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
6340
|
+
return path15;
|
|
6239
6341
|
}
|
|
6240
6342
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
6241
6343
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -8647,6 +8749,381 @@ var deleteFileTool = {
|
|
|
8647
8749
|
})
|
|
8648
8750
|
};
|
|
8649
8751
|
|
|
8752
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
8753
|
+
import { spawn } from "child_process";
|
|
8754
|
+
import path11 from "path";
|
|
8755
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
8756
|
+
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
8757
|
+
var DANGEROUS_PATTERNS = [
|
|
8758
|
+
// Destructive file operations
|
|
8759
|
+
{
|
|
8760
|
+
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
8761
|
+
reason: "Recursive delete with path",
|
|
8762
|
+
block: true
|
|
8763
|
+
},
|
|
8764
|
+
{
|
|
8765
|
+
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
8766
|
+
reason: "Force delete without preserve root",
|
|
8767
|
+
block: true
|
|
8768
|
+
},
|
|
8769
|
+
{
|
|
8770
|
+
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
8771
|
+
reason: "Recursive force delete on root paths",
|
|
8772
|
+
block: true
|
|
8773
|
+
},
|
|
8774
|
+
{
|
|
8775
|
+
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
8776
|
+
reason: "Force recursive delete on root paths",
|
|
8777
|
+
block: true
|
|
8778
|
+
},
|
|
8779
|
+
// System-level dangerous commands
|
|
8780
|
+
{ pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
|
|
8781
|
+
{ pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
|
|
8782
|
+
{ pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
|
|
8783
|
+
{ pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
|
|
8784
|
+
// Disk/partition operations
|
|
8785
|
+
{ pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
|
|
8786
|
+
{ pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
|
|
8787
|
+
{ pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
|
|
8788
|
+
// Network attacks
|
|
8789
|
+
{ pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
|
|
8790
|
+
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8791
|
+
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8792
|
+
// Fork bombs and resource exhaustion
|
|
8793
|
+
{ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
|
|
8794
|
+
{ pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
|
|
8795
|
+
// Credential/sensitive data access
|
|
8796
|
+
{ pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
|
|
8797
|
+
{ pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
|
|
8798
|
+
{ pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
|
|
8799
|
+
// History/log manipulation
|
|
8800
|
+
{ pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
|
|
8801
|
+
{ pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
|
|
8802
|
+
// Dangerous redirects
|
|
8803
|
+
{ pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
|
|
8804
|
+
{ pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
|
|
8805
|
+
// Environment manipulation
|
|
8806
|
+
{ pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
|
|
8807
|
+
{ pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
|
|
8808
|
+
// Process/system control
|
|
8809
|
+
{ pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
|
|
8810
|
+
{ pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
|
|
8811
|
+
{ pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
|
|
8812
|
+
{ pattern: /\breboot\b/i, reason: "System reboot", block: true },
|
|
8813
|
+
{ pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
|
|
8814
|
+
];
|
|
8815
|
+
var SAFE_COMMAND_PREFIXES = [
|
|
8816
|
+
"ls",
|
|
8817
|
+
"cat",
|
|
8818
|
+
"head",
|
|
8819
|
+
"tail",
|
|
8820
|
+
"grep",
|
|
8821
|
+
"find",
|
|
8822
|
+
"echo",
|
|
8823
|
+
"pwd",
|
|
8824
|
+
"whoami",
|
|
8825
|
+
"date",
|
|
8826
|
+
"cal",
|
|
8827
|
+
"wc",
|
|
8828
|
+
"sort",
|
|
8829
|
+
"uniq",
|
|
8830
|
+
"cut",
|
|
8831
|
+
"tr",
|
|
8832
|
+
"sed",
|
|
8833
|
+
"awk",
|
|
8834
|
+
"git",
|
|
8835
|
+
"npm",
|
|
8836
|
+
"pnpm",
|
|
8837
|
+
"yarn",
|
|
8838
|
+
"node",
|
|
8839
|
+
"npx",
|
|
8840
|
+
"tsx",
|
|
8841
|
+
"ts-node",
|
|
8842
|
+
"python",
|
|
8843
|
+
"python3",
|
|
8844
|
+
"pip",
|
|
8845
|
+
"pip3",
|
|
8846
|
+
"docker",
|
|
8847
|
+
"docker-compose",
|
|
8848
|
+
"curl",
|
|
8849
|
+
"wget",
|
|
8850
|
+
// These are safe for fetching, blocked when piped to shell
|
|
8851
|
+
"mkdir",
|
|
8852
|
+
"touch",
|
|
8853
|
+
"cp",
|
|
8854
|
+
"mv",
|
|
8855
|
+
// File operations (still require permission)
|
|
8856
|
+
"which",
|
|
8857
|
+
"whereis",
|
|
8858
|
+
"type",
|
|
8859
|
+
"file",
|
|
8860
|
+
"stat",
|
|
8861
|
+
"env",
|
|
8862
|
+
"printenv",
|
|
8863
|
+
"set",
|
|
8864
|
+
"man",
|
|
8865
|
+
"help",
|
|
8866
|
+
"info",
|
|
8867
|
+
"diff",
|
|
8868
|
+
"comm",
|
|
8869
|
+
"cmp",
|
|
8870
|
+
"tar",
|
|
8871
|
+
"zip",
|
|
8872
|
+
"unzip",
|
|
8873
|
+
"gzip",
|
|
8874
|
+
"gunzip",
|
|
8875
|
+
"ssh",
|
|
8876
|
+
"scp",
|
|
8877
|
+
"rsync",
|
|
8878
|
+
// Network tools
|
|
8879
|
+
"make",
|
|
8880
|
+
"cmake",
|
|
8881
|
+
"cargo",
|
|
8882
|
+
"go",
|
|
8883
|
+
"rustc",
|
|
8884
|
+
"gcc",
|
|
8885
|
+
"g++",
|
|
8886
|
+
// Build tools
|
|
8887
|
+
"jest",
|
|
8888
|
+
"vitest",
|
|
8889
|
+
"mocha",
|
|
8890
|
+
"pytest",
|
|
8891
|
+
// Test runners
|
|
8892
|
+
"eslint",
|
|
8893
|
+
"prettier",
|
|
8894
|
+
"tsc"
|
|
8895
|
+
// Linters/formatters
|
|
8896
|
+
];
|
|
8897
|
+
function checkDangerousPatterns(command) {
|
|
8898
|
+
for (const { pattern, reason, block } of DANGEROUS_PATTERNS) {
|
|
8899
|
+
if (pattern.test(command)) {
|
|
8900
|
+
return { blocked: block, reason };
|
|
8901
|
+
}
|
|
8902
|
+
}
|
|
8903
|
+
return { blocked: false };
|
|
8904
|
+
}
|
|
8905
|
+
function getBaseCommand(command) {
|
|
8906
|
+
const trimmed = command.trim();
|
|
8907
|
+
const match = trimmed.match(/^(\S+)/);
|
|
8908
|
+
return match ? match[1] : "";
|
|
8909
|
+
}
|
|
8910
|
+
function isSafeCommandPrefix(command) {
|
|
8911
|
+
const baseCommand = getBaseCommand(command);
|
|
8912
|
+
return SAFE_COMMAND_PREFIXES.some((safe) => baseCommand === safe || baseCommand.endsWith(`/${safe}`));
|
|
8913
|
+
}
|
|
8914
|
+
async function executeBashCommand(params) {
|
|
8915
|
+
const { command, cwd: relativeCwd, timeout = DEFAULT_TIMEOUT_MS } = params;
|
|
8916
|
+
if (!command || command.trim().length === 0) {
|
|
8917
|
+
return {
|
|
8918
|
+
stdout: "",
|
|
8919
|
+
stderr: "Error: Command cannot be empty",
|
|
8920
|
+
exitCode: 1,
|
|
8921
|
+
timedOut: false,
|
|
8922
|
+
blocked: true,
|
|
8923
|
+
blockedReason: "Empty command"
|
|
8924
|
+
};
|
|
8925
|
+
}
|
|
8926
|
+
const dangerCheck = checkDangerousPatterns(command);
|
|
8927
|
+
if (dangerCheck.blocked) {
|
|
8928
|
+
return {
|
|
8929
|
+
stdout: "",
|
|
8930
|
+
stderr: `Command blocked for safety: ${dangerCheck.reason}`,
|
|
8931
|
+
exitCode: 1,
|
|
8932
|
+
timedOut: false,
|
|
8933
|
+
blocked: true,
|
|
8934
|
+
blockedReason: dangerCheck.reason
|
|
8935
|
+
};
|
|
8936
|
+
}
|
|
8937
|
+
const baseCwd = process.cwd();
|
|
8938
|
+
const targetCwd = relativeCwd ? path11.resolve(baseCwd, relativeCwd) : baseCwd;
|
|
8939
|
+
const effectiveTimeout = Math.min(timeout, 5 * 60 * 1e3);
|
|
8940
|
+
return new Promise((resolve3) => {
|
|
8941
|
+
let stdout = "";
|
|
8942
|
+
let stderr = "";
|
|
8943
|
+
let timedOut = false;
|
|
8944
|
+
const proc = spawn("bash", ["-c", command], {
|
|
8945
|
+
cwd: targetCwd,
|
|
8946
|
+
env: {
|
|
8947
|
+
...process.env,
|
|
8948
|
+
// Prevent color codes that might be hard to read
|
|
8949
|
+
NO_COLOR: "1",
|
|
8950
|
+
FORCE_COLOR: "0"
|
|
8951
|
+
},
|
|
8952
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
8953
|
+
});
|
|
8954
|
+
const timeoutId = setTimeout(() => {
|
|
8955
|
+
timedOut = true;
|
|
8956
|
+
proc.kill("SIGTERM");
|
|
8957
|
+
setTimeout(() => {
|
|
8958
|
+
if (!proc.killed) {
|
|
8959
|
+
proc.kill("SIGKILL");
|
|
8960
|
+
}
|
|
8961
|
+
}, 5e3);
|
|
8962
|
+
}, effectiveTimeout);
|
|
8963
|
+
proc.stdout.on("data", (data) => {
|
|
8964
|
+
if (stdout.length < MAX_OUTPUT_SIZE) {
|
|
8965
|
+
stdout += data.toString();
|
|
8966
|
+
if (stdout.length > MAX_OUTPUT_SIZE) {
|
|
8967
|
+
stdout = stdout.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8968
|
+
}
|
|
8969
|
+
}
|
|
8970
|
+
});
|
|
8971
|
+
proc.stderr.on("data", (data) => {
|
|
8972
|
+
if (stderr.length < MAX_OUTPUT_SIZE) {
|
|
8973
|
+
stderr += data.toString();
|
|
8974
|
+
if (stderr.length > MAX_OUTPUT_SIZE) {
|
|
8975
|
+
stderr = stderr.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8976
|
+
}
|
|
8977
|
+
}
|
|
8978
|
+
});
|
|
8979
|
+
proc.on("close", (exitCode) => {
|
|
8980
|
+
clearTimeout(timeoutId);
|
|
8981
|
+
resolve3({
|
|
8982
|
+
stdout: stdout.trim(),
|
|
8983
|
+
stderr: stderr.trim(),
|
|
8984
|
+
exitCode,
|
|
8985
|
+
timedOut,
|
|
8986
|
+
blocked: false
|
|
8987
|
+
});
|
|
8988
|
+
});
|
|
8989
|
+
proc.on("error", (error) => {
|
|
8990
|
+
clearTimeout(timeoutId);
|
|
8991
|
+
resolve3({
|
|
8992
|
+
stdout: "",
|
|
8993
|
+
stderr: `Failed to execute command: ${error.message}`,
|
|
8994
|
+
exitCode: 1,
|
|
8995
|
+
timedOut: false,
|
|
8996
|
+
blocked: false
|
|
8997
|
+
});
|
|
8998
|
+
});
|
|
8999
|
+
});
|
|
9000
|
+
}
|
|
9001
|
+
function formatResult(result, command) {
|
|
9002
|
+
const parts = [];
|
|
9003
|
+
parts.push(`$ ${command}`);
|
|
9004
|
+
parts.push("");
|
|
9005
|
+
if (result.blocked) {
|
|
9006
|
+
parts.push(`BLOCKED: ${result.blockedReason}`);
|
|
9007
|
+
parts.push("");
|
|
9008
|
+
parts.push("This command was blocked for safety reasons.");
|
|
9009
|
+
parts.push("If you believe this is a false positive, please run the command manually.");
|
|
9010
|
+
return parts.join("\n");
|
|
9011
|
+
}
|
|
9012
|
+
if (result.timedOut) {
|
|
9013
|
+
parts.push("WARNING: Command timed out and was terminated.");
|
|
9014
|
+
parts.push("");
|
|
9015
|
+
}
|
|
9016
|
+
if (result.stdout) {
|
|
9017
|
+
parts.push(result.stdout);
|
|
9018
|
+
}
|
|
9019
|
+
if (result.stderr) {
|
|
9020
|
+
if (result.stdout) {
|
|
9021
|
+
parts.push("");
|
|
9022
|
+
}
|
|
9023
|
+
parts.push("STDERR:");
|
|
9024
|
+
parts.push(result.stderr);
|
|
9025
|
+
}
|
|
9026
|
+
if (result.exitCode !== 0 && result.exitCode !== null) {
|
|
9027
|
+
parts.push("");
|
|
9028
|
+
parts.push(`Exit code: ${result.exitCode}`);
|
|
9029
|
+
}
|
|
9030
|
+
if (!result.stdout && !result.stderr && !result.timedOut) {
|
|
9031
|
+
parts.push("(command completed with no output)");
|
|
9032
|
+
}
|
|
9033
|
+
return parts.join("\n");
|
|
9034
|
+
}
|
|
9035
|
+
var bashExecuteTool = {
|
|
9036
|
+
name: "bash_execute",
|
|
9037
|
+
implementation: (context) => ({
|
|
9038
|
+
toolFn: async (value) => {
|
|
9039
|
+
const params = value;
|
|
9040
|
+
const isSafe = isSafeCommandPrefix(params.command);
|
|
9041
|
+
context.logger.info("Bash: Executing command", {
|
|
9042
|
+
command: params.command,
|
|
9043
|
+
cwd: params.cwd || ".",
|
|
9044
|
+
timeout: params.timeout || DEFAULT_TIMEOUT_MS,
|
|
9045
|
+
isSafeCommand: isSafe
|
|
9046
|
+
});
|
|
9047
|
+
if (context.onStart) {
|
|
9048
|
+
await context.onStart("bash_execute", {
|
|
9049
|
+
command: params.command,
|
|
9050
|
+
cwd: params.cwd
|
|
9051
|
+
});
|
|
9052
|
+
}
|
|
9053
|
+
try {
|
|
9054
|
+
const result = await executeBashCommand(params);
|
|
9055
|
+
const formattedResult = formatResult(result, params.command);
|
|
9056
|
+
context.logger.info("Bash: Command completed", {
|
|
9057
|
+
exitCode: result.exitCode,
|
|
9058
|
+
timedOut: result.timedOut,
|
|
9059
|
+
blocked: result.blocked
|
|
9060
|
+
});
|
|
9061
|
+
if (context.onFinish) {
|
|
9062
|
+
await context.onFinish("bash_execute", {
|
|
9063
|
+
command: params.command,
|
|
9064
|
+
exitCode: result.exitCode,
|
|
9065
|
+
blocked: result.blocked
|
|
9066
|
+
});
|
|
9067
|
+
}
|
|
9068
|
+
return formattedResult;
|
|
9069
|
+
} catch (error) {
|
|
9070
|
+
context.logger.error("Bash: Command failed", error);
|
|
9071
|
+
if (context.onFinish) {
|
|
9072
|
+
await context.onFinish("bash_execute", {
|
|
9073
|
+
command: params.command,
|
|
9074
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
9075
|
+
});
|
|
9076
|
+
}
|
|
9077
|
+
throw error;
|
|
9078
|
+
}
|
|
9079
|
+
},
|
|
9080
|
+
toolSchema: {
|
|
9081
|
+
name: "bash_execute",
|
|
9082
|
+
description: `Execute a bash command in the terminal. Use this for running shell commands, scripts, build tools, git operations, and other CLI tasks.
|
|
9083
|
+
|
|
9084
|
+
SAFETY NOTES:
|
|
9085
|
+
- Commands are executed in the current working directory (or specified cwd)
|
|
9086
|
+
- Dangerous commands (sudo, rm -rf /, etc.) are automatically blocked
|
|
9087
|
+
- Commands have a default timeout of 60 seconds (max 5 minutes)
|
|
9088
|
+
- Output is limited to prevent overwhelming responses
|
|
9089
|
+
- This tool ALWAYS requires user permission before execution
|
|
9090
|
+
|
|
9091
|
+
COMMON USE CASES:
|
|
9092
|
+
- Running build commands: npm run build, make, cargo build
|
|
9093
|
+
- Git operations: git status, git log, git diff
|
|
9094
|
+
- Viewing system info: ls, pwd, cat, head, tail
|
|
9095
|
+
- Running tests: npm test, pytest, cargo test
|
|
9096
|
+
- Package management: npm install, pip install
|
|
9097
|
+
- File operations: mkdir, cp, mv (with permission)
|
|
9098
|
+
|
|
9099
|
+
BLOCKED OPERATIONS:
|
|
9100
|
+
- sudo and privilege escalation
|
|
9101
|
+
- Recursive deletes on system paths
|
|
9102
|
+
- Direct disk operations
|
|
9103
|
+
- Fork bombs and resource exhaustion
|
|
9104
|
+
- Piping remote scripts to shell`,
|
|
9105
|
+
parameters: {
|
|
9106
|
+
type: "object",
|
|
9107
|
+
properties: {
|
|
9108
|
+
command: {
|
|
9109
|
+
type: "string",
|
|
9110
|
+
description: "The bash command to execute. Can include pipes, redirects, and chained commands."
|
|
9111
|
+
},
|
|
9112
|
+
cwd: {
|
|
9113
|
+
type: "string",
|
|
9114
|
+
description: "Working directory for the command (optional). Can be relative or absolute path. Defaults to current directory."
|
|
9115
|
+
},
|
|
9116
|
+
timeout: {
|
|
9117
|
+
type: "number",
|
|
9118
|
+
description: "Timeout in milliseconds (optional, default: 60000, max: 300000). Command will be terminated if it exceeds this time."
|
|
9119
|
+
}
|
|
9120
|
+
},
|
|
9121
|
+
required: ["command"]
|
|
9122
|
+
}
|
|
9123
|
+
}
|
|
9124
|
+
})
|
|
9125
|
+
};
|
|
9126
|
+
|
|
8650
9127
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
8651
9128
|
var tools = {
|
|
8652
9129
|
dice_roll: diceRollTool,
|
|
@@ -8674,7 +9151,9 @@ var tools = {
|
|
|
8674
9151
|
create_file: createFileTool,
|
|
8675
9152
|
glob_files: globFilesTool,
|
|
8676
9153
|
grep_search: grepSearchTool,
|
|
8677
|
-
delete_file: deleteFileTool
|
|
9154
|
+
delete_file: deleteFileTool,
|
|
9155
|
+
// Shell execution
|
|
9156
|
+
bash_execute: bashExecuteTool
|
|
8678
9157
|
};
|
|
8679
9158
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
8680
9159
|
const context = {
|
|
@@ -8949,7 +9428,7 @@ async function generateFileDeletePreview(args) {
|
|
|
8949
9428
|
if (!existsSync7(args.path)) {
|
|
8950
9429
|
return `[File does not exist: ${args.path}]`;
|
|
8951
9430
|
}
|
|
8952
|
-
const stats = await import("fs/promises").then((
|
|
9431
|
+
const stats = await import("fs/promises").then((fs12) => fs12.stat(args.path));
|
|
8953
9432
|
return `[File will be deleted]
|
|
8954
9433
|
|
|
8955
9434
|
Path: ${args.path}
|
|
@@ -8962,7 +9441,7 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
8962
9441
|
|
|
8963
9442
|
// src/utils/Logger.ts
|
|
8964
9443
|
import fs10 from "fs/promises";
|
|
8965
|
-
import
|
|
9444
|
+
import path12 from "path";
|
|
8966
9445
|
import os from "os";
|
|
8967
9446
|
var Logger2 = class _Logger {
|
|
8968
9447
|
constructor() {
|
|
@@ -8985,9 +9464,9 @@ var Logger2 = class _Logger {
|
|
|
8985
9464
|
*/
|
|
8986
9465
|
async initialize(sessionId) {
|
|
8987
9466
|
this.sessionId = sessionId;
|
|
8988
|
-
const debugDir =
|
|
9467
|
+
const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
|
|
8989
9468
|
await fs10.mkdir(debugDir, { recursive: true });
|
|
8990
|
-
this.logFilePath =
|
|
9469
|
+
this.logFilePath = path12.join(debugDir, `${sessionId}.txt`);
|
|
8991
9470
|
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
8992
9471
|
}
|
|
8993
9472
|
/**
|
|
@@ -9197,12 +9676,12 @@ var Logger2 = class _Logger {
|
|
|
9197
9676
|
async cleanupOldLogs() {
|
|
9198
9677
|
if (!this.fileLoggingEnabled) return;
|
|
9199
9678
|
try {
|
|
9200
|
-
const debugDir =
|
|
9679
|
+
const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
|
|
9201
9680
|
const files = await fs10.readdir(debugDir);
|
|
9202
9681
|
const now = Date.now();
|
|
9203
9682
|
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9204
9683
|
for (const file of files) {
|
|
9205
|
-
const filePath =
|
|
9684
|
+
const filePath = path12.join(debugDir, file);
|
|
9206
9685
|
const stats = await fs10.stat(filePath);
|
|
9207
9686
|
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9208
9687
|
await fs10.unlink(filePath);
|
|
@@ -9267,7 +9746,8 @@ var LOCAL_TOOLS = [
|
|
|
9267
9746
|
"edit_file",
|
|
9268
9747
|
"dice_roll",
|
|
9269
9748
|
"math_evaluate",
|
|
9270
|
-
"current_datetime"
|
|
9749
|
+
"current_datetime",
|
|
9750
|
+
"bash_execute"
|
|
9271
9751
|
];
|
|
9272
9752
|
function isServerTool(toolName) {
|
|
9273
9753
|
return SERVER_TOOLS.includes(toolName);
|
|
@@ -9297,21 +9777,21 @@ var NoOpStorage = class extends BaseStorage {
|
|
|
9297
9777
|
async upload(input, destination, options) {
|
|
9298
9778
|
return `/tmp/${destination}`;
|
|
9299
9779
|
}
|
|
9300
|
-
async download(
|
|
9780
|
+
async download(path15) {
|
|
9301
9781
|
throw new Error("Download not supported in CLI");
|
|
9302
9782
|
}
|
|
9303
|
-
async delete(
|
|
9783
|
+
async delete(path15) {
|
|
9304
9784
|
}
|
|
9305
|
-
async getSignedUrl(
|
|
9306
|
-
return `/tmp/${
|
|
9785
|
+
async getSignedUrl(path15) {
|
|
9786
|
+
return `/tmp/${path15}`;
|
|
9307
9787
|
}
|
|
9308
|
-
getPublicUrl(
|
|
9309
|
-
return `/tmp/${
|
|
9788
|
+
getPublicUrl(path15) {
|
|
9789
|
+
return `/tmp/${path15}`;
|
|
9310
9790
|
}
|
|
9311
|
-
async getPreview(
|
|
9312
|
-
return `/tmp/${
|
|
9791
|
+
async getPreview(path15) {
|
|
9792
|
+
return `/tmp/${path15}`;
|
|
9313
9793
|
}
|
|
9314
|
-
async getMetadata(
|
|
9794
|
+
async getMetadata(path15) {
|
|
9315
9795
|
return { size: 0, contentType: "application/octet-stream" };
|
|
9316
9796
|
}
|
|
9317
9797
|
};
|
|
@@ -9369,6 +9849,10 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9369
9849
|
} catch (error) {
|
|
9370
9850
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9371
9851
|
}
|
|
9852
|
+
} else if (toolName === "bash_execute" && args?.command) {
|
|
9853
|
+
const cwd = args.cwd ? ` (in ${args.cwd})` : "";
|
|
9854
|
+
const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
|
|
9855
|
+
preview = `$ ${args.command}${cwd}${timeout}`;
|
|
9372
9856
|
}
|
|
9373
9857
|
const response = await showPermissionPrompt(toolName, args, preview);
|
|
9374
9858
|
if (response.action === "deny") {
|
|
@@ -9439,6 +9923,8 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9439
9923
|
glob_files: {},
|
|
9440
9924
|
grep_search: {},
|
|
9441
9925
|
delete_file: {},
|
|
9926
|
+
// Shell execution (always requires permission)
|
|
9927
|
+
bash_execute: {},
|
|
9442
9928
|
// Server-side tools (executed via /api/ai/v1/tools Lambda)
|
|
9443
9929
|
// Routed by ToolRouter to use B4M company API keys
|
|
9444
9930
|
weather_info: {},
|
|
@@ -9504,6 +9990,7 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
9504
9990
|
create_file: "prompt_always",
|
|
9505
9991
|
delete_file: "prompt_always",
|
|
9506
9992
|
shell_execute: "prompt_always",
|
|
9993
|
+
bash_execute: "prompt_always",
|
|
9507
9994
|
git_commit: "prompt_always",
|
|
9508
9995
|
git_push: "prompt_always",
|
|
9509
9996
|
// ===== PROMPT DEFAULT (Repository read tools) =====
|
|
@@ -9665,10 +10152,122 @@ function getEnvironmentName(configApiConfig) {
|
|
|
9665
10152
|
return "Bike4Mind";
|
|
9666
10153
|
}
|
|
9667
10154
|
|
|
10155
|
+
// src/utils/contextLoader.ts
|
|
10156
|
+
import * as fs11 from "fs";
|
|
10157
|
+
import * as path13 from "path";
|
|
10158
|
+
import { homedir as homedir4 } from "os";
|
|
10159
|
+
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
10160
|
+
var PROJECT_CONTEXT_FILES = [
|
|
10161
|
+
"CLAUDE.local.md",
|
|
10162
|
+
// gitignored, highest priority
|
|
10163
|
+
"CLAUDE.md",
|
|
10164
|
+
"AGENTS.md",
|
|
10165
|
+
// cross-tool standard
|
|
10166
|
+
"AI.local.md",
|
|
10167
|
+
// gitignored
|
|
10168
|
+
"AI.md",
|
|
10169
|
+
"INSTRUCTIONS.md"
|
|
10170
|
+
];
|
|
10171
|
+
var GLOBAL_CONTEXT_FILES = ["AI.local.md", "AI.md"];
|
|
10172
|
+
function formatFileSize2(bytes) {
|
|
10173
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
10174
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
10175
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
10176
|
+
}
|
|
10177
|
+
function tryReadContextFile(dir, filename, source) {
|
|
10178
|
+
const filePath = path13.join(dir, filename);
|
|
10179
|
+
try {
|
|
10180
|
+
const stats = fs11.lstatSync(filePath);
|
|
10181
|
+
if (stats.isDirectory()) {
|
|
10182
|
+
return null;
|
|
10183
|
+
}
|
|
10184
|
+
if (stats.isSymbolicLink()) {
|
|
10185
|
+
return {
|
|
10186
|
+
error: `${source === "global" ? "Global" : "Project"} ${filename} is a symlink (not allowed for security)`
|
|
10187
|
+
};
|
|
10188
|
+
}
|
|
10189
|
+
if (stats.size > CONTEXT_FILE_SIZE_LIMIT) {
|
|
10190
|
+
return {
|
|
10191
|
+
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
10192
|
+
};
|
|
10193
|
+
}
|
|
10194
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
10195
|
+
return {
|
|
10196
|
+
filename,
|
|
10197
|
+
content,
|
|
10198
|
+
source,
|
|
10199
|
+
path: filePath
|
|
10200
|
+
};
|
|
10201
|
+
} catch (err) {
|
|
10202
|
+
if (err.code === "ENOENT") {
|
|
10203
|
+
return null;
|
|
10204
|
+
}
|
|
10205
|
+
if (err.code === "EACCES") {
|
|
10206
|
+
return {
|
|
10207
|
+
error: `Cannot read ${source} ${filename}: permission denied`
|
|
10208
|
+
};
|
|
10209
|
+
}
|
|
10210
|
+
return {
|
|
10211
|
+
error: `Cannot read ${source} ${filename}: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
10212
|
+
};
|
|
10213
|
+
}
|
|
10214
|
+
}
|
|
10215
|
+
function findContextFile(dir, candidates, source) {
|
|
10216
|
+
for (const filename of candidates) {
|
|
10217
|
+
const result = tryReadContextFile(dir, filename, source);
|
|
10218
|
+
if (result === null) {
|
|
10219
|
+
continue;
|
|
10220
|
+
}
|
|
10221
|
+
if ("error" in result) {
|
|
10222
|
+
return { result: null, error: result.error };
|
|
10223
|
+
}
|
|
10224
|
+
return { result, error: null };
|
|
10225
|
+
}
|
|
10226
|
+
return { result: null, error: null };
|
|
10227
|
+
}
|
|
10228
|
+
function mergeContextContent(global, project) {
|
|
10229
|
+
if (global && project) {
|
|
10230
|
+
return `${global.content}
|
|
10231
|
+
|
|
10232
|
+
---
|
|
10233
|
+
|
|
10234
|
+
${project.content}`;
|
|
10235
|
+
}
|
|
10236
|
+
if (global) {
|
|
10237
|
+
return global.content;
|
|
10238
|
+
}
|
|
10239
|
+
if (project) {
|
|
10240
|
+
return project.content;
|
|
10241
|
+
}
|
|
10242
|
+
return "";
|
|
10243
|
+
}
|
|
10244
|
+
async function loadContextFiles(projectDir) {
|
|
10245
|
+
const errors = [];
|
|
10246
|
+
const globalDir = path13.join(homedir4(), ".bike4mind");
|
|
10247
|
+
const projectDirectory = projectDir || process.cwd();
|
|
10248
|
+
const [globalResult, projectResult] = await Promise.all([
|
|
10249
|
+
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
10250
|
+
Promise.resolve(findContextFile(projectDirectory, PROJECT_CONTEXT_FILES, "project"))
|
|
10251
|
+
]);
|
|
10252
|
+
if (globalResult.error) {
|
|
10253
|
+
errors.push(globalResult.error);
|
|
10254
|
+
}
|
|
10255
|
+
if (projectResult.error) {
|
|
10256
|
+
errors.push(projectResult.error);
|
|
10257
|
+
}
|
|
10258
|
+
const mergedContent = mergeContextContent(globalResult.result, projectResult.result);
|
|
10259
|
+
return {
|
|
10260
|
+
globalContext: globalResult.result,
|
|
10261
|
+
projectContext: projectResult.result,
|
|
10262
|
+
mergedContent,
|
|
10263
|
+
errors
|
|
10264
|
+
};
|
|
10265
|
+
}
|
|
10266
|
+
|
|
9668
10267
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
9669
10268
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
9670
10269
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9671
|
-
import
|
|
10270
|
+
import path14 from "path";
|
|
9672
10271
|
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
9673
10272
|
var MCPClient = class {
|
|
9674
10273
|
// Note: This class handles MCP server communication with repository filtering
|
|
@@ -9709,16 +10308,16 @@ var MCPClient = class {
|
|
|
9709
10308
|
const root = process.env.INIT_CWD || process.cwd();
|
|
9710
10309
|
const candidatePaths = [
|
|
9711
10310
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
9712
|
-
|
|
10311
|
+
path14.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
9713
10312
|
// When running from SST Lambda deployed environment (/var/task)
|
|
9714
|
-
|
|
10313
|
+
path14.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9715
10314
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
9716
|
-
|
|
10315
|
+
path14.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9717
10316
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
9718
|
-
|
|
10317
|
+
path14.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9719
10318
|
// Original paths (backward compatibility)
|
|
9720
|
-
|
|
9721
|
-
|
|
10319
|
+
path14.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10320
|
+
path14.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
9722
10321
|
];
|
|
9723
10322
|
const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
|
|
9724
10323
|
if (!serverScriptPath) {
|
|
@@ -10522,7 +11121,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
10522
11121
|
// package.json
|
|
10523
11122
|
var package_default = {
|
|
10524
11123
|
name: "@bike4mind/cli",
|
|
10525
|
-
version: "0.2.
|
|
11124
|
+
version: "0.2.10-cli-fix-model-change.17240+efd37dd24",
|
|
10526
11125
|
type: "module",
|
|
10527
11126
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
10528
11127
|
license: "UNLICENSED",
|
|
@@ -10577,7 +11176,7 @@ var package_default = {
|
|
|
10577
11176
|
"@google/generative-ai": "^0.21.0",
|
|
10578
11177
|
"@joplin/turndown-plugin-gfm": "^1.0.62",
|
|
10579
11178
|
"@mendable/firecrawl-js": "^1.29.3",
|
|
10580
|
-
"@modelcontextprotocol/sdk": "
|
|
11179
|
+
"@modelcontextprotocol/sdk": "1.20.1",
|
|
10581
11180
|
"@octokit/rest": "^22.0.0",
|
|
10582
11181
|
"@opensearch-project/opensearch": "2.11.0",
|
|
10583
11182
|
"async-mutex": "^0.5.0",
|
|
@@ -10625,11 +11224,11 @@ var package_default = {
|
|
|
10625
11224
|
},
|
|
10626
11225
|
devDependencies: {
|
|
10627
11226
|
"@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.
|
|
11227
|
+
"@bike4mind/common": "2.39.1-cli-fix-model-change.17240+efd37dd24",
|
|
11228
|
+
"@bike4mind/mcp": "1.20.4-cli-fix-model-change.17240+efd37dd24",
|
|
11229
|
+
"@bike4mind/services": "2.34.2-cli-fix-model-change.17240+efd37dd24",
|
|
11230
|
+
"@bike4mind/utils": "2.1.4-cli-fix-model-change.17240+efd37dd24",
|
|
11231
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
10633
11232
|
"@types/diff": "^5.0.9",
|
|
10634
11233
|
"@types/jsonwebtoken": "^9.0.4",
|
|
10635
11234
|
"@types/node": "^22.9.0",
|
|
@@ -10641,7 +11240,7 @@ var package_default = {
|
|
|
10641
11240
|
typescript: "^5.9.3",
|
|
10642
11241
|
vitest: "^3.2.4"
|
|
10643
11242
|
},
|
|
10644
|
-
gitHead: "
|
|
11243
|
+
gitHead: "efd37dd24812e8e34852cf32fa190f2b1c7663d9"
|
|
10645
11244
|
};
|
|
10646
11245
|
|
|
10647
11246
|
// src/config/constants.ts
|
|
@@ -10663,7 +11262,7 @@ var usageCache = null;
|
|
|
10663
11262
|
function CliApp() {
|
|
10664
11263
|
const { exit } = useApp();
|
|
10665
11264
|
const imageRenderer = new ImageRenderer();
|
|
10666
|
-
const [state, setState] =
|
|
11265
|
+
const [state, setState] = useState8({
|
|
10667
11266
|
session: null,
|
|
10668
11267
|
sessionStore: new SessionStore(),
|
|
10669
11268
|
configStore: new ConfigStore(),
|
|
@@ -10677,11 +11276,12 @@ function CliApp() {
|
|
|
10677
11276
|
permissionManager: null,
|
|
10678
11277
|
permissionPrompt: null,
|
|
10679
11278
|
trustLocationSelector: null,
|
|
10680
|
-
rewindSelector: null
|
|
11279
|
+
rewindSelector: null,
|
|
11280
|
+
sessionSelector: null
|
|
10681
11281
|
});
|
|
10682
|
-
const [isInitialized, setIsInitialized] =
|
|
10683
|
-
const [initError, setInitError] =
|
|
10684
|
-
const [commandHistory, setCommandHistory] =
|
|
11282
|
+
const [isInitialized, setIsInitialized] = useState8(false);
|
|
11283
|
+
const [initError, setInitError] = useState8(null);
|
|
11284
|
+
const [commandHistory, setCommandHistory] = useState8([]);
|
|
10685
11285
|
const imageStoreInitPromise = useRef(null);
|
|
10686
11286
|
const setStoreSession = useCliStore((state2) => state2.setSession);
|
|
10687
11287
|
const setPermissionPrompt = useCliStore((state2) => state2.setPermissionPrompt);
|
|
@@ -10722,7 +11322,7 @@ function CliApp() {
|
|
|
10722
11322
|
process.exit(0);
|
|
10723
11323
|
}, 100);
|
|
10724
11324
|
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
10725
|
-
|
|
11325
|
+
useInput6((input, key) => {
|
|
10726
11326
|
if (key.ctrl && input === "c") {
|
|
10727
11327
|
const now = Date.now();
|
|
10728
11328
|
if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
|
|
@@ -10892,6 +11492,24 @@ function CliApp() {
|
|
|
10892
11492
|
}
|
|
10893
11493
|
const allTools = [...b4mTools, ...mcpTools];
|
|
10894
11494
|
console.log(`\u2705 Total: ${allTools.length} tool(s) available`);
|
|
11495
|
+
const projectDir = state.configStore.getProjectConfigDir();
|
|
11496
|
+
const contextResult = await loadContextFiles(projectDir);
|
|
11497
|
+
if (contextResult.globalContext) {
|
|
11498
|
+
console.log(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
|
|
11499
|
+
}
|
|
11500
|
+
if (contextResult.projectContext) {
|
|
11501
|
+
console.log(`\u{1F4C4} Project context: ${contextResult.projectContext.filename}`);
|
|
11502
|
+
}
|
|
11503
|
+
for (const error of contextResult.errors) {
|
|
11504
|
+
console.log(`\u26A0\uFE0F Context file error: ${error}`);
|
|
11505
|
+
}
|
|
11506
|
+
const contextSection = contextResult.mergedContent ? `
|
|
11507
|
+
|
|
11508
|
+
## Project Context
|
|
11509
|
+
|
|
11510
|
+
Follow these project-specific instructions:
|
|
11511
|
+
|
|
11512
|
+
${contextResult.mergedContent}` : "";
|
|
10895
11513
|
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
11514
|
|
|
10897
11515
|
CORE BEHAVIOR:
|
|
@@ -10921,7 +11539,7 @@ EXAMPLES:
|
|
|
10921
11539
|
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
10922
11540
|
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
10923
11541
|
|
|
10924
|
-
Remember: Use context from previous messages to understand follow-up questions
|
|
11542
|
+
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
10925
11543
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
10926
11544
|
const agent = new ReActAgent({
|
|
10927
11545
|
userId: config.userId,
|
|
@@ -10976,6 +11594,29 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
10976
11594
|
console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
|
|
10977
11595
|
return;
|
|
10978
11596
|
}
|
|
11597
|
+
const currentSteps = [];
|
|
11598
|
+
const stepHandler = (step) => {
|
|
11599
|
+
currentSteps.push(step);
|
|
11600
|
+
const currentSession = useCliStore.getState().session;
|
|
11601
|
+
if (currentSession) {
|
|
11602
|
+
const messages = [...currentSession.messages];
|
|
11603
|
+
const lastMessage = messages[messages.length - 1];
|
|
11604
|
+
if (lastMessage && lastMessage.role === "assistant") {
|
|
11605
|
+
messages[messages.length - 1] = {
|
|
11606
|
+
...lastMessage,
|
|
11607
|
+
metadata: {
|
|
11608
|
+
...lastMessage.metadata,
|
|
11609
|
+
steps: [...currentSteps]
|
|
11610
|
+
}
|
|
11611
|
+
};
|
|
11612
|
+
setStoreSession({
|
|
11613
|
+
...currentSession,
|
|
11614
|
+
messages
|
|
11615
|
+
});
|
|
11616
|
+
}
|
|
11617
|
+
}
|
|
11618
|
+
};
|
|
11619
|
+
state.agent.on("action", stepHandler);
|
|
10979
11620
|
try {
|
|
10980
11621
|
let messageContent = message;
|
|
10981
11622
|
let userMessageContent = message;
|
|
@@ -10989,6 +11630,21 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
10989
11630
|
content: userMessageContent,
|
|
10990
11631
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10991
11632
|
};
|
|
11633
|
+
const pendingAssistantMessage = {
|
|
11634
|
+
role: "assistant",
|
|
11635
|
+
content: "...",
|
|
11636
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11637
|
+
metadata: {
|
|
11638
|
+
steps: []
|
|
11639
|
+
}
|
|
11640
|
+
};
|
|
11641
|
+
const sessionWithMessages = {
|
|
11642
|
+
...state.session,
|
|
11643
|
+
messages: [...state.session.messages, userMessage, pendingAssistantMessage],
|
|
11644
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11645
|
+
};
|
|
11646
|
+
setState((prev) => ({ ...prev, session: sessionWithMessages }));
|
|
11647
|
+
setStoreSession(sessionWithMessages);
|
|
10992
11648
|
const recentMessages = state.session.messages.slice(-20);
|
|
10993
11649
|
const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
|
|
10994
11650
|
role: msg.role,
|
|
@@ -11002,26 +11658,28 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11002
11658
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
11003
11659
|
}
|
|
11004
11660
|
const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
|
|
11005
|
-
const
|
|
11661
|
+
const currentSession = useCliStore.getState().session;
|
|
11662
|
+
if (!currentSession) return;
|
|
11663
|
+
const finalMessages = [...currentSession.messages];
|
|
11664
|
+
const finalAssistantMessage = {
|
|
11006
11665
|
role: "assistant",
|
|
11007
11666
|
content: result.finalAnswer,
|
|
11008
|
-
timestamp:
|
|
11667
|
+
timestamp: pendingAssistantMessage.timestamp,
|
|
11009
11668
|
metadata: {
|
|
11010
11669
|
tokenUsage: {
|
|
11011
11670
|
prompt: 0,
|
|
11012
|
-
// TODO: Extract from result
|
|
11013
11671
|
completion: 0,
|
|
11014
11672
|
total: result.completionInfo.totalTokens
|
|
11015
11673
|
},
|
|
11016
11674
|
steps: result.steps,
|
|
11017
11675
|
// Complete history: thoughts, actions, observations
|
|
11018
11676
|
permissionDenied
|
|
11019
|
-
// Mark if this ended due to permission denial
|
|
11020
11677
|
}
|
|
11021
11678
|
};
|
|
11679
|
+
finalMessages[finalMessages.length - 1] = finalAssistantMessage;
|
|
11022
11680
|
const updatedSession = {
|
|
11023
|
-
...
|
|
11024
|
-
messages:
|
|
11681
|
+
...currentSession,
|
|
11682
|
+
messages: finalMessages,
|
|
11025
11683
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11026
11684
|
metadata: {
|
|
11027
11685
|
...state.session.metadata,
|
|
@@ -11041,8 +11699,50 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11041
11699
|
}
|
|
11042
11700
|
}
|
|
11043
11701
|
console.error("Error processing message:", error);
|
|
11702
|
+
} finally {
|
|
11703
|
+
state.agent.off("action", stepHandler);
|
|
11044
11704
|
}
|
|
11045
11705
|
};
|
|
11706
|
+
const handleBashCommand = useCallback(
|
|
11707
|
+
(command) => {
|
|
11708
|
+
if (!state.session) return;
|
|
11709
|
+
let output;
|
|
11710
|
+
let isError = false;
|
|
11711
|
+
try {
|
|
11712
|
+
output = execSync(command, {
|
|
11713
|
+
encoding: "utf-8",
|
|
11714
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
11715
|
+
cwd: process.cwd(),
|
|
11716
|
+
maxBuffer: 10 * 1024 * 1024
|
|
11717
|
+
// 10MB buffer
|
|
11718
|
+
});
|
|
11719
|
+
} catch (error) {
|
|
11720
|
+
const execError = error;
|
|
11721
|
+
output = execError.stderr || execError.message || "Command failed";
|
|
11722
|
+
isError = true;
|
|
11723
|
+
}
|
|
11724
|
+
const userMessage = {
|
|
11725
|
+
role: "user",
|
|
11726
|
+
content: `$ ${command}`,
|
|
11727
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11728
|
+
};
|
|
11729
|
+
const assistantMessage = {
|
|
11730
|
+
role: "assistant",
|
|
11731
|
+
content: isError ? `\u274C Error:
|
|
11732
|
+
${output}` : output.trim() || "(no output)",
|
|
11733
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11734
|
+
};
|
|
11735
|
+
const updatedSession = {
|
|
11736
|
+
...state.session,
|
|
11737
|
+
messages: [...state.session.messages, userMessage, assistantMessage],
|
|
11738
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11739
|
+
};
|
|
11740
|
+
setState((prev) => ({ ...prev, session: updatedSession }));
|
|
11741
|
+
setStoreSession(updatedSession);
|
|
11742
|
+
state.sessionStore.save(updatedSession);
|
|
11743
|
+
},
|
|
11744
|
+
[state.session, state.sessionStore]
|
|
11745
|
+
);
|
|
11046
11746
|
const handleImageDetected = async (imageData) => {
|
|
11047
11747
|
try {
|
|
11048
11748
|
let imageStore = state.imageStore;
|
|
@@ -11143,15 +11843,44 @@ Project Configuration:
|
|
|
11143
11843
|
await state.sessionStore.save(state.session);
|
|
11144
11844
|
console.log(`\u2705 Session saved as "${sessionName}"`);
|
|
11145
11845
|
break;
|
|
11146
|
-
case "sessions":
|
|
11846
|
+
case "sessions": {
|
|
11147
11847
|
const sessions = await state.sessionStore.list();
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
console.log(
|
|
11151
|
-
|
|
11152
|
-
}
|
|
11153
|
-
|
|
11848
|
+
if (sessions.length === 0) {
|
|
11849
|
+
console.log("\n\u{1F4DA} No saved sessions found.");
|
|
11850
|
+
console.log("\u{1F4A1} Use /save <name> to save your current session.\n");
|
|
11851
|
+
break;
|
|
11852
|
+
}
|
|
11853
|
+
const handleSessionSelect = async (selectedSession) => {
|
|
11854
|
+
setState((prev) => ({ ...prev, sessionSelector: null }));
|
|
11855
|
+
if (!selectedSession) {
|
|
11856
|
+
console.log("\u274C Session selection cancelled");
|
|
11857
|
+
return;
|
|
11858
|
+
}
|
|
11859
|
+
const loadedSession = await state.sessionStore.load(selectedSession.id);
|
|
11860
|
+
if (!loadedSession) {
|
|
11861
|
+
console.log(`\u274C Failed to load session: ${selectedSession.name}`);
|
|
11862
|
+
console.log(" The session file may be corrupted or deleted.");
|
|
11863
|
+
return;
|
|
11864
|
+
}
|
|
11865
|
+
await logger.initialize(loadedSession.id);
|
|
11866
|
+
logger.debug("=== Session Resumed ===");
|
|
11867
|
+
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
11868
|
+
setStoreSession(loadedSession);
|
|
11869
|
+
useCliStore.getState().clearAgentSteps();
|
|
11870
|
+
usageCache = null;
|
|
11871
|
+
console.log(`
|
|
11872
|
+
\u2705 Session resumed: "${loadedSession.name}"`);
|
|
11873
|
+
console.log(
|
|
11874
|
+
`\u{1F4DD} ${loadedSession.messages.length} messages | \u{1F916} ${loadedSession.model} | \u{1F4CA} ${loadedSession.metadata.totalTokens.toLocaleString()} tokens
|
|
11875
|
+
`
|
|
11876
|
+
);
|
|
11877
|
+
};
|
|
11878
|
+
setState((prev) => ({
|
|
11879
|
+
...prev,
|
|
11880
|
+
sessionSelector: { sessions, resolve: handleSessionSelect }
|
|
11881
|
+
}));
|
|
11154
11882
|
break;
|
|
11883
|
+
}
|
|
11155
11884
|
case "config": {
|
|
11156
11885
|
setShowConfigEditor(true);
|
|
11157
11886
|
break;
|
|
@@ -11589,15 +12318,36 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11589
12318
|
};
|
|
11590
12319
|
const handleSaveConfig = async (updatedConfig) => {
|
|
11591
12320
|
await state.configStore.save(updatedConfig);
|
|
11592
|
-
|
|
12321
|
+
const modelChanged = state.config?.defaultModel !== updatedConfig.defaultModel;
|
|
12322
|
+
setState((prev) => {
|
|
12323
|
+
if (modelChanged && prev.session) {
|
|
12324
|
+
const updatedSession = {
|
|
12325
|
+
...prev.session,
|
|
12326
|
+
model: updatedConfig.defaultModel,
|
|
12327
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12328
|
+
};
|
|
12329
|
+
setStoreSession(updatedSession);
|
|
12330
|
+
if (prev.agent) {
|
|
12331
|
+
prev.agent.context.model = updatedConfig.defaultModel;
|
|
12332
|
+
}
|
|
12333
|
+
return { ...prev, config: updatedConfig, session: updatedSession };
|
|
12334
|
+
}
|
|
12335
|
+
return { ...prev, config: updatedConfig };
|
|
12336
|
+
});
|
|
12337
|
+
if (modelChanged && state.agent) {
|
|
12338
|
+
const llm = state.agent.context.llm;
|
|
12339
|
+
if (llm) {
|
|
12340
|
+
llm.currentModel = updatedConfig.defaultModel;
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
11593
12343
|
};
|
|
11594
12344
|
if (initError) {
|
|
11595
|
-
return /* @__PURE__ */
|
|
12345
|
+
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
12346
|
}
|
|
11597
12347
|
if (state.trustLocationSelector) {
|
|
11598
12348
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
11599
12349
|
const inProject = projectDir !== null;
|
|
11600
|
-
return /* @__PURE__ */
|
|
12350
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11601
12351
|
TrustLocationSelector,
|
|
11602
12352
|
{
|
|
11603
12353
|
inProject,
|
|
@@ -11615,7 +12365,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11615
12365
|
);
|
|
11616
12366
|
}
|
|
11617
12367
|
if (state.rewindSelector && state.session) {
|
|
11618
|
-
return /* @__PURE__ */
|
|
12368
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11619
12369
|
RewindSelector,
|
|
11620
12370
|
{
|
|
11621
12371
|
messages: state.session.messages,
|
|
@@ -11632,9 +12382,28 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11632
12382
|
}
|
|
11633
12383
|
);
|
|
11634
12384
|
}
|
|
12385
|
+
if (state.sessionSelector) {
|
|
12386
|
+
return /* @__PURE__ */ React16.createElement(
|
|
12387
|
+
SessionSelector,
|
|
12388
|
+
{
|
|
12389
|
+
sessions: state.sessionSelector.sessions,
|
|
12390
|
+
currentSession: state.session,
|
|
12391
|
+
onSelect: (session) => {
|
|
12392
|
+
if (state.sessionSelector) {
|
|
12393
|
+
state.sessionSelector.resolve(session);
|
|
12394
|
+
}
|
|
12395
|
+
},
|
|
12396
|
+
onCancel: () => {
|
|
12397
|
+
if (state.sessionSelector) {
|
|
12398
|
+
state.sessionSelector.resolve(null);
|
|
12399
|
+
}
|
|
12400
|
+
}
|
|
12401
|
+
}
|
|
12402
|
+
);
|
|
12403
|
+
}
|
|
11635
12404
|
if (state.showLoginFlow) {
|
|
11636
12405
|
const loginApiUrl = getApiUrl(state.config?.apiConfig);
|
|
11637
|
-
return /* @__PURE__ */
|
|
12406
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11638
12407
|
LoginFlow,
|
|
11639
12408
|
{
|
|
11640
12409
|
apiUrl: loginApiUrl,
|
|
@@ -11657,13 +12426,14 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11657
12426
|
);
|
|
11658
12427
|
}
|
|
11659
12428
|
if (!isInitialized) {
|
|
11660
|
-
return /* @__PURE__ */
|
|
12429
|
+
return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React16.createElement(Text15, null, "\u{1F680} Initializing..."));
|
|
11661
12430
|
}
|
|
11662
|
-
return /* @__PURE__ */
|
|
12431
|
+
return /* @__PURE__ */ React16.createElement(
|
|
11663
12432
|
App,
|
|
11664
12433
|
{
|
|
11665
12434
|
onMessage: handleMessage,
|
|
11666
12435
|
onCommand: handleCommand,
|
|
12436
|
+
onBashCommand: handleBashCommand,
|
|
11667
12437
|
onImageDetected: handleImageDetected,
|
|
11668
12438
|
commandHistory,
|
|
11669
12439
|
config: state.config,
|
|
@@ -11698,6 +12468,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
|
|
|
11698
12468
|
if (isDevMode) {
|
|
11699
12469
|
console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
|
|
11700
12470
|
}
|
|
11701
|
-
render(/* @__PURE__ */
|
|
12471
|
+
render(/* @__PURE__ */ React16.createElement(CliApp, null), {
|
|
11702
12472
|
exitOnCtrlC: false
|
|
11703
12473
|
});
|