@bike4mind/cli 0.2.8-cli-bash-tools.17140 → 0.2.8-fix-cli-type-error.17148
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 +0 -1
- package/dist/{artifactExtractor-LF5DAVZL.js → artifactExtractor-DNE5C6DY.js} +1 -1
- package/dist/{chunk-6S7HV2GF.js → chunk-3CCBDIFR.js} +2 -2
- package/dist/{chunk-SE2T5GED.js → chunk-DNSBC3LO.js} +1 -1
- package/dist/{chunk-HD4QQGS6.js → chunk-H6SHASMZ.js} +1 -3
- package/dist/{chunk-F2K7OCDJ.js → chunk-LIRY24M5.js} +2 -2
- package/dist/{chunk-RJYG7BUV.js → chunk-YXHQN7SK.js} +2 -2
- package/dist/{create-S7N2FBWR.js → create-PNU64QSF.js} +3 -3
- package/dist/index.js +634 -896
- package/dist/{llmMarkdownGenerator-VY7FSNOI.js → llmMarkdownGenerator-UQXKK2AS.js} +1 -1
- package/dist/{markdownGenerator-KES2TDKF.js → markdownGenerator-FLLZFXMT.js} +1 -1
- package/dist/{mementoService-S4OOMZIT.js → mementoService-LVFQ5XAW.js} +3 -3
- package/dist/{src-7PSZ4VA4.js → src-OH5AAQEW.js} +2 -2
- package/dist/{src-VFRCY2I4.js → src-OYQXRLTM.js} +1 -1
- package/dist/{subtractCredits-DD7PBL22.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,19 +73,19 @@ 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 Box14, Text as
|
|
82
|
+
import React15, { useState as useState6, useEffect as useEffect3, useCallback, useRef } from "react";
|
|
83
|
+
import { render, Box as Box14, Text as Text14, useApp, useInput as useInput5 } from "ink";
|
|
84
84
|
import { v4 as uuidv49 } from "uuid";
|
|
85
85
|
|
|
86
86
|
// src/components/App.tsx
|
|
87
|
-
import
|
|
88
|
-
import { Box as Box9, Text as
|
|
87
|
+
import React10 from "react";
|
|
88
|
+
import { Box as Box9, Text as Text9, Static } from "ink";
|
|
89
89
|
|
|
90
90
|
// src/components/StatusBar.tsx
|
|
91
91
|
import React from "react";
|
|
@@ -95,27 +95,127 @@ var StatusBar = React.memo(function StatusBar2({ sessionName, model, tokenUsage
|
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
// src/components/InputPrompt.tsx
|
|
98
|
-
import
|
|
99
|
-
import { Box as Box4, Text as
|
|
100
|
-
|
|
98
|
+
import React5, { useState as useState2, useMemo, useEffect } from "react";
|
|
99
|
+
import { Box as Box4, Text as Text5, useInput as useInput2 } from "ink";
|
|
100
|
+
|
|
101
|
+
// src/components/CustomTextInput.tsx
|
|
102
|
+
import React2, { useState } from "react";
|
|
103
|
+
import { Text as Text2, useInput } from "ink";
|
|
104
|
+
function CustomTextInput({
|
|
105
|
+
value,
|
|
106
|
+
onChange,
|
|
107
|
+
onSubmit,
|
|
108
|
+
placeholder = "",
|
|
109
|
+
showCursor = true
|
|
110
|
+
}) {
|
|
111
|
+
const [cursorOffset, setCursorOffset] = useState(value.length);
|
|
112
|
+
useInput(
|
|
113
|
+
(input, key) => {
|
|
114
|
+
if (key.return && !key.meta && !key.shift) {
|
|
115
|
+
onSubmit(value);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (key.ctrl) {
|
|
119
|
+
switch (input) {
|
|
120
|
+
case "u":
|
|
121
|
+
{
|
|
122
|
+
const lines = value.split("\n");
|
|
123
|
+
let currentLineStart = 0;
|
|
124
|
+
let currentLineIndex = 0;
|
|
125
|
+
let charCount = 0;
|
|
126
|
+
for (let i = 0; i < lines.length; i++) {
|
|
127
|
+
const lineLength = lines[i].length;
|
|
128
|
+
if (charCount + lineLength >= cursorOffset) {
|
|
129
|
+
currentLineIndex = i;
|
|
130
|
+
currentLineStart = charCount;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
charCount += lineLength + 1;
|
|
134
|
+
}
|
|
135
|
+
lines.splice(currentLineIndex, 1);
|
|
136
|
+
const newValue = lines.join("\n");
|
|
137
|
+
onChange(newValue);
|
|
138
|
+
setCursorOffset(Math.min(currentLineStart, newValue.length));
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
case "k":
|
|
142
|
+
onChange(value.slice(0, cursorOffset));
|
|
143
|
+
return;
|
|
144
|
+
case "w":
|
|
145
|
+
{
|
|
146
|
+
const beforeCursor2 = value.slice(0, cursorOffset);
|
|
147
|
+
const afterCursor2 = value.slice(cursorOffset);
|
|
148
|
+
const trimmed = beforeCursor2.trimEnd();
|
|
149
|
+
const lastSpace = trimmed.lastIndexOf(" ");
|
|
150
|
+
const newBefore = lastSpace === -1 ? "" : trimmed.slice(0, lastSpace + 1);
|
|
151
|
+
const newValue = newBefore + afterCursor2;
|
|
152
|
+
onChange(newValue);
|
|
153
|
+
setCursorOffset(newBefore.length);
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
case "a":
|
|
157
|
+
setCursorOffset(0);
|
|
158
|
+
return;
|
|
159
|
+
case "e":
|
|
160
|
+
setCursorOffset(value.length);
|
|
161
|
+
return;
|
|
162
|
+
case "l":
|
|
163
|
+
onChange("");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (key.backspace || key.delete) {
|
|
168
|
+
if (cursorOffset > 0) {
|
|
169
|
+
const newValue = value.slice(0, cursorOffset - 1) + value.slice(cursorOffset);
|
|
170
|
+
onChange(newValue);
|
|
171
|
+
setCursorOffset(cursorOffset - 1);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (key.leftArrow) {
|
|
176
|
+
setCursorOffset(Math.max(0, cursorOffset - 1));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (key.rightArrow) {
|
|
180
|
+
setCursorOffset(Math.min(value.length, cursorOffset + 1));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!key.ctrl && !key.meta && input.length === 1) {
|
|
184
|
+
const sanitizedInput = input === "\r" ? "\n" : input;
|
|
185
|
+
const newValue = value.slice(0, cursorOffset) + sanitizedInput + value.slice(cursorOffset);
|
|
186
|
+
onChange(newValue);
|
|
187
|
+
setCursorOffset(cursorOffset + 1);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{ isActive: true }
|
|
191
|
+
);
|
|
192
|
+
const hasValue = value.length > 0;
|
|
193
|
+
if (!hasValue) {
|
|
194
|
+
return /* @__PURE__ */ React2.createElement(Text2, null, showCursor ? /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, { inverse: true }, " "), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, placeholder)) : /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, placeholder));
|
|
195
|
+
}
|
|
196
|
+
const beforeCursor = value.slice(0, cursorOffset);
|
|
197
|
+
const cursorChar = value[cursorOffset] || " ";
|
|
198
|
+
const afterCursor = value.slice(cursorOffset + 1);
|
|
199
|
+
return /* @__PURE__ */ React2.createElement(Text2, null, beforeCursor, showCursor && /* @__PURE__ */ React2.createElement(Text2, { inverse: true }, cursorChar), !showCursor && cursorChar, afterCursor);
|
|
200
|
+
}
|
|
101
201
|
|
|
102
202
|
// src/components/CommandAutocomplete.tsx
|
|
103
|
-
import
|
|
104
|
-
import { Box as Box2, Text as
|
|
203
|
+
import React3 from "react";
|
|
204
|
+
import { Box as Box2, Text as Text3 } from "ink";
|
|
105
205
|
function CommandAutocomplete({ commands, selectedIndex }) {
|
|
106
206
|
if (commands.length === 0) {
|
|
107
|
-
return /* @__PURE__ */
|
|
207
|
+
return /* @__PURE__ */ React3.createElement(Box2, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No matching commands"));
|
|
108
208
|
}
|
|
109
|
-
return /* @__PURE__ */
|
|
209
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, commands.length === 1 ? "1 command" : `${commands.length} commands`, " \u2022 Use \u2191\u2193 to navigate, Enter to select")), commands.map((cmd, index) => {
|
|
110
210
|
const args = cmd.args ? ` ${cmd.args}` : "";
|
|
111
211
|
const isSelected = index === selectedIndex;
|
|
112
|
-
return /* @__PURE__ */
|
|
212
|
+
return /* @__PURE__ */ React3.createElement(Box2, { key: cmd.name, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "\u25B8 " : " ", "/", cmd.name, args, " - ", cmd.description));
|
|
113
213
|
}));
|
|
114
214
|
}
|
|
115
215
|
|
|
116
216
|
// src/components/FileAutocomplete.tsx
|
|
117
|
-
import
|
|
118
|
-
import { Box as Box3, Text as
|
|
217
|
+
import React4 from "react";
|
|
218
|
+
import { Box as Box3, Text as Text4 } from "ink";
|
|
119
219
|
|
|
120
220
|
// src/utils/fileSearch.ts
|
|
121
221
|
import * as fs from "fs";
|
|
@@ -304,14 +404,14 @@ var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
|
304
404
|
// src/components/FileAutocomplete.tsx
|
|
305
405
|
function FileAutocomplete({ files, selectedIndex, query }) {
|
|
306
406
|
if (files.length === 0) {
|
|
307
|
-
return /* @__PURE__ */
|
|
407
|
+
return /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No matching files", query ? ` for "${query}"` : ""));
|
|
308
408
|
}
|
|
309
|
-
return /* @__PURE__ */
|
|
409
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, files.length === 1 ? "1 match" : `${files.length} matches`, " - Use up/down to navigate, Tab to select")), files.map((file, index) => {
|
|
310
410
|
const isSelected = index === selectedIndex;
|
|
311
411
|
const icon = file.isDirectory ? "[folder]" : "[file] ";
|
|
312
412
|
const sizeDisplay = file.isDirectory ? "" : file.size !== void 0 ? ` (${formatFileSize(file.size)})` : "";
|
|
313
413
|
const pathDisplay = file.isDirectory ? `${file.path}/` : file.path;
|
|
314
|
-
return /* @__PURE__ */
|
|
414
|
+
return /* @__PURE__ */ React4.createElement(Box3, { key: file.path, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "> " : " "), /* @__PURE__ */ React4.createElement(Text4, { color: file.isDirectory ? "yellow" : isSelected ? "cyan" : void 0, bold: isSelected }, icon), /* @__PURE__ */ React4.createElement(Text4, { color: isSelected ? "cyan" : void 0, bold: isSelected }, " ", pathDisplay), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, sizeDisplay));
|
|
315
415
|
}));
|
|
316
416
|
}
|
|
317
417
|
|
|
@@ -638,20 +738,18 @@ function InputPrompt({
|
|
|
638
738
|
prefillInput,
|
|
639
739
|
onPrefillConsumed
|
|
640
740
|
}) {
|
|
641
|
-
const [value, setValue] =
|
|
642
|
-
const [selectedIndex, setSelectedIndex] =
|
|
643
|
-
const [historyIndex, setHistoryIndex] =
|
|
644
|
-
const [tempInput, setTempInput] =
|
|
645
|
-
const [inputKey, setInputKey] = useState(0);
|
|
741
|
+
const [value, setValue] = useState2("");
|
|
742
|
+
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
743
|
+
const [historyIndex, setHistoryIndex] = useState2(-1);
|
|
744
|
+
const [tempInput, setTempInput] = useState2("");
|
|
646
745
|
useEffect(() => {
|
|
647
746
|
if (prefillInput) {
|
|
648
747
|
setValue(prefillInput);
|
|
649
|
-
setInputKey((prev) => prev + 1);
|
|
650
748
|
onPrefillConsumed?.();
|
|
651
749
|
}
|
|
652
750
|
}, [prefillInput, onPrefillConsumed]);
|
|
653
|
-
const [fileAutocomplete, setFileAutocomplete] =
|
|
654
|
-
const [fileSelectedIndex, setFileSelectedIndex] =
|
|
751
|
+
const [fileAutocomplete, setFileAutocomplete] = useState2(null);
|
|
752
|
+
const [fileSelectedIndex, setFileSelectedIndex] = useState2(0);
|
|
655
753
|
const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
|
|
656
754
|
const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
|
|
657
755
|
const filteredCommands = useMemo(() => {
|
|
@@ -668,7 +766,7 @@ function InputPrompt({
|
|
|
668
766
|
useEffect(() => {
|
|
669
767
|
setFileSelectedIndex(0);
|
|
670
768
|
}, [filteredFiles]);
|
|
671
|
-
|
|
769
|
+
useInput2((_input, key) => {
|
|
672
770
|
if (fileAutocomplete?.active && filteredFiles.length > 0) {
|
|
673
771
|
if (key.upArrow) {
|
|
674
772
|
setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
|
|
@@ -725,7 +823,6 @@ function InputPrompt({
|
|
|
725
823
|
const pathToInsert = file.isDirectory ? `@${file.path}/` : `@${file.path}`;
|
|
726
824
|
const newValue = beforeAt + pathToInsert + afterQuery;
|
|
727
825
|
setValue(newValue);
|
|
728
|
-
setInputKey((prev) => prev + 1);
|
|
729
826
|
if (file.isDirectory) {
|
|
730
827
|
setFileAutocomplete({
|
|
731
828
|
active: true,
|
|
@@ -752,7 +849,6 @@ function InputPrompt({
|
|
|
752
849
|
if (selectedCommand.args) {
|
|
753
850
|
setValue(commandText + " ");
|
|
754
851
|
setHistoryIndex(-1);
|
|
755
|
-
setInputKey((prev) => prev + 1);
|
|
756
852
|
return;
|
|
757
853
|
}
|
|
758
854
|
setValue("");
|
|
@@ -771,7 +867,6 @@ function InputPrompt({
|
|
|
771
867
|
if (imageEvent && onImageDetected) {
|
|
772
868
|
const placeholder = await onImageDetected(imageEvent.data);
|
|
773
869
|
setValue(`${placeholder} `);
|
|
774
|
-
setInputKey((prev) => prev + 1);
|
|
775
870
|
return;
|
|
776
871
|
}
|
|
777
872
|
}
|
|
@@ -791,29 +886,28 @@ function InputPrompt({
|
|
|
791
886
|
setFileAutocomplete(null);
|
|
792
887
|
}
|
|
793
888
|
};
|
|
794
|
-
return /* @__PURE__ */
|
|
795
|
-
|
|
889
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(
|
|
890
|
+
CustomTextInput,
|
|
796
891
|
{
|
|
797
|
-
key: inputKey,
|
|
798
892
|
value,
|
|
799
893
|
onChange: handleChange,
|
|
800
894
|
onSubmit: handleSubmit,
|
|
801
|
-
placeholder: disabled ? "" : "Type your message, /help for commands, or @file to reference",
|
|
895
|
+
placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
|
|
802
896
|
showCursor: !disabled
|
|
803
897
|
}
|
|
804
|
-
)), shouldShowCommandAutocomplete && /* @__PURE__ */
|
|
898
|
+
)), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
|
|
805
899
|
}
|
|
806
900
|
|
|
807
901
|
// src/components/AgentThinking.tsx
|
|
808
|
-
import
|
|
902
|
+
import React7 from "react";
|
|
809
903
|
import { Box as Box6 } from "ink";
|
|
810
904
|
|
|
811
905
|
// src/components/ThoughtStream.tsx
|
|
812
|
-
import
|
|
813
|
-
import { Box as Box5, Text as
|
|
906
|
+
import React6 from "react";
|
|
907
|
+
import { Box as Box5, Text as Text6 } from "ink";
|
|
814
908
|
import Spinner from "ink-spinner";
|
|
815
|
-
var ThoughtStream =
|
|
816
|
-
return /* @__PURE__ */
|
|
909
|
+
var ThoughtStream = React6.memo(function ThoughtStream2({ steps }) {
|
|
910
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, steps.map((step, index) => /* @__PURE__ */ React6.createElement(Box5, { key: index, flexDirection: "column" }, step.type === "thought" && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "\u{1F914} Thought: "), /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.type === "action" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u26A1 Action: "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, step.metadata?.toolName || "unknown")), step.metadata?.toolInput && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, JSON.stringify(step.metadata.toolInput, null, 2)))), step.type === "observation" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, "\u{1F4CA} Observation: ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content))), step.type === "final_answer" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green", bold: true }, "\u2705 Final Answer:", " ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.metadata?.tokenUsage && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "(", step.metadata.tokenUsage.total, " tokens)"))))), !steps.some((s) => s.type === "final_answer") && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " ", steps.length === 0 ? "Thinking..." : "Processing...")));
|
|
817
911
|
});
|
|
818
912
|
|
|
819
913
|
// src/store/index.ts
|
|
@@ -829,7 +923,6 @@ var useCliStore = create((set) => ({
|
|
|
829
923
|
addAgentStep: (step) => set((state) => ({
|
|
830
924
|
agentSteps: [...state.agentSteps, step]
|
|
831
925
|
})),
|
|
832
|
-
setAgentSteps: (steps) => set({ agentSteps: steps }),
|
|
833
926
|
clearAgentSteps: () => set({ agentSteps: [] }),
|
|
834
927
|
// Permission prompt
|
|
835
928
|
permissionPrompt: null,
|
|
@@ -843,32 +936,32 @@ var useCliStore = create((set) => ({
|
|
|
843
936
|
}));
|
|
844
937
|
|
|
845
938
|
// src/components/AgentThinking.tsx
|
|
846
|
-
var AgentThinking =
|
|
939
|
+
var AgentThinking = React7.memo(function AgentThinking2() {
|
|
847
940
|
const isThinking = useCliStore((state) => state.isThinking);
|
|
848
941
|
const agentSteps = useCliStore((state) => state.agentSteps);
|
|
849
942
|
if (!isThinking) {
|
|
850
943
|
return null;
|
|
851
944
|
}
|
|
852
|
-
return /* @__PURE__ */
|
|
945
|
+
return /* @__PURE__ */ React7.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
|
|
853
946
|
});
|
|
854
947
|
|
|
855
948
|
// src/components/PermissionPrompt.tsx
|
|
856
|
-
import
|
|
857
|
-
import { Box as Box7, Text as
|
|
949
|
+
import React8 from "react";
|
|
950
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
858
951
|
import SelectInput from "ink-select-input";
|
|
859
952
|
function renderDiffPreview(preview) {
|
|
860
953
|
const lines = preview.split("\n");
|
|
861
954
|
return lines.map((line, index) => {
|
|
862
955
|
if (line.startsWith("+")) {
|
|
863
|
-
return /* @__PURE__ */
|
|
956
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "green" }, line);
|
|
864
957
|
}
|
|
865
958
|
if (line.startsWith("-")) {
|
|
866
|
-
return /* @__PURE__ */
|
|
959
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "red" }, line);
|
|
867
960
|
}
|
|
868
961
|
if (line.startsWith("@@")) {
|
|
869
|
-
return /* @__PURE__ */
|
|
962
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "cyan" }, line);
|
|
870
963
|
}
|
|
871
|
-
return /* @__PURE__ */
|
|
964
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, dimColor: true }, line);
|
|
872
965
|
});
|
|
873
966
|
}
|
|
874
967
|
function PermissionPrompt({
|
|
@@ -888,12 +981,12 @@ function PermissionPrompt({
|
|
|
888
981
|
{ label: "\u2717 Deny", value: "deny" }
|
|
889
982
|
];
|
|
890
983
|
const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
|
|
891
|
-
return /* @__PURE__ */
|
|
984
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Tool: "), /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Action: "), /* @__PURE__ */ React8.createElement(Text7, null, toolDescription)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Arguments:"), /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Preview:"), /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
|
|
892
985
|
}
|
|
893
986
|
|
|
894
987
|
// src/components/ConfigEditor.tsx
|
|
895
|
-
import
|
|
896
|
-
import { Box as Box8, Text as
|
|
988
|
+
import React9, { useState as useState3, useMemo as useMemo2 } from "react";
|
|
989
|
+
import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
|
|
897
990
|
var MAX_ITERATIONS_OPTIONS = [
|
|
898
991
|
{ label: "10", value: 10 },
|
|
899
992
|
{ label: "20", value: 20 },
|
|
@@ -1024,10 +1117,10 @@ function buildConfigItems(availableModels) {
|
|
|
1024
1117
|
return items;
|
|
1025
1118
|
}
|
|
1026
1119
|
function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
1027
|
-
const [selectedIndex, setSelectedIndex] =
|
|
1028
|
-
const [editedConfig, setEditedConfig] =
|
|
1029
|
-
const [saveError, setSaveError] =
|
|
1030
|
-
const [isSaving, setIsSaving] =
|
|
1120
|
+
const [selectedIndex, setSelectedIndex] = useState3(0);
|
|
1121
|
+
const [editedConfig, setEditedConfig] = useState3(config);
|
|
1122
|
+
const [saveError, setSaveError] = useState3(null);
|
|
1123
|
+
const [isSaving, setIsSaving] = useState3(false);
|
|
1031
1124
|
const configItems = useMemo2(() => buildConfigItems(availableModels), [availableModels]);
|
|
1032
1125
|
const hasChanges = useMemo2(() => {
|
|
1033
1126
|
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
|
|
@@ -1047,7 +1140,7 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1047
1140
|
}
|
|
1048
1141
|
onClose();
|
|
1049
1142
|
};
|
|
1050
|
-
|
|
1143
|
+
useInput3((input, key) => {
|
|
1051
1144
|
const currentItem = configItems[selectedIndex];
|
|
1052
1145
|
if (key.upArrow) {
|
|
1053
1146
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : configItems.length - 1);
|
|
@@ -1112,13 +1205,13 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1112
1205
|
}
|
|
1113
1206
|
return String(value);
|
|
1114
1207
|
};
|
|
1115
|
-
return /* @__PURE__ */
|
|
1208
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, marginY: 1 }, /* @__PURE__ */ React9.createElement(Box8, { justifyContent: "space-between", marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "cyan" }, "Settings"), isSaving ? /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, "Saving...") : hasChanges ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, color: "yellow" }, "(unsaved changes)") : null), saveError && /* @__PURE__ */ React9.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "red" }, "Error: ", saveError)), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginBottom: 1 }, configItems.map((item, index) => {
|
|
1116
1209
|
const isSelected = index === selectedIndex;
|
|
1117
1210
|
const value = item.getValue(editedConfig);
|
|
1118
1211
|
const displayValue = formatValue(item, value);
|
|
1119
1212
|
const hasOptions = item.type === "select" || item.type === "boolean" || item.type === "number";
|
|
1120
|
-
return /* @__PURE__ */
|
|
1121
|
-
})), /* @__PURE__ */
|
|
1213
|
+
return /* @__PURE__ */ React9.createElement(Box8, { key: item.key }, /* @__PURE__ */ React9.createElement(Text8, { color: isSelected ? "cyan" : void 0 }, isSelected ? "> " : " "), /* @__PURE__ */ React9.createElement(Box8, { width: 18 }, /* @__PURE__ */ React9.createElement(Text8, { bold: isSelected, color: isSelected ? "white" : "gray" }, item.label, ":")), /* @__PURE__ */ React9.createElement(Box8, null, hasOptions && isSelected && /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "< "), /* @__PURE__ */ React9.createElement(Text8, { bold: isSelected, color: isSelected ? "green" : void 0 }, displayValue), hasOptions && isSelected && /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " >")));
|
|
1214
|
+
})), /* @__PURE__ */ React9.createElement(Box8, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "\u2191/\u2193: Navigate | Space/\u2190/\u2192: Change | q/Esc: Save & Exit")));
|
|
1122
1215
|
}
|
|
1123
1216
|
|
|
1124
1217
|
// src/utils/processFileReferences.ts
|
|
@@ -1258,7 +1351,7 @@ function App({
|
|
|
1258
1351
|
const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
|
|
1259
1352
|
const exitRequested = useCliStore((state) => state.exitRequested);
|
|
1260
1353
|
const setIsThinking = useCliStore((state) => state.setIsThinking);
|
|
1261
|
-
const handleSubmit =
|
|
1354
|
+
const handleSubmit = React10.useCallback(
|
|
1262
1355
|
async (input) => {
|
|
1263
1356
|
const trimmed = input.trim();
|
|
1264
1357
|
if (!trimmed) return;
|
|
@@ -1287,7 +1380,7 @@ ${errorBlock}`;
|
|
|
1287
1380
|
},
|
|
1288
1381
|
[onMessage, onCommand, setIsThinking]
|
|
1289
1382
|
);
|
|
1290
|
-
return /* @__PURE__ */
|
|
1383
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), showConfigEditor && config && onSaveConfig ? /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
|
|
1291
1384
|
ConfigEditor,
|
|
1292
1385
|
{
|
|
1293
1386
|
config,
|
|
@@ -1295,7 +1388,7 @@ ${errorBlock}`;
|
|
|
1295
1388
|
onSave: onSaveConfig,
|
|
1296
1389
|
onClose: () => setShowConfigEditor(false)
|
|
1297
1390
|
}
|
|
1298
|
-
)) : permissionPrompt ? /* @__PURE__ */
|
|
1391
|
+
)) : permissionPrompt ? /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
|
|
1299
1392
|
PermissionPrompt,
|
|
1300
1393
|
{
|
|
1301
1394
|
toolName: permissionPrompt.toolName,
|
|
@@ -1304,7 +1397,7 @@ ${errorBlock}`;
|
|
|
1304
1397
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
1305
1398
|
onResponse: onPermissionResponse
|
|
1306
1399
|
}
|
|
1307
|
-
)) : /* @__PURE__ */
|
|
1400
|
+
)) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Static, { items: messages }, (message, index) => /* @__PURE__ */ React10.createElement(Box9, { key: index, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(MessageItem, { message }))), /* @__PURE__ */ React10.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React10.createElement(Box9, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
|
|
1308
1401
|
InputPrompt,
|
|
1309
1402
|
{
|
|
1310
1403
|
onSubmit: handleSubmit,
|
|
@@ -1317,37 +1410,36 @@ ${errorBlock}`;
|
|
|
1317
1410
|
))));
|
|
1318
1411
|
}
|
|
1319
1412
|
function MessageItem({ message }) {
|
|
1320
|
-
|
|
1321
|
-
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: isUser ? "cyan" : "green" }, isUser ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), isUser && message.content && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { backgroundColor: "whiteBright", color: "black" }, " ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { 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__ */ React9.createElement(Text8, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
1413
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React10.createElement(Text9, null, message.content)), 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) => {
|
|
1322
1414
|
if (step.type === "thought") {
|
|
1323
|
-
return /* @__PURE__ */
|
|
1415
|
+
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 ? "..." : ""}`));
|
|
1324
1416
|
}
|
|
1325
1417
|
if (step.type === "action") {
|
|
1326
1418
|
const toolName = step.metadata?.toolName || "unknown";
|
|
1327
1419
|
const toolInput = step.metadata?.toolInput;
|
|
1328
1420
|
const observationStep = message.metadata.steps[idx + 1];
|
|
1329
1421
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
1330
|
-
return /* @__PURE__ */
|
|
1422
|
+
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 ? "..." : ""}`));
|
|
1331
1423
|
}
|
|
1332
1424
|
return null;
|
|
1333
|
-
}).filter(Boolean)),
|
|
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`)));
|
|
1334
1426
|
}
|
|
1335
1427
|
|
|
1336
1428
|
// src/components/MessageList.tsx
|
|
1337
|
-
import
|
|
1338
|
-
import { Box as Box10, Text as
|
|
1429
|
+
import React11 from "react";
|
|
1430
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1339
1431
|
function stripThinkingTags(content) {
|
|
1340
1432
|
return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
1341
1433
|
}
|
|
1342
|
-
var MessageList =
|
|
1434
|
+
var MessageList = React11.memo(
|
|
1343
1435
|
function MessageList2({ messages }) {
|
|
1344
1436
|
if (messages.length === 0) {
|
|
1345
|
-
return /* @__PURE__ */
|
|
1437
|
+
return /* @__PURE__ */ React11.createElement(Box10, { paddingY: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "No messages yet. Type a message to start!"));
|
|
1346
1438
|
}
|
|
1347
|
-
return /* @__PURE__ */
|
|
1439
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", gap: 1, paddingY: 1 }, messages.map((message, index) => /* @__PURE__ */ React11.createElement(Box10, { key: index, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React11.createElement(Box10, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u26A0\uFE0F ", stripThinkingTags(message.content)) : /* @__PURE__ */ React11.createElement(Text10, null, stripThinkingTags(message.content))), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React11.createElement(Box10, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text10, { 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__ */ React11.createElement(Text10, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
1348
1440
|
if (step.type === "thought") {
|
|
1349
|
-
return /* @__PURE__ */
|
|
1350
|
-
|
|
1441
|
+
return /* @__PURE__ */ React11.createElement(Box10, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React11.createElement(
|
|
1442
|
+
Text10,
|
|
1351
1443
|
{
|
|
1352
1444
|
dimColor: true
|
|
1353
1445
|
},
|
|
@@ -1359,10 +1451,10 @@ var MessageList = React10.memo(
|
|
|
1359
1451
|
const toolInput = step.metadata?.toolInput;
|
|
1360
1452
|
const observationStep = message.metadata.steps[idx + 1];
|
|
1361
1453
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
1362
|
-
return /* @__PURE__ */
|
|
1454
|
+
return /* @__PURE__ */ React11.createElement(Box10, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React11.createElement(Text10, { 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 ? "..." : ""}`));
|
|
1363
1455
|
}
|
|
1364
1456
|
return null;
|
|
1365
|
-
}).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */
|
|
1457
|
+
}).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React11.createElement(Box10, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)))));
|
|
1366
1458
|
},
|
|
1367
1459
|
(prevProps, nextProps) => {
|
|
1368
1460
|
if (prevProps.messages.length !== nextProps.messages.length) {
|
|
@@ -1373,8 +1465,8 @@ var MessageList = React10.memo(
|
|
|
1373
1465
|
);
|
|
1374
1466
|
|
|
1375
1467
|
// src/components/TrustLocationSelector.tsx
|
|
1376
|
-
import
|
|
1377
|
-
import { Box as Box11, Text as
|
|
1468
|
+
import React12 from "react";
|
|
1469
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1378
1470
|
import SelectInput2 from "ink-select-input";
|
|
1379
1471
|
function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
1380
1472
|
const items = [];
|
|
@@ -1395,24 +1487,24 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
|
1395
1487
|
const handleSelect = (item) => {
|
|
1396
1488
|
onSelect(item.value);
|
|
1397
1489
|
};
|
|
1398
|
-
return /* @__PURE__ */
|
|
1490
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React12.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { bold: true }, "Where should this rule be saved?")), /* @__PURE__ */ React12.createElement(
|
|
1399
1491
|
SelectInput2,
|
|
1400
1492
|
{
|
|
1401
1493
|
items,
|
|
1402
1494
|
onSelect: handleSelect,
|
|
1403
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
1495
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1404
1496
|
}
|
|
1405
|
-
), /* @__PURE__ */
|
|
1497
|
+
), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Ctrl+C to cancel")));
|
|
1406
1498
|
}
|
|
1407
1499
|
|
|
1408
1500
|
// src/components/RewindSelector.tsx
|
|
1409
|
-
import
|
|
1410
|
-
import { Box as Box12, Text as
|
|
1501
|
+
import React13, { useState as useState4 } from "react";
|
|
1502
|
+
import { Box as Box12, Text as Text12, useInput as useInput4 } from "ink";
|
|
1411
1503
|
import SelectInput3 from "ink-select-input";
|
|
1412
1504
|
function RewindSelector({ messages, onSelect, onCancel }) {
|
|
1413
|
-
const [step, setStep] =
|
|
1414
|
-
const [selectedMessageIndex, setSelectedMessageIndex] =
|
|
1415
|
-
|
|
1505
|
+
const [step, setStep] = useState4("selection");
|
|
1506
|
+
const [selectedMessageIndex, setSelectedMessageIndex] = useState4(null);
|
|
1507
|
+
useInput4((input, key) => {
|
|
1416
1508
|
if (key.escape) {
|
|
1417
1509
|
if (step === "confirmation") {
|
|
1418
1510
|
setStep("selection");
|
|
@@ -1449,14 +1541,14 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
1449
1541
|
return sum2 + (msg.metadata?.tokenUsage?.total || 0);
|
|
1450
1542
|
}, 0);
|
|
1451
1543
|
if (step === "selection") {
|
|
1452
|
-
return /* @__PURE__ */
|
|
1544
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true }, "Select a point to rewind to:")), /* @__PURE__ */ React13.createElement(
|
|
1453
1545
|
SelectInput3,
|
|
1454
1546
|
{
|
|
1455
1547
|
items,
|
|
1456
1548
|
onSelect: handleSelectionSelect,
|
|
1457
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
1549
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1458
1550
|
}
|
|
1459
|
-
), /* @__PURE__ */
|
|
1551
|
+
), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
|
|
1460
1552
|
}
|
|
1461
1553
|
const confirmationItems = [
|
|
1462
1554
|
{ label: "Yes, rewind to this point", value: "confirm" },
|
|
@@ -1464,19 +1556,19 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
1464
1556
|
];
|
|
1465
1557
|
const selectedMessage = selectedMessageIndex !== null && selectedMessageIndex >= 0 && selectedMessageIndex < messages.length ? messages[selectedMessageIndex] : null;
|
|
1466
1558
|
const selectedPreview = selectedMessage ? selectedMessage.content.length > 50 ? selectedMessage.content.substring(0, 50) + "..." : selectedMessage.content : "";
|
|
1467
|
-
return /* @__PURE__ */
|
|
1559
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text12, { bold: true }, "Confirm rewind operation:"), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Message: ", selectedPreview), /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, "This will remove ", messagesToRemove.length, " message(s) (", tokensToRemove.toLocaleString(), " tokens)"), /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, "The selected message will be placed in your input for editing.")), /* @__PURE__ */ React13.createElement(
|
|
1468
1560
|
SelectInput3,
|
|
1469
1561
|
{
|
|
1470
1562
|
items: confirmationItems,
|
|
1471
1563
|
onSelect: handleConfirmationSelect,
|
|
1472
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
1564
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1473
1565
|
}
|
|
1474
|
-
), /* @__PURE__ */
|
|
1566
|
+
), /* @__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")));
|
|
1475
1567
|
}
|
|
1476
1568
|
|
|
1477
1569
|
// src/components/LoginFlow.tsx
|
|
1478
|
-
import
|
|
1479
|
-
import { Box as Box13, Text as
|
|
1570
|
+
import React14, { useState as useState5, useEffect as useEffect2 } from "react";
|
|
1571
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1480
1572
|
import Spinner2 from "ink-spinner";
|
|
1481
1573
|
import jwt from "jsonwebtoken";
|
|
1482
1574
|
import open from "open";
|
|
@@ -1592,10 +1684,10 @@ var OAuthClient = class {
|
|
|
1592
1684
|
|
|
1593
1685
|
// src/components/LoginFlow.tsx
|
|
1594
1686
|
function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, onError }) {
|
|
1595
|
-
const [status, setStatus] =
|
|
1596
|
-
const [deviceFlow, setDeviceFlow] =
|
|
1597
|
-
const [statusMessage, setStatusMessage] =
|
|
1598
|
-
const [error, setError] =
|
|
1687
|
+
const [status, setStatus] = useState5("initiating");
|
|
1688
|
+
const [deviceFlow, setDeviceFlow] = useState5(null);
|
|
1689
|
+
const [statusMessage, setStatusMessage] = useState5("Initiating device authorization...");
|
|
1690
|
+
const [error, setError] = useState5(null);
|
|
1599
1691
|
useEffect2(() => {
|
|
1600
1692
|
const runLoginFlow = async () => {
|
|
1601
1693
|
const oauth = new OAuthClient(apiUrl);
|
|
@@ -1639,15 +1731,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
1639
1731
|
}
|
|
1640
1732
|
}, [deviceFlow, status]);
|
|
1641
1733
|
if (status === "initiating") {
|
|
1642
|
-
return /* @__PURE__ */
|
|
1734
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan" }, /* @__PURE__ */ React14.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
|
|
1643
1735
|
}
|
|
1644
1736
|
if (status === "error") {
|
|
1645
|
-
return /* @__PURE__ */
|
|
1737
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: "red" }, error)));
|
|
1646
1738
|
}
|
|
1647
1739
|
if (status === "success") {
|
|
1648
|
-
return /* @__PURE__ */
|
|
1740
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "You can now use B4M CLI with your account.")));
|
|
1649
1741
|
}
|
|
1650
|
-
return /* @__PURE__ */
|
|
1742
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "And enter this code when prompted:")), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan" }, /* @__PURE__ */ React14.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
|
|
1651
1743
|
}
|
|
1652
1744
|
|
|
1653
1745
|
// src/storage/SessionStore.ts
|
|
@@ -2533,9 +2625,10 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
2533
2625
|
content: query
|
|
2534
2626
|
}
|
|
2535
2627
|
];
|
|
2628
|
+
console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
|
|
2536
2629
|
messages.forEach((msg, i) => {
|
|
2537
2630
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
2538
|
-
|
|
2631
|
+
console.log(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
|
|
2539
2632
|
});
|
|
2540
2633
|
let finalAnswer = "";
|
|
2541
2634
|
let reachedMaxIterations = false;
|
|
@@ -4928,8 +5021,8 @@ async function processAndStoreImages(images, context) {
|
|
|
4928
5021
|
const buffer = await downloadImage(image);
|
|
4929
5022
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
4930
5023
|
const filename = `${uuidv45()}.${fileType?.ext}`;
|
|
4931
|
-
const
|
|
4932
|
-
return
|
|
5024
|
+
const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
5025
|
+
return path13;
|
|
4933
5026
|
}));
|
|
4934
5027
|
}
|
|
4935
5028
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -6141,8 +6234,8 @@ async function processAndStoreImage(imageUrl, context) {
|
|
|
6141
6234
|
const buffer = await downloadImage2(imageUrl);
|
|
6142
6235
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
6143
6236
|
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
6144
|
-
const
|
|
6145
|
-
return
|
|
6237
|
+
const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
6238
|
+
return path13;
|
|
6146
6239
|
}
|
|
6147
6240
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
6148
6241
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -8554,381 +8647,6 @@ var deleteFileTool = {
|
|
|
8554
8647
|
})
|
|
8555
8648
|
};
|
|
8556
8649
|
|
|
8557
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
8558
|
-
import { spawn } from "child_process";
|
|
8559
|
-
import path11 from "path";
|
|
8560
|
-
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
8561
|
-
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
8562
|
-
var DANGEROUS_PATTERNS = [
|
|
8563
|
-
// Destructive file operations
|
|
8564
|
-
{
|
|
8565
|
-
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
8566
|
-
reason: "Recursive delete with path",
|
|
8567
|
-
block: true
|
|
8568
|
-
},
|
|
8569
|
-
{
|
|
8570
|
-
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
8571
|
-
reason: "Force delete without preserve root",
|
|
8572
|
-
block: true
|
|
8573
|
-
},
|
|
8574
|
-
{
|
|
8575
|
-
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
8576
|
-
reason: "Recursive force delete on root paths",
|
|
8577
|
-
block: true
|
|
8578
|
-
},
|
|
8579
|
-
{
|
|
8580
|
-
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
8581
|
-
reason: "Force recursive delete on root paths",
|
|
8582
|
-
block: true
|
|
8583
|
-
},
|
|
8584
|
-
// System-level dangerous commands
|
|
8585
|
-
{ pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
|
|
8586
|
-
{ pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
|
|
8587
|
-
{ pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
|
|
8588
|
-
{ pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
|
|
8589
|
-
// Disk/partition operations
|
|
8590
|
-
{ pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
|
|
8591
|
-
{ pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
|
|
8592
|
-
{ pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
|
|
8593
|
-
// Network attacks
|
|
8594
|
-
{ pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
|
|
8595
|
-
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8596
|
-
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8597
|
-
// Fork bombs and resource exhaustion
|
|
8598
|
-
{ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
|
|
8599
|
-
{ pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
|
|
8600
|
-
// Credential/sensitive data access
|
|
8601
|
-
{ pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
|
|
8602
|
-
{ pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
|
|
8603
|
-
{ pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
|
|
8604
|
-
// History/log manipulation
|
|
8605
|
-
{ pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
|
|
8606
|
-
{ pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
|
|
8607
|
-
// Dangerous redirects
|
|
8608
|
-
{ pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
|
|
8609
|
-
{ pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
|
|
8610
|
-
// Environment manipulation
|
|
8611
|
-
{ pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
|
|
8612
|
-
{ pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
|
|
8613
|
-
// Process/system control
|
|
8614
|
-
{ pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
|
|
8615
|
-
{ pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
|
|
8616
|
-
{ pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
|
|
8617
|
-
{ pattern: /\breboot\b/i, reason: "System reboot", block: true },
|
|
8618
|
-
{ pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
|
|
8619
|
-
];
|
|
8620
|
-
var SAFE_COMMAND_PREFIXES = [
|
|
8621
|
-
"ls",
|
|
8622
|
-
"cat",
|
|
8623
|
-
"head",
|
|
8624
|
-
"tail",
|
|
8625
|
-
"grep",
|
|
8626
|
-
"find",
|
|
8627
|
-
"echo",
|
|
8628
|
-
"pwd",
|
|
8629
|
-
"whoami",
|
|
8630
|
-
"date",
|
|
8631
|
-
"cal",
|
|
8632
|
-
"wc",
|
|
8633
|
-
"sort",
|
|
8634
|
-
"uniq",
|
|
8635
|
-
"cut",
|
|
8636
|
-
"tr",
|
|
8637
|
-
"sed",
|
|
8638
|
-
"awk",
|
|
8639
|
-
"git",
|
|
8640
|
-
"npm",
|
|
8641
|
-
"pnpm",
|
|
8642
|
-
"yarn",
|
|
8643
|
-
"node",
|
|
8644
|
-
"npx",
|
|
8645
|
-
"tsx",
|
|
8646
|
-
"ts-node",
|
|
8647
|
-
"python",
|
|
8648
|
-
"python3",
|
|
8649
|
-
"pip",
|
|
8650
|
-
"pip3",
|
|
8651
|
-
"docker",
|
|
8652
|
-
"docker-compose",
|
|
8653
|
-
"curl",
|
|
8654
|
-
"wget",
|
|
8655
|
-
// These are safe for fetching, blocked when piped to shell
|
|
8656
|
-
"mkdir",
|
|
8657
|
-
"touch",
|
|
8658
|
-
"cp",
|
|
8659
|
-
"mv",
|
|
8660
|
-
// File operations (still require permission)
|
|
8661
|
-
"which",
|
|
8662
|
-
"whereis",
|
|
8663
|
-
"type",
|
|
8664
|
-
"file",
|
|
8665
|
-
"stat",
|
|
8666
|
-
"env",
|
|
8667
|
-
"printenv",
|
|
8668
|
-
"set",
|
|
8669
|
-
"man",
|
|
8670
|
-
"help",
|
|
8671
|
-
"info",
|
|
8672
|
-
"diff",
|
|
8673
|
-
"comm",
|
|
8674
|
-
"cmp",
|
|
8675
|
-
"tar",
|
|
8676
|
-
"zip",
|
|
8677
|
-
"unzip",
|
|
8678
|
-
"gzip",
|
|
8679
|
-
"gunzip",
|
|
8680
|
-
"ssh",
|
|
8681
|
-
"scp",
|
|
8682
|
-
"rsync",
|
|
8683
|
-
// Network tools
|
|
8684
|
-
"make",
|
|
8685
|
-
"cmake",
|
|
8686
|
-
"cargo",
|
|
8687
|
-
"go",
|
|
8688
|
-
"rustc",
|
|
8689
|
-
"gcc",
|
|
8690
|
-
"g++",
|
|
8691
|
-
// Build tools
|
|
8692
|
-
"jest",
|
|
8693
|
-
"vitest",
|
|
8694
|
-
"mocha",
|
|
8695
|
-
"pytest",
|
|
8696
|
-
// Test runners
|
|
8697
|
-
"eslint",
|
|
8698
|
-
"prettier",
|
|
8699
|
-
"tsc"
|
|
8700
|
-
// Linters/formatters
|
|
8701
|
-
];
|
|
8702
|
-
function checkDangerousPatterns(command) {
|
|
8703
|
-
for (const { pattern, reason, block } of DANGEROUS_PATTERNS) {
|
|
8704
|
-
if (pattern.test(command)) {
|
|
8705
|
-
return { blocked: block, reason };
|
|
8706
|
-
}
|
|
8707
|
-
}
|
|
8708
|
-
return { blocked: false };
|
|
8709
|
-
}
|
|
8710
|
-
function getBaseCommand(command) {
|
|
8711
|
-
const trimmed = command.trim();
|
|
8712
|
-
const match = trimmed.match(/^(\S+)/);
|
|
8713
|
-
return match ? match[1] : "";
|
|
8714
|
-
}
|
|
8715
|
-
function isSafeCommandPrefix(command) {
|
|
8716
|
-
const baseCommand = getBaseCommand(command);
|
|
8717
|
-
return SAFE_COMMAND_PREFIXES.some((safe) => baseCommand === safe || baseCommand.endsWith(`/${safe}`));
|
|
8718
|
-
}
|
|
8719
|
-
async function executeBashCommand(params) {
|
|
8720
|
-
const { command, cwd: relativeCwd, timeout = DEFAULT_TIMEOUT_MS } = params;
|
|
8721
|
-
if (!command || command.trim().length === 0) {
|
|
8722
|
-
return {
|
|
8723
|
-
stdout: "",
|
|
8724
|
-
stderr: "Error: Command cannot be empty",
|
|
8725
|
-
exitCode: 1,
|
|
8726
|
-
timedOut: false,
|
|
8727
|
-
blocked: true,
|
|
8728
|
-
blockedReason: "Empty command"
|
|
8729
|
-
};
|
|
8730
|
-
}
|
|
8731
|
-
const dangerCheck = checkDangerousPatterns(command);
|
|
8732
|
-
if (dangerCheck.blocked) {
|
|
8733
|
-
return {
|
|
8734
|
-
stdout: "",
|
|
8735
|
-
stderr: `Command blocked for safety: ${dangerCheck.reason}`,
|
|
8736
|
-
exitCode: 1,
|
|
8737
|
-
timedOut: false,
|
|
8738
|
-
blocked: true,
|
|
8739
|
-
blockedReason: dangerCheck.reason
|
|
8740
|
-
};
|
|
8741
|
-
}
|
|
8742
|
-
const baseCwd = process.cwd();
|
|
8743
|
-
const targetCwd = relativeCwd ? path11.resolve(baseCwd, relativeCwd) : baseCwd;
|
|
8744
|
-
const effectiveTimeout = Math.min(timeout, 5 * 60 * 1e3);
|
|
8745
|
-
return new Promise((resolve3) => {
|
|
8746
|
-
let stdout = "";
|
|
8747
|
-
let stderr = "";
|
|
8748
|
-
let timedOut = false;
|
|
8749
|
-
const proc = spawn("bash", ["-c", command], {
|
|
8750
|
-
cwd: targetCwd,
|
|
8751
|
-
env: {
|
|
8752
|
-
...process.env,
|
|
8753
|
-
// Prevent color codes that might be hard to read
|
|
8754
|
-
NO_COLOR: "1",
|
|
8755
|
-
FORCE_COLOR: "0"
|
|
8756
|
-
},
|
|
8757
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
8758
|
-
});
|
|
8759
|
-
const timeoutId = setTimeout(() => {
|
|
8760
|
-
timedOut = true;
|
|
8761
|
-
proc.kill("SIGTERM");
|
|
8762
|
-
setTimeout(() => {
|
|
8763
|
-
if (!proc.killed) {
|
|
8764
|
-
proc.kill("SIGKILL");
|
|
8765
|
-
}
|
|
8766
|
-
}, 5e3);
|
|
8767
|
-
}, effectiveTimeout);
|
|
8768
|
-
proc.stdout.on("data", (data) => {
|
|
8769
|
-
if (stdout.length < MAX_OUTPUT_SIZE) {
|
|
8770
|
-
stdout += data.toString();
|
|
8771
|
-
if (stdout.length > MAX_OUTPUT_SIZE) {
|
|
8772
|
-
stdout = stdout.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8773
|
-
}
|
|
8774
|
-
}
|
|
8775
|
-
});
|
|
8776
|
-
proc.stderr.on("data", (data) => {
|
|
8777
|
-
if (stderr.length < MAX_OUTPUT_SIZE) {
|
|
8778
|
-
stderr += data.toString();
|
|
8779
|
-
if (stderr.length > MAX_OUTPUT_SIZE) {
|
|
8780
|
-
stderr = stderr.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8781
|
-
}
|
|
8782
|
-
}
|
|
8783
|
-
});
|
|
8784
|
-
proc.on("close", (exitCode) => {
|
|
8785
|
-
clearTimeout(timeoutId);
|
|
8786
|
-
resolve3({
|
|
8787
|
-
stdout: stdout.trim(),
|
|
8788
|
-
stderr: stderr.trim(),
|
|
8789
|
-
exitCode,
|
|
8790
|
-
timedOut,
|
|
8791
|
-
blocked: false
|
|
8792
|
-
});
|
|
8793
|
-
});
|
|
8794
|
-
proc.on("error", (error) => {
|
|
8795
|
-
clearTimeout(timeoutId);
|
|
8796
|
-
resolve3({
|
|
8797
|
-
stdout: "",
|
|
8798
|
-
stderr: `Failed to execute command: ${error.message}`,
|
|
8799
|
-
exitCode: 1,
|
|
8800
|
-
timedOut: false,
|
|
8801
|
-
blocked: false
|
|
8802
|
-
});
|
|
8803
|
-
});
|
|
8804
|
-
});
|
|
8805
|
-
}
|
|
8806
|
-
function formatResult(result, command) {
|
|
8807
|
-
const parts = [];
|
|
8808
|
-
parts.push(`$ ${command}`);
|
|
8809
|
-
parts.push("");
|
|
8810
|
-
if (result.blocked) {
|
|
8811
|
-
parts.push(`BLOCKED: ${result.blockedReason}`);
|
|
8812
|
-
parts.push("");
|
|
8813
|
-
parts.push("This command was blocked for safety reasons.");
|
|
8814
|
-
parts.push("If you believe this is a false positive, please run the command manually.");
|
|
8815
|
-
return parts.join("\n");
|
|
8816
|
-
}
|
|
8817
|
-
if (result.timedOut) {
|
|
8818
|
-
parts.push("WARNING: Command timed out and was terminated.");
|
|
8819
|
-
parts.push("");
|
|
8820
|
-
}
|
|
8821
|
-
if (result.stdout) {
|
|
8822
|
-
parts.push(result.stdout);
|
|
8823
|
-
}
|
|
8824
|
-
if (result.stderr) {
|
|
8825
|
-
if (result.stdout) {
|
|
8826
|
-
parts.push("");
|
|
8827
|
-
}
|
|
8828
|
-
parts.push("STDERR:");
|
|
8829
|
-
parts.push(result.stderr);
|
|
8830
|
-
}
|
|
8831
|
-
if (result.exitCode !== 0 && result.exitCode !== null) {
|
|
8832
|
-
parts.push("");
|
|
8833
|
-
parts.push(`Exit code: ${result.exitCode}`);
|
|
8834
|
-
}
|
|
8835
|
-
if (!result.stdout && !result.stderr && !result.timedOut) {
|
|
8836
|
-
parts.push("(command completed with no output)");
|
|
8837
|
-
}
|
|
8838
|
-
return parts.join("\n");
|
|
8839
|
-
}
|
|
8840
|
-
var bashExecuteTool = {
|
|
8841
|
-
name: "bash_execute",
|
|
8842
|
-
implementation: (context) => ({
|
|
8843
|
-
toolFn: async (value) => {
|
|
8844
|
-
const params = value;
|
|
8845
|
-
const isSafe = isSafeCommandPrefix(params.command);
|
|
8846
|
-
context.logger.info("Bash: Executing command", {
|
|
8847
|
-
command: params.command,
|
|
8848
|
-
cwd: params.cwd || ".",
|
|
8849
|
-
timeout: params.timeout || DEFAULT_TIMEOUT_MS,
|
|
8850
|
-
isSafeCommand: isSafe
|
|
8851
|
-
});
|
|
8852
|
-
if (context.onStart) {
|
|
8853
|
-
await context.onStart("bash_execute", {
|
|
8854
|
-
command: params.command,
|
|
8855
|
-
cwd: params.cwd
|
|
8856
|
-
});
|
|
8857
|
-
}
|
|
8858
|
-
try {
|
|
8859
|
-
const result = await executeBashCommand(params);
|
|
8860
|
-
const formattedResult = formatResult(result, params.command);
|
|
8861
|
-
context.logger.info("Bash: Command completed", {
|
|
8862
|
-
exitCode: result.exitCode,
|
|
8863
|
-
timedOut: result.timedOut,
|
|
8864
|
-
blocked: result.blocked
|
|
8865
|
-
});
|
|
8866
|
-
if (context.onFinish) {
|
|
8867
|
-
await context.onFinish("bash_execute", {
|
|
8868
|
-
command: params.command,
|
|
8869
|
-
exitCode: result.exitCode,
|
|
8870
|
-
blocked: result.blocked
|
|
8871
|
-
});
|
|
8872
|
-
}
|
|
8873
|
-
return formattedResult;
|
|
8874
|
-
} catch (error) {
|
|
8875
|
-
context.logger.error("Bash: Command failed", error);
|
|
8876
|
-
if (context.onFinish) {
|
|
8877
|
-
await context.onFinish("bash_execute", {
|
|
8878
|
-
command: params.command,
|
|
8879
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
8880
|
-
});
|
|
8881
|
-
}
|
|
8882
|
-
throw error;
|
|
8883
|
-
}
|
|
8884
|
-
},
|
|
8885
|
-
toolSchema: {
|
|
8886
|
-
name: "bash_execute",
|
|
8887
|
-
description: `Execute a bash command in the terminal. Use this for running shell commands, scripts, build tools, git operations, and other CLI tasks.
|
|
8888
|
-
|
|
8889
|
-
SAFETY NOTES:
|
|
8890
|
-
- Commands are executed in the current working directory (or specified cwd)
|
|
8891
|
-
- Dangerous commands (sudo, rm -rf /, etc.) are automatically blocked
|
|
8892
|
-
- Commands have a default timeout of 60 seconds (max 5 minutes)
|
|
8893
|
-
- Output is limited to prevent overwhelming responses
|
|
8894
|
-
- This tool ALWAYS requires user permission before execution
|
|
8895
|
-
|
|
8896
|
-
COMMON USE CASES:
|
|
8897
|
-
- Running build commands: npm run build, make, cargo build
|
|
8898
|
-
- Git operations: git status, git log, git diff
|
|
8899
|
-
- Viewing system info: ls, pwd, cat, head, tail
|
|
8900
|
-
- Running tests: npm test, pytest, cargo test
|
|
8901
|
-
- Package management: npm install, pip install
|
|
8902
|
-
- File operations: mkdir, cp, mv (with permission)
|
|
8903
|
-
|
|
8904
|
-
BLOCKED OPERATIONS:
|
|
8905
|
-
- sudo and privilege escalation
|
|
8906
|
-
- Recursive deletes on system paths
|
|
8907
|
-
- Direct disk operations
|
|
8908
|
-
- Fork bombs and resource exhaustion
|
|
8909
|
-
- Piping remote scripts to shell`,
|
|
8910
|
-
parameters: {
|
|
8911
|
-
type: "object",
|
|
8912
|
-
properties: {
|
|
8913
|
-
command: {
|
|
8914
|
-
type: "string",
|
|
8915
|
-
description: "The bash command to execute. Can include pipes, redirects, and chained commands."
|
|
8916
|
-
},
|
|
8917
|
-
cwd: {
|
|
8918
|
-
type: "string",
|
|
8919
|
-
description: "Working directory for the command (optional). Can be relative or absolute path. Defaults to current directory."
|
|
8920
|
-
},
|
|
8921
|
-
timeout: {
|
|
8922
|
-
type: "number",
|
|
8923
|
-
description: "Timeout in milliseconds (optional, default: 60000, max: 300000). Command will be terminated if it exceeds this time."
|
|
8924
|
-
}
|
|
8925
|
-
},
|
|
8926
|
-
required: ["command"]
|
|
8927
|
-
}
|
|
8928
|
-
}
|
|
8929
|
-
})
|
|
8930
|
-
};
|
|
8931
|
-
|
|
8932
8650
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
8933
8651
|
var tools = {
|
|
8934
8652
|
dice_roll: diceRollTool,
|
|
@@ -8956,9 +8674,7 @@ var tools = {
|
|
|
8956
8674
|
create_file: createFileTool,
|
|
8957
8675
|
glob_files: globFilesTool,
|
|
8958
8676
|
grep_search: grepSearchTool,
|
|
8959
|
-
delete_file: deleteFileTool
|
|
8960
|
-
// Shell execution
|
|
8961
|
-
bash_execute: bashExecuteTool
|
|
8677
|
+
delete_file: deleteFileTool
|
|
8962
8678
|
};
|
|
8963
8679
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
8964
8680
|
const context = {
|
|
@@ -9183,6 +8899,17 @@ var MementoEvalResponseSchema = z142.object({
|
|
|
9183
8899
|
// ../../b4m-core/packages/services/dist/src/auth/AccessTokenGeneratorService.js
|
|
9184
8900
|
import jwt2 from "jsonwebtoken";
|
|
9185
8901
|
|
|
8902
|
+
// ../../b4m-core/packages/services/dist/src/cliTools/types.js
|
|
8903
|
+
var ToolErrorType;
|
|
8904
|
+
(function(ToolErrorType2) {
|
|
8905
|
+
ToolErrorType2["INVALID_INPUT"] = "INVALID_INPUT";
|
|
8906
|
+
ToolErrorType2["API_KEY_MISSING"] = "API_KEY_MISSING";
|
|
8907
|
+
ToolErrorType2["EXTERNAL_API_ERROR"] = "EXTERNAL_API_ERROR";
|
|
8908
|
+
ToolErrorType2["RATE_LIMIT"] = "RATE_LIMIT";
|
|
8909
|
+
ToolErrorType2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
8910
|
+
ToolErrorType2["UNKNOWN"] = "UNKNOWN";
|
|
8911
|
+
})(ToolErrorType || (ToolErrorType = {}));
|
|
8912
|
+
|
|
9186
8913
|
// src/utils/diffPreview.ts
|
|
9187
8914
|
import * as Diff from "diff";
|
|
9188
8915
|
import { readFile } from "fs/promises";
|
|
@@ -9233,57 +8960,389 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
9233
8960
|
}
|
|
9234
8961
|
}
|
|
9235
8962
|
|
|
9236
|
-
// src/utils/
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
8963
|
+
// src/utils/Logger.ts
|
|
8964
|
+
import fs10 from "fs/promises";
|
|
8965
|
+
import path11 from "path";
|
|
8966
|
+
import os from "os";
|
|
8967
|
+
var Logger2 = class _Logger {
|
|
8968
|
+
constructor() {
|
|
8969
|
+
this.logFilePath = null;
|
|
8970
|
+
this.sessionId = null;
|
|
8971
|
+
this.fileLoggingEnabled = true;
|
|
8972
|
+
this.consoleVerbose = false;
|
|
9245
8973
|
}
|
|
9246
|
-
|
|
9247
|
-
|
|
8974
|
+
static {
|
|
8975
|
+
this.instance = null;
|
|
9248
8976
|
}
|
|
9249
|
-
|
|
9250
|
-
|
|
8977
|
+
static getInstance() {
|
|
8978
|
+
if (!_Logger.instance) {
|
|
8979
|
+
_Logger.instance = new _Logger();
|
|
8980
|
+
}
|
|
8981
|
+
return _Logger.instance;
|
|
9251
8982
|
}
|
|
9252
|
-
|
|
9253
|
-
|
|
8983
|
+
/**
|
|
8984
|
+
* Initialize the logger with a session ID
|
|
8985
|
+
*/
|
|
8986
|
+
async initialize(sessionId) {
|
|
8987
|
+
this.sessionId = sessionId;
|
|
8988
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
8989
|
+
await fs10.mkdir(debugDir, { recursive: true });
|
|
8990
|
+
this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
|
|
8991
|
+
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9254
8992
|
}
|
|
9255
|
-
|
|
9256
|
-
|
|
8993
|
+
/**
|
|
8994
|
+
* Set whether verbose console logging is enabled
|
|
8995
|
+
*/
|
|
8996
|
+
setVerbose(enabled) {
|
|
8997
|
+
this.consoleVerbose = enabled;
|
|
9257
8998
|
}
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
8999
|
+
/**
|
|
9000
|
+
* Set whether file logging is enabled
|
|
9001
|
+
*/
|
|
9002
|
+
setFileLoggingEnabled(enabled) {
|
|
9003
|
+
this.fileLoggingEnabled = enabled;
|
|
9262
9004
|
}
|
|
9263
|
-
|
|
9264
|
-
|
|
9005
|
+
/**
|
|
9006
|
+
* DEBUG level - verbose-only console, always file
|
|
9007
|
+
*/
|
|
9008
|
+
debug(message) {
|
|
9009
|
+
this.writeToFile("DEBUG", message).catch(() => {
|
|
9010
|
+
});
|
|
9011
|
+
if (this.consoleVerbose) {
|
|
9012
|
+
console.log(message);
|
|
9013
|
+
}
|
|
9265
9014
|
}
|
|
9266
|
-
|
|
9015
|
+
/**
|
|
9016
|
+
* INFO level - always shown to user
|
|
9017
|
+
*/
|
|
9018
|
+
info(message) {
|
|
9019
|
+
this.writeToFile("INFO", message).catch(() => {
|
|
9020
|
+
});
|
|
9021
|
+
console.log(message);
|
|
9267
9022
|
}
|
|
9268
|
-
|
|
9023
|
+
/**
|
|
9024
|
+
* WARN level - always shown to user
|
|
9025
|
+
*/
|
|
9026
|
+
warn(message) {
|
|
9027
|
+
this.writeToFile("WARN", message).catch(() => {
|
|
9028
|
+
});
|
|
9029
|
+
console.warn(message);
|
|
9269
9030
|
}
|
|
9270
|
-
|
|
9031
|
+
/**
|
|
9032
|
+
* ERROR level - always shown to user
|
|
9033
|
+
*/
|
|
9034
|
+
error(message, err) {
|
|
9035
|
+
this.writeToFile("ERROR", message).catch(() => {
|
|
9036
|
+
});
|
|
9037
|
+
if (err) {
|
|
9038
|
+
this.logErrorDetailsToFile(err).catch(() => {
|
|
9039
|
+
});
|
|
9040
|
+
}
|
|
9041
|
+
console.error(message);
|
|
9271
9042
|
}
|
|
9272
|
-
|
|
9043
|
+
/**
|
|
9044
|
+
* Write log entry to file
|
|
9045
|
+
*/
|
|
9046
|
+
async writeToFile(level, message) {
|
|
9047
|
+
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
9048
|
+
return;
|
|
9049
|
+
}
|
|
9050
|
+
try {
|
|
9051
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
9052
|
+
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
9053
|
+
`;
|
|
9054
|
+
await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
9055
|
+
} catch (error) {
|
|
9056
|
+
console.error("File logging failed:", error);
|
|
9057
|
+
}
|
|
9273
9058
|
}
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9059
|
+
/**
|
|
9060
|
+
* Log error details to file
|
|
9061
|
+
*/
|
|
9062
|
+
async logErrorDetailsToFile(err) {
|
|
9063
|
+
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
9064
|
+
return;
|
|
9065
|
+
}
|
|
9066
|
+
try {
|
|
9067
|
+
if (err && typeof err === "object" && "response" in err && err.response) {
|
|
9068
|
+
const response = err.response;
|
|
9069
|
+
const config = err && typeof err === "object" && "config" in err ? err.config : void 0;
|
|
9070
|
+
await this.writeToFile("ERROR", ` Status: ${response.status} ${response.statusText || ""}`);
|
|
9071
|
+
await this.writeToFile("ERROR", ` URL: ${config?.url || "unknown"}`);
|
|
9072
|
+
await this.writeToFile("ERROR", ` Headers: ${this.safeStringify(response.headers)}`);
|
|
9073
|
+
if (response.data) {
|
|
9074
|
+
const errorText = this.extractErrorMessage(response.data);
|
|
9075
|
+
if (errorText.trim().startsWith("<!DOCTYPE") || errorText.trim().startsWith("<html")) {
|
|
9076
|
+
await this.writeToFile("ERROR", ` Response Type: HTML Error Page`);
|
|
9077
|
+
const parsedError = this.parseHtmlError(errorText);
|
|
9078
|
+
if (parsedError) {
|
|
9079
|
+
await this.writeToFile("ERROR", ` Error Message: ${parsedError}`);
|
|
9080
|
+
}
|
|
9081
|
+
await this.writeToFile("ERROR", ` Raw HTML: ${this.truncate(errorText, 1e3)}`);
|
|
9082
|
+
} else {
|
|
9083
|
+
const preview = this.truncate(errorText, 500);
|
|
9084
|
+
await this.writeToFile("ERROR", ` Response: ${preview}`);
|
|
9085
|
+
}
|
|
9086
|
+
} else {
|
|
9087
|
+
await this.writeToFile("ERROR", ` Response: (no data)`);
|
|
9088
|
+
}
|
|
9285
9089
|
}
|
|
9286
|
-
|
|
9090
|
+
if (err && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
|
|
9091
|
+
const stackLines = err.stack.split("\n").slice(0, 5).join("\n ");
|
|
9092
|
+
await this.writeToFile("ERROR", ` Stack: ${stackLines}`);
|
|
9093
|
+
} else if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
9094
|
+
await this.writeToFile("ERROR", ` Message: ${err.message}`);
|
|
9095
|
+
}
|
|
9096
|
+
} catch (error) {
|
|
9097
|
+
}
|
|
9098
|
+
}
|
|
9099
|
+
/**
|
|
9100
|
+
* Safely stringify object, handling circular references
|
|
9101
|
+
*/
|
|
9102
|
+
safeStringify(obj) {
|
|
9103
|
+
try {
|
|
9104
|
+
return JSON.stringify(obj);
|
|
9105
|
+
} catch (error) {
|
|
9106
|
+
if (error instanceof Error && error.message.includes("circular")) {
|
|
9107
|
+
try {
|
|
9108
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
9109
|
+
return JSON.stringify(obj, (key, value) => {
|
|
9110
|
+
if (typeof value === "object" && value !== null) {
|
|
9111
|
+
if (seen.has(value)) {
|
|
9112
|
+
return "[Circular]";
|
|
9113
|
+
}
|
|
9114
|
+
seen.add(value);
|
|
9115
|
+
}
|
|
9116
|
+
return value;
|
|
9117
|
+
});
|
|
9118
|
+
} catch {
|
|
9119
|
+
return "[Unable to stringify]";
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
9122
|
+
return "[Stringify error]";
|
|
9123
|
+
}
|
|
9124
|
+
}
|
|
9125
|
+
/**
|
|
9126
|
+
* Extract readable text from error response data
|
|
9127
|
+
*/
|
|
9128
|
+
extractErrorMessage(data) {
|
|
9129
|
+
if (Buffer.isBuffer(data)) {
|
|
9130
|
+
return data.toString("utf-8");
|
|
9131
|
+
}
|
|
9132
|
+
if (typeof data === "string") {
|
|
9133
|
+
return data;
|
|
9134
|
+
}
|
|
9135
|
+
if (data && typeof data === "object" && "_readableState" in data && data._readableState && typeof data._readableState === "object" && "buffer" in data._readableState && Array.isArray(data._readableState.buffer) && data._readableState.buffer.length > 0) {
|
|
9136
|
+
const chunks = [];
|
|
9137
|
+
for (const chunk of data._readableState.buffer) {
|
|
9138
|
+
if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "Buffer" && "data" in chunk && Array.isArray(chunk.data)) {
|
|
9139
|
+
chunks.push(Buffer.from(chunk.data));
|
|
9140
|
+
} else if (Buffer.isBuffer(chunk)) {
|
|
9141
|
+
chunks.push(chunk);
|
|
9142
|
+
} else if (chunk && typeof chunk === "object" && "data" in chunk) {
|
|
9143
|
+
if (Buffer.isBuffer(chunk.data)) {
|
|
9144
|
+
chunks.push(chunk.data);
|
|
9145
|
+
} else if (Array.isArray(chunk.data)) {
|
|
9146
|
+
chunks.push(Buffer.from(chunk.data));
|
|
9147
|
+
}
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
if (chunks.length > 0) {
|
|
9151
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
9152
|
+
}
|
|
9153
|
+
}
|
|
9154
|
+
return this.safeStringify(data);
|
|
9155
|
+
}
|
|
9156
|
+
/**
|
|
9157
|
+
* Parse HTML error page to extract error message
|
|
9158
|
+
*/
|
|
9159
|
+
parseHtmlError(html) {
|
|
9160
|
+
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
9161
|
+
const h1Match = html.match(/<h1>(.*?)<\/h1>/i);
|
|
9162
|
+
const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
|
|
9163
|
+
if (titleMatch && titleMatch[1] !== "Error") {
|
|
9164
|
+
return titleMatch[1].trim();
|
|
9165
|
+
}
|
|
9166
|
+
if (h1Match) {
|
|
9167
|
+
return h1Match[1].trim();
|
|
9168
|
+
}
|
|
9169
|
+
if (bodyMatch) {
|
|
9170
|
+
const text = bodyMatch[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
9171
|
+
return text.substring(0, 200);
|
|
9172
|
+
}
|
|
9173
|
+
return null;
|
|
9174
|
+
}
|
|
9175
|
+
/**
|
|
9176
|
+
* Truncate string to max length with ellipsis
|
|
9177
|
+
*/
|
|
9178
|
+
truncate(str, maxLength) {
|
|
9179
|
+
if (str.length <= maxLength) {
|
|
9180
|
+
return str;
|
|
9181
|
+
}
|
|
9182
|
+
return str.substring(0, maxLength) + "... [truncated]";
|
|
9183
|
+
}
|
|
9184
|
+
/**
|
|
9185
|
+
* Format bytes to human-readable size
|
|
9186
|
+
*/
|
|
9187
|
+
formatBytes(bytes) {
|
|
9188
|
+
if (bytes === 0) return "0 B";
|
|
9189
|
+
const k = 1024;
|
|
9190
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
9191
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
9192
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
9193
|
+
}
|
|
9194
|
+
/**
|
|
9195
|
+
* Clean up old debug logs (older than 30 days)
|
|
9196
|
+
*/
|
|
9197
|
+
async cleanupOldLogs() {
|
|
9198
|
+
if (!this.fileLoggingEnabled) return;
|
|
9199
|
+
try {
|
|
9200
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9201
|
+
const files = await fs10.readdir(debugDir);
|
|
9202
|
+
const now = Date.now();
|
|
9203
|
+
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9204
|
+
for (const file of files) {
|
|
9205
|
+
const filePath = path11.join(debugDir, file);
|
|
9206
|
+
const stats = await fs10.stat(filePath);
|
|
9207
|
+
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9208
|
+
await fs10.unlink(filePath);
|
|
9209
|
+
}
|
|
9210
|
+
}
|
|
9211
|
+
} catch (error) {
|
|
9212
|
+
console.error("Failed to cleanup old logs:", error);
|
|
9213
|
+
}
|
|
9214
|
+
}
|
|
9215
|
+
};
|
|
9216
|
+
var logger = Logger2.getInstance();
|
|
9217
|
+
|
|
9218
|
+
// src/llm/ServerToolExecutor.ts
|
|
9219
|
+
var ServerToolExecutor = class {
|
|
9220
|
+
constructor(apiClient) {
|
|
9221
|
+
this.toolsEndpoint = "/api/ai/v1/tools";
|
|
9222
|
+
this.apiClient = apiClient;
|
|
9223
|
+
}
|
|
9224
|
+
/**
|
|
9225
|
+
* Execute a tool server-side
|
|
9226
|
+
*
|
|
9227
|
+
* @param toolName - Name of the tool to execute (e.g., 'weather_info', 'web_search')
|
|
9228
|
+
* @param input - Tool input parameters
|
|
9229
|
+
* @returns Tool execution result (content or error)
|
|
9230
|
+
*/
|
|
9231
|
+
async executeTool(toolName, input) {
|
|
9232
|
+
logger.debug(`[ServerToolExecutor] Executing tool: ${toolName}`);
|
|
9233
|
+
logger.debug(`[ServerToolExecutor] Endpoint: ${this.toolsEndpoint}`);
|
|
9234
|
+
logger.debug(`[ServerToolExecutor] Input: ${JSON.stringify(input)}`);
|
|
9235
|
+
try {
|
|
9236
|
+
const result = await this.apiClient.post(this.toolsEndpoint, {
|
|
9237
|
+
toolName,
|
|
9238
|
+
input
|
|
9239
|
+
});
|
|
9240
|
+
logger.debug(`[ServerToolExecutor] Response: ${JSON.stringify(result)}`);
|
|
9241
|
+
if (!result.success) {
|
|
9242
|
+
const errorMessage = result.error || "Tool execution failed";
|
|
9243
|
+
logger.error(`[ServerToolExecutor] Tool ${toolName} failed: ${errorMessage}`);
|
|
9244
|
+
return `Error executing ${toolName}: ${errorMessage}`;
|
|
9245
|
+
}
|
|
9246
|
+
logger.debug(`[ServerToolExecutor] Tool ${toolName} succeeded in ${result.executionTimeMs}ms`);
|
|
9247
|
+
return result.content || "";
|
|
9248
|
+
} catch (error) {
|
|
9249
|
+
const err = error;
|
|
9250
|
+
const errorMessage = err?.response?.data?.error || err?.message || "Unknown error";
|
|
9251
|
+
const status = err?.response?.status || "unknown";
|
|
9252
|
+
logger.error(`[ServerToolExecutor] Request failed for ${toolName}: ${errorMessage} (status: ${status})`);
|
|
9253
|
+
logger.error(`[ServerToolExecutor] Full error: ${JSON.stringify(err, null, 2)}`);
|
|
9254
|
+
return `Error executing ${toolName}: ${errorMessage}`;
|
|
9255
|
+
}
|
|
9256
|
+
}
|
|
9257
|
+
};
|
|
9258
|
+
|
|
9259
|
+
// src/llm/ToolRouter.ts
|
|
9260
|
+
var SERVER_TOOLS = ["weather_info", "web_search"];
|
|
9261
|
+
var LOCAL_TOOLS = [
|
|
9262
|
+
"file_read",
|
|
9263
|
+
"create_file",
|
|
9264
|
+
"glob_files",
|
|
9265
|
+
"grep_search",
|
|
9266
|
+
"delete_file",
|
|
9267
|
+
"edit_file",
|
|
9268
|
+
"dice_roll",
|
|
9269
|
+
"math_evaluate",
|
|
9270
|
+
"current_datetime"
|
|
9271
|
+
];
|
|
9272
|
+
function isServerTool(toolName) {
|
|
9273
|
+
return SERVER_TOOLS.includes(toolName);
|
|
9274
|
+
}
|
|
9275
|
+
function isLocalTool(toolName) {
|
|
9276
|
+
return LOCAL_TOOLS.includes(toolName);
|
|
9277
|
+
}
|
|
9278
|
+
async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
9279
|
+
if (isServerTool(toolName)) {
|
|
9280
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server`);
|
|
9281
|
+
const executor = new ServerToolExecutor(apiClient);
|
|
9282
|
+
return await executor.executeTool(toolName, input);
|
|
9283
|
+
} else if (isLocalTool(toolName)) {
|
|
9284
|
+
logger.debug(`[ToolRouter] Executing ${toolName} locally`);
|
|
9285
|
+
if (!localToolFn) {
|
|
9286
|
+
throw new Error(`Local tool ${toolName} has no implementation`);
|
|
9287
|
+
}
|
|
9288
|
+
const result = await localToolFn(input);
|
|
9289
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
9290
|
+
} else {
|
|
9291
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
9292
|
+
}
|
|
9293
|
+
}
|
|
9294
|
+
|
|
9295
|
+
// src/utils/toolsAdapter.ts
|
|
9296
|
+
var NoOpStorage = class extends BaseStorage {
|
|
9297
|
+
async upload(input, destination, options) {
|
|
9298
|
+
return `/tmp/${destination}`;
|
|
9299
|
+
}
|
|
9300
|
+
async download(path13) {
|
|
9301
|
+
throw new Error("Download not supported in CLI");
|
|
9302
|
+
}
|
|
9303
|
+
async delete(path13) {
|
|
9304
|
+
}
|
|
9305
|
+
async getSignedUrl(path13) {
|
|
9306
|
+
return `/tmp/${path13}`;
|
|
9307
|
+
}
|
|
9308
|
+
getPublicUrl(path13) {
|
|
9309
|
+
return `/tmp/${path13}`;
|
|
9310
|
+
}
|
|
9311
|
+
async getPreview(path13) {
|
|
9312
|
+
return `/tmp/${path13}`;
|
|
9313
|
+
}
|
|
9314
|
+
async getMetadata(path13) {
|
|
9315
|
+
return { size: 0, contentType: "application/octet-stream" };
|
|
9316
|
+
}
|
|
9317
|
+
};
|
|
9318
|
+
var CliLogger = class extends Logger {
|
|
9319
|
+
constructor() {
|
|
9320
|
+
super({ logInJson: false });
|
|
9321
|
+
}
|
|
9322
|
+
// Override all logging methods to be silent
|
|
9323
|
+
info(...args) {
|
|
9324
|
+
}
|
|
9325
|
+
warn(...args) {
|
|
9326
|
+
}
|
|
9327
|
+
error(...args) {
|
|
9328
|
+
}
|
|
9329
|
+
debug(...args) {
|
|
9330
|
+
}
|
|
9331
|
+
log(...args) {
|
|
9332
|
+
}
|
|
9333
|
+
};
|
|
9334
|
+
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient) {
|
|
9335
|
+
const originalFn = tool.toolFn;
|
|
9336
|
+
const toolName = tool.toolSchema.name;
|
|
9337
|
+
return {
|
|
9338
|
+
...tool,
|
|
9339
|
+
toolFn: async (args) => {
|
|
9340
|
+
if (!permissionManager.needsPermission(toolName)) {
|
|
9341
|
+
const result2 = await executeTool(toolName, args, apiClient, originalFn);
|
|
9342
|
+
agentContext.observationQueue.push({ toolName, result: result2 });
|
|
9343
|
+
return result2;
|
|
9344
|
+
}
|
|
9345
|
+
let preview;
|
|
9287
9346
|
if (toolName === "edit_file" && args?.path && args?.content) {
|
|
9288
9347
|
try {
|
|
9289
9348
|
preview = await generateFileDiffPreview({
|
|
@@ -9310,10 +9369,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9310
9369
|
} catch (error) {
|
|
9311
9370
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9312
9371
|
}
|
|
9313
|
-
} else if (toolName === "bash_execute" && args?.command) {
|
|
9314
|
-
const cwd = args.cwd ? ` (in ${args.cwd})` : "";
|
|
9315
|
-
const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
|
|
9316
|
-
preview = `$ ${args.command}${cwd}${timeout}`;
|
|
9317
9372
|
}
|
|
9318
9373
|
const response = await showPermissionPrompt(toolName, args, preview);
|
|
9319
9374
|
if (response.action === "deny") {
|
|
@@ -9340,13 +9395,13 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9340
9395
|
}
|
|
9341
9396
|
}
|
|
9342
9397
|
}
|
|
9343
|
-
const result = await
|
|
9398
|
+
const result = await executeTool(toolName, args, apiClient, originalFn);
|
|
9344
9399
|
agentContext.observationQueue.push({ toolName, result });
|
|
9345
9400
|
return result;
|
|
9346
9401
|
}
|
|
9347
9402
|
};
|
|
9348
9403
|
}
|
|
9349
|
-
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore,
|
|
9404
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient) {
|
|
9350
9405
|
const logger2 = new CliLogger();
|
|
9351
9406
|
const storage = new NoOpStorage();
|
|
9352
9407
|
const user = {
|
|
@@ -9363,18 +9418,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9363
9418
|
};
|
|
9364
9419
|
const mockAdminSettings = {
|
|
9365
9420
|
findBySettingName: async (settingName) => {
|
|
9366
|
-
if (settingName === "OpenWeatherKey") {
|
|
9367
|
-
const key = toolApiKeys?.openweather || process.env.OPENWEATHER_API_KEY;
|
|
9368
|
-
if (key) {
|
|
9369
|
-
return { settingValue: key };
|
|
9370
|
-
}
|
|
9371
|
-
}
|
|
9372
|
-
if (settingName === "SerperKey") {
|
|
9373
|
-
const key = toolApiKeys?.serper || process.env.SERPER_API_KEY;
|
|
9374
|
-
if (key) {
|
|
9375
|
-
return { settingValue: key };
|
|
9376
|
-
}
|
|
9377
|
-
}
|
|
9378
9421
|
return null;
|
|
9379
9422
|
}
|
|
9380
9423
|
};
|
|
@@ -9384,29 +9427,22 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9384
9427
|
adminSettings: mockAdminSettings
|
|
9385
9428
|
}
|
|
9386
9429
|
};
|
|
9387
|
-
const hasSerperKey = !!(toolApiKeys?.serper || process.env.SERPER_API_KEY);
|
|
9388
|
-
const hasOpenWeatherKey = !!(toolApiKeys?.openweather || process.env.OPENWEATHER_API_KEY);
|
|
9389
9430
|
const toolConfig = {
|
|
9390
|
-
//
|
|
9431
|
+
// Local-only tools (no external API keys needed)
|
|
9391
9432
|
dice_roll: {},
|
|
9392
9433
|
math_evaluate: {},
|
|
9393
9434
|
current_datetime: {},
|
|
9394
9435
|
prompt_enhancement: {},
|
|
9395
|
-
// File operation tools (CLI-specific)
|
|
9436
|
+
// File operation tools (CLI-specific, local execution)
|
|
9396
9437
|
file_read: {},
|
|
9397
9438
|
create_file: {},
|
|
9398
9439
|
glob_files: {},
|
|
9399
9440
|
grep_search: {},
|
|
9400
9441
|
delete_file: {},
|
|
9401
|
-
//
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
// Requires SERPER_API_KEY
|
|
9406
|
-
...hasOpenWeatherKey && { weather_info: {} },
|
|
9407
|
-
// Requires OPENWEATHER_API_KEY
|
|
9408
|
-
...hasSerperKey && { deep_research: {} }
|
|
9409
|
-
// Requires SERPER_API_KEY
|
|
9442
|
+
// Server-side tools (executed via /api/ai/v1/tools Lambda)
|
|
9443
|
+
// Routed by ToolRouter to use B4M company API keys
|
|
9444
|
+
weather_info: {},
|
|
9445
|
+
web_search: {}
|
|
9410
9446
|
// Disable web-only tools
|
|
9411
9447
|
// blog_publish: undefined,
|
|
9412
9448
|
// blog_edit: undefined,
|
|
@@ -9416,6 +9452,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9416
9452
|
// mermaid_chart: undefined,
|
|
9417
9453
|
// recharts: undefined,
|
|
9418
9454
|
// edit_file: undefined,
|
|
9455
|
+
// deep_research: undefined,
|
|
9419
9456
|
};
|
|
9420
9457
|
const toolsMap = generateTools(
|
|
9421
9458
|
userId,
|
|
@@ -9433,7 +9470,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9433
9470
|
model
|
|
9434
9471
|
);
|
|
9435
9472
|
const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
|
|
9436
|
-
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore)
|
|
9473
|
+
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient)
|
|
9437
9474
|
);
|
|
9438
9475
|
return { tools: tools2, agentContext };
|
|
9439
9476
|
}
|
|
@@ -9467,7 +9504,6 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
9467
9504
|
create_file: "prompt_always",
|
|
9468
9505
|
delete_file: "prompt_always",
|
|
9469
9506
|
shell_execute: "prompt_always",
|
|
9470
|
-
bash_execute: "prompt_always",
|
|
9471
9507
|
git_commit: "prompt_always",
|
|
9472
9508
|
git_push: "prompt_always",
|
|
9473
9509
|
// ===== PROMPT DEFAULT (Repository read tools) =====
|
|
@@ -9629,265 +9665,10 @@ function getEnvironmentName(configApiConfig) {
|
|
|
9629
9665
|
return "Bike4Mind";
|
|
9630
9666
|
}
|
|
9631
9667
|
|
|
9632
|
-
// src/utils/Logger.ts
|
|
9633
|
-
import fs10 from "fs/promises";
|
|
9634
|
-
import path12 from "path";
|
|
9635
|
-
import os from "os";
|
|
9636
|
-
var Logger2 = class _Logger {
|
|
9637
|
-
constructor() {
|
|
9638
|
-
this.logFilePath = null;
|
|
9639
|
-
this.sessionId = null;
|
|
9640
|
-
this.fileLoggingEnabled = true;
|
|
9641
|
-
this.consoleVerbose = false;
|
|
9642
|
-
}
|
|
9643
|
-
static {
|
|
9644
|
-
this.instance = null;
|
|
9645
|
-
}
|
|
9646
|
-
static getInstance() {
|
|
9647
|
-
if (!_Logger.instance) {
|
|
9648
|
-
_Logger.instance = new _Logger();
|
|
9649
|
-
}
|
|
9650
|
-
return _Logger.instance;
|
|
9651
|
-
}
|
|
9652
|
-
/**
|
|
9653
|
-
* Initialize the logger with a session ID
|
|
9654
|
-
*/
|
|
9655
|
-
async initialize(sessionId) {
|
|
9656
|
-
this.sessionId = sessionId;
|
|
9657
|
-
const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
|
|
9658
|
-
await fs10.mkdir(debugDir, { recursive: true });
|
|
9659
|
-
this.logFilePath = path12.join(debugDir, `${sessionId}.txt`);
|
|
9660
|
-
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9661
|
-
}
|
|
9662
|
-
/**
|
|
9663
|
-
* Set whether verbose console logging is enabled
|
|
9664
|
-
*/
|
|
9665
|
-
setVerbose(enabled) {
|
|
9666
|
-
this.consoleVerbose = enabled;
|
|
9667
|
-
}
|
|
9668
|
-
/**
|
|
9669
|
-
* Set whether file logging is enabled
|
|
9670
|
-
*/
|
|
9671
|
-
setFileLoggingEnabled(enabled) {
|
|
9672
|
-
this.fileLoggingEnabled = enabled;
|
|
9673
|
-
}
|
|
9674
|
-
/**
|
|
9675
|
-
* DEBUG level - verbose-only console, always file
|
|
9676
|
-
*/
|
|
9677
|
-
debug(message) {
|
|
9678
|
-
this.writeToFile("DEBUG", message).catch(() => {
|
|
9679
|
-
});
|
|
9680
|
-
if (this.consoleVerbose) {
|
|
9681
|
-
console.log(message);
|
|
9682
|
-
}
|
|
9683
|
-
}
|
|
9684
|
-
/**
|
|
9685
|
-
* INFO level - always shown to user
|
|
9686
|
-
*/
|
|
9687
|
-
info(message) {
|
|
9688
|
-
this.writeToFile("INFO", message).catch(() => {
|
|
9689
|
-
});
|
|
9690
|
-
console.log(message);
|
|
9691
|
-
}
|
|
9692
|
-
/**
|
|
9693
|
-
* WARN level - always shown to user
|
|
9694
|
-
*/
|
|
9695
|
-
warn(message) {
|
|
9696
|
-
this.writeToFile("WARN", message).catch(() => {
|
|
9697
|
-
});
|
|
9698
|
-
console.warn(message);
|
|
9699
|
-
}
|
|
9700
|
-
/**
|
|
9701
|
-
* ERROR level - always shown to user
|
|
9702
|
-
*/
|
|
9703
|
-
error(message, err) {
|
|
9704
|
-
this.writeToFile("ERROR", message).catch(() => {
|
|
9705
|
-
});
|
|
9706
|
-
if (err) {
|
|
9707
|
-
this.logErrorDetailsToFile(err).catch(() => {
|
|
9708
|
-
});
|
|
9709
|
-
}
|
|
9710
|
-
console.error(message);
|
|
9711
|
-
}
|
|
9712
|
-
/**
|
|
9713
|
-
* Write log entry to file
|
|
9714
|
-
*/
|
|
9715
|
-
async writeToFile(level, message) {
|
|
9716
|
-
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
9717
|
-
return;
|
|
9718
|
-
}
|
|
9719
|
-
try {
|
|
9720
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
9721
|
-
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
9722
|
-
`;
|
|
9723
|
-
await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
9724
|
-
} catch (error) {
|
|
9725
|
-
console.error("File logging failed:", error);
|
|
9726
|
-
}
|
|
9727
|
-
}
|
|
9728
|
-
/**
|
|
9729
|
-
* Log error details to file
|
|
9730
|
-
*/
|
|
9731
|
-
async logErrorDetailsToFile(err) {
|
|
9732
|
-
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
9733
|
-
return;
|
|
9734
|
-
}
|
|
9735
|
-
try {
|
|
9736
|
-
if (err && typeof err === "object" && "response" in err && err.response) {
|
|
9737
|
-
const response = err.response;
|
|
9738
|
-
const config = err && typeof err === "object" && "config" in err ? err.config : void 0;
|
|
9739
|
-
await this.writeToFile("ERROR", ` Status: ${response.status} ${response.statusText || ""}`);
|
|
9740
|
-
await this.writeToFile("ERROR", ` URL: ${config?.url || "unknown"}`);
|
|
9741
|
-
await this.writeToFile("ERROR", ` Headers: ${this.safeStringify(response.headers)}`);
|
|
9742
|
-
if (response.data) {
|
|
9743
|
-
const errorText = this.extractErrorMessage(response.data);
|
|
9744
|
-
if (errorText.trim().startsWith("<!DOCTYPE") || errorText.trim().startsWith("<html")) {
|
|
9745
|
-
await this.writeToFile("ERROR", ` Response Type: HTML Error Page`);
|
|
9746
|
-
const parsedError = this.parseHtmlError(errorText);
|
|
9747
|
-
if (parsedError) {
|
|
9748
|
-
await this.writeToFile("ERROR", ` Error Message: ${parsedError}`);
|
|
9749
|
-
}
|
|
9750
|
-
await this.writeToFile("ERROR", ` Raw HTML: ${this.truncate(errorText, 1e3)}`);
|
|
9751
|
-
} else {
|
|
9752
|
-
const preview = this.truncate(errorText, 500);
|
|
9753
|
-
await this.writeToFile("ERROR", ` Response: ${preview}`);
|
|
9754
|
-
}
|
|
9755
|
-
} else {
|
|
9756
|
-
await this.writeToFile("ERROR", ` Response: (no data)`);
|
|
9757
|
-
}
|
|
9758
|
-
}
|
|
9759
|
-
if (err && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
|
|
9760
|
-
const stackLines = err.stack.split("\n").slice(0, 5).join("\n ");
|
|
9761
|
-
await this.writeToFile("ERROR", ` Stack: ${stackLines}`);
|
|
9762
|
-
} else if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
9763
|
-
await this.writeToFile("ERROR", ` Message: ${err.message}`);
|
|
9764
|
-
}
|
|
9765
|
-
} catch (error) {
|
|
9766
|
-
}
|
|
9767
|
-
}
|
|
9768
|
-
/**
|
|
9769
|
-
* Safely stringify object, handling circular references
|
|
9770
|
-
*/
|
|
9771
|
-
safeStringify(obj) {
|
|
9772
|
-
try {
|
|
9773
|
-
return JSON.stringify(obj);
|
|
9774
|
-
} catch (error) {
|
|
9775
|
-
if (error instanceof Error && error.message.includes("circular")) {
|
|
9776
|
-
try {
|
|
9777
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
9778
|
-
return JSON.stringify(obj, (key, value) => {
|
|
9779
|
-
if (typeof value === "object" && value !== null) {
|
|
9780
|
-
if (seen.has(value)) {
|
|
9781
|
-
return "[Circular]";
|
|
9782
|
-
}
|
|
9783
|
-
seen.add(value);
|
|
9784
|
-
}
|
|
9785
|
-
return value;
|
|
9786
|
-
});
|
|
9787
|
-
} catch {
|
|
9788
|
-
return "[Unable to stringify]";
|
|
9789
|
-
}
|
|
9790
|
-
}
|
|
9791
|
-
return "[Stringify error]";
|
|
9792
|
-
}
|
|
9793
|
-
}
|
|
9794
|
-
/**
|
|
9795
|
-
* Extract readable text from error response data
|
|
9796
|
-
*/
|
|
9797
|
-
extractErrorMessage(data) {
|
|
9798
|
-
if (Buffer.isBuffer(data)) {
|
|
9799
|
-
return data.toString("utf-8");
|
|
9800
|
-
}
|
|
9801
|
-
if (typeof data === "string") {
|
|
9802
|
-
return data;
|
|
9803
|
-
}
|
|
9804
|
-
if (data && typeof data === "object" && "_readableState" in data && data._readableState && typeof data._readableState === "object" && "buffer" in data._readableState && Array.isArray(data._readableState.buffer) && data._readableState.buffer.length > 0) {
|
|
9805
|
-
const chunks = [];
|
|
9806
|
-
for (const chunk of data._readableState.buffer) {
|
|
9807
|
-
if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "Buffer" && "data" in chunk && Array.isArray(chunk.data)) {
|
|
9808
|
-
chunks.push(Buffer.from(chunk.data));
|
|
9809
|
-
} else if (Buffer.isBuffer(chunk)) {
|
|
9810
|
-
chunks.push(chunk);
|
|
9811
|
-
} else if (chunk && typeof chunk === "object" && "data" in chunk) {
|
|
9812
|
-
if (Buffer.isBuffer(chunk.data)) {
|
|
9813
|
-
chunks.push(chunk.data);
|
|
9814
|
-
} else if (Array.isArray(chunk.data)) {
|
|
9815
|
-
chunks.push(Buffer.from(chunk.data));
|
|
9816
|
-
}
|
|
9817
|
-
}
|
|
9818
|
-
}
|
|
9819
|
-
if (chunks.length > 0) {
|
|
9820
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
9821
|
-
}
|
|
9822
|
-
}
|
|
9823
|
-
return this.safeStringify(data);
|
|
9824
|
-
}
|
|
9825
|
-
/**
|
|
9826
|
-
* Parse HTML error page to extract error message
|
|
9827
|
-
*/
|
|
9828
|
-
parseHtmlError(html) {
|
|
9829
|
-
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
9830
|
-
const h1Match = html.match(/<h1>(.*?)<\/h1>/i);
|
|
9831
|
-
const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
|
|
9832
|
-
if (titleMatch && titleMatch[1] !== "Error") {
|
|
9833
|
-
return titleMatch[1].trim();
|
|
9834
|
-
}
|
|
9835
|
-
if (h1Match) {
|
|
9836
|
-
return h1Match[1].trim();
|
|
9837
|
-
}
|
|
9838
|
-
if (bodyMatch) {
|
|
9839
|
-
const text = bodyMatch[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
9840
|
-
return text.substring(0, 200);
|
|
9841
|
-
}
|
|
9842
|
-
return null;
|
|
9843
|
-
}
|
|
9844
|
-
/**
|
|
9845
|
-
* Truncate string to max length with ellipsis
|
|
9846
|
-
*/
|
|
9847
|
-
truncate(str, maxLength) {
|
|
9848
|
-
if (str.length <= maxLength) {
|
|
9849
|
-
return str;
|
|
9850
|
-
}
|
|
9851
|
-
return str.substring(0, maxLength) + "... [truncated]";
|
|
9852
|
-
}
|
|
9853
|
-
/**
|
|
9854
|
-
* Format bytes to human-readable size
|
|
9855
|
-
*/
|
|
9856
|
-
formatBytes(bytes) {
|
|
9857
|
-
if (bytes === 0) return "0 B";
|
|
9858
|
-
const k = 1024;
|
|
9859
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
9860
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
9861
|
-
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
9862
|
-
}
|
|
9863
|
-
/**
|
|
9864
|
-
* Clean up old debug logs (older than 30 days)
|
|
9865
|
-
*/
|
|
9866
|
-
async cleanupOldLogs() {
|
|
9867
|
-
if (!this.fileLoggingEnabled) return;
|
|
9868
|
-
try {
|
|
9869
|
-
const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
|
|
9870
|
-
const files = await fs10.readdir(debugDir);
|
|
9871
|
-
const now = Date.now();
|
|
9872
|
-
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9873
|
-
for (const file of files) {
|
|
9874
|
-
const filePath = path12.join(debugDir, file);
|
|
9875
|
-
const stats = await fs10.stat(filePath);
|
|
9876
|
-
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9877
|
-
await fs10.unlink(filePath);
|
|
9878
|
-
}
|
|
9879
|
-
}
|
|
9880
|
-
} catch (error) {
|
|
9881
|
-
console.error("Failed to cleanup old logs:", error);
|
|
9882
|
-
}
|
|
9883
|
-
}
|
|
9884
|
-
};
|
|
9885
|
-
var logger = Logger2.getInstance();
|
|
9886
|
-
|
|
9887
9668
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
9888
9669
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
9889
9670
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9890
|
-
import
|
|
9671
|
+
import path12 from "path";
|
|
9891
9672
|
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
9892
9673
|
var MCPClient = class {
|
|
9893
9674
|
// Note: This class handles MCP server communication with repository filtering
|
|
@@ -9928,16 +9709,16 @@ var MCPClient = class {
|
|
|
9928
9709
|
const root = process.env.INIT_CWD || process.cwd();
|
|
9929
9710
|
const candidatePaths = [
|
|
9930
9711
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
9931
|
-
|
|
9712
|
+
path12.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
9932
9713
|
// When running from SST Lambda deployed environment (/var/task)
|
|
9933
|
-
|
|
9714
|
+
path12.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9934
9715
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
9935
|
-
|
|
9716
|
+
path12.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9936
9717
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
9937
|
-
|
|
9718
|
+
path12.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9938
9719
|
// Original paths (backward compatibility)
|
|
9939
|
-
|
|
9940
|
-
|
|
9720
|
+
path12.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
9721
|
+
path12.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
9941
9722
|
];
|
|
9942
9723
|
const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
|
|
9943
9724
|
if (!serverScriptPath) {
|
|
@@ -10687,7 +10468,10 @@ var ApiClient = class {
|
|
|
10687
10468
|
* Make a POST request
|
|
10688
10469
|
*/
|
|
10689
10470
|
async post(url, data, config) {
|
|
10471
|
+
logger.debug(`[ApiClient] POST ${this.client.defaults.baseURL}${url}`);
|
|
10472
|
+
logger.debug(`[ApiClient] Request body: ${JSON.stringify(data)}`);
|
|
10690
10473
|
const response = await this.client.post(url, data, config);
|
|
10474
|
+
logger.debug(`[ApiClient] Response status: ${response.status}`);
|
|
10691
10475
|
return response.data;
|
|
10692
10476
|
}
|
|
10693
10477
|
/**
|
|
@@ -10738,7 +10522,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
10738
10522
|
// package.json
|
|
10739
10523
|
var package_default = {
|
|
10740
10524
|
name: "@bike4mind/cli",
|
|
10741
|
-
version: "0.2.8-cli-
|
|
10525
|
+
version: "0.2.8-fix-cli-type-error.17148+5ef98d7d2",
|
|
10742
10526
|
type: "module",
|
|
10743
10527
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
10744
10528
|
license: "UNLICENSED",
|
|
@@ -10841,10 +10625,10 @@ var package_default = {
|
|
|
10841
10625
|
},
|
|
10842
10626
|
devDependencies: {
|
|
10843
10627
|
"@bike4mind/agents": "0.1.0",
|
|
10844
|
-
"@bike4mind/common": "2.38.2-cli-
|
|
10845
|
-
"@bike4mind/mcp": "1.20.2-cli-
|
|
10846
|
-
"@bike4mind/services": "2.33.2-cli-
|
|
10847
|
-
"@bike4mind/utils": "2.1.3-cli-
|
|
10628
|
+
"@bike4mind/common": "2.38.2-fix-cli-type-error.17148+5ef98d7d2",
|
|
10629
|
+
"@bike4mind/mcp": "1.20.2-fix-cli-type-error.17148+5ef98d7d2",
|
|
10630
|
+
"@bike4mind/services": "2.33.2-fix-cli-type-error.17148+5ef98d7d2",
|
|
10631
|
+
"@bike4mind/utils": "2.1.3-fix-cli-type-error.17148+5ef98d7d2",
|
|
10848
10632
|
"@types/better-sqlite3": "^7.6.12",
|
|
10849
10633
|
"@types/diff": "^5.0.9",
|
|
10850
10634
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -10857,7 +10641,7 @@ var package_default = {
|
|
|
10857
10641
|
typescript: "^5.9.3",
|
|
10858
10642
|
vitest: "^3.2.4"
|
|
10859
10643
|
},
|
|
10860
|
-
gitHead: "
|
|
10644
|
+
gitHead: "5ef98d7d29cde0f6125959fe3a2acc3c5d7f40e6"
|
|
10861
10645
|
};
|
|
10862
10646
|
|
|
10863
10647
|
// src/config/constants.ts
|
|
@@ -10879,7 +10663,7 @@ var usageCache = null;
|
|
|
10879
10663
|
function CliApp() {
|
|
10880
10664
|
const { exit } = useApp();
|
|
10881
10665
|
const imageRenderer = new ImageRenderer();
|
|
10882
|
-
const [state, setState] =
|
|
10666
|
+
const [state, setState] = useState6({
|
|
10883
10667
|
session: null,
|
|
10884
10668
|
sessionStore: new SessionStore(),
|
|
10885
10669
|
configStore: new ConfigStore(),
|
|
@@ -10895,9 +10679,9 @@ function CliApp() {
|
|
|
10895
10679
|
trustLocationSelector: null,
|
|
10896
10680
|
rewindSelector: null
|
|
10897
10681
|
});
|
|
10898
|
-
const [isInitialized, setIsInitialized] =
|
|
10899
|
-
const [initError, setInitError] =
|
|
10900
|
-
const [commandHistory, setCommandHistory] =
|
|
10682
|
+
const [isInitialized, setIsInitialized] = useState6(false);
|
|
10683
|
+
const [initError, setInitError] = useState6(null);
|
|
10684
|
+
const [commandHistory, setCommandHistory] = useState6([]);
|
|
10901
10685
|
const imageStoreInitPromise = useRef(null);
|
|
10902
10686
|
const setStoreSession = useCliStore((state2) => state2.setSession);
|
|
10903
10687
|
const setPermissionPrompt = useCliStore((state2) => state2.setPermissionPrompt);
|
|
@@ -10938,7 +10722,7 @@ function CliApp() {
|
|
|
10938
10722
|
process.exit(0);
|
|
10939
10723
|
}, 100);
|
|
10940
10724
|
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
10941
|
-
|
|
10725
|
+
useInput5((input, key) => {
|
|
10942
10726
|
if (key.ctrl && input === "c") {
|
|
10943
10727
|
const now = Date.now();
|
|
10944
10728
|
if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
|
|
@@ -11082,10 +10866,6 @@ function CliApp() {
|
|
|
11082
10866
|
setPermissionPrompt(prompt);
|
|
11083
10867
|
});
|
|
11084
10868
|
};
|
|
11085
|
-
console.log("\u{1F511} Tool API Keys:", {
|
|
11086
|
-
openweather: config.toolApiKeys?.openweather ? "\u2713 configured" : "\u2717 missing",
|
|
11087
|
-
serper: config.toolApiKeys?.serper ? "\u2713 configured" : "\u2717 missing"
|
|
11088
|
-
});
|
|
11089
10869
|
const agentContext = {
|
|
11090
10870
|
currentAgent: null,
|
|
11091
10871
|
observationQueue: []
|
|
@@ -11098,7 +10878,7 @@ function CliApp() {
|
|
|
11098
10878
|
promptFn,
|
|
11099
10879
|
agentContext,
|
|
11100
10880
|
state.configStore,
|
|
11101
|
-
|
|
10881
|
+
apiClient
|
|
11102
10882
|
);
|
|
11103
10883
|
console.log(`\u{1F6E0}\uFE0F Loaded ${b4mTools.length} B4M tool(s)`);
|
|
11104
10884
|
const mcpManager = new McpManager(config);
|
|
@@ -11196,29 +10976,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11196
10976
|
console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
|
|
11197
10977
|
return;
|
|
11198
10978
|
}
|
|
11199
|
-
const currentSteps = [];
|
|
11200
|
-
const stepHandler = (step) => {
|
|
11201
|
-
currentSteps.push(step);
|
|
11202
|
-
const currentSession = useCliStore.getState().session;
|
|
11203
|
-
if (currentSession) {
|
|
11204
|
-
const messages = [...currentSession.messages];
|
|
11205
|
-
const lastMessage = messages[messages.length - 1];
|
|
11206
|
-
if (lastMessage && lastMessage.role === "assistant") {
|
|
11207
|
-
messages[messages.length - 1] = {
|
|
11208
|
-
...lastMessage,
|
|
11209
|
-
metadata: {
|
|
11210
|
-
...lastMessage.metadata,
|
|
11211
|
-
steps: [...currentSteps]
|
|
11212
|
-
}
|
|
11213
|
-
};
|
|
11214
|
-
setStoreSession({
|
|
11215
|
-
...currentSession,
|
|
11216
|
-
messages
|
|
11217
|
-
});
|
|
11218
|
-
}
|
|
11219
|
-
}
|
|
11220
|
-
};
|
|
11221
|
-
state.agent.on("action", stepHandler);
|
|
11222
10979
|
try {
|
|
11223
10980
|
let messageContent = message;
|
|
11224
10981
|
let userMessageContent = message;
|
|
@@ -11232,21 +10989,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11232
10989
|
content: userMessageContent,
|
|
11233
10990
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11234
10991
|
};
|
|
11235
|
-
const pendingAssistantMessage = {
|
|
11236
|
-
role: "assistant",
|
|
11237
|
-
content: "...",
|
|
11238
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11239
|
-
metadata: {
|
|
11240
|
-
steps: []
|
|
11241
|
-
}
|
|
11242
|
-
};
|
|
11243
|
-
const sessionWithMessages = {
|
|
11244
|
-
...state.session,
|
|
11245
|
-
messages: [...state.session.messages, userMessage, pendingAssistantMessage],
|
|
11246
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11247
|
-
};
|
|
11248
|
-
setState((prev) => ({ ...prev, session: sessionWithMessages }));
|
|
11249
|
-
setStoreSession(sessionWithMessages);
|
|
11250
10992
|
const recentMessages = state.session.messages.slice(-20);
|
|
11251
10993
|
const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
|
|
11252
10994
|
role: msg.role,
|
|
@@ -11260,28 +11002,26 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11260
11002
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
11261
11003
|
}
|
|
11262
11004
|
const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
|
|
11263
|
-
const
|
|
11264
|
-
if (!currentSession) return;
|
|
11265
|
-
const finalMessages = [...currentSession.messages];
|
|
11266
|
-
const finalAssistantMessage = {
|
|
11005
|
+
const assistantMessage = {
|
|
11267
11006
|
role: "assistant",
|
|
11268
11007
|
content: result.finalAnswer,
|
|
11269
|
-
timestamp:
|
|
11008
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11270
11009
|
metadata: {
|
|
11271
11010
|
tokenUsage: {
|
|
11272
11011
|
prompt: 0,
|
|
11012
|
+
// TODO: Extract from result
|
|
11273
11013
|
completion: 0,
|
|
11274
11014
|
total: result.completionInfo.totalTokens
|
|
11275
11015
|
},
|
|
11276
11016
|
steps: result.steps,
|
|
11277
11017
|
// Complete history: thoughts, actions, observations
|
|
11278
11018
|
permissionDenied
|
|
11019
|
+
// Mark if this ended due to permission denial
|
|
11279
11020
|
}
|
|
11280
11021
|
};
|
|
11281
|
-
finalMessages[finalMessages.length - 1] = finalAssistantMessage;
|
|
11282
11022
|
const updatedSession = {
|
|
11283
|
-
...
|
|
11284
|
-
messages:
|
|
11023
|
+
...state.session,
|
|
11024
|
+
messages: [...state.session.messages, userMessage, assistantMessage],
|
|
11285
11025
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11286
11026
|
metadata: {
|
|
11287
11027
|
...state.session.metadata,
|
|
@@ -11301,8 +11041,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11301
11041
|
}
|
|
11302
11042
|
}
|
|
11303
11043
|
console.error("Error processing message:", error);
|
|
11304
|
-
} finally {
|
|
11305
|
-
state.agent.off("action", stepHandler);
|
|
11306
11044
|
}
|
|
11307
11045
|
};
|
|
11308
11046
|
const handleImageDetected = async (imageData) => {
|
|
@@ -11854,12 +11592,12 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11854
11592
|
setState((prev) => ({ ...prev, config: updatedConfig }));
|
|
11855
11593
|
};
|
|
11856
11594
|
if (initError) {
|
|
11857
|
-
return /* @__PURE__ */
|
|
11595
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React15.createElement(Text14, null, initError), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
|
|
11858
11596
|
}
|
|
11859
11597
|
if (state.trustLocationSelector) {
|
|
11860
11598
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
11861
11599
|
const inProject = projectDir !== null;
|
|
11862
|
-
return /* @__PURE__ */
|
|
11600
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11863
11601
|
TrustLocationSelector,
|
|
11864
11602
|
{
|
|
11865
11603
|
inProject,
|
|
@@ -11877,7 +11615,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11877
11615
|
);
|
|
11878
11616
|
}
|
|
11879
11617
|
if (state.rewindSelector && state.session) {
|
|
11880
|
-
return /* @__PURE__ */
|
|
11618
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11881
11619
|
RewindSelector,
|
|
11882
11620
|
{
|
|
11883
11621
|
messages: state.session.messages,
|
|
@@ -11896,7 +11634,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11896
11634
|
}
|
|
11897
11635
|
if (state.showLoginFlow) {
|
|
11898
11636
|
const loginApiUrl = getApiUrl(state.config?.apiConfig);
|
|
11899
|
-
return /* @__PURE__ */
|
|
11637
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11900
11638
|
LoginFlow,
|
|
11901
11639
|
{
|
|
11902
11640
|
apiUrl: loginApiUrl,
|
|
@@ -11919,9 +11657,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11919
11657
|
);
|
|
11920
11658
|
}
|
|
11921
11659
|
if (!isInitialized) {
|
|
11922
|
-
return /* @__PURE__ */
|
|
11660
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "\u{1F680} Initializing..."));
|
|
11923
11661
|
}
|
|
11924
|
-
return /* @__PURE__ */
|
|
11662
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11925
11663
|
App,
|
|
11926
11664
|
{
|
|
11927
11665
|
onMessage: handleMessage,
|
|
@@ -11960,6 +11698,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
|
|
|
11960
11698
|
if (isDevMode) {
|
|
11961
11699
|
console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
|
|
11962
11700
|
}
|
|
11963
|
-
render(/* @__PURE__ */
|
|
11701
|
+
render(/* @__PURE__ */ React15.createElement(CliApp, null), {
|
|
11964
11702
|
exitOnCtrlC: false
|
|
11965
11703
|
});
|