@bike4mind/cli 0.2.8-cli-bash-tools.17156 → 0.2.8-feat-cli-context-file-loading.17149
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 +47 -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 +167 -462
- 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/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Interactive command-line interface for Bike4Mind with ReAct agents.
|
|
|
10
10
|
- 🛠️ B4M tools + MCP integration
|
|
11
11
|
- 🎨 Rich terminal UI with Ink
|
|
12
12
|
- 🐛 Debug logging with `--verbose` flag
|
|
13
|
+
- 📄 Context file loading (CLAUDE.md, AGENTS.md, AI.md)
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -160,7 +161,6 @@ export SERPER_API_KEY="your-key-here"
|
|
|
160
161
|
- ✅ `math_evaluate` - No API key needed
|
|
161
162
|
- ✅ `current_datetime` - No API key needed
|
|
162
163
|
- ✅ `prompt_enhancement` - No API key needed
|
|
163
|
-
- ✅ `bash_execute` - No API key needed
|
|
164
164
|
- 🔑 `weather_info` - Requires `toolApiKeys.openweather`
|
|
165
165
|
- 🔑 `web_search` - Requires `toolApiKeys.serper`
|
|
166
166
|
- 🔑 `deep_research` - Requires `toolApiKeys.serper`
|
|
@@ -242,6 +242,51 @@ You can also run any MCP server via npx or custom executables:
|
|
|
242
242
|
|
|
243
243
|
**Note:** Internal MCP servers must be built and available in the `b4m-core/packages/mcp/dist/src/` directory. The CLI will automatically find them if you're running from the monorepo. For Docker-based servers, ensure Docker is installed and the image is accessible.
|
|
244
244
|
|
|
245
|
+
## Context Files
|
|
246
|
+
|
|
247
|
+
The CLI supports loading project-specific instructions from context files, similar to CLAUDE.md in Claude Code. These files provide persistent instructions that are automatically included in the agent's system prompt.
|
|
248
|
+
|
|
249
|
+
### Supported Files
|
|
250
|
+
|
|
251
|
+
**Project-level** (in your project directory, checked in priority order):
|
|
252
|
+
1. `CLAUDE.local.md` - Personal/gitignored instructions (highest priority)
|
|
253
|
+
2. `CLAUDE.md` - Project instructions
|
|
254
|
+
3. `AGENTS.md` - Cross-tool standard
|
|
255
|
+
4. `AI.local.md` - Personal/gitignored instructions
|
|
256
|
+
5. `AI.md` - Project instructions
|
|
257
|
+
6. `INSTRUCTIONS.md` - Project instructions (lowest priority)
|
|
258
|
+
|
|
259
|
+
**Global** (in `~/.bike4mind/`):
|
|
260
|
+
1. `AI.local.md` - Personal global instructions
|
|
261
|
+
2. `AI.md` - Global instructions
|
|
262
|
+
|
|
263
|
+
### How It Works
|
|
264
|
+
|
|
265
|
+
- The CLI loads the **first matching file** from each layer (global and project)
|
|
266
|
+
- Project files take precedence over global files
|
|
267
|
+
- `.local.md` variants are intended to be gitignored for personal preferences
|
|
268
|
+
- Files must be under 100KB
|
|
269
|
+
- Symlinks are rejected for security
|
|
270
|
+
|
|
271
|
+
### Example
|
|
272
|
+
|
|
273
|
+
Create a `CLAUDE.md` in your project:
|
|
274
|
+
|
|
275
|
+
```markdown
|
|
276
|
+
# Project Instructions
|
|
277
|
+
|
|
278
|
+
- Always use TypeScript strict mode
|
|
279
|
+
- Prefer functional components with hooks
|
|
280
|
+
- Run tests before committing
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
On startup, you'll see:
|
|
284
|
+
```
|
|
285
|
+
📄 Project context: CLAUDE.md
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The agent will follow these instructions for all interactions in that project.
|
|
289
|
+
|
|
245
290
|
## Session Storage
|
|
246
291
|
|
|
247
292
|
Sessions are saved to `~/.bike4mind/sessions/`
|
|
@@ -339,6 +384,7 @@ Current implementation includes:
|
|
|
339
384
|
✅ B4M tools integration
|
|
340
385
|
✅ MCP tools support
|
|
341
386
|
✅ Debug logging with --verbose flag
|
|
387
|
+
✅ Context file loading (CLAUDE.md, AGENTS.md, AI.md)
|
|
342
388
|
|
|
343
389
|
Coming soon:
|
|
344
390
|
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
getSettingsByNames,
|
|
7
7
|
obfuscateApiKey,
|
|
8
8
|
secureParameters
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-DNSBC3LO.js";
|
|
10
10
|
import {
|
|
11
11
|
ApiKeyType,
|
|
12
12
|
MementoTier,
|
|
13
13
|
isSupportedEmbeddingModel
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-H6SHASMZ.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
dayjsConfig_default,
|
|
17
17
|
extractSnippetMeta,
|
|
18
18
|
settingsMap
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-H6SHASMZ.js";
|
|
20
20
|
|
|
21
21
|
// ../../b4m-core/packages/utils/dist/src/storage/S3Storage.js
|
|
22
22
|
import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
|
|
@@ -230,9 +230,7 @@ var b4mLLMTools = z3.enum([
|
|
|
230
230
|
"create_file",
|
|
231
231
|
"glob_files",
|
|
232
232
|
"grep_search",
|
|
233
|
-
"delete_file"
|
|
234
|
-
// Shell execution
|
|
235
|
-
"bash_execute"
|
|
233
|
+
"delete_file"
|
|
236
234
|
]);
|
|
237
235
|
var B4MLLMToolsList = b4mLLMTools.options.map((tool) => tool);
|
|
238
236
|
var RechartsChartTypeSchema = z3.enum([
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BadRequestError,
|
|
4
4
|
secureParameters
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DNSBC3LO.js";
|
|
6
6
|
import {
|
|
7
7
|
GenericCreditDeductTransaction,
|
|
8
8
|
ImageEditUsageTransaction,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
RealtimeVoiceUsageTransaction,
|
|
11
11
|
TextGenerationUsageTransaction,
|
|
12
12
|
TransferCreditTransaction
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-H6SHASMZ.js";
|
|
14
14
|
|
|
15
15
|
// ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
|
|
16
16
|
import { z } from "zod";
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
getSettingsMap,
|
|
8
8
|
getSettingsValue,
|
|
9
9
|
secureParameters
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DNSBC3LO.js";
|
|
11
11
|
import {
|
|
12
12
|
KnowledgeType,
|
|
13
13
|
SupportedFabFileMimeTypes
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-H6SHASMZ.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/fabFileService/create.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFabFile,
|
|
4
4
|
createFabFileSchema
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-YXHQN7SK.js";
|
|
6
|
+
import "./chunk-DNSBC3LO.js";
|
|
7
7
|
import "./chunk-AMDXHL6S.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-H6SHASMZ.js";
|
|
9
9
|
import "./chunk-PDX44BCA.js";
|
|
10
10
|
export {
|
|
11
11
|
createFabFile,
|
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,7 +73,7 @@ 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";
|
|
@@ -85,7 +85,7 @@ import { v4 as uuidv49 } from "uuid";
|
|
|
85
85
|
|
|
86
86
|
// src/components/App.tsx
|
|
87
87
|
import React10 from "react";
|
|
88
|
-
import { Box as Box9, Text as Text9 } from "ink";
|
|
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";
|
|
@@ -742,9 +742,11 @@ function InputPrompt({
|
|
|
742
742
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
743
743
|
const [historyIndex, setHistoryIndex] = useState2(-1);
|
|
744
744
|
const [tempInput, setTempInput] = useState2("");
|
|
745
|
+
const [inputKey, setInputKey] = useState2(0);
|
|
745
746
|
useEffect(() => {
|
|
746
747
|
if (prefillInput) {
|
|
747
748
|
setValue(prefillInput);
|
|
749
|
+
setInputKey((prev) => prev + 1);
|
|
748
750
|
onPrefillConsumed?.();
|
|
749
751
|
}
|
|
750
752
|
}, [prefillInput, onPrefillConsumed]);
|
|
@@ -889,10 +891,11 @@ function InputPrompt({
|
|
|
889
891
|
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(
|
|
890
892
|
CustomTextInput,
|
|
891
893
|
{
|
|
894
|
+
key: inputKey,
|
|
892
895
|
value,
|
|
893
896
|
onChange: handleChange,
|
|
894
897
|
onSubmit: handleSubmit,
|
|
895
|
-
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",
|
|
896
899
|
showCursor: !disabled
|
|
897
900
|
}
|
|
898
901
|
)), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
|
|
@@ -923,7 +926,6 @@ var useCliStore = create((set) => ({
|
|
|
923
926
|
addAgentStep: (step) => set((state) => ({
|
|
924
927
|
agentSteps: [...state.agentSteps, step]
|
|
925
928
|
})),
|
|
926
|
-
setAgentSteps: (steps) => set({ agentSteps: steps }),
|
|
927
929
|
clearAgentSteps: () => set({ agentSteps: [] }),
|
|
928
930
|
// Permission prompt
|
|
929
931
|
permissionPrompt: null,
|
|
@@ -943,7 +945,7 @@ var AgentThinking = React7.memo(function AgentThinking2() {
|
|
|
943
945
|
if (!isThinking) {
|
|
944
946
|
return null;
|
|
945
947
|
}
|
|
946
|
-
return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1,
|
|
948
|
+
return /* @__PURE__ */ React7.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
|
|
947
949
|
});
|
|
948
950
|
|
|
949
951
|
// src/components/PermissionPrompt.tsx
|
|
@@ -1398,7 +1400,7 @@ ${errorBlock}`;
|
|
|
1398
1400
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
1399
1401
|
onResponse: onPermissionResponse
|
|
1400
1402
|
}
|
|
1401
|
-
)) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
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(
|
|
1402
1404
|
InputPrompt,
|
|
1403
1405
|
{
|
|
1404
1406
|
onSubmit: handleSubmit,
|
|
@@ -1411,8 +1413,7 @@ ${errorBlock}`;
|
|
|
1411
1413
|
))));
|
|
1412
1414
|
}
|
|
1413
1415
|
function MessageItem({ message }) {
|
|
1414
|
-
|
|
1415
|
-
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: isUser ? "cyan" : "green" }, isUser ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), isUser && message.content && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { backgroundColor: "whiteBright", color: "black" }, " ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " ", "tools used, ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
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) => {
|
|
1416
1417
|
if (step.type === "thought") {
|
|
1417
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 ? "..." : ""}`));
|
|
1418
1419
|
}
|
|
@@ -1424,7 +1425,7 @@ function MessageItem({ message }) {
|
|
|
1424
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 ? "..." : ""}`));
|
|
1425
1426
|
}
|
|
1426
1427
|
return null;
|
|
1427
|
-
}).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`)));
|
|
1428
1429
|
}
|
|
1429
1430
|
|
|
1430
1431
|
// src/components/MessageList.tsx
|
|
@@ -2627,9 +2628,10 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
2627
2628
|
content: query
|
|
2628
2629
|
}
|
|
2629
2630
|
];
|
|
2631
|
+
console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
|
|
2630
2632
|
messages.forEach((msg, i) => {
|
|
2631
2633
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
2632
|
-
|
|
2634
|
+
console.log(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
|
|
2633
2635
|
});
|
|
2634
2636
|
let finalAnswer = "";
|
|
2635
2637
|
let reachedMaxIterations = false;
|
|
@@ -8648,381 +8650,6 @@ var deleteFileTool = {
|
|
|
8648
8650
|
})
|
|
8649
8651
|
};
|
|
8650
8652
|
|
|
8651
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
8652
|
-
import { spawn } from "child_process";
|
|
8653
|
-
import path11 from "path";
|
|
8654
|
-
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
8655
|
-
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
8656
|
-
var DANGEROUS_PATTERNS = [
|
|
8657
|
-
// Destructive file operations
|
|
8658
|
-
{
|
|
8659
|
-
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
8660
|
-
reason: "Recursive delete with path",
|
|
8661
|
-
block: true
|
|
8662
|
-
},
|
|
8663
|
-
{
|
|
8664
|
-
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
8665
|
-
reason: "Force delete without preserve root",
|
|
8666
|
-
block: true
|
|
8667
|
-
},
|
|
8668
|
-
{
|
|
8669
|
-
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
8670
|
-
reason: "Recursive force delete on root paths",
|
|
8671
|
-
block: true
|
|
8672
|
-
},
|
|
8673
|
-
{
|
|
8674
|
-
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
8675
|
-
reason: "Force recursive delete on root paths",
|
|
8676
|
-
block: true
|
|
8677
|
-
},
|
|
8678
|
-
// System-level dangerous commands
|
|
8679
|
-
{ pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
|
|
8680
|
-
{ pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
|
|
8681
|
-
{ pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
|
|
8682
|
-
{ pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
|
|
8683
|
-
// Disk/partition operations
|
|
8684
|
-
{ pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
|
|
8685
|
-
{ pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
|
|
8686
|
-
{ pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
|
|
8687
|
-
// Network attacks
|
|
8688
|
-
{ pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
|
|
8689
|
-
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8690
|
-
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
8691
|
-
// Fork bombs and resource exhaustion
|
|
8692
|
-
{ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
|
|
8693
|
-
{ pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
|
|
8694
|
-
// Credential/sensitive data access
|
|
8695
|
-
{ pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
|
|
8696
|
-
{ pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
|
|
8697
|
-
{ pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
|
|
8698
|
-
// History/log manipulation
|
|
8699
|
-
{ pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
|
|
8700
|
-
{ pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
|
|
8701
|
-
// Dangerous redirects
|
|
8702
|
-
{ pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
|
|
8703
|
-
{ pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
|
|
8704
|
-
// Environment manipulation
|
|
8705
|
-
{ pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
|
|
8706
|
-
{ pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
|
|
8707
|
-
// Process/system control
|
|
8708
|
-
{ pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
|
|
8709
|
-
{ pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
|
|
8710
|
-
{ pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
|
|
8711
|
-
{ pattern: /\breboot\b/i, reason: "System reboot", block: true },
|
|
8712
|
-
{ pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
|
|
8713
|
-
];
|
|
8714
|
-
var SAFE_COMMAND_PREFIXES = [
|
|
8715
|
-
"ls",
|
|
8716
|
-
"cat",
|
|
8717
|
-
"head",
|
|
8718
|
-
"tail",
|
|
8719
|
-
"grep",
|
|
8720
|
-
"find",
|
|
8721
|
-
"echo",
|
|
8722
|
-
"pwd",
|
|
8723
|
-
"whoami",
|
|
8724
|
-
"date",
|
|
8725
|
-
"cal",
|
|
8726
|
-
"wc",
|
|
8727
|
-
"sort",
|
|
8728
|
-
"uniq",
|
|
8729
|
-
"cut",
|
|
8730
|
-
"tr",
|
|
8731
|
-
"sed",
|
|
8732
|
-
"awk",
|
|
8733
|
-
"git",
|
|
8734
|
-
"npm",
|
|
8735
|
-
"pnpm",
|
|
8736
|
-
"yarn",
|
|
8737
|
-
"node",
|
|
8738
|
-
"npx",
|
|
8739
|
-
"tsx",
|
|
8740
|
-
"ts-node",
|
|
8741
|
-
"python",
|
|
8742
|
-
"python3",
|
|
8743
|
-
"pip",
|
|
8744
|
-
"pip3",
|
|
8745
|
-
"docker",
|
|
8746
|
-
"docker-compose",
|
|
8747
|
-
"curl",
|
|
8748
|
-
"wget",
|
|
8749
|
-
// These are safe for fetching, blocked when piped to shell
|
|
8750
|
-
"mkdir",
|
|
8751
|
-
"touch",
|
|
8752
|
-
"cp",
|
|
8753
|
-
"mv",
|
|
8754
|
-
// File operations (still require permission)
|
|
8755
|
-
"which",
|
|
8756
|
-
"whereis",
|
|
8757
|
-
"type",
|
|
8758
|
-
"file",
|
|
8759
|
-
"stat",
|
|
8760
|
-
"env",
|
|
8761
|
-
"printenv",
|
|
8762
|
-
"set",
|
|
8763
|
-
"man",
|
|
8764
|
-
"help",
|
|
8765
|
-
"info",
|
|
8766
|
-
"diff",
|
|
8767
|
-
"comm",
|
|
8768
|
-
"cmp",
|
|
8769
|
-
"tar",
|
|
8770
|
-
"zip",
|
|
8771
|
-
"unzip",
|
|
8772
|
-
"gzip",
|
|
8773
|
-
"gunzip",
|
|
8774
|
-
"ssh",
|
|
8775
|
-
"scp",
|
|
8776
|
-
"rsync",
|
|
8777
|
-
// Network tools
|
|
8778
|
-
"make",
|
|
8779
|
-
"cmake",
|
|
8780
|
-
"cargo",
|
|
8781
|
-
"go",
|
|
8782
|
-
"rustc",
|
|
8783
|
-
"gcc",
|
|
8784
|
-
"g++",
|
|
8785
|
-
// Build tools
|
|
8786
|
-
"jest",
|
|
8787
|
-
"vitest",
|
|
8788
|
-
"mocha",
|
|
8789
|
-
"pytest",
|
|
8790
|
-
// Test runners
|
|
8791
|
-
"eslint",
|
|
8792
|
-
"prettier",
|
|
8793
|
-
"tsc"
|
|
8794
|
-
// Linters/formatters
|
|
8795
|
-
];
|
|
8796
|
-
function checkDangerousPatterns(command) {
|
|
8797
|
-
for (const { pattern, reason, block } of DANGEROUS_PATTERNS) {
|
|
8798
|
-
if (pattern.test(command)) {
|
|
8799
|
-
return { blocked: block, reason };
|
|
8800
|
-
}
|
|
8801
|
-
}
|
|
8802
|
-
return { blocked: false };
|
|
8803
|
-
}
|
|
8804
|
-
function getBaseCommand(command) {
|
|
8805
|
-
const trimmed = command.trim();
|
|
8806
|
-
const match = trimmed.match(/^(\S+)/);
|
|
8807
|
-
return match ? match[1] : "";
|
|
8808
|
-
}
|
|
8809
|
-
function isSafeCommandPrefix(command) {
|
|
8810
|
-
const baseCommand = getBaseCommand(command);
|
|
8811
|
-
return SAFE_COMMAND_PREFIXES.some((safe) => baseCommand === safe || baseCommand.endsWith(`/${safe}`));
|
|
8812
|
-
}
|
|
8813
|
-
async function executeBashCommand(params) {
|
|
8814
|
-
const { command, cwd: relativeCwd, timeout = DEFAULT_TIMEOUT_MS } = params;
|
|
8815
|
-
if (!command || command.trim().length === 0) {
|
|
8816
|
-
return {
|
|
8817
|
-
stdout: "",
|
|
8818
|
-
stderr: "Error: Command cannot be empty",
|
|
8819
|
-
exitCode: 1,
|
|
8820
|
-
timedOut: false,
|
|
8821
|
-
blocked: true,
|
|
8822
|
-
blockedReason: "Empty command"
|
|
8823
|
-
};
|
|
8824
|
-
}
|
|
8825
|
-
const dangerCheck = checkDangerousPatterns(command);
|
|
8826
|
-
if (dangerCheck.blocked) {
|
|
8827
|
-
return {
|
|
8828
|
-
stdout: "",
|
|
8829
|
-
stderr: `Command blocked for safety: ${dangerCheck.reason}`,
|
|
8830
|
-
exitCode: 1,
|
|
8831
|
-
timedOut: false,
|
|
8832
|
-
blocked: true,
|
|
8833
|
-
blockedReason: dangerCheck.reason
|
|
8834
|
-
};
|
|
8835
|
-
}
|
|
8836
|
-
const baseCwd = process.cwd();
|
|
8837
|
-
const targetCwd = relativeCwd ? path11.resolve(baseCwd, relativeCwd) : baseCwd;
|
|
8838
|
-
const effectiveTimeout = Math.min(timeout, 5 * 60 * 1e3);
|
|
8839
|
-
return new Promise((resolve3) => {
|
|
8840
|
-
let stdout = "";
|
|
8841
|
-
let stderr = "";
|
|
8842
|
-
let timedOut = false;
|
|
8843
|
-
const proc = spawn("bash", ["-c", command], {
|
|
8844
|
-
cwd: targetCwd,
|
|
8845
|
-
env: {
|
|
8846
|
-
...process.env,
|
|
8847
|
-
// Prevent color codes that might be hard to read
|
|
8848
|
-
NO_COLOR: "1",
|
|
8849
|
-
FORCE_COLOR: "0"
|
|
8850
|
-
},
|
|
8851
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
8852
|
-
});
|
|
8853
|
-
const timeoutId = setTimeout(() => {
|
|
8854
|
-
timedOut = true;
|
|
8855
|
-
proc.kill("SIGTERM");
|
|
8856
|
-
setTimeout(() => {
|
|
8857
|
-
if (!proc.killed) {
|
|
8858
|
-
proc.kill("SIGKILL");
|
|
8859
|
-
}
|
|
8860
|
-
}, 5e3);
|
|
8861
|
-
}, effectiveTimeout);
|
|
8862
|
-
proc.stdout.on("data", (data) => {
|
|
8863
|
-
if (stdout.length < MAX_OUTPUT_SIZE) {
|
|
8864
|
-
stdout += data.toString();
|
|
8865
|
-
if (stdout.length > MAX_OUTPUT_SIZE) {
|
|
8866
|
-
stdout = stdout.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8867
|
-
}
|
|
8868
|
-
}
|
|
8869
|
-
});
|
|
8870
|
-
proc.stderr.on("data", (data) => {
|
|
8871
|
-
if (stderr.length < MAX_OUTPUT_SIZE) {
|
|
8872
|
-
stderr += data.toString();
|
|
8873
|
-
if (stderr.length > MAX_OUTPUT_SIZE) {
|
|
8874
|
-
stderr = stderr.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
8875
|
-
}
|
|
8876
|
-
}
|
|
8877
|
-
});
|
|
8878
|
-
proc.on("close", (exitCode) => {
|
|
8879
|
-
clearTimeout(timeoutId);
|
|
8880
|
-
resolve3({
|
|
8881
|
-
stdout: stdout.trim(),
|
|
8882
|
-
stderr: stderr.trim(),
|
|
8883
|
-
exitCode,
|
|
8884
|
-
timedOut,
|
|
8885
|
-
blocked: false
|
|
8886
|
-
});
|
|
8887
|
-
});
|
|
8888
|
-
proc.on("error", (error) => {
|
|
8889
|
-
clearTimeout(timeoutId);
|
|
8890
|
-
resolve3({
|
|
8891
|
-
stdout: "",
|
|
8892
|
-
stderr: `Failed to execute command: ${error.message}`,
|
|
8893
|
-
exitCode: 1,
|
|
8894
|
-
timedOut: false,
|
|
8895
|
-
blocked: false
|
|
8896
|
-
});
|
|
8897
|
-
});
|
|
8898
|
-
});
|
|
8899
|
-
}
|
|
8900
|
-
function formatResult(result, command) {
|
|
8901
|
-
const parts = [];
|
|
8902
|
-
parts.push(`$ ${command}`);
|
|
8903
|
-
parts.push("");
|
|
8904
|
-
if (result.blocked) {
|
|
8905
|
-
parts.push(`BLOCKED: ${result.blockedReason}`);
|
|
8906
|
-
parts.push("");
|
|
8907
|
-
parts.push("This command was blocked for safety reasons.");
|
|
8908
|
-
parts.push("If you believe this is a false positive, please run the command manually.");
|
|
8909
|
-
return parts.join("\n");
|
|
8910
|
-
}
|
|
8911
|
-
if (result.timedOut) {
|
|
8912
|
-
parts.push("WARNING: Command timed out and was terminated.");
|
|
8913
|
-
parts.push("");
|
|
8914
|
-
}
|
|
8915
|
-
if (result.stdout) {
|
|
8916
|
-
parts.push(result.stdout);
|
|
8917
|
-
}
|
|
8918
|
-
if (result.stderr) {
|
|
8919
|
-
if (result.stdout) {
|
|
8920
|
-
parts.push("");
|
|
8921
|
-
}
|
|
8922
|
-
parts.push("STDERR:");
|
|
8923
|
-
parts.push(result.stderr);
|
|
8924
|
-
}
|
|
8925
|
-
if (result.exitCode !== 0 && result.exitCode !== null) {
|
|
8926
|
-
parts.push("");
|
|
8927
|
-
parts.push(`Exit code: ${result.exitCode}`);
|
|
8928
|
-
}
|
|
8929
|
-
if (!result.stdout && !result.stderr && !result.timedOut) {
|
|
8930
|
-
parts.push("(command completed with no output)");
|
|
8931
|
-
}
|
|
8932
|
-
return parts.join("\n");
|
|
8933
|
-
}
|
|
8934
|
-
var bashExecuteTool = {
|
|
8935
|
-
name: "bash_execute",
|
|
8936
|
-
implementation: (context) => ({
|
|
8937
|
-
toolFn: async (value) => {
|
|
8938
|
-
const params = value;
|
|
8939
|
-
const isSafe = isSafeCommandPrefix(params.command);
|
|
8940
|
-
context.logger.info("Bash: Executing command", {
|
|
8941
|
-
command: params.command,
|
|
8942
|
-
cwd: params.cwd || ".",
|
|
8943
|
-
timeout: params.timeout || DEFAULT_TIMEOUT_MS,
|
|
8944
|
-
isSafeCommand: isSafe
|
|
8945
|
-
});
|
|
8946
|
-
if (context.onStart) {
|
|
8947
|
-
await context.onStart("bash_execute", {
|
|
8948
|
-
command: params.command,
|
|
8949
|
-
cwd: params.cwd
|
|
8950
|
-
});
|
|
8951
|
-
}
|
|
8952
|
-
try {
|
|
8953
|
-
const result = await executeBashCommand(params);
|
|
8954
|
-
const formattedResult = formatResult(result, params.command);
|
|
8955
|
-
context.logger.info("Bash: Command completed", {
|
|
8956
|
-
exitCode: result.exitCode,
|
|
8957
|
-
timedOut: result.timedOut,
|
|
8958
|
-
blocked: result.blocked
|
|
8959
|
-
});
|
|
8960
|
-
if (context.onFinish) {
|
|
8961
|
-
await context.onFinish("bash_execute", {
|
|
8962
|
-
command: params.command,
|
|
8963
|
-
exitCode: result.exitCode,
|
|
8964
|
-
blocked: result.blocked
|
|
8965
|
-
});
|
|
8966
|
-
}
|
|
8967
|
-
return formattedResult;
|
|
8968
|
-
} catch (error) {
|
|
8969
|
-
context.logger.error("Bash: Command failed", error);
|
|
8970
|
-
if (context.onFinish) {
|
|
8971
|
-
await context.onFinish("bash_execute", {
|
|
8972
|
-
command: params.command,
|
|
8973
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
8974
|
-
});
|
|
8975
|
-
}
|
|
8976
|
-
throw error;
|
|
8977
|
-
}
|
|
8978
|
-
},
|
|
8979
|
-
toolSchema: {
|
|
8980
|
-
name: "bash_execute",
|
|
8981
|
-
description: `Execute a bash command in the terminal. Use this for running shell commands, scripts, build tools, git operations, and other CLI tasks.
|
|
8982
|
-
|
|
8983
|
-
SAFETY NOTES:
|
|
8984
|
-
- Commands are executed in the current working directory (or specified cwd)
|
|
8985
|
-
- Dangerous commands (sudo, rm -rf /, etc.) are automatically blocked
|
|
8986
|
-
- Commands have a default timeout of 60 seconds (max 5 minutes)
|
|
8987
|
-
- Output is limited to prevent overwhelming responses
|
|
8988
|
-
- This tool ALWAYS requires user permission before execution
|
|
8989
|
-
|
|
8990
|
-
COMMON USE CASES:
|
|
8991
|
-
- Running build commands: npm run build, make, cargo build
|
|
8992
|
-
- Git operations: git status, git log, git diff
|
|
8993
|
-
- Viewing system info: ls, pwd, cat, head, tail
|
|
8994
|
-
- Running tests: npm test, pytest, cargo test
|
|
8995
|
-
- Package management: npm install, pip install
|
|
8996
|
-
- File operations: mkdir, cp, mv (with permission)
|
|
8997
|
-
|
|
8998
|
-
BLOCKED OPERATIONS:
|
|
8999
|
-
- sudo and privilege escalation
|
|
9000
|
-
- Recursive deletes on system paths
|
|
9001
|
-
- Direct disk operations
|
|
9002
|
-
- Fork bombs and resource exhaustion
|
|
9003
|
-
- Piping remote scripts to shell`,
|
|
9004
|
-
parameters: {
|
|
9005
|
-
type: "object",
|
|
9006
|
-
properties: {
|
|
9007
|
-
command: {
|
|
9008
|
-
type: "string",
|
|
9009
|
-
description: "The bash command to execute. Can include pipes, redirects, and chained commands."
|
|
9010
|
-
},
|
|
9011
|
-
cwd: {
|
|
9012
|
-
type: "string",
|
|
9013
|
-
description: "Working directory for the command (optional). Can be relative or absolute path. Defaults to current directory."
|
|
9014
|
-
},
|
|
9015
|
-
timeout: {
|
|
9016
|
-
type: "number",
|
|
9017
|
-
description: "Timeout in milliseconds (optional, default: 60000, max: 300000). Command will be terminated if it exceeds this time."
|
|
9018
|
-
}
|
|
9019
|
-
},
|
|
9020
|
-
required: ["command"]
|
|
9021
|
-
}
|
|
9022
|
-
}
|
|
9023
|
-
})
|
|
9024
|
-
};
|
|
9025
|
-
|
|
9026
8653
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
9027
8654
|
var tools = {
|
|
9028
8655
|
dice_roll: diceRollTool,
|
|
@@ -9050,9 +8677,7 @@ var tools = {
|
|
|
9050
8677
|
create_file: createFileTool,
|
|
9051
8678
|
glob_files: globFilesTool,
|
|
9052
8679
|
grep_search: grepSearchTool,
|
|
9053
|
-
delete_file: deleteFileTool
|
|
9054
|
-
// Shell execution
|
|
9055
|
-
bash_execute: bashExecuteTool
|
|
8680
|
+
delete_file: deleteFileTool
|
|
9056
8681
|
};
|
|
9057
8682
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
9058
8683
|
const context = {
|
|
@@ -9327,7 +8952,7 @@ async function generateFileDeletePreview(args) {
|
|
|
9327
8952
|
if (!existsSync7(args.path)) {
|
|
9328
8953
|
return `[File does not exist: ${args.path}]`;
|
|
9329
8954
|
}
|
|
9330
|
-
const stats = await import("fs/promises").then((
|
|
8955
|
+
const stats = await import("fs/promises").then((fs12) => fs12.stat(args.path));
|
|
9331
8956
|
return `[File will be deleted]
|
|
9332
8957
|
|
|
9333
8958
|
Path: ${args.path}
|
|
@@ -9340,7 +8965,7 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
9340
8965
|
|
|
9341
8966
|
// src/utils/Logger.ts
|
|
9342
8967
|
import fs10 from "fs/promises";
|
|
9343
|
-
import
|
|
8968
|
+
import path11 from "path";
|
|
9344
8969
|
import os from "os";
|
|
9345
8970
|
var Logger2 = class _Logger {
|
|
9346
8971
|
constructor() {
|
|
@@ -9363,9 +8988,9 @@ var Logger2 = class _Logger {
|
|
|
9363
8988
|
*/
|
|
9364
8989
|
async initialize(sessionId) {
|
|
9365
8990
|
this.sessionId = sessionId;
|
|
9366
|
-
const debugDir =
|
|
8991
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9367
8992
|
await fs10.mkdir(debugDir, { recursive: true });
|
|
9368
|
-
this.logFilePath =
|
|
8993
|
+
this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
|
|
9369
8994
|
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9370
8995
|
}
|
|
9371
8996
|
/**
|
|
@@ -9575,12 +9200,12 @@ var Logger2 = class _Logger {
|
|
|
9575
9200
|
async cleanupOldLogs() {
|
|
9576
9201
|
if (!this.fileLoggingEnabled) return;
|
|
9577
9202
|
try {
|
|
9578
|
-
const debugDir =
|
|
9203
|
+
const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
|
|
9579
9204
|
const files = await fs10.readdir(debugDir);
|
|
9580
9205
|
const now = Date.now();
|
|
9581
9206
|
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
9582
9207
|
for (const file of files) {
|
|
9583
|
-
const filePath =
|
|
9208
|
+
const filePath = path11.join(debugDir, file);
|
|
9584
9209
|
const stats = await fs10.stat(filePath);
|
|
9585
9210
|
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
9586
9211
|
await fs10.unlink(filePath);
|
|
@@ -9645,8 +9270,7 @@ var LOCAL_TOOLS = [
|
|
|
9645
9270
|
"edit_file",
|
|
9646
9271
|
"dice_roll",
|
|
9647
9272
|
"math_evaluate",
|
|
9648
|
-
"current_datetime"
|
|
9649
|
-
"bash_execute"
|
|
9273
|
+
"current_datetime"
|
|
9650
9274
|
];
|
|
9651
9275
|
function isServerTool(toolName) {
|
|
9652
9276
|
return SERVER_TOOLS.includes(toolName);
|
|
@@ -9748,10 +9372,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
9748
9372
|
} catch (error) {
|
|
9749
9373
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9750
9374
|
}
|
|
9751
|
-
} else if (toolName === "bash_execute" && args?.command) {
|
|
9752
|
-
const cwd = args.cwd ? ` (in ${args.cwd})` : "";
|
|
9753
|
-
const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
|
|
9754
|
-
preview = `$ ${args.command}${cwd}${timeout}`;
|
|
9755
9375
|
}
|
|
9756
9376
|
const response = await showPermissionPrompt(toolName, args, preview);
|
|
9757
9377
|
if (response.action === "deny") {
|
|
@@ -9822,8 +9442,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
9822
9442
|
glob_files: {},
|
|
9823
9443
|
grep_search: {},
|
|
9824
9444
|
delete_file: {},
|
|
9825
|
-
// Shell execution (always requires permission)
|
|
9826
|
-
bash_execute: {},
|
|
9827
9445
|
// Server-side tools (executed via /api/ai/v1/tools Lambda)
|
|
9828
9446
|
// Routed by ToolRouter to use B4M company API keys
|
|
9829
9447
|
weather_info: {},
|
|
@@ -9889,7 +9507,6 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
9889
9507
|
create_file: "prompt_always",
|
|
9890
9508
|
delete_file: "prompt_always",
|
|
9891
9509
|
shell_execute: "prompt_always",
|
|
9892
|
-
bash_execute: "prompt_always",
|
|
9893
9510
|
git_commit: "prompt_always",
|
|
9894
9511
|
git_push: "prompt_always",
|
|
9895
9512
|
// ===== PROMPT DEFAULT (Repository read tools) =====
|
|
@@ -10051,6 +9668,118 @@ function getEnvironmentName(configApiConfig) {
|
|
|
10051
9668
|
return "Bike4Mind";
|
|
10052
9669
|
}
|
|
10053
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
|
+
|
|
10054
9783
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
10055
9784
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10056
9785
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -10908,7 +10637,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
10908
10637
|
// package.json
|
|
10909
10638
|
var package_default = {
|
|
10910
10639
|
name: "@bike4mind/cli",
|
|
10911
|
-
version: "0.2.8-cli-
|
|
10640
|
+
version: "0.2.8-feat-cli-context-file-loading.17149+1a918591e",
|
|
10912
10641
|
type: "module",
|
|
10913
10642
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
10914
10643
|
license: "UNLICENSED",
|
|
@@ -11011,10 +10740,10 @@ var package_default = {
|
|
|
11011
10740
|
},
|
|
11012
10741
|
devDependencies: {
|
|
11013
10742
|
"@bike4mind/agents": "0.1.0",
|
|
11014
|
-
"@bike4mind/common": "2.38.2-cli-
|
|
11015
|
-
"@bike4mind/mcp": "1.20.2-cli-
|
|
11016
|
-
"@bike4mind/services": "2.33.2-cli-
|
|
11017
|
-
"@bike4mind/utils": "2.1.3-cli-
|
|
10743
|
+
"@bike4mind/common": "2.38.2-feat-cli-context-file-loading.17149+1a918591e",
|
|
10744
|
+
"@bike4mind/mcp": "1.20.2-feat-cli-context-file-loading.17149+1a918591e",
|
|
10745
|
+
"@bike4mind/services": "2.33.2-feat-cli-context-file-loading.17149+1a918591e",
|
|
10746
|
+
"@bike4mind/utils": "2.1.3-feat-cli-context-file-loading.17149+1a918591e",
|
|
11018
10747
|
"@types/better-sqlite3": "^7.6.12",
|
|
11019
10748
|
"@types/diff": "^5.0.9",
|
|
11020
10749
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -11027,7 +10756,7 @@ var package_default = {
|
|
|
11027
10756
|
typescript: "^5.9.3",
|
|
11028
10757
|
vitest: "^3.2.4"
|
|
11029
10758
|
},
|
|
11030
|
-
gitHead: "
|
|
10759
|
+
gitHead: "1a918591e2031dfd0197eab12dccf8e5a2db737e"
|
|
11031
10760
|
};
|
|
11032
10761
|
|
|
11033
10762
|
// src/config/constants.ts
|
|
@@ -11278,6 +11007,24 @@ function CliApp() {
|
|
|
11278
11007
|
}
|
|
11279
11008
|
const allTools = [...b4mTools, ...mcpTools];
|
|
11280
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}` : "";
|
|
11281
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.
|
|
11282
11029
|
|
|
11283
11030
|
CORE BEHAVIOR:
|
|
@@ -11307,7 +11054,7 @@ EXAMPLES:
|
|
|
11307
11054
|
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
11308
11055
|
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
11309
11056
|
|
|
11310
|
-
Remember: Use context from previous messages to understand follow-up questions
|
|
11057
|
+
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
11311
11058
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
11312
11059
|
const agent = new ReActAgent({
|
|
11313
11060
|
userId: config.userId,
|
|
@@ -11362,29 +11109,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11362
11109
|
console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
|
|
11363
11110
|
return;
|
|
11364
11111
|
}
|
|
11365
|
-
const currentSteps = [];
|
|
11366
|
-
const stepHandler = (step) => {
|
|
11367
|
-
currentSteps.push(step);
|
|
11368
|
-
const currentSession = useCliStore.getState().session;
|
|
11369
|
-
if (currentSession) {
|
|
11370
|
-
const messages = [...currentSession.messages];
|
|
11371
|
-
const lastMessage = messages[messages.length - 1];
|
|
11372
|
-
if (lastMessage && lastMessage.role === "assistant") {
|
|
11373
|
-
messages[messages.length - 1] = {
|
|
11374
|
-
...lastMessage,
|
|
11375
|
-
metadata: {
|
|
11376
|
-
...lastMessage.metadata,
|
|
11377
|
-
steps: [...currentSteps]
|
|
11378
|
-
}
|
|
11379
|
-
};
|
|
11380
|
-
setStoreSession({
|
|
11381
|
-
...currentSession,
|
|
11382
|
-
messages
|
|
11383
|
-
});
|
|
11384
|
-
}
|
|
11385
|
-
}
|
|
11386
|
-
};
|
|
11387
|
-
state.agent.on("action", stepHandler);
|
|
11388
11112
|
try {
|
|
11389
11113
|
let messageContent = message;
|
|
11390
11114
|
let userMessageContent = message;
|
|
@@ -11398,21 +11122,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11398
11122
|
content: userMessageContent,
|
|
11399
11123
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11400
11124
|
};
|
|
11401
|
-
const pendingAssistantMessage = {
|
|
11402
|
-
role: "assistant",
|
|
11403
|
-
content: "...",
|
|
11404
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11405
|
-
metadata: {
|
|
11406
|
-
steps: []
|
|
11407
|
-
}
|
|
11408
|
-
};
|
|
11409
|
-
const sessionWithMessages = {
|
|
11410
|
-
...state.session,
|
|
11411
|
-
messages: [...state.session.messages, userMessage, pendingAssistantMessage],
|
|
11412
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11413
|
-
};
|
|
11414
|
-
setState((prev) => ({ ...prev, session: sessionWithMessages }));
|
|
11415
|
-
setStoreSession(sessionWithMessages);
|
|
11416
11125
|
const recentMessages = state.session.messages.slice(-20);
|
|
11417
11126
|
const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
|
|
11418
11127
|
role: msg.role,
|
|
@@ -11426,28 +11135,26 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11426
11135
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
11427
11136
|
}
|
|
11428
11137
|
const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
|
|
11429
|
-
const
|
|
11430
|
-
if (!currentSession) return;
|
|
11431
|
-
const finalMessages = [...currentSession.messages];
|
|
11432
|
-
const finalAssistantMessage = {
|
|
11138
|
+
const assistantMessage = {
|
|
11433
11139
|
role: "assistant",
|
|
11434
11140
|
content: result.finalAnswer,
|
|
11435
|
-
timestamp:
|
|
11141
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11436
11142
|
metadata: {
|
|
11437
11143
|
tokenUsage: {
|
|
11438
11144
|
prompt: 0,
|
|
11145
|
+
// TODO: Extract from result
|
|
11439
11146
|
completion: 0,
|
|
11440
11147
|
total: result.completionInfo.totalTokens
|
|
11441
11148
|
},
|
|
11442
11149
|
steps: result.steps,
|
|
11443
11150
|
// Complete history: thoughts, actions, observations
|
|
11444
11151
|
permissionDenied
|
|
11152
|
+
// Mark if this ended due to permission denial
|
|
11445
11153
|
}
|
|
11446
11154
|
};
|
|
11447
|
-
finalMessages[finalMessages.length - 1] = finalAssistantMessage;
|
|
11448
11155
|
const updatedSession = {
|
|
11449
|
-
...
|
|
11450
|
-
messages:
|
|
11156
|
+
...state.session,
|
|
11157
|
+
messages: [...state.session.messages, userMessage, assistantMessage],
|
|
11451
11158
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11452
11159
|
metadata: {
|
|
11453
11160
|
...state.session.metadata,
|
|
@@ -11467,8 +11174,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
|
|
|
11467
11174
|
}
|
|
11468
11175
|
}
|
|
11469
11176
|
console.error("Error processing message:", error);
|
|
11470
|
-
} finally {
|
|
11471
|
-
state.agent.off("action", stepHandler);
|
|
11472
11177
|
}
|
|
11473
11178
|
};
|
|
11474
11179
|
const handleImageDetected = async (imageData) => {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
findMostSimilarMemento,
|
|
4
4
|
getRelevantMementos
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-3CCBDIFR.js";
|
|
6
|
+
import "./chunk-DNSBC3LO.js";
|
|
7
7
|
import "./chunk-AMDXHL6S.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-H6SHASMZ.js";
|
|
9
9
|
import "./chunk-PDX44BCA.js";
|
|
10
10
|
export {
|
|
11
11
|
findMostSimilarMemento,
|
|
@@ -120,7 +120,7 @@ import {
|
|
|
120
120
|
validateMermaidSyntax,
|
|
121
121
|
warmUpSettingsCache,
|
|
122
122
|
withRetry
|
|
123
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-DNSBC3LO.js";
|
|
124
124
|
import {
|
|
125
125
|
Logger,
|
|
126
126
|
NotificationDeduplicator,
|
|
@@ -129,7 +129,7 @@ import {
|
|
|
129
129
|
postLowCreditsNotificationToSlack,
|
|
130
130
|
postMessageToSlack
|
|
131
131
|
} from "./chunk-AMDXHL6S.js";
|
|
132
|
-
import "./chunk-
|
|
132
|
+
import "./chunk-H6SHASMZ.js";
|
|
133
133
|
import "./chunk-PDX44BCA.js";
|
|
134
134
|
export {
|
|
135
135
|
AWSBackend,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SubtractCreditsSchema,
|
|
4
4
|
subtractCredits
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-LIRY24M5.js";
|
|
6
|
+
import "./chunk-DNSBC3LO.js";
|
|
7
7
|
import "./chunk-AMDXHL6S.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-H6SHASMZ.js";
|
|
9
9
|
import "./chunk-PDX44BCA.js";
|
|
10
10
|
export {
|
|
11
11
|
SubtractCreditsSchema,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.8-cli-
|
|
3
|
+
"version": "0.2.8-feat-cli-context-file-loading.17149+1a918591e",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -103,10 +103,10 @@
|
|
|
103
103
|
},
|
|
104
104
|
"devDependencies": {
|
|
105
105
|
"@bike4mind/agents": "0.1.0",
|
|
106
|
-
"@bike4mind/common": "2.38.2-cli-
|
|
107
|
-
"@bike4mind/mcp": "1.20.2-cli-
|
|
108
|
-
"@bike4mind/services": "2.33.2-cli-
|
|
109
|
-
"@bike4mind/utils": "2.1.3-cli-
|
|
106
|
+
"@bike4mind/common": "2.38.2-feat-cli-context-file-loading.17149+1a918591e",
|
|
107
|
+
"@bike4mind/mcp": "1.20.2-feat-cli-context-file-loading.17149+1a918591e",
|
|
108
|
+
"@bike4mind/services": "2.33.2-feat-cli-context-file-loading.17149+1a918591e",
|
|
109
|
+
"@bike4mind/utils": "2.1.3-feat-cli-context-file-loading.17149+1a918591e",
|
|
110
110
|
"@types/better-sqlite3": "^7.6.12",
|
|
111
111
|
"@types/diff": "^5.0.9",
|
|
112
112
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -119,5 +119,5 @@
|
|
|
119
119
|
"typescript": "^5.9.3",
|
|
120
120
|
"vitest": "^3.2.4"
|
|
121
121
|
},
|
|
122
|
-
"gitHead": "
|
|
122
|
+
"gitHead": "1a918591e2031dfd0197eab12dccf8e5a2db737e"
|
|
123
123
|
}
|