@bike4mind/cli 0.2.8-cli-bash-tools.17146 → 0.2.8-feat-cli-context-file-loading.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 +365 -565
- 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,11 +738,11 @@ 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] =
|
|
741
|
+
const [value, setValue] = useState2("");
|
|
742
|
+
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
743
|
+
const [historyIndex, setHistoryIndex] = useState2(-1);
|
|
744
|
+
const [tempInput, setTempInput] = useState2("");
|
|
745
|
+
const [inputKey, setInputKey] = useState2(0);
|
|
646
746
|
useEffect(() => {
|
|
647
747
|
if (prefillInput) {
|
|
648
748
|
setValue(prefillInput);
|
|
@@ -650,8 +750,8 @@ function InputPrompt({
|
|
|
650
750
|
onPrefillConsumed?.();
|
|
651
751
|
}
|
|
652
752
|
}, [prefillInput, onPrefillConsumed]);
|
|
653
|
-
const [fileAutocomplete, setFileAutocomplete] =
|
|
654
|
-
const [fileSelectedIndex, setFileSelectedIndex] =
|
|
753
|
+
const [fileAutocomplete, setFileAutocomplete] = useState2(null);
|
|
754
|
+
const [fileSelectedIndex, setFileSelectedIndex] = useState2(0);
|
|
655
755
|
const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
|
|
656
756
|
const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
|
|
657
757
|
const filteredCommands = useMemo(() => {
|
|
@@ -668,7 +768,7 @@ function InputPrompt({
|
|
|
668
768
|
useEffect(() => {
|
|
669
769
|
setFileSelectedIndex(0);
|
|
670
770
|
}, [filteredFiles]);
|
|
671
|
-
|
|
771
|
+
useInput2((_input, key) => {
|
|
672
772
|
if (fileAutocomplete?.active && filteredFiles.length > 0) {
|
|
673
773
|
if (key.upArrow) {
|
|
674
774
|
setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
|
|
@@ -725,7 +825,6 @@ function InputPrompt({
|
|
|
725
825
|
const pathToInsert = file.isDirectory ? `@${file.path}/` : `@${file.path}`;
|
|
726
826
|
const newValue = beforeAt + pathToInsert + afterQuery;
|
|
727
827
|
setValue(newValue);
|
|
728
|
-
setInputKey((prev) => prev + 1);
|
|
729
828
|
if (file.isDirectory) {
|
|
730
829
|
setFileAutocomplete({
|
|
731
830
|
active: true,
|
|
@@ -752,7 +851,6 @@ function InputPrompt({
|
|
|
752
851
|
if (selectedCommand.args) {
|
|
753
852
|
setValue(commandText + " ");
|
|
754
853
|
setHistoryIndex(-1);
|
|
755
|
-
setInputKey((prev) => prev + 1);
|
|
756
854
|
return;
|
|
757
855
|
}
|
|
758
856
|
setValue("");
|
|
@@ -771,7 +869,6 @@ function InputPrompt({
|
|
|
771
869
|
if (imageEvent && onImageDetected) {
|
|
772
870
|
const placeholder = await onImageDetected(imageEvent.data);
|
|
773
871
|
setValue(`${placeholder} `);
|
|
774
|
-
setInputKey((prev) => prev + 1);
|
|
775
872
|
return;
|
|
776
873
|
}
|
|
777
874
|
}
|
|
@@ -791,29 +888,29 @@ function InputPrompt({
|
|
|
791
888
|
setFileAutocomplete(null);
|
|
792
889
|
}
|
|
793
890
|
};
|
|
794
|
-
return /* @__PURE__ */
|
|
795
|
-
|
|
891
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(
|
|
892
|
+
CustomTextInput,
|
|
796
893
|
{
|
|
797
894
|
key: inputKey,
|
|
798
895
|
value,
|
|
799
896
|
onChange: handleChange,
|
|
800
897
|
onSubmit: handleSubmit,
|
|
801
|
-
placeholder: disabled ? "" : "Type your message, /help for commands, or @file to reference",
|
|
898
|
+
placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
|
|
802
899
|
showCursor: !disabled
|
|
803
900
|
}
|
|
804
|
-
)), shouldShowCommandAutocomplete && /* @__PURE__ */
|
|
901
|
+
)), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
|
|
805
902
|
}
|
|
806
903
|
|
|
807
904
|
// src/components/AgentThinking.tsx
|
|
808
|
-
import
|
|
905
|
+
import React7 from "react";
|
|
809
906
|
import { Box as Box6 } from "ink";
|
|
810
907
|
|
|
811
908
|
// src/components/ThoughtStream.tsx
|
|
812
|
-
import
|
|
813
|
-
import { Box as Box5, Text as
|
|
909
|
+
import React6 from "react";
|
|
910
|
+
import { Box as Box5, Text as Text6 } from "ink";
|
|
814
911
|
import Spinner from "ink-spinner";
|
|
815
|
-
var ThoughtStream =
|
|
816
|
-
return /* @__PURE__ */
|
|
912
|
+
var ThoughtStream = React6.memo(function ThoughtStream2({ steps }) {
|
|
913
|
+
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
914
|
});
|
|
818
915
|
|
|
819
916
|
// src/store/index.ts
|
|
@@ -829,7 +926,6 @@ var useCliStore = create((set) => ({
|
|
|
829
926
|
addAgentStep: (step) => set((state) => ({
|
|
830
927
|
agentSteps: [...state.agentSteps, step]
|
|
831
928
|
})),
|
|
832
|
-
setAgentSteps: (steps) => set({ agentSteps: steps }),
|
|
833
929
|
clearAgentSteps: () => set({ agentSteps: [] }),
|
|
834
930
|
// Permission prompt
|
|
835
931
|
permissionPrompt: null,
|
|
@@ -843,32 +939,32 @@ var useCliStore = create((set) => ({
|
|
|
843
939
|
}));
|
|
844
940
|
|
|
845
941
|
// src/components/AgentThinking.tsx
|
|
846
|
-
var AgentThinking =
|
|
942
|
+
var AgentThinking = React7.memo(function AgentThinking2() {
|
|
847
943
|
const isThinking = useCliStore((state) => state.isThinking);
|
|
848
944
|
const agentSteps = useCliStore((state) => state.agentSteps);
|
|
849
945
|
if (!isThinking) {
|
|
850
946
|
return null;
|
|
851
947
|
}
|
|
852
|
-
return /* @__PURE__ */
|
|
948
|
+
return /* @__PURE__ */ React7.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
|
|
853
949
|
});
|
|
854
950
|
|
|
855
951
|
// src/components/PermissionPrompt.tsx
|
|
856
|
-
import
|
|
857
|
-
import { Box as Box7, Text as
|
|
952
|
+
import React8 from "react";
|
|
953
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
858
954
|
import SelectInput from "ink-select-input";
|
|
859
955
|
function renderDiffPreview(preview) {
|
|
860
956
|
const lines = preview.split("\n");
|
|
861
957
|
return lines.map((line, index) => {
|
|
862
958
|
if (line.startsWith("+")) {
|
|
863
|
-
return /* @__PURE__ */
|
|
959
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "green" }, line);
|
|
864
960
|
}
|
|
865
961
|
if (line.startsWith("-")) {
|
|
866
|
-
return /* @__PURE__ */
|
|
962
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "red" }, line);
|
|
867
963
|
}
|
|
868
964
|
if (line.startsWith("@@")) {
|
|
869
|
-
return /* @__PURE__ */
|
|
965
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "cyan" }, line);
|
|
870
966
|
}
|
|
871
|
-
return /* @__PURE__ */
|
|
967
|
+
return /* @__PURE__ */ React8.createElement(Text7, { key: index, dimColor: true }, line);
|
|
872
968
|
});
|
|
873
969
|
}
|
|
874
970
|
function PermissionPrompt({
|
|
@@ -888,12 +984,12 @@ function PermissionPrompt({
|
|
|
888
984
|
{ label: "\u2717 Deny", value: "deny" }
|
|
889
985
|
];
|
|
890
986
|
const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
|
|
891
|
-
return /* @__PURE__ */
|
|
987
|
+
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
988
|
}
|
|
893
989
|
|
|
894
990
|
// src/components/ConfigEditor.tsx
|
|
895
|
-
import
|
|
896
|
-
import { Box as Box8, Text as
|
|
991
|
+
import React9, { useState as useState3, useMemo as useMemo2 } from "react";
|
|
992
|
+
import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
|
|
897
993
|
var MAX_ITERATIONS_OPTIONS = [
|
|
898
994
|
{ label: "10", value: 10 },
|
|
899
995
|
{ label: "20", value: 20 },
|
|
@@ -1024,10 +1120,10 @@ function buildConfigItems(availableModels) {
|
|
|
1024
1120
|
return items;
|
|
1025
1121
|
}
|
|
1026
1122
|
function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
1027
|
-
const [selectedIndex, setSelectedIndex] =
|
|
1028
|
-
const [editedConfig, setEditedConfig] =
|
|
1029
|
-
const [saveError, setSaveError] =
|
|
1030
|
-
const [isSaving, setIsSaving] =
|
|
1123
|
+
const [selectedIndex, setSelectedIndex] = useState3(0);
|
|
1124
|
+
const [editedConfig, setEditedConfig] = useState3(config);
|
|
1125
|
+
const [saveError, setSaveError] = useState3(null);
|
|
1126
|
+
const [isSaving, setIsSaving] = useState3(false);
|
|
1031
1127
|
const configItems = useMemo2(() => buildConfigItems(availableModels), [availableModels]);
|
|
1032
1128
|
const hasChanges = useMemo2(() => {
|
|
1033
1129
|
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
|
|
@@ -1047,7 +1143,7 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1047
1143
|
}
|
|
1048
1144
|
onClose();
|
|
1049
1145
|
};
|
|
1050
|
-
|
|
1146
|
+
useInput3((input, key) => {
|
|
1051
1147
|
const currentItem = configItems[selectedIndex];
|
|
1052
1148
|
if (key.upArrow) {
|
|
1053
1149
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : configItems.length - 1);
|
|
@@ -1112,13 +1208,13 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1112
1208
|
}
|
|
1113
1209
|
return String(value);
|
|
1114
1210
|
};
|
|
1115
|
-
return /* @__PURE__ */
|
|
1211
|
+
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
1212
|
const isSelected = index === selectedIndex;
|
|
1117
1213
|
const value = item.getValue(editedConfig);
|
|
1118
1214
|
const displayValue = formatValue(item, value);
|
|
1119
1215
|
const hasOptions = item.type === "select" || item.type === "boolean" || item.type === "number";
|
|
1120
|
-
return /* @__PURE__ */
|
|
1121
|
-
})), /* @__PURE__ */
|
|
1216
|
+
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 }, " >")));
|
|
1217
|
+
})), /* @__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
1218
|
}
|
|
1123
1219
|
|
|
1124
1220
|
// src/utils/processFileReferences.ts
|
|
@@ -1258,7 +1354,7 @@ function App({
|
|
|
1258
1354
|
const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
|
|
1259
1355
|
const exitRequested = useCliStore((state) => state.exitRequested);
|
|
1260
1356
|
const setIsThinking = useCliStore((state) => state.setIsThinking);
|
|
1261
|
-
const handleSubmit =
|
|
1357
|
+
const handleSubmit = React10.useCallback(
|
|
1262
1358
|
async (input) => {
|
|
1263
1359
|
const trimmed = input.trim();
|
|
1264
1360
|
if (!trimmed) return;
|
|
@@ -1287,7 +1383,7 @@ ${errorBlock}`;
|
|
|
1287
1383
|
},
|
|
1288
1384
|
[onMessage, onCommand, setIsThinking]
|
|
1289
1385
|
);
|
|
1290
|
-
return /* @__PURE__ */
|
|
1386
|
+
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
1387
|
ConfigEditor,
|
|
1292
1388
|
{
|
|
1293
1389
|
config,
|
|
@@ -1295,7 +1391,7 @@ ${errorBlock}`;
|
|
|
1295
1391
|
onSave: onSaveConfig,
|
|
1296
1392
|
onClose: () => setShowConfigEditor(false)
|
|
1297
1393
|
}
|
|
1298
|
-
)) : permissionPrompt ? /* @__PURE__ */
|
|
1394
|
+
)) : permissionPrompt ? /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
|
|
1299
1395
|
PermissionPrompt,
|
|
1300
1396
|
{
|
|
1301
1397
|
toolName: permissionPrompt.toolName,
|
|
@@ -1304,7 +1400,7 @@ ${errorBlock}`;
|
|
|
1304
1400
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
1305
1401
|
onResponse: onPermissionResponse
|
|
1306
1402
|
}
|
|
1307
|
-
)) : /* @__PURE__ */
|
|
1403
|
+
)) : /* @__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
1404
|
InputPrompt,
|
|
1309
1405
|
{
|
|
1310
1406
|
onSubmit: handleSubmit,
|
|
@@ -1317,37 +1413,36 @@ ${errorBlock}`;
|
|
|
1317
1413
|
))));
|
|
1318
1414
|
}
|
|
1319
1415
|
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) => {
|
|
1416
|
+
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
1417
|
if (step.type === "thought") {
|
|
1323
|
-
return /* @__PURE__ */
|
|
1418
|
+
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
1419
|
}
|
|
1325
1420
|
if (step.type === "action") {
|
|
1326
1421
|
const toolName = step.metadata?.toolName || "unknown";
|
|
1327
1422
|
const toolInput = step.metadata?.toolInput;
|
|
1328
1423
|
const observationStep = message.metadata.steps[idx + 1];
|
|
1329
1424
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
1330
|
-
return /* @__PURE__ */
|
|
1425
|
+
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
1426
|
}
|
|
1332
1427
|
return null;
|
|
1333
|
-
}).filter(Boolean)),
|
|
1428
|
+
}).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
1429
|
}
|
|
1335
1430
|
|
|
1336
1431
|
// src/components/MessageList.tsx
|
|
1337
|
-
import
|
|
1338
|
-
import { Box as Box10, Text as
|
|
1432
|
+
import React11 from "react";
|
|
1433
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1339
1434
|
function stripThinkingTags(content) {
|
|
1340
1435
|
return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
1341
1436
|
}
|
|
1342
|
-
var MessageList =
|
|
1437
|
+
var MessageList = React11.memo(
|
|
1343
1438
|
function MessageList2({ messages }) {
|
|
1344
1439
|
if (messages.length === 0) {
|
|
1345
|
-
return /* @__PURE__ */
|
|
1440
|
+
return /* @__PURE__ */ React11.createElement(Box10, { paddingY: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "No messages yet. Type a message to start!"));
|
|
1346
1441
|
}
|
|
1347
|
-
return /* @__PURE__ */
|
|
1442
|
+
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
1443
|
if (step.type === "thought") {
|
|
1349
|
-
return /* @__PURE__ */
|
|
1350
|
-
|
|
1444
|
+
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(
|
|
1445
|
+
Text10,
|
|
1351
1446
|
{
|
|
1352
1447
|
dimColor: true
|
|
1353
1448
|
},
|
|
@@ -1359,10 +1454,10 @@ var MessageList = React10.memo(
|
|
|
1359
1454
|
const toolInput = step.metadata?.toolInput;
|
|
1360
1455
|
const observationStep = message.metadata.steps[idx + 1];
|
|
1361
1456
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
1362
|
-
return /* @__PURE__ */
|
|
1457
|
+
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
1458
|
}
|
|
1364
1459
|
return null;
|
|
1365
|
-
}).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */
|
|
1460
|
+
}).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
1461
|
},
|
|
1367
1462
|
(prevProps, nextProps) => {
|
|
1368
1463
|
if (prevProps.messages.length !== nextProps.messages.length) {
|
|
@@ -1373,8 +1468,8 @@ var MessageList = React10.memo(
|
|
|
1373
1468
|
);
|
|
1374
1469
|
|
|
1375
1470
|
// src/components/TrustLocationSelector.tsx
|
|
1376
|
-
import
|
|
1377
|
-
import { Box as Box11, Text as
|
|
1471
|
+
import React12 from "react";
|
|
1472
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1378
1473
|
import SelectInput2 from "ink-select-input";
|
|
1379
1474
|
function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
1380
1475
|
const items = [];
|
|
@@ -1395,24 +1490,24 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
|
1395
1490
|
const handleSelect = (item) => {
|
|
1396
1491
|
onSelect(item.value);
|
|
1397
1492
|
};
|
|
1398
|
-
return /* @__PURE__ */
|
|
1493
|
+
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
1494
|
SelectInput2,
|
|
1400
1495
|
{
|
|
1401
1496
|
items,
|
|
1402
1497
|
onSelect: handleSelect,
|
|
1403
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
1498
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1404
1499
|
}
|
|
1405
|
-
), /* @__PURE__ */
|
|
1500
|
+
), /* @__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
1501
|
}
|
|
1407
1502
|
|
|
1408
1503
|
// src/components/RewindSelector.tsx
|
|
1409
|
-
import
|
|
1410
|
-
import { Box as Box12, Text as
|
|
1504
|
+
import React13, { useState as useState4 } from "react";
|
|
1505
|
+
import { Box as Box12, Text as Text12, useInput as useInput4 } from "ink";
|
|
1411
1506
|
import SelectInput3 from "ink-select-input";
|
|
1412
1507
|
function RewindSelector({ messages, onSelect, onCancel }) {
|
|
1413
|
-
const [step, setStep] =
|
|
1414
|
-
const [selectedMessageIndex, setSelectedMessageIndex] =
|
|
1415
|
-
|
|
1508
|
+
const [step, setStep] = useState4("selection");
|
|
1509
|
+
const [selectedMessageIndex, setSelectedMessageIndex] = useState4(null);
|
|
1510
|
+
useInput4((input, key) => {
|
|
1416
1511
|
if (key.escape) {
|
|
1417
1512
|
if (step === "confirmation") {
|
|
1418
1513
|
setStep("selection");
|
|
@@ -1449,14 +1544,14 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
1449
1544
|
return sum2 + (msg.metadata?.tokenUsage?.total || 0);
|
|
1450
1545
|
}, 0);
|
|
1451
1546
|
if (step === "selection") {
|
|
1452
|
-
return /* @__PURE__ */
|
|
1547
|
+
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
1548
|
SelectInput3,
|
|
1454
1549
|
{
|
|
1455
1550
|
items,
|
|
1456
1551
|
onSelect: handleSelectionSelect,
|
|
1457
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
1552
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1458
1553
|
}
|
|
1459
|
-
), /* @__PURE__ */
|
|
1554
|
+
), /* @__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
1555
|
}
|
|
1461
1556
|
const confirmationItems = [
|
|
1462
1557
|
{ label: "Yes, rewind to this point", value: "confirm" },
|
|
@@ -1464,19 +1559,19 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
1464
1559
|
];
|
|
1465
1560
|
const selectedMessage = selectedMessageIndex !== null && selectedMessageIndex >= 0 && selectedMessageIndex < messages.length ? messages[selectedMessageIndex] : null;
|
|
1466
1561
|
const selectedPreview = selectedMessage ? selectedMessage.content.length > 50 ? selectedMessage.content.substring(0, 50) + "..." : selectedMessage.content : "";
|
|
1467
|
-
return /* @__PURE__ */
|
|
1562
|
+
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
1563
|
SelectInput3,
|
|
1469
1564
|
{
|
|
1470
1565
|
items: confirmationItems,
|
|
1471
1566
|
onSelect: handleConfirmationSelect,
|
|
1472
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
1567
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
1473
1568
|
}
|
|
1474
|
-
), /* @__PURE__ */
|
|
1569
|
+
), /* @__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
1570
|
}
|
|
1476
1571
|
|
|
1477
1572
|
// src/components/LoginFlow.tsx
|
|
1478
|
-
import
|
|
1479
|
-
import { Box as Box13, Text as
|
|
1573
|
+
import React14, { useState as useState5, useEffect as useEffect2 } from "react";
|
|
1574
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1480
1575
|
import Spinner2 from "ink-spinner";
|
|
1481
1576
|
import jwt from "jsonwebtoken";
|
|
1482
1577
|
import open from "open";
|
|
@@ -1592,10 +1687,10 @@ var OAuthClient = class {
|
|
|
1592
1687
|
|
|
1593
1688
|
// src/components/LoginFlow.tsx
|
|
1594
1689
|
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] =
|
|
1690
|
+
const [status, setStatus] = useState5("initiating");
|
|
1691
|
+
const [deviceFlow, setDeviceFlow] = useState5(null);
|
|
1692
|
+
const [statusMessage, setStatusMessage] = useState5("Initiating device authorization...");
|
|
1693
|
+
const [error, setError] = useState5(null);
|
|
1599
1694
|
useEffect2(() => {
|
|
1600
1695
|
const runLoginFlow = async () => {
|
|
1601
1696
|
const oauth = new OAuthClient(apiUrl);
|
|
@@ -1639,15 +1734,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
1639
1734
|
}
|
|
1640
1735
|
}, [deviceFlow, status]);
|
|
1641
1736
|
if (status === "initiating") {
|
|
1642
|
-
return /* @__PURE__ */
|
|
1737
|
+
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
1738
|
}
|
|
1644
1739
|
if (status === "error") {
|
|
1645
|
-
return /* @__PURE__ */
|
|
1740
|
+
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
1741
|
}
|
|
1647
1742
|
if (status === "success") {
|
|
1648
|
-
return /* @__PURE__ */
|
|
1743
|
+
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
1744
|
}
|
|
1650
|
-
return /* @__PURE__ */
|
|
1745
|
+
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
1746
|
}
|
|
1652
1747
|
|
|
1653
1748
|
// src/storage/SessionStore.ts
|
|
@@ -2533,9 +2628,10 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
2533
2628
|
content: query
|
|
2534
2629
|
}
|
|
2535
2630
|
];
|
|
2631
|
+
console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
|
|
2536
2632
|
messages.forEach((msg, i) => {
|
|
2537
2633
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
2538
|
-
|
|
2634
|
+
console.log(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
|
|
2539
2635
|
});
|
|
2540
2636
|
let finalAnswer = "";
|
|
2541
2637
|
let reachedMaxIterations = false;
|
|
@@ -8554,381 +8650,6 @@ var deleteFileTool = {
|
|
|
8554
8650
|
})
|
|
8555
8651
|
};
|
|
8556
8652
|
|
|
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
8653
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
8933
8654
|
var tools = {
|
|
8934
8655
|
dice_roll: diceRollTool,
|
|
@@ -8956,9 +8677,7 @@ var tools = {
|
|
|
8956
8677
|
create_file: createFileTool,
|
|
8957
8678
|
glob_files: globFilesTool,
|
|
8958
8679
|
grep_search: grepSearchTool,
|
|
8959
|
-
delete_file: deleteFileTool
|
|
8960
|
-
// Shell execution
|
|
8961
|
-
bash_execute: bashExecuteTool
|
|
8680
|
+
delete_file: deleteFileTool
|
|
8962
8681
|
};
|
|
8963
8682
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
8964
8683
|
const context = {
|
|
@@ -9233,7 +8952,7 @@ async function generateFileDeletePreview(args) {
|
|
|
9233
8952
|
if (!existsSync7(args.path)) {
|
|
9234
8953
|
return `[File does not exist: ${args.path}]`;
|
|
9235
8954
|
}
|
|
9236
|
-
const stats = await import("fs/promises").then((
|
|
8955
|
+
const stats = await import("fs/promises").then((fs12) => fs12.stat(args.path));
|
|
9237
8956
|
return `[File will be deleted]
|
|
9238
8957
|
|
|
9239
8958
|
Path: ${args.path}
|
|
@@ -9246,7 +8965,7 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
9246
8965
|
|
|
9247
8966
|
// src/utils/Logger.ts
|
|
9248
8967
|
import fs10 from "fs/promises";
|
|
9249
|
-
import
|
|
8968
|
+
import path11 from "path";
|
|
9250
8969
|
import os from "os";
|
|
9251
8970
|
var Logger2 = class _Logger {
|
|
9252
8971
|
constructor() {
|
|
@@ -9269,9 +8988,9 @@ var Logger2 = class _Logger {
|
|
|
9269
8988
|
*/
|
|
9270
8989
|
async initialize(sessionId) {
|
|
9271
8990
|
this.sessionId = sessionId;
|
|
9272
|
-
const debugDir =
|
|
8991
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9273
8992
|
await fs10.mkdir(debugDir, { recursive: true });
|
|
9274
|
-
this.logFilePath =
|
|
8993
|
+
this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
|
|
9275
8994
|
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9276
8995
|
}
|
|
9277
8996
|
/**
|
|
@@ -9481,12 +9200,12 @@ var Logger2 = class _Logger {
|
|
|
9481
9200
|
async cleanupOldLogs() {
|
|
9482
9201
|
if (!this.fileLoggingEnabled) return;
|
|
9483
9202
|
try {
|
|
9484
|
-
const debugDir =
|
|
9203
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9485
9204
|
const files = await fs10.readdir(debugDir);
|
|
9486
9205
|
const now = Date.now();
|
|
9487
9206
|
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9488
9207
|
for (const file of files) {
|
|
9489
|
-
const filePath =
|
|
9208
|
+
const filePath = path11.join(debugDir, file);
|
|
9490
9209
|
const stats = await fs10.stat(filePath);
|
|
9491
9210
|
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9492
9211
|
await fs10.unlink(filePath);
|
|
@@ -9653,10 +9372,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9653
9372
|
} catch (error) {
|
|
9654
9373
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9655
9374
|
}
|
|
9656
|
-
} else if (toolName === "bash_execute" && args?.command) {
|
|
9657
|
-
const cwd = args.cwd ? ` (in ${args.cwd})` : "";
|
|
9658
|
-
const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
|
|
9659
|
-
preview = `$ ${args.command}${cwd}${timeout}`;
|
|
9660
9375
|
}
|
|
9661
9376
|
const response = await showPermissionPrompt(toolName, args, preview);
|
|
9662
9377
|
if (response.action === "deny") {
|
|
@@ -9727,8 +9442,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9727
9442
|
glob_files: {},
|
|
9728
9443
|
grep_search: {},
|
|
9729
9444
|
delete_file: {},
|
|
9730
|
-
// Shell execution (always requires permission)
|
|
9731
|
-
bash_execute: {},
|
|
9732
9445
|
// Server-side tools (executed via /api/ai/v1/tools Lambda)
|
|
9733
9446
|
// Routed by ToolRouter to use B4M company API keys
|
|
9734
9447
|
weather_info: {},
|
|
@@ -9794,7 +9507,6 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
9794
9507
|
create_file: "prompt_always",
|
|
9795
9508
|
delete_file: "prompt_always",
|
|
9796
9509
|
shell_execute: "prompt_always",
|
|
9797
|
-
bash_execute: "prompt_always",
|
|
9798
9510
|
git_commit: "prompt_always",
|
|
9799
9511
|
git_push: "prompt_always",
|
|
9800
9512
|
// ===== PROMPT DEFAULT (Repository read tools) =====
|
|
@@ -9956,6 +9668,118 @@ function getEnvironmentName(configApiConfig) {
|
|
|
9956
9668
|
return "Bike4Mind";
|
|
9957
9669
|
}
|
|
9958
9670
|
|
|
9671
|
+
// src/utils/contextLoader.ts
|
|
9672
|
+
import * as fs11 from "fs";
|
|
9673
|
+
import * as path12 from "path";
|
|
9674
|
+
import { homedir as homedir4 } from "os";
|
|
9675
|
+
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
9676
|
+
var PROJECT_CONTEXT_FILES = [
|
|
9677
|
+
"CLAUDE.local.md",
|
|
9678
|
+
// gitignored, highest priority
|
|
9679
|
+
"CLAUDE.md",
|
|
9680
|
+
"AGENTS.md",
|
|
9681
|
+
// cross-tool standard
|
|
9682
|
+
"AI.local.md",
|
|
9683
|
+
// gitignored
|
|
9684
|
+
"AI.md",
|
|
9685
|
+
"INSTRUCTIONS.md"
|
|
9686
|
+
];
|
|
9687
|
+
var GLOBAL_CONTEXT_FILES = ["AI.local.md", "AI.md"];
|
|
9688
|
+
function formatFileSize2(bytes) {
|
|
9689
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
9690
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
9691
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
9692
|
+
}
|
|
9693
|
+
function tryReadContextFile(dir, filename, source) {
|
|
9694
|
+
const filePath = path12.join(dir, filename);
|
|
9695
|
+
try {
|
|
9696
|
+
const stats = fs11.lstatSync(filePath);
|
|
9697
|
+
if (stats.isDirectory()) {
|
|
9698
|
+
return null;
|
|
9699
|
+
}
|
|
9700
|
+
if (stats.isSymbolicLink()) {
|
|
9701
|
+
return {
|
|
9702
|
+
error: `${source === "global" ? "Global" : "Project"} ${filename} is a symlink (not allowed for security)`
|
|
9703
|
+
};
|
|
9704
|
+
}
|
|
9705
|
+
if (stats.size > CONTEXT_FILE_SIZE_LIMIT) {
|
|
9706
|
+
return {
|
|
9707
|
+
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
9708
|
+
};
|
|
9709
|
+
}
|
|
9710
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
9711
|
+
return {
|
|
9712
|
+
filename,
|
|
9713
|
+
content,
|
|
9714
|
+
source,
|
|
9715
|
+
path: filePath
|
|
9716
|
+
};
|
|
9717
|
+
} catch (err) {
|
|
9718
|
+
if (err.code === "ENOENT") {
|
|
9719
|
+
return null;
|
|
9720
|
+
}
|
|
9721
|
+
if (err.code === "EACCES") {
|
|
9722
|
+
return {
|
|
9723
|
+
error: `Cannot read ${source} ${filename}: permission denied`
|
|
9724
|
+
};
|
|
9725
|
+
}
|
|
9726
|
+
return {
|
|
9727
|
+
error: `Cannot read ${source} ${filename}: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
9728
|
+
};
|
|
9729
|
+
}
|
|
9730
|
+
}
|
|
9731
|
+
function findContextFile(dir, candidates, source) {
|
|
9732
|
+
for (const filename of candidates) {
|
|
9733
|
+
const result = tryReadContextFile(dir, filename, source);
|
|
9734
|
+
if (result === null) {
|
|
9735
|
+
continue;
|
|
9736
|
+
}
|
|
9737
|
+
if ("error" in result) {
|
|
9738
|
+
return { result: null, error: result.error };
|
|
9739
|
+
}
|
|
9740
|
+
return { result, error: null };
|
|
9741
|
+
}
|
|
9742
|
+
return { result: null, error: null };
|
|
9743
|
+
}
|
|
9744
|
+
function mergeContextContent(global, project) {
|
|
9745
|
+
if (global && project) {
|
|
9746
|
+
return `${global.content}
|
|
9747
|
+
|
|
9748
|
+
---
|
|
9749
|
+
|
|
9750
|
+
${project.content}`;
|
|
9751
|
+
}
|
|
9752
|
+
if (global) {
|
|
9753
|
+
return global.content;
|
|
9754
|
+
}
|
|
9755
|
+
if (project) {
|
|
9756
|
+
return project.content;
|
|
9757
|
+
}
|
|
9758
|
+
return "";
|
|
9759
|
+
}
|
|
9760
|
+
async function loadContextFiles(projectDir) {
|
|
9761
|
+
const errors = [];
|
|
9762
|
+
const globalDir = path12.join(homedir4(), ".bike4mind");
|
|
9763
|
+
const projectDirectory = projectDir || process.cwd();
|
|
9764
|
+
const [globalResult, projectResult] = await Promise.all([
|
|
9765
|
+
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
9766
|
+
Promise.resolve(findContextFile(projectDirectory, PROJECT_CONTEXT_FILES, "project"))
|
|
9767
|
+
]);
|
|
9768
|
+
if (globalResult.error) {
|
|
9769
|
+
errors.push(globalResult.error);
|
|
9770
|
+
}
|
|
9771
|
+
if (projectResult.error) {
|
|
9772
|
+
errors.push(projectResult.error);
|
|
9773
|
+
}
|
|
9774
|
+
const mergedContent = mergeContextContent(globalResult.result, projectResult.result);
|
|
9775
|
+
return {
|
|
9776
|
+
globalContext: globalResult.result,
|
|
9777
|
+
projectContext: projectResult.result,
|
|
9778
|
+
mergedContent,
|
|
9779
|
+
errors
|
|
9780
|
+
};
|
|
9781
|
+
}
|
|
9782
|
+
|
|
9959
9783
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
9960
9784
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
9961
9785
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -10813,7 +10637,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
10813
10637
|
// package.json
|
|
10814
10638
|
var package_default = {
|
|
10815
10639
|
name: "@bike4mind/cli",
|
|
10816
|
-
version: "0.2.8-cli-
|
|
10640
|
+
version: "0.2.8-feat-cli-context-file-loading.17148+ce4df6add",
|
|
10817
10641
|
type: "module",
|
|
10818
10642
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
10819
10643
|
license: "UNLICENSED",
|
|
@@ -10916,10 +10740,10 @@ var package_default = {
|
|
|
10916
10740
|
},
|
|
10917
10741
|
devDependencies: {
|
|
10918
10742
|
"@bike4mind/agents": "0.1.0",
|
|
10919
|
-
"@bike4mind/common": "2.38.2-cli-
|
|
10920
|
-
"@bike4mind/mcp": "1.20.2-cli-
|
|
10921
|
-
"@bike4mind/services": "2.33.2-cli-
|
|
10922
|
-
"@bike4mind/utils": "2.1.3-cli-
|
|
10743
|
+
"@bike4mind/common": "2.38.2-feat-cli-context-file-loading.17148+ce4df6add",
|
|
10744
|
+
"@bike4mind/mcp": "1.20.2-feat-cli-context-file-loading.17148+ce4df6add",
|
|
10745
|
+
"@bike4mind/services": "2.33.2-feat-cli-context-file-loading.17148+ce4df6add",
|
|
10746
|
+
"@bike4mind/utils": "2.1.3-feat-cli-context-file-loading.17148+ce4df6add",
|
|
10923
10747
|
"@types/better-sqlite3": "^7.6.12",
|
|
10924
10748
|
"@types/diff": "^5.0.9",
|
|
10925
10749
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -10932,7 +10756,7 @@ var package_default = {
|
|
|
10932
10756
|
typescript: "^5.9.3",
|
|
10933
10757
|
vitest: "^3.2.4"
|
|
10934
10758
|
},
|
|
10935
|
-
gitHead: "
|
|
10759
|
+
gitHead: "ce4df6add3c7091ebe97f2b87790ef684c56404d"
|
|
10936
10760
|
};
|
|
10937
10761
|
|
|
10938
10762
|
// src/config/constants.ts
|
|
@@ -10954,7 +10778,7 @@ var usageCache = null;
|
|
|
10954
10778
|
function CliApp() {
|
|
10955
10779
|
const { exit } = useApp();
|
|
10956
10780
|
const imageRenderer = new ImageRenderer();
|
|
10957
|
-
const [state, setState] =
|
|
10781
|
+
const [state, setState] = useState6({
|
|
10958
10782
|
session: null,
|
|
10959
10783
|
sessionStore: new SessionStore(),
|
|
10960
10784
|
configStore: new ConfigStore(),
|
|
@@ -10970,9 +10794,9 @@ function CliApp() {
|
|
|
10970
10794
|
trustLocationSelector: null,
|
|
10971
10795
|
rewindSelector: null
|
|
10972
10796
|
});
|
|
10973
|
-
const [isInitialized, setIsInitialized] =
|
|
10974
|
-
const [initError, setInitError] =
|
|
10975
|
-
const [commandHistory, setCommandHistory] =
|
|
10797
|
+
const [isInitialized, setIsInitialized] = useState6(false);
|
|
10798
|
+
const [initError, setInitError] = useState6(null);
|
|
10799
|
+
const [commandHistory, setCommandHistory] = useState6([]);
|
|
10976
10800
|
const imageStoreInitPromise = useRef(null);
|
|
10977
10801
|
const setStoreSession = useCliStore((state2) => state2.setSession);
|
|
10978
10802
|
const setPermissionPrompt = useCliStore((state2) => state2.setPermissionPrompt);
|
|
@@ -11013,7 +10837,7 @@ function CliApp() {
|
|
|
11013
10837
|
process.exit(0);
|
|
11014
10838
|
}, 100);
|
|
11015
10839
|
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
11016
|
-
|
|
10840
|
+
useInput5((input, key) => {
|
|
11017
10841
|
if (key.ctrl && input === "c") {
|
|
11018
10842
|
const now = Date.now();
|
|
11019
10843
|
if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
|
|
@@ -11183,6 +11007,24 @@ function CliApp() {
|
|
|
11183
11007
|
}
|
|
11184
11008
|
const allTools = [...b4mTools, ...mcpTools];
|
|
11185
11009
|
console.log(`\u2705 Total: ${allTools.length} tool(s) available`);
|
|
11010
|
+
const projectDir = state.configStore.getProjectConfigDir();
|
|
11011
|
+
const contextResult = await loadContextFiles(projectDir);
|
|
11012
|
+
if (contextResult.globalContext) {
|
|
11013
|
+
console.log(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
|
|
11014
|
+
}
|
|
11015
|
+
if (contextResult.projectContext) {
|
|
11016
|
+
console.log(`\u{1F4C4} Project context: ${contextResult.projectContext.filename}`);
|
|
11017
|
+
}
|
|
11018
|
+
for (const error of contextResult.errors) {
|
|
11019
|
+
console.log(`\u26A0\uFE0F Context file error: ${error}`);
|
|
11020
|
+
}
|
|
11021
|
+
const contextSection = contextResult.mergedContent ? `
|
|
11022
|
+
|
|
11023
|
+
## Project Context
|
|
11024
|
+
|
|
11025
|
+
Follow these project-specific instructions:
|
|
11026
|
+
|
|
11027
|
+
${contextResult.mergedContent}` : "";
|
|
11186
11028
|
const cliSystemPrompt = `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
11187
11029
|
|
|
11188
11030
|
CORE BEHAVIOR:
|
|
@@ -11212,7 +11054,7 @@ EXAMPLES:
|
|
|
11212
11054
|
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
11213
11055
|
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
11214
11056
|
|
|
11215
|
-
Remember: Use context from previous messages to understand follow-up questions
|
|
11057
|
+
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
11216
11058
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
11217
11059
|
const agent = new ReActAgent({
|
|
11218
11060
|
userId: config.userId,
|
|
@@ -11267,29 +11109,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11267
11109
|
console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
|
|
11268
11110
|
return;
|
|
11269
11111
|
}
|
|
11270
|
-
const currentSteps = [];
|
|
11271
|
-
const stepHandler = (step) => {
|
|
11272
|
-
currentSteps.push(step);
|
|
11273
|
-
const currentSession = useCliStore.getState().session;
|
|
11274
|
-
if (currentSession) {
|
|
11275
|
-
const messages = [...currentSession.messages];
|
|
11276
|
-
const lastMessage = messages[messages.length - 1];
|
|
11277
|
-
if (lastMessage && lastMessage.role === "assistant") {
|
|
11278
|
-
messages[messages.length - 1] = {
|
|
11279
|
-
...lastMessage,
|
|
11280
|
-
metadata: {
|
|
11281
|
-
...lastMessage.metadata,
|
|
11282
|
-
steps: [...currentSteps]
|
|
11283
|
-
}
|
|
11284
|
-
};
|
|
11285
|
-
setStoreSession({
|
|
11286
|
-
...currentSession,
|
|
11287
|
-
messages
|
|
11288
|
-
});
|
|
11289
|
-
}
|
|
11290
|
-
}
|
|
11291
|
-
};
|
|
11292
|
-
state.agent.on("action", stepHandler);
|
|
11293
11112
|
try {
|
|
11294
11113
|
let messageContent = message;
|
|
11295
11114
|
let userMessageContent = message;
|
|
@@ -11303,21 +11122,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11303
11122
|
content: userMessageContent,
|
|
11304
11123
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11305
11124
|
};
|
|
11306
|
-
const pendingAssistantMessage = {
|
|
11307
|
-
role: "assistant",
|
|
11308
|
-
content: "...",
|
|
11309
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11310
|
-
metadata: {
|
|
11311
|
-
steps: []
|
|
11312
|
-
}
|
|
11313
|
-
};
|
|
11314
|
-
const sessionWithMessages = {
|
|
11315
|
-
...state.session,
|
|
11316
|
-
messages: [...state.session.messages, userMessage, pendingAssistantMessage],
|
|
11317
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11318
|
-
};
|
|
11319
|
-
setState((prev) => ({ ...prev, session: sessionWithMessages }));
|
|
11320
|
-
setStoreSession(sessionWithMessages);
|
|
11321
11125
|
const recentMessages = state.session.messages.slice(-20);
|
|
11322
11126
|
const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
|
|
11323
11127
|
role: msg.role,
|
|
@@ -11331,28 +11135,26 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11331
11135
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
11332
11136
|
}
|
|
11333
11137
|
const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
|
|
11334
|
-
const
|
|
11335
|
-
if (!currentSession) return;
|
|
11336
|
-
const finalMessages = [...currentSession.messages];
|
|
11337
|
-
const finalAssistantMessage = {
|
|
11138
|
+
const assistantMessage = {
|
|
11338
11139
|
role: "assistant",
|
|
11339
11140
|
content: result.finalAnswer,
|
|
11340
|
-
timestamp:
|
|
11141
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11341
11142
|
metadata: {
|
|
11342
11143
|
tokenUsage: {
|
|
11343
11144
|
prompt: 0,
|
|
11145
|
+
// TODO: Extract from result
|
|
11344
11146
|
completion: 0,
|
|
11345
11147
|
total: result.completionInfo.totalTokens
|
|
11346
11148
|
},
|
|
11347
11149
|
steps: result.steps,
|
|
11348
11150
|
// Complete history: thoughts, actions, observations
|
|
11349
11151
|
permissionDenied
|
|
11152
|
+
// Mark if this ended due to permission denial
|
|
11350
11153
|
}
|
|
11351
11154
|
};
|
|
11352
|
-
finalMessages[finalMessages.length - 1] = finalAssistantMessage;
|
|
11353
11155
|
const updatedSession = {
|
|
11354
|
-
...
|
|
11355
|
-
messages:
|
|
11156
|
+
...state.session,
|
|
11157
|
+
messages: [...state.session.messages, userMessage, assistantMessage],
|
|
11356
11158
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11357
11159
|
metadata: {
|
|
11358
11160
|
...state.session.metadata,
|
|
@@ -11372,8 +11174,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11372
11174
|
}
|
|
11373
11175
|
}
|
|
11374
11176
|
console.error("Error processing message:", error);
|
|
11375
|
-
} finally {
|
|
11376
|
-
state.agent.off("action", stepHandler);
|
|
11377
11177
|
}
|
|
11378
11178
|
};
|
|
11379
11179
|
const handleImageDetected = async (imageData) => {
|
|
@@ -11925,12 +11725,12 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11925
11725
|
setState((prev) => ({ ...prev, config: updatedConfig }));
|
|
11926
11726
|
};
|
|
11927
11727
|
if (initError) {
|
|
11928
|
-
return /* @__PURE__ */
|
|
11728
|
+
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"));
|
|
11929
11729
|
}
|
|
11930
11730
|
if (state.trustLocationSelector) {
|
|
11931
11731
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
11932
11732
|
const inProject = projectDir !== null;
|
|
11933
|
-
return /* @__PURE__ */
|
|
11733
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11934
11734
|
TrustLocationSelector,
|
|
11935
11735
|
{
|
|
11936
11736
|
inProject,
|
|
@@ -11948,7 +11748,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11948
11748
|
);
|
|
11949
11749
|
}
|
|
11950
11750
|
if (state.rewindSelector && state.session) {
|
|
11951
|
-
return /* @__PURE__ */
|
|
11751
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11952
11752
|
RewindSelector,
|
|
11953
11753
|
{
|
|
11954
11754
|
messages: state.session.messages,
|
|
@@ -11967,7 +11767,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11967
11767
|
}
|
|
11968
11768
|
if (state.showLoginFlow) {
|
|
11969
11769
|
const loginApiUrl = getApiUrl(state.config?.apiConfig);
|
|
11970
|
-
return /* @__PURE__ */
|
|
11770
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11971
11771
|
LoginFlow,
|
|
11972
11772
|
{
|
|
11973
11773
|
apiUrl: loginApiUrl,
|
|
@@ -11990,9 +11790,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
11990
11790
|
);
|
|
11991
11791
|
}
|
|
11992
11792
|
if (!isInitialized) {
|
|
11993
|
-
return /* @__PURE__ */
|
|
11793
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "\u{1F680} Initializing..."));
|
|
11994
11794
|
}
|
|
11995
|
-
return /* @__PURE__ */
|
|
11795
|
+
return /* @__PURE__ */ React15.createElement(
|
|
11996
11796
|
App,
|
|
11997
11797
|
{
|
|
11998
11798
|
onMessage: handleMessage,
|
|
@@ -12031,6 +11831,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
|
|
|
12031
11831
|
if (isDevMode) {
|
|
12032
11832
|
console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
|
|
12033
11833
|
}
|
|
12034
|
-
render(/* @__PURE__ */
|
|
11834
|
+
render(/* @__PURE__ */ React15.createElement(CliApp, null), {
|
|
12035
11835
|
exitOnCtrlC: false
|
|
12036
11836
|
});
|