@bike4mind/cli 0.2.5-fix-github-issue-type.17095 → 0.2.6-fix-cli-mcp-type-mismatch.17119
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 +50 -4
- package/dist/{artifactExtractor-XKSGESLB.js → artifactExtractor-DNE5C6DY.js} +1 -1
- package/dist/{chunk-MPZQL3KY.js → chunk-3CCBDIFR.js} +2 -2
- package/dist/{chunk-KH2C4VVX.js → chunk-DNSBC3LO.js} +1 -1
- package/dist/{chunk-7Y3E4OY6.js → chunk-H6SHASMZ.js} +33 -1
- package/dist/{chunk-PKOGN2ZZ.js → chunk-LIRY24M5.js} +2 -2
- package/dist/{chunk-TPWKBMIZ.js → chunk-YXHQN7SK.js} +2 -2
- package/dist/{create-VQAEHGW2.js → create-PNU64QSF.js} +3 -3
- package/dist/index.js +841 -222
- package/dist/{llmMarkdownGenerator-2CYNNMDZ.js → llmMarkdownGenerator-UQXKK2AS.js} +1 -1
- package/dist/{markdownGenerator-ILNTIASI.js → markdownGenerator-FLLZFXMT.js} +1 -1
- package/dist/{mementoService-ZQFTU4CW.js → mementoService-LVFQ5XAW.js} +3 -3
- package/dist/{src-RDXIYUAV.js → src-OH5AAQEW.js} +2 -2
- package/dist/{src-U3DNYA5K.js → src-OYQXRLTM.js} +3 -1
- package/dist/{subtractCredits-FHCRDFZ3.js → subtractCredits-75VT7HP2.js} +3 -3
- package/package.json +6 -6
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-3CCBDIFR.js";
|
|
8
|
+
import "./chunk-LIRY24M5.js";
|
|
9
|
+
import "./chunk-YXHQN7SK.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-DNSBC3LO.js";
|
|
19
19
|
import {
|
|
20
20
|
Logger
|
|
21
21
|
} from "./chunk-AMDXHL6S.js";
|
|
@@ -73,14 +73,14 @@ import {
|
|
|
73
73
|
XAI_IMAGE_MODELS,
|
|
74
74
|
b4mLLMTools,
|
|
75
75
|
getMcpProviderMetadata
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-H6SHASMZ.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 React13, { useState as useState4, useEffect as useEffect3, useCallback } from "react";
|
|
83
|
+
import { render, Box as Box13, Text as Text12, useApp, useInput as useInput3 } from "ink";
|
|
84
84
|
import { v4 as uuidv49 } from "uuid";
|
|
85
85
|
|
|
86
86
|
// src/components/App.tsx
|
|
@@ -685,103 +685,128 @@ var EXPORT_FORMAT_OPTIONS = [
|
|
|
685
685
|
{ label: "markdown", value: "markdown" },
|
|
686
686
|
{ label: "json", value: "json" }
|
|
687
687
|
];
|
|
688
|
-
|
|
689
|
-
{
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
step: 256,
|
|
710
|
-
getValue: (config) => config.preferences.maxTokens,
|
|
711
|
-
setValue: (config, value) => ({
|
|
712
|
-
...config,
|
|
713
|
-
preferences: {
|
|
714
|
-
...config.preferences,
|
|
715
|
-
maxTokens: value
|
|
716
|
-
}
|
|
717
|
-
})
|
|
718
|
-
},
|
|
719
|
-
{
|
|
720
|
-
key: "temperature",
|
|
721
|
-
label: "Temperature",
|
|
722
|
-
type: "number",
|
|
723
|
-
min: 0,
|
|
724
|
-
max: 2,
|
|
725
|
-
step: 0.1,
|
|
726
|
-
getValue: (config) => config.preferences.temperature,
|
|
727
|
-
setValue: (config, value) => ({
|
|
728
|
-
...config,
|
|
729
|
-
preferences: {
|
|
730
|
-
...config.preferences,
|
|
731
|
-
temperature: value
|
|
732
|
-
}
|
|
733
|
-
})
|
|
734
|
-
},
|
|
735
|
-
{
|
|
736
|
-
key: "autoSave",
|
|
737
|
-
label: "Auto Save",
|
|
738
|
-
type: "boolean",
|
|
739
|
-
getValue: (config) => config.preferences.autoSave,
|
|
740
|
-
setValue: (config, value) => ({
|
|
741
|
-
...config,
|
|
742
|
-
preferences: {
|
|
743
|
-
...config.preferences,
|
|
744
|
-
autoSave: value
|
|
745
|
-
}
|
|
746
|
-
})
|
|
747
|
-
},
|
|
748
|
-
{
|
|
749
|
-
key: "theme",
|
|
750
|
-
label: "Theme",
|
|
751
|
-
type: "select",
|
|
752
|
-
options: THEME_OPTIONS,
|
|
753
|
-
getValue: (config) => config.preferences.theme,
|
|
754
|
-
setValue: (config, value) => ({
|
|
755
|
-
...config,
|
|
756
|
-
preferences: {
|
|
757
|
-
...config.preferences,
|
|
758
|
-
theme: value
|
|
759
|
-
}
|
|
760
|
-
})
|
|
761
|
-
},
|
|
762
|
-
{
|
|
763
|
-
key: "exportFormat",
|
|
764
|
-
label: "Export Format",
|
|
765
|
-
type: "select",
|
|
766
|
-
options: EXPORT_FORMAT_OPTIONS,
|
|
767
|
-
getValue: (config) => config.preferences.exportFormat,
|
|
768
|
-
setValue: (config, value) => ({
|
|
769
|
-
...config,
|
|
770
|
-
preferences: {
|
|
771
|
-
...config.preferences,
|
|
772
|
-
exportFormat: value
|
|
773
|
-
}
|
|
774
|
-
})
|
|
688
|
+
function buildConfigItems(availableModels) {
|
|
689
|
+
const modelOptions = availableModels.map((model) => ({
|
|
690
|
+
label: model.name,
|
|
691
|
+
value: model.id
|
|
692
|
+
}));
|
|
693
|
+
const items = [];
|
|
694
|
+
if (modelOptions.length > 0) {
|
|
695
|
+
items.push({
|
|
696
|
+
key: "model",
|
|
697
|
+
label: "Model",
|
|
698
|
+
type: "select",
|
|
699
|
+
options: modelOptions,
|
|
700
|
+
getValue: (config) => {
|
|
701
|
+
const modelExists = modelOptions.some((opt) => opt.value === config.defaultModel);
|
|
702
|
+
return modelExists ? config.defaultModel : modelOptions[0]?.value ?? config.defaultModel;
|
|
703
|
+
},
|
|
704
|
+
setValue: (config, value) => ({
|
|
705
|
+
...config,
|
|
706
|
+
defaultModel: value
|
|
707
|
+
})
|
|
708
|
+
});
|
|
775
709
|
}
|
|
776
|
-
|
|
777
|
-
|
|
710
|
+
items.push(
|
|
711
|
+
{
|
|
712
|
+
key: "maxIterations",
|
|
713
|
+
label: "Max Iterations",
|
|
714
|
+
type: "select",
|
|
715
|
+
options: MAX_ITERATIONS_OPTIONS,
|
|
716
|
+
getValue: (config) => config.preferences.maxIterations,
|
|
717
|
+
setValue: (config, value) => ({
|
|
718
|
+
...config,
|
|
719
|
+
preferences: {
|
|
720
|
+
...config.preferences,
|
|
721
|
+
maxIterations: value
|
|
722
|
+
}
|
|
723
|
+
})
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
key: "maxTokens",
|
|
727
|
+
label: "Max Tokens",
|
|
728
|
+
type: "number",
|
|
729
|
+
min: 256,
|
|
730
|
+
max: 128e3,
|
|
731
|
+
step: 256,
|
|
732
|
+
getValue: (config) => config.preferences.maxTokens,
|
|
733
|
+
setValue: (config, value) => ({
|
|
734
|
+
...config,
|
|
735
|
+
preferences: {
|
|
736
|
+
...config.preferences,
|
|
737
|
+
maxTokens: value
|
|
738
|
+
}
|
|
739
|
+
})
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
key: "temperature",
|
|
743
|
+
label: "Temperature",
|
|
744
|
+
type: "number",
|
|
745
|
+
min: 0,
|
|
746
|
+
max: 2,
|
|
747
|
+
step: 0.1,
|
|
748
|
+
getValue: (config) => config.preferences.temperature,
|
|
749
|
+
setValue: (config, value) => ({
|
|
750
|
+
...config,
|
|
751
|
+
preferences: {
|
|
752
|
+
...config.preferences,
|
|
753
|
+
temperature: value
|
|
754
|
+
}
|
|
755
|
+
})
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
key: "autoSave",
|
|
759
|
+
label: "Auto Save",
|
|
760
|
+
type: "boolean",
|
|
761
|
+
getValue: (config) => config.preferences.autoSave,
|
|
762
|
+
setValue: (config, value) => ({
|
|
763
|
+
...config,
|
|
764
|
+
preferences: {
|
|
765
|
+
...config.preferences,
|
|
766
|
+
autoSave: value
|
|
767
|
+
}
|
|
768
|
+
})
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
key: "theme",
|
|
772
|
+
label: "Theme",
|
|
773
|
+
type: "select",
|
|
774
|
+
options: THEME_OPTIONS,
|
|
775
|
+
getValue: (config) => config.preferences.theme,
|
|
776
|
+
setValue: (config, value) => ({
|
|
777
|
+
...config,
|
|
778
|
+
preferences: {
|
|
779
|
+
...config.preferences,
|
|
780
|
+
theme: value
|
|
781
|
+
}
|
|
782
|
+
})
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
key: "exportFormat",
|
|
786
|
+
label: "Export Format",
|
|
787
|
+
type: "select",
|
|
788
|
+
options: EXPORT_FORMAT_OPTIONS,
|
|
789
|
+
getValue: (config) => config.preferences.exportFormat,
|
|
790
|
+
setValue: (config, value) => ({
|
|
791
|
+
...config,
|
|
792
|
+
preferences: {
|
|
793
|
+
...config.preferences,
|
|
794
|
+
exportFormat: value
|
|
795
|
+
}
|
|
796
|
+
})
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
return items;
|
|
800
|
+
}
|
|
801
|
+
function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
778
802
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
779
803
|
const [editedConfig, setEditedConfig] = useState2(config);
|
|
780
804
|
const [saveError, setSaveError] = useState2(null);
|
|
781
805
|
const [isSaving, setIsSaving] = useState2(false);
|
|
806
|
+
const configItems = useMemo2(() => buildConfigItems(availableModels), [availableModels]);
|
|
782
807
|
const hasChanges = useMemo2(() => {
|
|
783
|
-
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences);
|
|
784
|
-
}, [config.preferences, editedConfig.preferences]);
|
|
808
|
+
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
|
|
809
|
+
}, [config.preferences, editedConfig.preferences, config.defaultModel, editedConfig.defaultModel]);
|
|
785
810
|
const handleSaveAndClose = async () => {
|
|
786
811
|
if (hasChanges) {
|
|
787
812
|
try {
|
|
@@ -798,13 +823,13 @@ function ConfigEditor({ config, onSave, onClose }) {
|
|
|
798
823
|
onClose();
|
|
799
824
|
};
|
|
800
825
|
useInput2((input, key) => {
|
|
801
|
-
const currentItem =
|
|
826
|
+
const currentItem = configItems[selectedIndex];
|
|
802
827
|
if (key.upArrow) {
|
|
803
|
-
setSelectedIndex((prev) => prev > 0 ? prev - 1 :
|
|
828
|
+
setSelectedIndex((prev) => prev > 0 ? prev - 1 : configItems.length - 1);
|
|
804
829
|
return;
|
|
805
830
|
}
|
|
806
831
|
if (key.downArrow) {
|
|
807
|
-
setSelectedIndex((prev) => prev <
|
|
832
|
+
setSelectedIndex((prev) => prev < configItems.length - 1 ? prev + 1 : 0);
|
|
808
833
|
return;
|
|
809
834
|
}
|
|
810
835
|
if ((key.escape || input === "q") && !isSaving) {
|
|
@@ -862,7 +887,7 @@ function ConfigEditor({ config, onSave, onClose }) {
|
|
|
862
887
|
}
|
|
863
888
|
return String(value);
|
|
864
889
|
};
|
|
865
|
-
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "space-between", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, "Settings"), isSaving ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "Saving...") : hasChanges ? /* @__PURE__ */ React8.createElement(Text7, { dimColor: true, color: "yellow" }, "(unsaved changes)") : null), saveError && /* @__PURE__ */ React8.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red" }, "Error: ", saveError)), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginBottom: 1 },
|
|
890
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "space-between", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, "Settings"), isSaving ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "Saving...") : hasChanges ? /* @__PURE__ */ React8.createElement(Text7, { dimColor: true, color: "yellow" }, "(unsaved changes)") : null), saveError && /* @__PURE__ */ React8.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red" }, "Error: ", saveError)), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginBottom: 1 }, configItems.map((item, index) => {
|
|
866
891
|
const isSelected = index === selectedIndex;
|
|
867
892
|
const value = item.getValue(editedConfig);
|
|
868
893
|
const displayValue = formatValue(item, value);
|
|
@@ -992,6 +1017,7 @@ function App({
|
|
|
992
1017
|
onPermissionResponse,
|
|
993
1018
|
commandHistory = [],
|
|
994
1019
|
config,
|
|
1020
|
+
availableModels = [],
|
|
995
1021
|
onSaveConfig
|
|
996
1022
|
}) {
|
|
997
1023
|
const messages = useCliStore((state) => state.session?.messages || []);
|
|
@@ -1033,7 +1059,15 @@ ${errorBlock}`;
|
|
|
1033
1059
|
},
|
|
1034
1060
|
[onMessage, onCommand, setIsThinking]
|
|
1035
1061
|
);
|
|
1036
|
-
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), showConfigEditor && config && onSaveConfig ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
|
|
1062
|
+
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), showConfigEditor && config && onSaveConfig ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
|
|
1063
|
+
ConfigEditor,
|
|
1064
|
+
{
|
|
1065
|
+
config,
|
|
1066
|
+
availableModels,
|
|
1067
|
+
onSave: onSaveConfig,
|
|
1068
|
+
onClose: () => setShowConfigEditor(false)
|
|
1069
|
+
}
|
|
1070
|
+
)) : permissionPrompt ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
|
|
1037
1071
|
PermissionPrompt,
|
|
1038
1072
|
{
|
|
1039
1073
|
toolName: permissionPrompt.toolName,
|
|
@@ -1099,9 +1133,42 @@ var MessageList = React10.memo(
|
|
|
1099
1133
|
}
|
|
1100
1134
|
);
|
|
1101
1135
|
|
|
1102
|
-
// src/components/
|
|
1103
|
-
import React11
|
|
1136
|
+
// src/components/TrustLocationSelector.tsx
|
|
1137
|
+
import React11 from "react";
|
|
1104
1138
|
import { Box as Box11, Text as Text10 } from "ink";
|
|
1139
|
+
import SelectInput2 from "ink-select-input";
|
|
1140
|
+
function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
1141
|
+
const items = [];
|
|
1142
|
+
if (inProject) {
|
|
1143
|
+
items.push({
|
|
1144
|
+
label: "Project settings (local) - Saved in .bike4mind/local.json (not committed)",
|
|
1145
|
+
value: "local"
|
|
1146
|
+
});
|
|
1147
|
+
items.push({
|
|
1148
|
+
label: "Project settings (team-wide) - Checked in at .bike4mind/config.json",
|
|
1149
|
+
value: "project"
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
items.push({
|
|
1153
|
+
label: "User settings - Saved at ~/.bike4mind/config.json",
|
|
1154
|
+
value: "global"
|
|
1155
|
+
});
|
|
1156
|
+
const handleSelect = (item) => {
|
|
1157
|
+
onSelect(item.value);
|
|
1158
|
+
};
|
|
1159
|
+
return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React11.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "Where should this rule be saved?")), /* @__PURE__ */ React11.createElement(
|
|
1160
|
+
SelectInput2,
|
|
1161
|
+
{
|
|
1162
|
+
items,
|
|
1163
|
+
onSelect: handleSelect,
|
|
1164
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text10, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1165
|
+
}
|
|
1166
|
+
), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Ctrl+C to cancel")));
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// src/components/LoginFlow.tsx
|
|
1170
|
+
import React12, { useState as useState3, useEffect as useEffect2 } from "react";
|
|
1171
|
+
import { Box as Box12, Text as Text11 } from "ink";
|
|
1105
1172
|
import Spinner2 from "ink-spinner";
|
|
1106
1173
|
import jwt from "jsonwebtoken";
|
|
1107
1174
|
import open from "open";
|
|
@@ -1264,15 +1331,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
1264
1331
|
}
|
|
1265
1332
|
}, [deviceFlow, status]);
|
|
1266
1333
|
if (status === "initiating") {
|
|
1267
|
-
return /* @__PURE__ */
|
|
1334
|
+
return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, /* @__PURE__ */ React12.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
|
|
1268
1335
|
}
|
|
1269
1336
|
if (status === "error") {
|
|
1270
|
-
return /* @__PURE__ */
|
|
1337
|
+
return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: "red" }, error)));
|
|
1271
1338
|
}
|
|
1272
1339
|
if (status === "success") {
|
|
1273
|
-
return /* @__PURE__ */
|
|
1340
|
+
return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "You can now use B4M CLI with your account.")));
|
|
1274
1341
|
}
|
|
1275
|
-
return /* @__PURE__ */
|
|
1342
|
+
return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, null, "And enter this code when prompted:")), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React12.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, /* @__PURE__ */ React12.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React12.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
|
|
1276
1343
|
}
|
|
1277
1344
|
|
|
1278
1345
|
// src/storage/SessionStore.ts
|
|
@@ -1394,7 +1461,7 @@ var SessionStore = class {
|
|
|
1394
1461
|
};
|
|
1395
1462
|
|
|
1396
1463
|
// src/storage/ConfigStore.ts
|
|
1397
|
-
import { promises as fs4 } from "fs";
|
|
1464
|
+
import { promises as fs4, existsSync as existsSync2 } from "fs";
|
|
1398
1465
|
import path4 from "path";
|
|
1399
1466
|
import { homedir as homedir2 } from "os";
|
|
1400
1467
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -1421,8 +1488,8 @@ var CliConfigSchema = z.object({
|
|
|
1421
1488
|
mcpServers: z.array(
|
|
1422
1489
|
z.object({
|
|
1423
1490
|
name: z.string(),
|
|
1424
|
-
command: z.string(),
|
|
1425
|
-
args: z.array(z.string()),
|
|
1491
|
+
command: z.string().optional(),
|
|
1492
|
+
args: z.array(z.string()).optional(),
|
|
1426
1493
|
env: z.record(z.string()),
|
|
1427
1494
|
enabled: z.boolean()
|
|
1428
1495
|
})
|
|
@@ -1442,6 +1509,53 @@ var CliConfigSchema = z.object({
|
|
|
1442
1509
|
}),
|
|
1443
1510
|
trustedTools: z.array(z.string()).optional().default([])
|
|
1444
1511
|
});
|
|
1512
|
+
var ProjectConfigSchema = z.object({
|
|
1513
|
+
tools: z.object({
|
|
1514
|
+
enabled: z.array(z.string()).optional(),
|
|
1515
|
+
denied: z.array(z.string()).optional(),
|
|
1516
|
+
config: z.record(z.any()).optional()
|
|
1517
|
+
}).optional(),
|
|
1518
|
+
defaultModel: z.string().optional(),
|
|
1519
|
+
mcpServers: z.array(
|
|
1520
|
+
z.object({
|
|
1521
|
+
name: z.string(),
|
|
1522
|
+
command: z.string().optional(),
|
|
1523
|
+
args: z.array(z.string()).optional(),
|
|
1524
|
+
env: z.record(z.string()),
|
|
1525
|
+
enabled: z.boolean()
|
|
1526
|
+
})
|
|
1527
|
+
).optional(),
|
|
1528
|
+
preferences: z.object({
|
|
1529
|
+
maxTokens: z.number().optional(),
|
|
1530
|
+
temperature: z.number().optional(),
|
|
1531
|
+
autoSave: z.boolean().optional(),
|
|
1532
|
+
theme: z.enum(["light", "dark"]).optional(),
|
|
1533
|
+
exportFormat: z.enum(["markdown", "json"]).optional()
|
|
1534
|
+
}).optional()
|
|
1535
|
+
});
|
|
1536
|
+
var ProjectLocalConfigSchema = z.object({
|
|
1537
|
+
trustedTools: z.array(z.string()).optional(),
|
|
1538
|
+
toolApiKeys: z.object({
|
|
1539
|
+
openweather: z.string().optional(),
|
|
1540
|
+
serper: z.string().optional()
|
|
1541
|
+
}).optional(),
|
|
1542
|
+
preferences: z.object({
|
|
1543
|
+
maxTokens: z.number().optional(),
|
|
1544
|
+
temperature: z.number().optional(),
|
|
1545
|
+
autoSave: z.boolean().optional(),
|
|
1546
|
+
theme: z.enum(["light", "dark"]).optional(),
|
|
1547
|
+
exportFormat: z.enum(["markdown", "json"]).optional()
|
|
1548
|
+
}).optional(),
|
|
1549
|
+
mcpServers: z.array(
|
|
1550
|
+
z.object({
|
|
1551
|
+
name: z.string(),
|
|
1552
|
+
command: z.string().optional(),
|
|
1553
|
+
args: z.array(z.string()).optional(),
|
|
1554
|
+
env: z.record(z.string()),
|
|
1555
|
+
enabled: z.boolean()
|
|
1556
|
+
})
|
|
1557
|
+
).optional()
|
|
1558
|
+
});
|
|
1445
1559
|
var DEFAULT_CONFIG = {
|
|
1446
1560
|
version: "0.1.0",
|
|
1447
1561
|
userId: uuidv4(),
|
|
@@ -1468,9 +1582,124 @@ var DEFAULT_CONFIG = {
|
|
|
1468
1582
|
trustedTools: []
|
|
1469
1583
|
// No tools trusted by default
|
|
1470
1584
|
};
|
|
1585
|
+
function findProjectConfigDir(startDir = process.cwd()) {
|
|
1586
|
+
let currentDir = startDir;
|
|
1587
|
+
const { root } = path4.parse(currentDir);
|
|
1588
|
+
while (currentDir !== root) {
|
|
1589
|
+
const gitPath = path4.join(currentDir, ".git");
|
|
1590
|
+
try {
|
|
1591
|
+
if (existsSync2(gitPath)) {
|
|
1592
|
+
return currentDir;
|
|
1593
|
+
}
|
|
1594
|
+
} catch {
|
|
1595
|
+
}
|
|
1596
|
+
currentDir = path4.dirname(currentDir);
|
|
1597
|
+
}
|
|
1598
|
+
return process.cwd();
|
|
1599
|
+
}
|
|
1600
|
+
async function loadProjectConfig(projectDir) {
|
|
1601
|
+
const configPath = path4.join(projectDir, ".bike4mind", "config.json");
|
|
1602
|
+
try {
|
|
1603
|
+
const data = await fs4.readFile(configPath, "utf-8");
|
|
1604
|
+
const rawConfig = JSON.parse(data);
|
|
1605
|
+
const validated = ProjectConfigSchema.parse(rawConfig);
|
|
1606
|
+
return validated;
|
|
1607
|
+
} catch (error) {
|
|
1608
|
+
if (error.code === "ENOENT") {
|
|
1609
|
+
return null;
|
|
1610
|
+
}
|
|
1611
|
+
if (error instanceof z.ZodError) {
|
|
1612
|
+
console.error("Project config validation error:", error.errors);
|
|
1613
|
+
return null;
|
|
1614
|
+
}
|
|
1615
|
+
console.error("Failed to load project config:", error);
|
|
1616
|
+
return null;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
async function loadProjectLocalConfig(projectDir) {
|
|
1620
|
+
const configPath = path4.join(projectDir, ".bike4mind", "local.json");
|
|
1621
|
+
try {
|
|
1622
|
+
const data = await fs4.readFile(configPath, "utf-8");
|
|
1623
|
+
const rawConfig = JSON.parse(data);
|
|
1624
|
+
const validated = ProjectLocalConfigSchema.parse(rawConfig);
|
|
1625
|
+
return validated;
|
|
1626
|
+
} catch (error) {
|
|
1627
|
+
if (error.code === "ENOENT") {
|
|
1628
|
+
return null;
|
|
1629
|
+
}
|
|
1630
|
+
if (error instanceof z.ZodError) {
|
|
1631
|
+
console.error("Project local config validation error:", error.errors);
|
|
1632
|
+
return null;
|
|
1633
|
+
}
|
|
1634
|
+
console.error("Failed to load project local config:", error);
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
function mergeMcpServers(...serverArrays) {
|
|
1639
|
+
const serverMap = /* @__PURE__ */ new Map();
|
|
1640
|
+
for (const servers of serverArrays) {
|
|
1641
|
+
if (servers) {
|
|
1642
|
+
for (const server of servers) {
|
|
1643
|
+
serverMap.set(server.name, server);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
return Array.from(serverMap.values());
|
|
1648
|
+
}
|
|
1649
|
+
function mergeConfigs(global, project, local) {
|
|
1650
|
+
const merged = { ...global };
|
|
1651
|
+
if (project) {
|
|
1652
|
+
if (project.defaultModel) {
|
|
1653
|
+
merged.defaultModel = project.defaultModel;
|
|
1654
|
+
}
|
|
1655
|
+
if (project.preferences) {
|
|
1656
|
+
merged.preferences = {
|
|
1657
|
+
...merged.preferences,
|
|
1658
|
+
...project.preferences
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
if (project.tools) {
|
|
1662
|
+
merged.tools = {
|
|
1663
|
+
...merged.tools,
|
|
1664
|
+
enabled: [...merged.tools.enabled || [], ...project.tools.enabled || []],
|
|
1665
|
+
disabled: [...merged.tools.disabled, ...project.tools.denied || []],
|
|
1666
|
+
config: {
|
|
1667
|
+
...merged.tools.config,
|
|
1668
|
+
...project.tools.config
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
if (project.mcpServers) {
|
|
1673
|
+
merged.mcpServers = mergeMcpServers(merged.mcpServers, project.mcpServers);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
if (local) {
|
|
1677
|
+
if (local.trustedTools) {
|
|
1678
|
+
const trustedSet = /* @__PURE__ */ new Set([...merged.trustedTools || [], ...local.trustedTools]);
|
|
1679
|
+
merged.trustedTools = Array.from(trustedSet);
|
|
1680
|
+
}
|
|
1681
|
+
if (local.toolApiKeys) {
|
|
1682
|
+
merged.toolApiKeys = {
|
|
1683
|
+
...merged.toolApiKeys,
|
|
1684
|
+
...local.toolApiKeys
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
if (local.preferences) {
|
|
1688
|
+
merged.preferences = {
|
|
1689
|
+
...merged.preferences,
|
|
1690
|
+
...local.preferences
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
if (local.mcpServers) {
|
|
1694
|
+
merged.mcpServers = mergeMcpServers(merged.mcpServers, local.mcpServers);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
return merged;
|
|
1698
|
+
}
|
|
1471
1699
|
var ConfigStore = class {
|
|
1472
1700
|
constructor(configPath) {
|
|
1473
1701
|
this.config = null;
|
|
1702
|
+
this.projectConfigDir = null;
|
|
1474
1703
|
this.configPath = configPath || path4.join(homedir2(), ".bike4mind", "config.json");
|
|
1475
1704
|
}
|
|
1476
1705
|
/**
|
|
@@ -1487,51 +1716,76 @@ var ConfigStore = class {
|
|
|
1487
1716
|
}
|
|
1488
1717
|
/**
|
|
1489
1718
|
* Load configuration from disk with Zod validation
|
|
1719
|
+
* Merges global → project → local configs
|
|
1490
1720
|
*/
|
|
1491
1721
|
async load() {
|
|
1492
1722
|
if (this.config) {
|
|
1493
1723
|
return this.config;
|
|
1494
1724
|
}
|
|
1495
1725
|
try {
|
|
1726
|
+
let globalConfig;
|
|
1496
1727
|
try {
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1728
|
+
try {
|
|
1729
|
+
const stats = await fs4.stat(this.configPath);
|
|
1730
|
+
const mode = stats.mode & 511;
|
|
1731
|
+
if (mode !== 384) {
|
|
1732
|
+
console.warn(`\u26A0\uFE0F Config file has insecure permissions (${mode.toString(8)}). Setting to 0600...`);
|
|
1733
|
+
await fs4.chmod(this.configPath, 384);
|
|
1734
|
+
}
|
|
1735
|
+
} catch (statError) {
|
|
1736
|
+
}
|
|
1737
|
+
const data = await fs4.readFile(this.configPath, "utf-8");
|
|
1738
|
+
const rawConfig = JSON.parse(data);
|
|
1739
|
+
if (rawConfig.apiConfig && "environment" in rawConfig.apiConfig) {
|
|
1740
|
+
const oldApiConfig = rawConfig.apiConfig;
|
|
1741
|
+
if (oldApiConfig.environment === "custom" && oldApiConfig.customUrl) {
|
|
1742
|
+
rawConfig.apiConfig = { customUrl: oldApiConfig.customUrl };
|
|
1743
|
+
} else {
|
|
1744
|
+
rawConfig.apiConfig = {};
|
|
1745
|
+
}
|
|
1502
1746
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1747
|
+
const validated = CliConfigSchema.parse(rawConfig);
|
|
1748
|
+
globalConfig = {
|
|
1749
|
+
...DEFAULT_CONFIG,
|
|
1750
|
+
...validated,
|
|
1751
|
+
auth: validated.auth,
|
|
1752
|
+
// Explicitly preserve auth field
|
|
1753
|
+
preferences: {
|
|
1754
|
+
...DEFAULT_CONFIG.preferences,
|
|
1755
|
+
...validated.preferences
|
|
1756
|
+
},
|
|
1757
|
+
tools: {
|
|
1758
|
+
...DEFAULT_CONFIG.tools,
|
|
1759
|
+
...validated.tools
|
|
1760
|
+
},
|
|
1761
|
+
toolApiKeys: {
|
|
1762
|
+
...DEFAULT_CONFIG.toolApiKeys,
|
|
1763
|
+
...validated.toolApiKeys || {}
|
|
1764
|
+
},
|
|
1765
|
+
trustedTools: validated.trustedTools || []
|
|
1766
|
+
};
|
|
1767
|
+
} catch (error) {
|
|
1768
|
+
if (error.code === "ENOENT") {
|
|
1769
|
+
globalConfig = { ...DEFAULT_CONFIG };
|
|
1770
|
+
} else if (error instanceof z.ZodError) {
|
|
1771
|
+
console.error("Global config validation error:", error.errors);
|
|
1772
|
+
console.error("Using default configuration");
|
|
1773
|
+
globalConfig = { ...DEFAULT_CONFIG };
|
|
1511
1774
|
} else {
|
|
1512
|
-
|
|
1775
|
+
throw error;
|
|
1513
1776
|
}
|
|
1514
1777
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
...DEFAULT_CONFIG.tools,
|
|
1527
|
-
...validated.tools
|
|
1528
|
-
},
|
|
1529
|
-
toolApiKeys: {
|
|
1530
|
-
...DEFAULT_CONFIG.toolApiKeys,
|
|
1531
|
-
...validated.toolApiKeys || {}
|
|
1532
|
-
},
|
|
1533
|
-
trustedTools: validated.trustedTools || []
|
|
1534
|
-
};
|
|
1778
|
+
this.projectConfigDir = findProjectConfigDir();
|
|
1779
|
+
let projectConfig = null;
|
|
1780
|
+
let projectLocalConfig = null;
|
|
1781
|
+
if (this.projectConfigDir) {
|
|
1782
|
+
projectConfig = await loadProjectConfig(this.projectConfigDir);
|
|
1783
|
+
projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
|
|
1784
|
+
if (projectConfig) {
|
|
1785
|
+
console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
this.config = mergeConfigs(globalConfig, projectConfig, projectLocalConfig);
|
|
1535
1789
|
return this.config;
|
|
1536
1790
|
} catch (error) {
|
|
1537
1791
|
if (error.code === "ENOENT") {
|
|
@@ -1720,6 +1974,92 @@ var ConfigStore = class {
|
|
|
1720
1974
|
}
|
|
1721
1975
|
await this.save(config);
|
|
1722
1976
|
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Get project config directory (if any)
|
|
1979
|
+
*/
|
|
1980
|
+
getProjectConfigDir() {
|
|
1981
|
+
return this.projectConfigDir;
|
|
1982
|
+
}
|
|
1983
|
+
/**
|
|
1984
|
+
* Initialize project config directory
|
|
1985
|
+
* Creates .bike4mind/ directory and ensures local.json is gitignored
|
|
1986
|
+
* Does NOT auto-create config.json (user creates that manually)
|
|
1987
|
+
*/
|
|
1988
|
+
async initProjectConfig() {
|
|
1989
|
+
const projectDir = this.projectConfigDir || findProjectConfigDir();
|
|
1990
|
+
if (!projectDir) {
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
const configDir = path4.join(projectDir, ".bike4mind");
|
|
1994
|
+
await fs4.mkdir(configDir, { recursive: true });
|
|
1995
|
+
await this.ensureGitignore(projectDir);
|
|
1996
|
+
}
|
|
1997
|
+
/**
|
|
1998
|
+
* Ensure .gitignore includes .bike4mind/local.json
|
|
1999
|
+
*/
|
|
2000
|
+
async ensureGitignore(projectDir) {
|
|
2001
|
+
const gitignorePath = path4.join(projectDir, ".gitignore");
|
|
2002
|
+
const entryToAdd = ".bike4mind/local.json";
|
|
2003
|
+
try {
|
|
2004
|
+
let gitignoreContent = "";
|
|
2005
|
+
try {
|
|
2006
|
+
gitignoreContent = await fs4.readFile(gitignorePath, "utf-8");
|
|
2007
|
+
} catch {
|
|
2008
|
+
}
|
|
2009
|
+
if (gitignoreContent.includes(entryToAdd)) {
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
const newContent = gitignoreContent.trim() + (gitignoreContent ? "\n" : "") + `
|
|
2013
|
+
# Bike4Mind local config (developer-specific)
|
|
2014
|
+
${entryToAdd}
|
|
2015
|
+
`;
|
|
2016
|
+
await fs4.writeFile(gitignorePath, newContent, "utf-8");
|
|
2017
|
+
console.log(`\u2705 Added ${entryToAdd} to .gitignore`);
|
|
2018
|
+
} catch (error) {
|
|
2019
|
+
console.warn(`\u26A0\uFE0F Failed to update .gitignore:`, error);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
/**
|
|
2023
|
+
* Save project config to .bike4mind/config.json
|
|
2024
|
+
*/
|
|
2025
|
+
async saveProjectConfig(config, projectDir) {
|
|
2026
|
+
const targetDir = projectDir || this.projectConfigDir || process.cwd();
|
|
2027
|
+
const configPath = path4.join(targetDir, ".bike4mind", "config.json");
|
|
2028
|
+
await fs4.mkdir(path4.dirname(configPath), { recursive: true });
|
|
2029
|
+
const validated = ProjectConfigSchema.parse(config);
|
|
2030
|
+
await fs4.writeFile(configPath, JSON.stringify(validated, null, 2), "utf-8");
|
|
2031
|
+
console.log(`\u2705 Saved project config to: ${configPath}`);
|
|
2032
|
+
}
|
|
2033
|
+
/**
|
|
2034
|
+
* Save project-local config to .bike4mind/local.json
|
|
2035
|
+
*/
|
|
2036
|
+
async saveProjectLocalConfig(config, projectDir) {
|
|
2037
|
+
const targetDir = projectDir || this.projectConfigDir || process.cwd();
|
|
2038
|
+
const configPath = path4.join(targetDir, ".bike4mind", "local.json");
|
|
2039
|
+
await fs4.mkdir(path4.dirname(configPath), { recursive: true });
|
|
2040
|
+
const validated = ProjectLocalConfigSchema.parse(config);
|
|
2041
|
+
await fs4.writeFile(configPath, JSON.stringify(validated, null, 2), "utf-8");
|
|
2042
|
+
await fs4.chmod(configPath, 384);
|
|
2043
|
+
console.log(`\u2705 Saved project-local config to: ${configPath}`);
|
|
2044
|
+
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Load raw project config (without merging)
|
|
2047
|
+
*/
|
|
2048
|
+
async loadRawProjectConfig() {
|
|
2049
|
+
if (!this.projectConfigDir) {
|
|
2050
|
+
return null;
|
|
2051
|
+
}
|
|
2052
|
+
return loadProjectConfig(this.projectConfigDir);
|
|
2053
|
+
}
|
|
2054
|
+
/**
|
|
2055
|
+
* Load raw project-local config (without merging)
|
|
2056
|
+
*/
|
|
2057
|
+
async loadRawProjectLocalConfig() {
|
|
2058
|
+
if (!this.projectConfigDir) {
|
|
2059
|
+
return null;
|
|
2060
|
+
}
|
|
2061
|
+
return loadProjectLocalConfig(this.projectConfigDir);
|
|
2062
|
+
}
|
|
1723
2063
|
};
|
|
1724
2064
|
|
|
1725
2065
|
// src/storage/CommandHistoryStore.ts
|
|
@@ -4471,13 +4811,30 @@ async function performWebSearch(adapters, params) {
|
|
|
4471
4811
|
link: result.link,
|
|
4472
4812
|
snippet: result.snippet
|
|
4473
4813
|
})) || [];
|
|
4814
|
+
const citables = results.map((result, index) => ({
|
|
4815
|
+
id: result.link,
|
|
4816
|
+
// Use URL as unique identifier
|
|
4817
|
+
type: "web_url",
|
|
4818
|
+
title: result.title,
|
|
4819
|
+
url: result.link,
|
|
4820
|
+
description: result.snippet,
|
|
4821
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4822
|
+
status: "complete",
|
|
4823
|
+
metadata: {
|
|
4824
|
+
sourceSystem: "web_search",
|
|
4825
|
+
relevanceScore: 1 - index * 0.1,
|
|
4826
|
+
// Higher relevance for earlier results
|
|
4827
|
+
fullContext: result.snippet
|
|
4828
|
+
}
|
|
4829
|
+
}));
|
|
4474
4830
|
const formattedResults = results.map((result, index) => `${index + 1}. **${result.title}**
|
|
4475
4831
|
${result.snippet}
|
|
4476
4832
|
Source: [${new URL(result.link).hostname}](${result.link})
|
|
4477
4833
|
`).join("\n");
|
|
4478
|
-
|
|
4834
|
+
const formattedOutput = formattedResults ? `Here's what I found from searching the web:
|
|
4479
4835
|
|
|
4480
4836
|
${formattedResults}` : "No results found from web search.";
|
|
4837
|
+
return { formattedResults: formattedOutput, citables };
|
|
4481
4838
|
} catch (error) {
|
|
4482
4839
|
console.error("\u274C WebSearch Tool: Error during search:", error);
|
|
4483
4840
|
throw error;
|
|
@@ -4488,7 +4845,18 @@ var webSearchTool = {
|
|
|
4488
4845
|
implementation: (context) => ({
|
|
4489
4846
|
toolFn: async (value) => {
|
|
4490
4847
|
const params = value;
|
|
4491
|
-
|
|
4848
|
+
const { formattedResults, citables } = await performWebSearch({ db: context.db }, params);
|
|
4849
|
+
if (citables.length > 0) {
|
|
4850
|
+
await context.statusUpdate({
|
|
4851
|
+
// Store citables in promptMeta - statusUpdate will Object.assign this
|
|
4852
|
+
// The receiving code needs to handle merging promptMeta.citables
|
|
4853
|
+
promptMeta: {
|
|
4854
|
+
citables
|
|
4855
|
+
}
|
|
4856
|
+
}, "Web search complete");
|
|
4857
|
+
console.log(`\u{1F4DA} WebSearch Tool: Stored ${citables.length} citables`);
|
|
4858
|
+
}
|
|
4859
|
+
return formattedResults;
|
|
4492
4860
|
},
|
|
4493
4861
|
toolSchema: {
|
|
4494
4862
|
name: "web_search",
|
|
@@ -7305,7 +7673,7 @@ var planetVisibilityTool = {
|
|
|
7305
7673
|
|
|
7306
7674
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/fileRead/index.js
|
|
7307
7675
|
import { promises as fs7 } from "fs";
|
|
7308
|
-
import { existsSync as
|
|
7676
|
+
import { existsSync as existsSync3, statSync as statSync3 } from "fs";
|
|
7309
7677
|
import path6 from "path";
|
|
7310
7678
|
var MAX_FILE_SIZE2 = 10 * 1024 * 1024;
|
|
7311
7679
|
async function readFileContent(params) {
|
|
@@ -7316,7 +7684,7 @@ async function readFileContent(params) {
|
|
|
7316
7684
|
if (!resolvedPath.startsWith(cwd)) {
|
|
7317
7685
|
throw new Error(`Access denied: Cannot read files outside of current working directory`);
|
|
7318
7686
|
}
|
|
7319
|
-
if (!
|
|
7687
|
+
if (!existsSync3(resolvedPath)) {
|
|
7320
7688
|
throw new Error(`File not found: ${filePath}`);
|
|
7321
7689
|
}
|
|
7322
7690
|
const stats = statSync3(resolvedPath);
|
|
@@ -7402,7 +7770,7 @@ var fileReadTool = {
|
|
|
7402
7770
|
|
|
7403
7771
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/createFile/index.js
|
|
7404
7772
|
import { promises as fs8 } from "fs";
|
|
7405
|
-
import { existsSync as
|
|
7773
|
+
import { existsSync as existsSync4 } from "fs";
|
|
7406
7774
|
import path7 from "path";
|
|
7407
7775
|
async function createFile(params) {
|
|
7408
7776
|
const { path: filePath, content, createDirectories = true } = params;
|
|
@@ -7412,7 +7780,7 @@ async function createFile(params) {
|
|
|
7412
7780
|
if (!resolvedPath.startsWith(cwd)) {
|
|
7413
7781
|
throw new Error(`Access denied: Cannot create files outside of current working directory`);
|
|
7414
7782
|
}
|
|
7415
|
-
const fileExists =
|
|
7783
|
+
const fileExists = existsSync4(resolvedPath);
|
|
7416
7784
|
const action = fileExists ? "overwritten" : "created";
|
|
7417
7785
|
if (createDirectories) {
|
|
7418
7786
|
const dir = path7.dirname(resolvedPath);
|
|
@@ -7430,7 +7798,7 @@ var createFileTool = {
|
|
|
7430
7798
|
implementation: (context) => ({
|
|
7431
7799
|
toolFn: async (value) => {
|
|
7432
7800
|
const params = value;
|
|
7433
|
-
const fileExists =
|
|
7801
|
+
const fileExists = existsSync4(path7.resolve(process.cwd(), path7.normalize(params.path)));
|
|
7434
7802
|
context.logger.info(`\u{1F4DD} CreateFile: ${fileExists ? "Overwriting" : "Creating"} file`, {
|
|
7435
7803
|
path: params.path,
|
|
7436
7804
|
size: params.content.length
|
|
@@ -7810,7 +8178,7 @@ var grepSearchTool = {
|
|
|
7810
8178
|
|
|
7811
8179
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
|
|
7812
8180
|
import { promises as fs9 } from "fs";
|
|
7813
|
-
import { existsSync as
|
|
8181
|
+
import { existsSync as existsSync5, statSync as statSync6 } from "fs";
|
|
7814
8182
|
import path10 from "path";
|
|
7815
8183
|
async function deleteFile(params) {
|
|
7816
8184
|
const { path: filePath, recursive = false } = params;
|
|
@@ -7820,7 +8188,7 @@ async function deleteFile(params) {
|
|
|
7820
8188
|
if (!resolvedPath.startsWith(cwd)) {
|
|
7821
8189
|
throw new Error(`Access denied: Cannot delete files outside of current working directory`);
|
|
7822
8190
|
}
|
|
7823
|
-
if (!
|
|
8191
|
+
if (!existsSync5(resolvedPath)) {
|
|
7824
8192
|
throw new Error(`File or directory not found: ${filePath}`);
|
|
7825
8193
|
}
|
|
7826
8194
|
const stats = statSync6(resolvedPath);
|
|
@@ -7844,7 +8212,7 @@ var deleteFileTool = {
|
|
|
7844
8212
|
toolFn: async (value) => {
|
|
7845
8213
|
const params = value;
|
|
7846
8214
|
const resolvedPath = path10.resolve(process.cwd(), path10.normalize(params.path));
|
|
7847
|
-
const isDirectory =
|
|
8215
|
+
const isDirectory = existsSync5(resolvedPath) && statSync6(resolvedPath).isDirectory();
|
|
7848
8216
|
context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
|
|
7849
8217
|
path: params.path,
|
|
7850
8218
|
recursive: params.recursive
|
|
@@ -8134,10 +8502,10 @@ import jwt2 from "jsonwebtoken";
|
|
|
8134
8502
|
// src/utils/diffPreview.ts
|
|
8135
8503
|
import * as Diff from "diff";
|
|
8136
8504
|
import { readFile } from "fs/promises";
|
|
8137
|
-
import { existsSync as
|
|
8505
|
+
import { existsSync as existsSync6 } from "fs";
|
|
8138
8506
|
async function generateFileDiffPreview(args) {
|
|
8139
8507
|
try {
|
|
8140
|
-
if (!
|
|
8508
|
+
if (!existsSync6(args.path)) {
|
|
8141
8509
|
const lines2 = args.content.split("\n");
|
|
8142
8510
|
const preview = lines2.slice(0, 20).join("\n");
|
|
8143
8511
|
const hasMore = lines2.length > 20;
|
|
@@ -8167,7 +8535,7 @@ ${preview}${hasMore ? `
|
|
|
8167
8535
|
}
|
|
8168
8536
|
async function generateFileDeletePreview(args) {
|
|
8169
8537
|
try {
|
|
8170
|
-
if (!
|
|
8538
|
+
if (!existsSync6(args.path)) {
|
|
8171
8539
|
return `[File does not exist: ${args.path}]`;
|
|
8172
8540
|
}
|
|
8173
8541
|
const stats = await import("fs/promises").then((fs11) => fs11.stat(args.path));
|
|
@@ -8220,7 +8588,7 @@ var CliLogger = class extends Logger {
|
|
|
8220
8588
|
log(...args) {
|
|
8221
8589
|
}
|
|
8222
8590
|
};
|
|
8223
|
-
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext) {
|
|
8591
|
+
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore) {
|
|
8224
8592
|
const originalFn = tool.toolFn;
|
|
8225
8593
|
const toolName = tool.toolSchema.name;
|
|
8226
8594
|
return {
|
|
@@ -8264,7 +8632,25 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
8264
8632
|
throw new PermissionDeniedError(toolName, args);
|
|
8265
8633
|
}
|
|
8266
8634
|
if (response.action === "allow-always") {
|
|
8267
|
-
permissionManager.trustTool(toolName);
|
|
8635
|
+
const canTrust = permissionManager.trustTool(toolName);
|
|
8636
|
+
if (canTrust) {
|
|
8637
|
+
const projectDir = configStore.getProjectConfigDir();
|
|
8638
|
+
if (projectDir) {
|
|
8639
|
+
try {
|
|
8640
|
+
await configStore.initProjectConfig();
|
|
8641
|
+
const existingLocal = await configStore.loadRawProjectLocalConfig() || {};
|
|
8642
|
+
const updatedLocal = {
|
|
8643
|
+
...existingLocal,
|
|
8644
|
+
trustedTools: [...existingLocal.trustedTools || [], toolName]
|
|
8645
|
+
};
|
|
8646
|
+
await configStore.saveProjectLocalConfig(updatedLocal);
|
|
8647
|
+
} catch (error) {
|
|
8648
|
+
await configStore.trustTool(toolName);
|
|
8649
|
+
}
|
|
8650
|
+
} else {
|
|
8651
|
+
await configStore.trustTool(toolName);
|
|
8652
|
+
}
|
|
8653
|
+
}
|
|
8268
8654
|
}
|
|
8269
8655
|
const result = await originalFn(args);
|
|
8270
8656
|
agentContext.observationQueue.push({ toolName, result });
|
|
@@ -8272,7 +8658,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
8272
8658
|
}
|
|
8273
8659
|
};
|
|
8274
8660
|
}
|
|
8275
|
-
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, toolApiKeys) {
|
|
8661
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, toolApiKeys) {
|
|
8276
8662
|
const logger2 = new CliLogger();
|
|
8277
8663
|
const storage = new NoOpStorage();
|
|
8278
8664
|
const user = {
|
|
@@ -8356,7 +8742,9 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
8356
8742
|
toolConfig,
|
|
8357
8743
|
model
|
|
8358
8744
|
);
|
|
8359
|
-
const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
|
|
8745
|
+
const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
|
|
8746
|
+
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore)
|
|
8747
|
+
);
|
|
8360
8748
|
return { tools: tools2, agentContext };
|
|
8361
8749
|
}
|
|
8362
8750
|
|
|
@@ -8421,23 +8809,30 @@ function canTrustTool(toolName, customCategories) {
|
|
|
8421
8809
|
|
|
8422
8810
|
// src/utils/PermissionManager.ts
|
|
8423
8811
|
var PermissionManager = class {
|
|
8424
|
-
constructor(trustedTools = [], customCategories) {
|
|
8812
|
+
constructor(trustedTools = [], customCategories, deniedTools) {
|
|
8425
8813
|
this.trustedTools = /* @__PURE__ */ new Set();
|
|
8814
|
+
this.deniedTools = /* @__PURE__ */ new Set();
|
|
8426
8815
|
this.trustedTools = new Set(trustedTools);
|
|
8427
8816
|
this.customCategories = new Map(Object.entries(customCategories || {}));
|
|
8817
|
+
this.deniedTools = new Set(deniedTools || []);
|
|
8428
8818
|
}
|
|
8429
8819
|
/**
|
|
8430
8820
|
* Check if a tool needs permission before execution
|
|
8431
8821
|
*
|
|
8432
8822
|
* A tool needs permission if:
|
|
8433
|
-
* 1. It's
|
|
8434
|
-
* 2. It's not in the
|
|
8823
|
+
* 1. It's in the denied tools list (from project config), OR
|
|
8824
|
+
* 2. It's not in the auto_approve category, AND
|
|
8825
|
+
* 3. It's not in the trusted tools set
|
|
8435
8826
|
*
|
|
8436
8827
|
* Note: prompt_always tools CANNOT be trusted, so they always need permission
|
|
8828
|
+
* Note: denied tools from project config ALWAYS need permission (cannot be overridden locally)
|
|
8437
8829
|
*/
|
|
8438
8830
|
needsPermission(toolName) {
|
|
8439
8831
|
const categoryMap = Object.fromEntries(this.customCategories);
|
|
8440
8832
|
const category = getToolCategory(toolName, categoryMap);
|
|
8833
|
+
if (this.deniedTools.has(toolName)) {
|
|
8834
|
+
return true;
|
|
8835
|
+
}
|
|
8441
8836
|
if (category === "auto_approve") {
|
|
8442
8837
|
return false;
|
|
8443
8838
|
}
|
|
@@ -8448,10 +8843,13 @@ var PermissionManager = class {
|
|
|
8448
8843
|
}
|
|
8449
8844
|
/**
|
|
8450
8845
|
* Add a tool to the trusted list
|
|
8451
|
-
* Returns false if the tool cannot be trusted (prompt_always category)
|
|
8846
|
+
* Returns false if the tool cannot be trusted (prompt_always category or denied by project)
|
|
8452
8847
|
*/
|
|
8453
8848
|
trustTool(toolName) {
|
|
8454
8849
|
const categoryMap = Object.fromEntries(this.customCategories);
|
|
8850
|
+
if (this.deniedTools.has(toolName)) {
|
|
8851
|
+
return false;
|
|
8852
|
+
}
|
|
8455
8853
|
if (!canTrustTool(toolName, categoryMap)) {
|
|
8456
8854
|
return false;
|
|
8457
8855
|
}
|
|
@@ -8484,12 +8882,27 @@ var PermissionManager = class {
|
|
|
8484
8882
|
return getToolCategory(toolName, categoryMap);
|
|
8485
8883
|
}
|
|
8486
8884
|
/**
|
|
8487
|
-
* Check if a tool can be trusted (not in prompt_always category)
|
|
8885
|
+
* Check if a tool can be trusted (not in prompt_always category or denied by project)
|
|
8488
8886
|
*/
|
|
8489
8887
|
canBeTrusted(toolName) {
|
|
8490
8888
|
const categoryMap = Object.fromEntries(this.customCategories);
|
|
8889
|
+
if (this.deniedTools.has(toolName)) {
|
|
8890
|
+
return false;
|
|
8891
|
+
}
|
|
8491
8892
|
return canTrustTool(toolName, categoryMap);
|
|
8492
8893
|
}
|
|
8894
|
+
/**
|
|
8895
|
+
* Check if a tool is denied by project config
|
|
8896
|
+
*/
|
|
8897
|
+
isDenied(toolName) {
|
|
8898
|
+
return this.deniedTools.has(toolName);
|
|
8899
|
+
}
|
|
8900
|
+
/**
|
|
8901
|
+
* Get list of denied tools
|
|
8902
|
+
*/
|
|
8903
|
+
getDeniedTools() {
|
|
8904
|
+
return Array.from(this.deniedTools).sort();
|
|
8905
|
+
}
|
|
8493
8906
|
/**
|
|
8494
8907
|
* Clear all trusted tools
|
|
8495
8908
|
*/
|
|
@@ -8784,18 +9197,22 @@ var logger = Logger2.getInstance();
|
|
|
8784
9197
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
8785
9198
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
8786
9199
|
import path12 from "path";
|
|
8787
|
-
import { existsSync as
|
|
9200
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3 } from "fs";
|
|
8788
9201
|
var MCPClient = class {
|
|
8789
9202
|
// Note: This class handles MCP server communication with repository filtering
|
|
8790
9203
|
mcp;
|
|
8791
9204
|
transport = null;
|
|
8792
9205
|
envVariables;
|
|
9206
|
+
customCommand;
|
|
9207
|
+
customArgs;
|
|
8793
9208
|
tools = [];
|
|
8794
9209
|
serverName;
|
|
8795
|
-
constructor({ envVariables, name, selectedRepositories }) {
|
|
9210
|
+
constructor({ envVariables, name, selectedRepositories, command, args }) {
|
|
8796
9211
|
this.mcp = new Client2({ name: "mcp-client-cli", version: "1.0.0" });
|
|
8797
9212
|
this.envVariables = [...envVariables];
|
|
8798
9213
|
this.serverName = name;
|
|
9214
|
+
this.customCommand = command;
|
|
9215
|
+
this.customArgs = args;
|
|
8799
9216
|
if (name === "github" && selectedRepositories) {
|
|
8800
9217
|
const reposJson = JSON.stringify(selectedRepositories);
|
|
8801
9218
|
this.envVariables.push({
|
|
@@ -8806,37 +9223,48 @@ var MCPClient = class {
|
|
|
8806
9223
|
}
|
|
8807
9224
|
async connectToServer() {
|
|
8808
9225
|
try {
|
|
8809
|
-
const
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
9226
|
+
const envVarsObject = this.envVariables.reduce((acc, env) => ({
|
|
9227
|
+
...acc,
|
|
9228
|
+
[env.key]: env.value
|
|
9229
|
+
}), {});
|
|
9230
|
+
let command;
|
|
9231
|
+
let args;
|
|
9232
|
+
if (this.customCommand && this.customCommand.trim() !== "") {
|
|
9233
|
+
command = this.customCommand;
|
|
9234
|
+
args = this.customArgs ?? [];
|
|
9235
|
+
console.log(`[MCP] Using external command for ${this.serverName}: ${command} ${args.join(" ")}`);
|
|
9236
|
+
} else {
|
|
9237
|
+
const root = process.env.INIT_CWD || process.cwd();
|
|
9238
|
+
const candidatePaths = [
|
|
9239
|
+
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
9240
|
+
path12.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
9241
|
+
// When running from SST Lambda deployed environment (/var/task)
|
|
9242
|
+
path12.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9243
|
+
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
9244
|
+
path12.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9245
|
+
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
9246
|
+
path12.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9247
|
+
// Original paths (backward compatibility)
|
|
9248
|
+
path12.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9249
|
+
path12.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
9250
|
+
];
|
|
9251
|
+
const serverScriptPath = candidatePaths.find((p) => existsSync7(p));
|
|
9252
|
+
if (!serverScriptPath) {
|
|
9253
|
+
const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
9254
|
+
console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
|
|
9255
|
+
console.error(`[MCP] Available directories in ${root}:`, getDirectories(root));
|
|
9256
|
+
throw new Error(`MCP Server script path not found for ${this.serverName}. Root: ${root}, Available dirs: ${getDirectories(root).join(", ")}`);
|
|
9257
|
+
}
|
|
9258
|
+
command = process.execPath;
|
|
9259
|
+
args = [serverScriptPath];
|
|
9260
|
+
console.log(`[MCP] Using server: ${this.serverName} at ${serverScriptPath}`);
|
|
9261
|
+
}
|
|
8831
9262
|
this.transport = new StdioClientTransport({
|
|
8832
|
-
command
|
|
8833
|
-
args
|
|
9263
|
+
command,
|
|
9264
|
+
args,
|
|
8834
9265
|
env: {
|
|
8835
|
-
...process.env,
|
|
8836
|
-
...
|
|
8837
|
-
...acc,
|
|
8838
|
-
[env.key]: env.value
|
|
8839
|
-
}), {})
|
|
9266
|
+
...Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== void 0)),
|
|
9267
|
+
...envVarsObject
|
|
8840
9268
|
}
|
|
8841
9269
|
});
|
|
8842
9270
|
this.transport.onerror = (error) => {
|
|
@@ -8944,7 +9372,9 @@ var McpManager = class {
|
|
|
8944
9372
|
}));
|
|
8945
9373
|
const client = new MCPClient({
|
|
8946
9374
|
envVariables,
|
|
8947
|
-
name: serverConfig.name
|
|
9375
|
+
name: serverConfig.name,
|
|
9376
|
+
command: serverConfig.command,
|
|
9377
|
+
args: serverConfig.args
|
|
8948
9378
|
});
|
|
8949
9379
|
await client.connectToServer();
|
|
8950
9380
|
const mcpData = {
|
|
@@ -9215,9 +9645,40 @@ var ServerLlmBackend = class {
|
|
|
9215
9645
|
}
|
|
9216
9646
|
/**
|
|
9217
9647
|
* Get available models from server
|
|
9218
|
-
*
|
|
9648
|
+
* Fetches from /api/models and filters for CLI-compatible models
|
|
9649
|
+
* Falls back to hardcoded list if API fails
|
|
9219
9650
|
*/
|
|
9220
9651
|
async getModelInfo() {
|
|
9652
|
+
try {
|
|
9653
|
+
logger.debug("[ServerLlmBackend] Fetching models from /api/models");
|
|
9654
|
+
const response = await this.apiClient.get("/api/models");
|
|
9655
|
+
if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
|
|
9656
|
+
logger.warn("[ServerLlmBackend] Invalid API response format, using fallback models");
|
|
9657
|
+
logger.info("\u26A0\uFE0F Using fallback model list (API returned invalid format)");
|
|
9658
|
+
return this.getFallbackModels();
|
|
9659
|
+
}
|
|
9660
|
+
const filteredModels = response.models.filter((model) => model.type === "text" && model.supportsTools === true);
|
|
9661
|
+
logger.debug(`[ServerLlmBackend] Fetched ${filteredModels.length} CLI-compatible models`);
|
|
9662
|
+
if (filteredModels.length === 0) {
|
|
9663
|
+
logger.warn("[ServerLlmBackend] No CLI-compatible models found from API, using fallback");
|
|
9664
|
+
logger.info("\u26A0\uFE0F Using fallback model list (no CLI-compatible models available)");
|
|
9665
|
+
return this.getFallbackModels();
|
|
9666
|
+
}
|
|
9667
|
+
logger.info(`\u{1F4CB} Loaded ${filteredModels.length} models from server`);
|
|
9668
|
+
return filteredModels;
|
|
9669
|
+
} catch (error) {
|
|
9670
|
+
logger.warn(
|
|
9671
|
+
`[ServerLlmBackend] Failed to fetch models from API, using fallback: ${error instanceof Error ? error.message : String(error)}`
|
|
9672
|
+
);
|
|
9673
|
+
logger.info("\u26A0\uFE0F Using fallback model list (API unavailable)");
|
|
9674
|
+
return this.getFallbackModels();
|
|
9675
|
+
}
|
|
9676
|
+
}
|
|
9677
|
+
/**
|
|
9678
|
+
* Fallback models when API is unavailable
|
|
9679
|
+
* Returns hardcoded list of commonly supported models
|
|
9680
|
+
*/
|
|
9681
|
+
getFallbackModels() {
|
|
9221
9682
|
return [
|
|
9222
9683
|
{
|
|
9223
9684
|
id: "claude-sonnet-4-5-20250929",
|
|
@@ -9402,7 +9863,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
9402
9863
|
// package.json
|
|
9403
9864
|
var package_default = {
|
|
9404
9865
|
name: "@bike4mind/cli",
|
|
9405
|
-
version: "0.2.
|
|
9866
|
+
version: "0.2.6-fix-cli-mcp-type-mismatch.17119+0906e1e34",
|
|
9406
9867
|
type: "module",
|
|
9407
9868
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
9408
9869
|
license: "UNLICENSED",
|
|
@@ -9504,10 +9965,10 @@ var package_default = {
|
|
|
9504
9965
|
},
|
|
9505
9966
|
devDependencies: {
|
|
9506
9967
|
"@bike4mind/agents": "0.1.0",
|
|
9507
|
-
"@bike4mind/common": "2.
|
|
9508
|
-
"@bike4mind/mcp": "1.
|
|
9509
|
-
"@bike4mind/services": "2.
|
|
9510
|
-
"@bike4mind/utils": "2.1.
|
|
9968
|
+
"@bike4mind/common": "2.38.1-fix-cli-mcp-type-mismatch.17119+0906e1e34",
|
|
9969
|
+
"@bike4mind/mcp": "1.20.1-fix-cli-mcp-type-mismatch.17119+0906e1e34",
|
|
9970
|
+
"@bike4mind/services": "2.33.1-fix-cli-mcp-type-mismatch.17119+0906e1e34",
|
|
9971
|
+
"@bike4mind/utils": "2.1.2-fix-cli-mcp-type-mismatch.17119+0906e1e34",
|
|
9511
9972
|
"@types/diff": "^5.0.9",
|
|
9512
9973
|
"@types/jsonwebtoken": "^9.0.4",
|
|
9513
9974
|
"@types/node": "^22.9.0",
|
|
@@ -9519,7 +9980,7 @@ var package_default = {
|
|
|
9519
9980
|
typescript: "^5.9.3",
|
|
9520
9981
|
vitest: "^3.2.4"
|
|
9521
9982
|
},
|
|
9522
|
-
gitHead: "
|
|
9983
|
+
gitHead: "0906e1e34709a52074b386d9b51a94776db1d33d"
|
|
9523
9984
|
};
|
|
9524
9985
|
|
|
9525
9986
|
// src/config/constants.ts
|
|
@@ -9548,7 +10009,8 @@ function CliApp() {
|
|
|
9548
10009
|
agent: null,
|
|
9549
10010
|
mcpManager: null,
|
|
9550
10011
|
permissionManager: null,
|
|
9551
|
-
permissionPrompt: null
|
|
10012
|
+
permissionPrompt: null,
|
|
10013
|
+
trustLocationSelector: null
|
|
9552
10014
|
});
|
|
9553
10015
|
const [isInitialized, setIsInitialized] = useState4(false);
|
|
9554
10016
|
const [initError, setInitError] = useState4(null);
|
|
@@ -9710,7 +10172,13 @@ function CliApp() {
|
|
|
9710
10172
|
debug: () => {
|
|
9711
10173
|
}
|
|
9712
10174
|
};
|
|
9713
|
-
const permissionManager = new PermissionManager(
|
|
10175
|
+
const permissionManager = new PermissionManager(
|
|
10176
|
+
config.trustedTools || [],
|
|
10177
|
+
void 0,
|
|
10178
|
+
// customCategories (not used yet)
|
|
10179
|
+
config.tools.disabled || []
|
|
10180
|
+
// denied tools from project config
|
|
10181
|
+
);
|
|
9714
10182
|
const promptFn = (toolName, args, preview) => {
|
|
9715
10183
|
return new Promise((resolve3) => {
|
|
9716
10184
|
const canBeTrusted = permissionManager.canBeTrusted(toolName);
|
|
@@ -9738,6 +10206,7 @@ function CliApp() {
|
|
|
9738
10206
|
permissionManager,
|
|
9739
10207
|
promptFn,
|
|
9740
10208
|
agentContext,
|
|
10209
|
+
state.configStore,
|
|
9741
10210
|
config.toolApiKeys
|
|
9742
10211
|
);
|
|
9743
10212
|
console.log(`\u{1F6E0}\uFE0F Loaded ${b4mTools.length} B4M tool(s)`);
|
|
@@ -9802,8 +10271,10 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
9802
10271
|
agent,
|
|
9803
10272
|
mcpManager,
|
|
9804
10273
|
permissionManager,
|
|
9805
|
-
config
|
|
10274
|
+
config,
|
|
9806
10275
|
// Store config for synchronous access
|
|
10276
|
+
availableModels: models
|
|
10277
|
+
// Store models for ConfigEditor
|
|
9807
10278
|
}));
|
|
9808
10279
|
setStoreSession(newSession);
|
|
9809
10280
|
setIsInitialized(true);
|
|
@@ -9919,6 +10390,9 @@ Tool Permissions:
|
|
|
9919
10390
|
/trust <tool-name> - Trust a tool (won't ask permission again)
|
|
9920
10391
|
/untrust <tool-name> - Remove tool from trusted list
|
|
9921
10392
|
/trusted - List all trusted tools
|
|
10393
|
+
|
|
10394
|
+
Project Configuration:
|
|
10395
|
+
/project-config - Show merged project configuration
|
|
9922
10396
|
`);
|
|
9923
10397
|
break;
|
|
9924
10398
|
case "exit":
|
|
@@ -9997,7 +10471,7 @@ Tool Permissions:
|
|
|
9997
10471
|
console.log("");
|
|
9998
10472
|
break;
|
|
9999
10473
|
}
|
|
10000
|
-
case "trust":
|
|
10474
|
+
case "trust": {
|
|
10001
10475
|
if (!state.permissionManager) {
|
|
10002
10476
|
console.log("Permission manager not initialized");
|
|
10003
10477
|
return;
|
|
@@ -10005,16 +10479,97 @@ Tool Permissions:
|
|
|
10005
10479
|
const toolToTrust = args[0];
|
|
10006
10480
|
if (!toolToTrust) {
|
|
10007
10481
|
console.log("Usage: /trust <tool-name>");
|
|
10482
|
+
console.log("");
|
|
10483
|
+
console.log("Example:");
|
|
10484
|
+
console.log(" /trust file_read - Opens interactive location selector");
|
|
10485
|
+
console.log("");
|
|
10008
10486
|
return;
|
|
10009
10487
|
}
|
|
10010
|
-
const
|
|
10011
|
-
if (
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10488
|
+
const canTrust = state.permissionManager.trustTool(toolToTrust);
|
|
10489
|
+
if (!canTrust) {
|
|
10490
|
+
if (state.permissionManager.isDenied(toolToTrust)) {
|
|
10491
|
+
console.log(`\u274C Tool '${toolToTrust}' is denied by project configuration and cannot be trusted`);
|
|
10492
|
+
} else {
|
|
10493
|
+
console.log(`\u274C Tool '${toolToTrust}' cannot be trusted (it's in the 'prompt_always' category)`);
|
|
10494
|
+
}
|
|
10495
|
+
return;
|
|
10016
10496
|
}
|
|
10497
|
+
state.permissionManager.untrustTool(toolToTrust);
|
|
10498
|
+
const handleLocationSelect = async (location) => {
|
|
10499
|
+
setState((prev) => ({ ...prev, trustLocationSelector: null }));
|
|
10500
|
+
if (!location) {
|
|
10501
|
+
console.log("\u274C Trust operation cancelled");
|
|
10502
|
+
return;
|
|
10503
|
+
}
|
|
10504
|
+
const projectDir = state.configStore.getProjectConfigDir();
|
|
10505
|
+
switch (location) {
|
|
10506
|
+
case "local": {
|
|
10507
|
+
if (!projectDir) {
|
|
10508
|
+
console.log('\u274C No project found. Use "global" to save to ~/.bike4mind/config.json');
|
|
10509
|
+
return;
|
|
10510
|
+
}
|
|
10511
|
+
try {
|
|
10512
|
+
await state.configStore.initProjectConfig();
|
|
10513
|
+
const existingLocal = await state.configStore.loadRawProjectLocalConfig() || {};
|
|
10514
|
+
const updatedLocal = {
|
|
10515
|
+
...existingLocal,
|
|
10516
|
+
trustedTools: [.../* @__PURE__ */ new Set([...existingLocal.trustedTools || [], toolToTrust])]
|
|
10517
|
+
};
|
|
10518
|
+
await state.configStore.saveProjectLocalConfig(updatedLocal);
|
|
10519
|
+
state.permissionManager?.trustTool(toolToTrust);
|
|
10520
|
+
console.log(`\u2705 Tool '${toolToTrust}' trusted for this project only`);
|
|
10521
|
+
console.log(` Saved in: ${projectDir}/.bike4mind/local.json`);
|
|
10522
|
+
} catch (error) {
|
|
10523
|
+
console.error(`\u274C Failed to save project-local config:`, error);
|
|
10524
|
+
}
|
|
10525
|
+
break;
|
|
10526
|
+
}
|
|
10527
|
+
case "project": {
|
|
10528
|
+
if (!projectDir) {
|
|
10529
|
+
console.log('\u274C No project found. Use "global" to save to ~/.bike4mind/config.json');
|
|
10530
|
+
return;
|
|
10531
|
+
}
|
|
10532
|
+
try {
|
|
10533
|
+
const existingProject = await state.configStore.loadRawProjectConfig() || {};
|
|
10534
|
+
const updatedProject = {
|
|
10535
|
+
...existingProject,
|
|
10536
|
+
tools: {
|
|
10537
|
+
...existingProject.tools,
|
|
10538
|
+
enabled: [.../* @__PURE__ */ new Set([...existingProject.tools?.enabled || [], toolToTrust])]
|
|
10539
|
+
}
|
|
10540
|
+
};
|
|
10541
|
+
await state.configStore.saveProjectConfig(updatedProject);
|
|
10542
|
+
state.permissionManager?.trustTool(toolToTrust);
|
|
10543
|
+
console.log(`\u2705 Tool '${toolToTrust}' trusted for entire team`);
|
|
10544
|
+
console.log(` Saved in: ${projectDir}/.bike4mind/config.json`);
|
|
10545
|
+
console.log(" \u26A0\uFE0F Remember to commit this file to share with your team!");
|
|
10546
|
+
} catch (error) {
|
|
10547
|
+
console.error(`\u274C Failed to save project config:`, error);
|
|
10548
|
+
}
|
|
10549
|
+
break;
|
|
10550
|
+
}
|
|
10551
|
+
case "global": {
|
|
10552
|
+
try {
|
|
10553
|
+
await state.configStore.trustTool(toolToTrust);
|
|
10554
|
+
state.permissionManager?.trustTool(toolToTrust);
|
|
10555
|
+
console.log(`\u2705 Tool '${toolToTrust}' trusted globally (all projects)`);
|
|
10556
|
+
console.log(" Saved in: ~/.bike4mind/config.json");
|
|
10557
|
+
} catch (error) {
|
|
10558
|
+
console.error(`\u274C Failed to save global config:`, error);
|
|
10559
|
+
}
|
|
10560
|
+
break;
|
|
10561
|
+
}
|
|
10562
|
+
}
|
|
10563
|
+
};
|
|
10564
|
+
setState((prev) => ({
|
|
10565
|
+
...prev,
|
|
10566
|
+
trustLocationSelector: {
|
|
10567
|
+
toolName: toolToTrust,
|
|
10568
|
+
resolve: handleLocationSelect
|
|
10569
|
+
}
|
|
10570
|
+
}));
|
|
10017
10571
|
break;
|
|
10572
|
+
}
|
|
10018
10573
|
case "untrust":
|
|
10019
10574
|
if (!state.permissionManager) {
|
|
10020
10575
|
console.log("Permission manager not initialized");
|
|
@@ -10190,6 +10745,49 @@ Usage by Model (Last ${USAGE_DAYS} days):`);
|
|
|
10190
10745
|
console.log(`
|
|
10191
10746
|
No usage data available for the last ${USAGE_DAYS} days.`);
|
|
10192
10747
|
}
|
|
10748
|
+
break;
|
|
10749
|
+
}
|
|
10750
|
+
case "project-config": {
|
|
10751
|
+
const projectDir = state.configStore.getProjectConfigDir();
|
|
10752
|
+
const config = await state.configStore.get();
|
|
10753
|
+
console.log("\n\u{1F4C1} Project Configuration:\n");
|
|
10754
|
+
if (projectDir) {
|
|
10755
|
+
console.log(`Project Directory: ${projectDir}/.bike4mind/`);
|
|
10756
|
+
console.log("");
|
|
10757
|
+
const projectConfig = await state.configStore.loadRawProjectConfig();
|
|
10758
|
+
const localConfig = await state.configStore.loadRawProjectLocalConfig();
|
|
10759
|
+
if (projectConfig) {
|
|
10760
|
+
console.log("Team Config (.bike4mind/config.json):");
|
|
10761
|
+
if (projectConfig.defaultModel) {
|
|
10762
|
+
console.log(` Default Model: ${projectConfig.defaultModel}`);
|
|
10763
|
+
}
|
|
10764
|
+
if (projectConfig.tools?.denied && projectConfig.tools.denied.length > 0) {
|
|
10765
|
+
console.log(` Denied Tools: ${projectConfig.tools.denied.join(", ")}`);
|
|
10766
|
+
}
|
|
10767
|
+
if (projectConfig.mcpServers && projectConfig.mcpServers.length > 0) {
|
|
10768
|
+
console.log(` MCP Servers: ${projectConfig.mcpServers.map((s) => s.name).join(", ")}`);
|
|
10769
|
+
}
|
|
10770
|
+
console.log("");
|
|
10771
|
+
}
|
|
10772
|
+
if (localConfig) {
|
|
10773
|
+
console.log("Local Config (.bike4mind/local.json):");
|
|
10774
|
+
if (localConfig.trustedTools && localConfig.trustedTools.length > 0) {
|
|
10775
|
+
console.log(` Trusted Tools: ${localConfig.trustedTools.join(", ")}`);
|
|
10776
|
+
}
|
|
10777
|
+
if (localConfig.mcpServers && localConfig.mcpServers.length > 0) {
|
|
10778
|
+
console.log(` MCP Servers: ${localConfig.mcpServers.map((s) => s.name).join(", ")}`);
|
|
10779
|
+
}
|
|
10780
|
+
console.log("");
|
|
10781
|
+
}
|
|
10782
|
+
console.log("Merged Configuration (what you're using):");
|
|
10783
|
+
console.log(` Default Model: ${config.defaultModel}`);
|
|
10784
|
+
console.log(` Trusted Tools: ${config.trustedTools?.length || 0} tools`);
|
|
10785
|
+
console.log(` Denied Tools: ${config.tools.disabled.length} tools`);
|
|
10786
|
+
console.log(` MCP Servers: ${config.mcpServers.length} servers`);
|
|
10787
|
+
} else {
|
|
10788
|
+
console.log("No project configuration found.");
|
|
10789
|
+
console.log("Tip: Create .bike4mind/config.json in your project root for team-wide settings.");
|
|
10790
|
+
}
|
|
10193
10791
|
console.log("");
|
|
10194
10792
|
break;
|
|
10195
10793
|
}
|
|
@@ -10203,11 +10801,31 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
10203
10801
|
setState((prev) => ({ ...prev, config: updatedConfig }));
|
|
10204
10802
|
};
|
|
10205
10803
|
if (initError) {
|
|
10206
|
-
return /* @__PURE__ */
|
|
10804
|
+
return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React13.createElement(Text12, null, initError), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
|
|
10805
|
+
}
|
|
10806
|
+
if (state.trustLocationSelector) {
|
|
10807
|
+
const projectDir = state.configStore.getProjectConfigDir();
|
|
10808
|
+
const inProject = projectDir !== null;
|
|
10809
|
+
return /* @__PURE__ */ React13.createElement(
|
|
10810
|
+
TrustLocationSelector,
|
|
10811
|
+
{
|
|
10812
|
+
inProject,
|
|
10813
|
+
onSelect: (location) => {
|
|
10814
|
+
if (state.trustLocationSelector) {
|
|
10815
|
+
state.trustLocationSelector.resolve(location);
|
|
10816
|
+
}
|
|
10817
|
+
},
|
|
10818
|
+
onCancel: () => {
|
|
10819
|
+
if (state.trustLocationSelector) {
|
|
10820
|
+
state.trustLocationSelector.resolve(null);
|
|
10821
|
+
}
|
|
10822
|
+
}
|
|
10823
|
+
}
|
|
10824
|
+
);
|
|
10207
10825
|
}
|
|
10208
10826
|
if (state.showLoginFlow) {
|
|
10209
10827
|
const loginApiUrl = getApiUrl(state.config?.apiConfig);
|
|
10210
|
-
return /* @__PURE__ */
|
|
10828
|
+
return /* @__PURE__ */ React13.createElement(
|
|
10211
10829
|
LoginFlow,
|
|
10212
10830
|
{
|
|
10213
10831
|
apiUrl: loginApiUrl,
|
|
@@ -10230,15 +10848,16 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
10230
10848
|
);
|
|
10231
10849
|
}
|
|
10232
10850
|
if (!isInitialized) {
|
|
10233
|
-
return /* @__PURE__ */
|
|
10851
|
+
return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Text12, null, "\u{1F680} Initializing..."));
|
|
10234
10852
|
}
|
|
10235
|
-
return /* @__PURE__ */
|
|
10853
|
+
return /* @__PURE__ */ React13.createElement(
|
|
10236
10854
|
App,
|
|
10237
10855
|
{
|
|
10238
10856
|
onMessage: handleMessage,
|
|
10239
10857
|
onCommand: handleCommand,
|
|
10240
10858
|
commandHistory,
|
|
10241
10859
|
config: state.config,
|
|
10860
|
+
availableModels: state.availableModels,
|
|
10242
10861
|
onSaveConfig: handleSaveConfig,
|
|
10243
10862
|
onPermissionResponse: (response) => {
|
|
10244
10863
|
if (state.permissionPrompt) {
|
|
@@ -10265,6 +10884,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
|
|
|
10265
10884
|
if (isDevMode) {
|
|
10266
10885
|
console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
|
|
10267
10886
|
}
|
|
10268
|
-
render(/* @__PURE__ */
|
|
10887
|
+
render(/* @__PURE__ */ React13.createElement(CliApp, null), {
|
|
10269
10888
|
exitOnCtrlC: false
|
|
10270
10889
|
});
|