@bike4mind/cli 0.2.64-worktree-refactor-extract-search-query-builders.21815 → 0.2.64
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/bin/bike4mind-cli.mjs +6 -6
- package/dist/BubblewrapRuntime-BHbtqvLx.mjs +72 -0
- package/dist/ConfigStore-CllM6jOf.mjs +8614 -0
- package/dist/ImageStore-DaKT_Ew8.mjs +202 -0
- package/dist/ProxyManager-Dl2nFk-A.mjs +259 -0
- package/dist/ProxyManager-kiOD1X8-.mjs +3 -0
- package/dist/SandboxOrchestrator-BEW3rqYi.mjs +159 -0
- package/dist/SandboxOrchestrator-CHZgSR3P.mjs +3 -0
- package/dist/SandboxRuntimeAdapter-C1B4t20N.mjs +57 -0
- package/dist/SandboxRuntimeAdapter-D7UAG13n.mjs +3 -0
- package/dist/SeatbeltRuntime-D4m0VOcD.mjs +116 -0
- package/dist/StderrViolationParser-D0afQ3-1.mjs +70 -0
- package/dist/ViolationLogStore-CZl35HcA.mjs +96 -0
- package/dist/bashExecute-BTkdqlSs-5foM20Lb.mjs +466 -0
- package/dist/commands/doctorCommand.mjs +101 -0
- package/dist/commands/headlessCommand.mjs +319 -0
- package/dist/commands/mcpCommand.mjs +218 -0
- package/dist/commands/updateCommand.mjs +40 -0
- package/dist/createFile-yQfh8uvk-I-yM5DxC.mjs +63 -0
- package/dist/deleteFile-DKHfnyny-G3b1Kj2T.mjs +66 -0
- package/dist/globFiles-D1en6joM-8jekiXdX.mjs +100 -0
- package/dist/grepSearch-aMamoBn_-DCJcY8JS.mjs +173 -0
- package/dist/index.mjs +6722 -0
- package/dist/pathValidation-Cgjh5WQO-DiCZTcq6.mjs +63 -0
- package/dist/store-Dw1nZX2Y.mjs +128 -0
- package/dist/store-nZExNOWX.mjs +3 -0
- package/dist/terminalSetup-rmr1P8KF.mjs +254 -0
- package/dist/tools-C6M5aW8W.mjs +20907 -0
- package/dist/treeSitterEngine-DCSXcm_3.mjs +309 -0
- package/dist/types-DBEjF9YS.mjs +59 -0
- package/dist/types-DK3P88Px.mjs +3 -0
- package/dist/updateChecker-Cu9dkHxV.mjs +120 -0
- package/package.json +10 -10
- package/dist/BubblewrapRuntime-PMIOLWKR.js +0 -71
- package/dist/HydrationEngine-YL2HWJ3V.js +0 -9
- package/dist/ImageStore-MMUOUPI2.js +0 -224
- package/dist/ProxyManager-HEB4TLVX.js +0 -7
- package/dist/SandboxOrchestrator-UIJ5GYBB.js +0 -8
- package/dist/SandboxRuntimeAdapter-FQ56MAB2.js +0 -13
- package/dist/SeatbeltRuntime-EE3TTLEP.js +0 -98
- package/dist/StderrViolationParser-7OYPM2DJ.js +0 -59
- package/dist/ViolationLogStore-RIIUVURH.js +0 -104
- package/dist/artifactExtractor-R7DIP2XO.js +0 -180
- package/dist/bashExecute-GLGLD3JD.js +0 -379
- package/dist/chunk-4BIBE3J7.js +0 -48
- package/dist/chunk-5LZS5CVJ.js +0 -161
- package/dist/chunk-BDQBOLYG.js +0 -120
- package/dist/chunk-BPFEGDC7.js +0 -192
- package/dist/chunk-EPIYC3LA.js +0 -13770
- package/dist/chunk-G4ZGEQFT.js +0 -250
- package/dist/chunk-GQGOWACU.js +0 -770
- package/dist/chunk-J6ZBI6TI.js +0 -1079
- package/dist/chunk-JW3JRHH7.js +0 -12433
- package/dist/chunk-KQAMBXAW.js +0 -163
- package/dist/chunk-KUVV2NAB.js +0 -19125
- package/dist/chunk-LTLJRF6I.js +0 -44
- package/dist/chunk-PFBYGCOW.js +0 -449
- package/dist/chunk-QWB6ZYY4.js +0 -48
- package/dist/chunk-SGPRXN4C.js +0 -245
- package/dist/chunk-UZUHPHZC.js +0 -95
- package/dist/chunk-WBE7SQUB.js +0 -241
- package/dist/chunk-Y4WOJJM3.js +0 -147
- package/dist/commands/doctorCommand.js +0 -87
- package/dist/commands/headlessCommand.js +0 -380
- package/dist/commands/mcpCommand.js +0 -203
- package/dist/commands/updateCommand.js +0 -42
- package/dist/create-C4VEEEYR.js +0 -12
- package/dist/createFile-6PSPLW6R.js +0 -71
- package/dist/deleteFile-AUSRLWIK.js +0 -73
- package/dist/formatConverter-5QEJDW24.js +0 -7
- package/dist/globFiles-TSRN64N2.js +0 -120
- package/dist/grepSearch-634XWZOJ.js +0 -216
- package/dist/index.js +0 -6779
- package/dist/llmMarkdownGenerator-Z6NB26TT.js +0 -371
- package/dist/markdownGenerator-SK2ZQQL4.js +0 -269
- package/dist/mementoService-N4IM6QAC.js +0 -12
- package/dist/notificationDeduplicator-HUC53NEW.js +0 -9
- package/dist/src-F4KZCAA2.js +0 -319
- package/dist/src-ISX322I7.js +0 -1101
- package/dist/store-CAB6BV3P.js +0 -11
- package/dist/subtractCredits-D4KEM6VU.js +0 -12
- package/dist/terminalSetup-C5FHMLC3.js +0 -214
- package/dist/treeSitterEngine-4SGFQDY3.js +0 -330
- package/dist/types-KB5NP6T4.js +0 -7
- package/dist/utils-JCHWDM4Z.js +0 -31
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { I as isReadOnlyTool, L as ReActAgent, M as setWebSocketToolExecutor, P as buildCoreSystemPrompt, R as CustomCommandStore, S as getApiUrl, T as generateCliTools, V as SessionStore, _ as McpManager, a as createBackgroundAgentTools, c as AgentStore, f as ApiClient, g as ServerLlmBackend, h as WebSocketLlmBackend, i as createWriteTodosTool, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, w as PermissionManager, x as loadContextFiles, z as CheckpointStore } from "../tools-C6M5aW8W.mjs";
|
|
3
|
+
import { n as logger, t as ConfigStore } from "../ConfigStore-CllM6jOf.mjs";
|
|
4
|
+
import { t as DEFAULT_SANDBOX_CONFIG } from "../types-DBEjF9YS.mjs";
|
|
5
|
+
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-C1B4t20N.mjs";
|
|
6
|
+
import { t as SandboxOrchestrator } from "../SandboxOrchestrator-BEW3rqYi.mjs";
|
|
7
|
+
import { t as ProxyManager } from "../ProxyManager-Dl2nFk-A.mjs";
|
|
8
|
+
import { randomBytes } from "crypto";
|
|
9
|
+
import { v4 } from "uuid";
|
|
10
|
+
//#region src/commands/headlessCommand.ts
|
|
11
|
+
/**
|
|
12
|
+
* Headless/programmatic mode command (b4m -p "query")
|
|
13
|
+
*
|
|
14
|
+
* Enables non-interactive execution for CI/CD pipelines, scripting, and automation.
|
|
15
|
+
* Runs the agent once with the given prompt and exits with an appropriate exit code.
|
|
16
|
+
*/
|
|
17
|
+
/** Read all data from stdin if it's being piped (non-TTY). Returns empty string if no piped data. */
|
|
18
|
+
async function readStdin() {
|
|
19
|
+
if (process.stdin.isTTY) return "";
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const chunks = [];
|
|
22
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
23
|
+
process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8").trim()));
|
|
24
|
+
process.stdin.on("error", reject);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const silentLogger = {
|
|
28
|
+
log: () => {},
|
|
29
|
+
info: () => {},
|
|
30
|
+
warn: () => {},
|
|
31
|
+
error: () => {},
|
|
32
|
+
debug: () => {}
|
|
33
|
+
};
|
|
34
|
+
async function handleHeadlessCommand(options) {
|
|
35
|
+
const { prompt, outputFormat, dangerouslySkipPermissions, addDirs } = options;
|
|
36
|
+
logger.setVerbose(options.verbose);
|
|
37
|
+
const stdinContent = await readStdin();
|
|
38
|
+
const fullPrompt = stdinContent ? `${prompt}\n\n<stdin>\n${stdinContent}\n</stdin>` : prompt;
|
|
39
|
+
const configStore = new ConfigStore();
|
|
40
|
+
const sessionStore = new SessionStore();
|
|
41
|
+
const customCommandStore = new CustomCommandStore();
|
|
42
|
+
try {
|
|
43
|
+
const config = await configStore.load();
|
|
44
|
+
const configDirs = await configStore.getAdditionalDirectories();
|
|
45
|
+
const flagDirs = process.env.B4M_ADDITIONAL_DIRS ? JSON.parse(process.env.B4M_ADDITIONAL_DIRS) : [];
|
|
46
|
+
const additionalDirectories = [...new Set([
|
|
47
|
+
...configDirs,
|
|
48
|
+
...flagDirs,
|
|
49
|
+
...addDirs
|
|
50
|
+
])];
|
|
51
|
+
try {
|
|
52
|
+
await customCommandStore.loadCommands();
|
|
53
|
+
} catch {}
|
|
54
|
+
const authTokens = await configStore.getAuthTokens();
|
|
55
|
+
if (!authTokens) {
|
|
56
|
+
process.stderr.write("Error: Not authenticated. Run `b4m /login` to authenticate.\n");
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
if (new Date(authTokens.expiresAt) <= /* @__PURE__ */ new Date()) {
|
|
60
|
+
await configStore.clearAuthTokens();
|
|
61
|
+
process.stderr.write("Error: Authentication token expired. Run `b4m /login` to re-authenticate.\n");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
const apiClient = new ApiClient(getApiUrl(config.apiConfig), configStore);
|
|
65
|
+
const tokenGetter = async () => {
|
|
66
|
+
return (await configStore.getAuthTokens())?.accessToken ?? null;
|
|
67
|
+
};
|
|
68
|
+
let wsManager = null;
|
|
69
|
+
let llm;
|
|
70
|
+
try {
|
|
71
|
+
const serverConfig = await apiClient.get("/api/settings/serverConfig");
|
|
72
|
+
const wsUrl = serverConfig?.websocketUrl;
|
|
73
|
+
const wsCompletionUrl = serverConfig?.wsCompletionUrl;
|
|
74
|
+
if (wsUrl && wsCompletionUrl) {
|
|
75
|
+
wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
|
|
76
|
+
await wsManager.connect();
|
|
77
|
+
setWebSocketToolExecutor(new WebSocketToolExecutor(wsManager, tokenGetter));
|
|
78
|
+
llm = new WebSocketLlmBackend({
|
|
79
|
+
wsManager,
|
|
80
|
+
apiClient,
|
|
81
|
+
model: config.defaultModel,
|
|
82
|
+
tokenGetter,
|
|
83
|
+
wsCompletionUrl
|
|
84
|
+
});
|
|
85
|
+
logger.debug("[headless] Using WebSocket transport");
|
|
86
|
+
} else throw new Error("No websocketUrl or wsCompletionUrl in server config");
|
|
87
|
+
} catch {
|
|
88
|
+
wsManager = null;
|
|
89
|
+
setWebSocketToolExecutor(null);
|
|
90
|
+
llm = new ServerLlmBackend({
|
|
91
|
+
apiClient,
|
|
92
|
+
model: config.defaultModel
|
|
93
|
+
});
|
|
94
|
+
logger.debug("[headless] Using SSE transport fallback");
|
|
95
|
+
}
|
|
96
|
+
const models = await llm.getModelInfo();
|
|
97
|
+
if (models.length === 0) throw new Error("No models available from server.");
|
|
98
|
+
const modelInfo = models.find((m) => m.id === config.defaultModel) ?? models[0];
|
|
99
|
+
llm.currentModel = modelInfo.id;
|
|
100
|
+
const session = {
|
|
101
|
+
id: v4(),
|
|
102
|
+
name: `Headless ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
103
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
104
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
105
|
+
model: modelInfo.id,
|
|
106
|
+
messages: [],
|
|
107
|
+
metadata: {
|
|
108
|
+
totalTokens: 0,
|
|
109
|
+
totalCost: 0,
|
|
110
|
+
toolCallCount: 0
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
await logger.initialize(session.id);
|
|
114
|
+
const permissionManager = new PermissionManager(config.trustedTools ?? [], void 0, config.tools.disabled);
|
|
115
|
+
const promptFn = (toolName, _args, _preview) => {
|
|
116
|
+
if (dangerouslySkipPermissions) {
|
|
117
|
+
logger.debug(`[headless] Auto-allowing tool: ${toolName}`);
|
|
118
|
+
return Promise.resolve({ action: "allow-once" });
|
|
119
|
+
}
|
|
120
|
+
process.stderr.write(`Warning: Tool "${toolName}" requires permission and was denied. Use --dangerously-skip-permissions to auto-allow tools in headless mode.\n`);
|
|
121
|
+
return Promise.resolve({ action: "deny" });
|
|
122
|
+
};
|
|
123
|
+
const userQuestionFn = (_payload) => {
|
|
124
|
+
process.stderr.write("Warning: Agent requested user input; headless mode cannot respond interactively. Answering with empty response.\n");
|
|
125
|
+
return Promise.resolve({ answers: [] });
|
|
126
|
+
};
|
|
127
|
+
const sandboxConfig = config.sandbox ?? DEFAULT_SANDBOX_CONFIG;
|
|
128
|
+
const checkpointStore = new CheckpointStore(configStore.getProjectConfigDir() ?? process.cwd());
|
|
129
|
+
const [sandboxRuntime] = await Promise.all([createSandboxRuntime(), checkpointStore.init(session.id).catch(() => {})]);
|
|
130
|
+
const sandboxOrchestrator = new SandboxOrchestrator(sandboxConfig, sandboxRuntime, new ProxyManager(sandboxConfig.network));
|
|
131
|
+
permissionManager.setSandboxState(sandboxConfig.mode, sandboxOrchestrator.isActive());
|
|
132
|
+
const agentContext = {
|
|
133
|
+
currentAgent: null,
|
|
134
|
+
observationQueue: []
|
|
135
|
+
};
|
|
136
|
+
const { tools: b4mTools } = await generateCliTools(config.userId, llm, modelInfo.id, permissionManager, promptFn, agentContext, configStore, apiClient, void 0, userQuestionFn, checkpointStore, sandboxOrchestrator, additionalDirectories);
|
|
137
|
+
const mcpManager = new McpManager(config);
|
|
138
|
+
const projectConfigDir = configStore.getProjectConfigDir();
|
|
139
|
+
const builtinAgentsDir = new URL("../agents/defaults/", import.meta.url).pathname;
|
|
140
|
+
const agentStore = new AgentStore(builtinAgentsDir, projectConfigDir ?? process.cwd());
|
|
141
|
+
const [, , contextResult] = await Promise.all([
|
|
142
|
+
mcpManager.initialize(),
|
|
143
|
+
agentStore.loadAgents(),
|
|
144
|
+
loadContextFiles(projectConfigDir)
|
|
145
|
+
]);
|
|
146
|
+
const mcpTools = mcpManager.getTools();
|
|
147
|
+
const orchestrator = new SubagentOrchestrator({
|
|
148
|
+
userId: config.userId,
|
|
149
|
+
llm,
|
|
150
|
+
logger: silentLogger,
|
|
151
|
+
permissionManager,
|
|
152
|
+
showPermissionPrompt: promptFn,
|
|
153
|
+
configStore,
|
|
154
|
+
apiClient,
|
|
155
|
+
agentStore,
|
|
156
|
+
customCommandStore,
|
|
157
|
+
enableParallelToolExecution: config.preferences.enableParallelToolExecution === true,
|
|
158
|
+
showUserQuestion: userQuestionFn,
|
|
159
|
+
checkpointStore
|
|
160
|
+
});
|
|
161
|
+
const backgroundManager = new BackgroundAgentManager(orchestrator);
|
|
162
|
+
const agentDelegateTool = createAgentDelegateTool(orchestrator, agentStore, session.id, backgroundManager);
|
|
163
|
+
const backgroundTools = createBackgroundAgentTools(backgroundManager);
|
|
164
|
+
const writeTodosTool = createWriteTodosTool(createTodoStore());
|
|
165
|
+
const findDefinitionTool = createFindDefinitionTool();
|
|
166
|
+
const getFileStructureTool = createGetFileStructureTool();
|
|
167
|
+
const enableSkillTool = config.preferences.enableSkillTool !== false;
|
|
168
|
+
const skillTool = enableSkillTool ? createSkillTool({
|
|
169
|
+
customCommandStore,
|
|
170
|
+
subagentOrchestrator: orchestrator,
|
|
171
|
+
sessionId: session.id
|
|
172
|
+
}) : null;
|
|
173
|
+
const cliTools = [
|
|
174
|
+
agentDelegateTool,
|
|
175
|
+
...backgroundTools,
|
|
176
|
+
writeTodosTool,
|
|
177
|
+
findDefinitionTool,
|
|
178
|
+
getFileStructureTool
|
|
179
|
+
];
|
|
180
|
+
if (skillTool) cliTools.push(skillTool);
|
|
181
|
+
const allTools = [
|
|
182
|
+
...b4mTools,
|
|
183
|
+
...mcpTools,
|
|
184
|
+
...cliTools
|
|
185
|
+
];
|
|
186
|
+
const systemPrompt = buildCoreSystemPrompt({
|
|
187
|
+
contextContent: contextResult.mergedContent,
|
|
188
|
+
agentStore,
|
|
189
|
+
customCommands: customCommandStore.getAllCommands(),
|
|
190
|
+
enableSkillTool,
|
|
191
|
+
enableDynamicAgentCreation: false,
|
|
192
|
+
additionalDirectories
|
|
193
|
+
});
|
|
194
|
+
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
195
|
+
const agent = new ReActAgent({
|
|
196
|
+
userId: config.userId,
|
|
197
|
+
logger: silentLogger,
|
|
198
|
+
llm,
|
|
199
|
+
model: modelInfo.id,
|
|
200
|
+
tools: allTools,
|
|
201
|
+
maxIterations,
|
|
202
|
+
maxTokens: config.preferences.maxTokens,
|
|
203
|
+
temperature: config.preferences.temperature,
|
|
204
|
+
systemPrompt
|
|
205
|
+
});
|
|
206
|
+
agentContext.currentAgent = agent;
|
|
207
|
+
agent.observationQueue = agentContext.observationQueue;
|
|
208
|
+
if (outputFormat === "stream-json") {
|
|
209
|
+
const emitNdjson = (obj) => process.stdout.write(JSON.stringify(obj) + "\n");
|
|
210
|
+
agent.on("thought", (step) => {
|
|
211
|
+
emitNdjson({
|
|
212
|
+
type: "thought",
|
|
213
|
+
content: step.content
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
agent.on("action", (step) => {
|
|
217
|
+
emitNdjson({
|
|
218
|
+
type: "action",
|
|
219
|
+
content: step.content,
|
|
220
|
+
toolName: step.metadata?.toolName,
|
|
221
|
+
toolInput: step.metadata?.toolInput
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
agent.on("observation", (step) => {
|
|
225
|
+
emitNdjson({
|
|
226
|
+
type: "observation",
|
|
227
|
+
content: step.content,
|
|
228
|
+
toolName: step.metadata?.toolName
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const turnId = `turn-${randomBytes(4).toString("hex")}`;
|
|
233
|
+
backgroundManager.setCurrentTurn(turnId);
|
|
234
|
+
let result;
|
|
235
|
+
try {
|
|
236
|
+
result = await agent.run(fullPrompt, {
|
|
237
|
+
parallelExecution: config.preferences.enableParallelToolExecution === true,
|
|
238
|
+
isReadOnlyTool
|
|
239
|
+
});
|
|
240
|
+
} finally {
|
|
241
|
+
backgroundManager.setCurrentTurn(null);
|
|
242
|
+
}
|
|
243
|
+
const finalSession = {
|
|
244
|
+
...session,
|
|
245
|
+
messages: [{
|
|
246
|
+
id: v4(),
|
|
247
|
+
role: "user",
|
|
248
|
+
content: fullPrompt,
|
|
249
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
250
|
+
}, {
|
|
251
|
+
id: v4(),
|
|
252
|
+
role: "assistant",
|
|
253
|
+
content: result.finalAnswer,
|
|
254
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
255
|
+
}],
|
|
256
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
257
|
+
metadata: {
|
|
258
|
+
totalTokens: result.completionInfo.totalTokens,
|
|
259
|
+
totalCost: 0,
|
|
260
|
+
toolCallCount: result.completionInfo.toolCalls
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
await sessionStore.save(finalSession);
|
|
264
|
+
switch (outputFormat) {
|
|
265
|
+
case "text":
|
|
266
|
+
process.stdout.write(result.finalAnswer + "\n");
|
|
267
|
+
break;
|
|
268
|
+
case "json": {
|
|
269
|
+
const jsonResult = {
|
|
270
|
+
result: result.finalAnswer,
|
|
271
|
+
steps: result.steps.map((s) => ({
|
|
272
|
+
type: s.type,
|
|
273
|
+
content: s.content,
|
|
274
|
+
toolName: s.metadata?.toolName,
|
|
275
|
+
toolInput: s.metadata?.toolInput
|
|
276
|
+
})),
|
|
277
|
+
tokenUsage: {
|
|
278
|
+
totalTokens: result.completionInfo.totalTokens,
|
|
279
|
+
inputTokens: result.completionInfo.totalInputTokens,
|
|
280
|
+
outputTokens: result.completionInfo.totalOutputTokens
|
|
281
|
+
},
|
|
282
|
+
iterations: result.completionInfo.iterations,
|
|
283
|
+
toolCalls: result.completionInfo.toolCalls
|
|
284
|
+
};
|
|
285
|
+
process.stdout.write(JSON.stringify(jsonResult, null, 2) + "\n");
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
case "stream-json":
|
|
289
|
+
process.stdout.write(JSON.stringify({
|
|
290
|
+
type: "result",
|
|
291
|
+
content: result.finalAnswer,
|
|
292
|
+
tokenUsage: {
|
|
293
|
+
totalTokens: result.completionInfo.totalTokens,
|
|
294
|
+
inputTokens: result.completionInfo.totalInputTokens,
|
|
295
|
+
outputTokens: result.completionInfo.totalOutputTokens
|
|
296
|
+
},
|
|
297
|
+
iterations: result.completionInfo.iterations,
|
|
298
|
+
toolCalls: result.completionInfo.toolCalls
|
|
299
|
+
}) + "\n");
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
await mcpManager.disconnect().catch(() => {});
|
|
303
|
+
if (wsManager) wsManager.disconnect();
|
|
304
|
+
setWebSocketToolExecutor(null);
|
|
305
|
+
agent.removeAllListeners();
|
|
306
|
+
process.exit(0);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
309
|
+
if (outputFormat === "json") process.stdout.write(JSON.stringify({ error: message }) + "\n");
|
|
310
|
+
else if (outputFormat === "stream-json") process.stdout.write(JSON.stringify({
|
|
311
|
+
type: "error",
|
|
312
|
+
error: message
|
|
313
|
+
}) + "\n");
|
|
314
|
+
else process.stderr.write(`Error: ${message}\n`);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
319
|
+
export { handleHeadlessCommand };
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as ConfigStore } from "../ConfigStore-CllM6jOf.mjs";
|
|
3
|
+
//#region src/commands/mcpCommand.ts
|
|
4
|
+
/**
|
|
5
|
+
* External MCP commands (b4m mcp list, b4m mcp add, etc.)
|
|
6
|
+
* These run outside the interactive CLI session
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Main handler for MCP subcommands
|
|
10
|
+
*/
|
|
11
|
+
async function handleMcpCommand(subcommand, argv) {
|
|
12
|
+
const configStore = new ConfigStore();
|
|
13
|
+
const config = await configStore.load();
|
|
14
|
+
switch (subcommand) {
|
|
15
|
+
case "list":
|
|
16
|
+
await handleList(config);
|
|
17
|
+
break;
|
|
18
|
+
case "add": {
|
|
19
|
+
if (!argv.name) {
|
|
20
|
+
console.error("❌ Usage: b4m mcp add <name> -- <command> [args...]");
|
|
21
|
+
console.error("");
|
|
22
|
+
console.error("The -- separator is required to separate the server name from the command.");
|
|
23
|
+
console.error("");
|
|
24
|
+
console.error("Examples:");
|
|
25
|
+
console.error(" b4m mcp add context7 -- npx -y @upstash/context7-mcp");
|
|
26
|
+
console.error(" b4m mcp add github -- docker run -i ghcr.io/modelcontextprotocol/servers/github");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const dashDashIndex = process.argv.indexOf("--");
|
|
30
|
+
if (dashDashIndex === -1) {
|
|
31
|
+
console.error("❌ Missing -- separator");
|
|
32
|
+
console.error("");
|
|
33
|
+
console.error("Usage: b4m mcp add <name> -- <command> [args...]");
|
|
34
|
+
console.error("");
|
|
35
|
+
console.error("The -- separator is required to separate the server name from the command.");
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const commandParts = process.argv.slice(dashDashIndex + 1);
|
|
39
|
+
if (commandParts.length === 0) {
|
|
40
|
+
console.error("❌ No command specified after --");
|
|
41
|
+
console.error("");
|
|
42
|
+
console.error("Usage: b4m mcp add <name> -- <command> [args...]");
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const command = commandParts[0];
|
|
46
|
+
const args = commandParts.slice(1);
|
|
47
|
+
await handleAdd(config, argv.name, command, args, configStore);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "remove":
|
|
51
|
+
if (!argv.name) {
|
|
52
|
+
console.error("❌ Usage: b4m mcp remove <name>");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
await handleRemove(config, argv.name, configStore);
|
|
56
|
+
break;
|
|
57
|
+
case "enable":
|
|
58
|
+
if (!argv.name) {
|
|
59
|
+
console.error("❌ Usage: b4m mcp enable <name>");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
await handleEnable(config, argv.name, configStore);
|
|
63
|
+
break;
|
|
64
|
+
case "disable":
|
|
65
|
+
if (!argv.name) {
|
|
66
|
+
console.error("❌ Usage: b4m mcp disable <name>");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
await handleDisable(config, argv.name, configStore);
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
console.error(`❌ Unknown MCP subcommand: ${subcommand}`);
|
|
73
|
+
console.error("");
|
|
74
|
+
console.error("Available commands:");
|
|
75
|
+
console.error(" b4m mcp list - List configured MCP servers");
|
|
76
|
+
console.error(" b4m mcp add <name> -- <command> - Add a new MCP server");
|
|
77
|
+
console.error(" b4m mcp remove <name> - Remove an MCP server");
|
|
78
|
+
console.error(" b4m mcp enable <name> - Enable an MCP server");
|
|
79
|
+
console.error(" b4m mcp disable <name> - Disable an MCP server");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* List configured MCP servers
|
|
85
|
+
*/
|
|
86
|
+
async function handleList(config) {
|
|
87
|
+
if (config.mcpServers.length === 0) {
|
|
88
|
+
console.log("📡 No MCP servers configured.");
|
|
89
|
+
console.log("");
|
|
90
|
+
console.log("To add an MCP server:");
|
|
91
|
+
console.log(" b4m mcp add <name> -- <command> [args...]");
|
|
92
|
+
console.log("");
|
|
93
|
+
console.log("Examples:");
|
|
94
|
+
console.log(" b4m mcp add context7 -- npx -y @upstash/context7-mcp");
|
|
95
|
+
console.log(" b4m mcp add github -- docker run -i ghcr.io/modelcontextprotocol/servers/github");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
console.log("📡 Configured MCP Servers:\n");
|
|
99
|
+
for (const server of config.mcpServers) {
|
|
100
|
+
const status = server.enabled ? "✅ Enabled" : "⏸️ Disabled";
|
|
101
|
+
const commandInfo = server.command ? `${server.command} ${(server.args || []).join(" ")}` : "(internal)";
|
|
102
|
+
console.log(`• ${server.name} - ${status}`);
|
|
103
|
+
console.log(` Command: ${commandInfo}`);
|
|
104
|
+
if (Object.keys(server.env).length > 0) {
|
|
105
|
+
const envKeys = Object.keys(server.env).join(", ");
|
|
106
|
+
console.log(` Env vars: ${envKeys}`);
|
|
107
|
+
}
|
|
108
|
+
console.log("");
|
|
109
|
+
}
|
|
110
|
+
console.log("To manage servers:");
|
|
111
|
+
console.log(" b4m mcp add <name> -- <command> [args...] - Add server");
|
|
112
|
+
console.log(" b4m mcp remove <name> - Remove server");
|
|
113
|
+
console.log(" b4m mcp enable <name> - Enable server");
|
|
114
|
+
console.log(" b4m mcp disable <name> - Disable server");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Add a new MCP server
|
|
118
|
+
*/
|
|
119
|
+
async function handleAdd(config, name, command, args, configStore) {
|
|
120
|
+
if (config.mcpServers.find((s) => s.name === name)) {
|
|
121
|
+
console.error(`❌ MCP server "${name}" already exists.`);
|
|
122
|
+
console.error(" Use \"b4m mcp remove\" first to replace it.");
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
126
|
+
console.error("❌ Server name must contain only alphanumeric characters, dashes, and underscores.");
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
const newServer = {
|
|
130
|
+
name,
|
|
131
|
+
command,
|
|
132
|
+
args,
|
|
133
|
+
env: {},
|
|
134
|
+
enabled: true
|
|
135
|
+
};
|
|
136
|
+
config.mcpServers.push(newServer);
|
|
137
|
+
try {
|
|
138
|
+
await configStore.save(config);
|
|
139
|
+
console.log(`✅ Added MCP server "${name}"`);
|
|
140
|
+
console.log("");
|
|
141
|
+
console.log("Configuration saved to: ~/.bike4mind/config.json");
|
|
142
|
+
console.log("");
|
|
143
|
+
console.log("The server will be available next time you start the CLI.");
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(`❌ Failed to save configuration:`, error instanceof Error ? error.message : String(error));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Remove an MCP server
|
|
151
|
+
*/
|
|
152
|
+
async function handleRemove(config, name, configStore) {
|
|
153
|
+
const index = config.mcpServers.findIndex((s) => s.name === name);
|
|
154
|
+
if (index === -1) {
|
|
155
|
+
console.error(`❌ MCP server "${name}" not found.`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
config.mcpServers.splice(index, 1);
|
|
159
|
+
try {
|
|
160
|
+
await configStore.save(config);
|
|
161
|
+
console.log(`✅ Removed MCP server "${name}"`);
|
|
162
|
+
console.log("");
|
|
163
|
+
console.log("Configuration saved to: ~/.bike4mind/config.json");
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error(`❌ Failed to save configuration:`, error instanceof Error ? error.message : String(error));
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Enable an MCP server
|
|
171
|
+
*/
|
|
172
|
+
async function handleEnable(config, name, configStore) {
|
|
173
|
+
const server = config.mcpServers.find((s) => s.name === name);
|
|
174
|
+
if (!server) {
|
|
175
|
+
console.error(`❌ MCP server "${name}" not found.`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
if (server.enabled) {
|
|
179
|
+
console.log(`ℹ️ MCP server "${name}" is already enabled.`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
server.enabled = true;
|
|
183
|
+
try {
|
|
184
|
+
await configStore.save(config);
|
|
185
|
+
console.log(`✅ Enabled MCP server "${name}"`);
|
|
186
|
+
console.log("");
|
|
187
|
+
console.log("The server will connect next time you start the CLI.");
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(`❌ Failed to save configuration:`, error instanceof Error ? error.message : String(error));
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Disable an MCP server
|
|
195
|
+
*/
|
|
196
|
+
async function handleDisable(config, name, configStore) {
|
|
197
|
+
const server = config.mcpServers.find((s) => s.name === name);
|
|
198
|
+
if (!server) {
|
|
199
|
+
console.error(`❌ MCP server "${name}" not found.`);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
if (!server.enabled) {
|
|
203
|
+
console.log(`ℹ️ MCP server "${name}" is already disabled.`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
server.enabled = false;
|
|
207
|
+
try {
|
|
208
|
+
await configStore.save(config);
|
|
209
|
+
console.log(`✅ Disabled MCP server "${name}"`);
|
|
210
|
+
console.log("");
|
|
211
|
+
console.log("The server will not connect next time you start the CLI.");
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.error(`❌ Failed to save configuration:`, error instanceof Error ? error.message : String(error));
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
export { handleMcpCommand };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as version, r as forceCheckForUpdate } from "../updateChecker-Cu9dkHxV.mjs";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
//#region src/commands/updateCommand.ts
|
|
5
|
+
/**
|
|
6
|
+
* External update command (b4m update)
|
|
7
|
+
* Checks for and installs CLI updates.
|
|
8
|
+
* Runs outside the interactive CLI session.
|
|
9
|
+
*/
|
|
10
|
+
async function handleUpdateCommand() {
|
|
11
|
+
const currentVersion = version;
|
|
12
|
+
console.log(`Current version: v${currentVersion}`);
|
|
13
|
+
console.log("Checking for updates...\n");
|
|
14
|
+
const result = await forceCheckForUpdate(currentVersion);
|
|
15
|
+
if (!result) {
|
|
16
|
+
console.error("Failed to check for updates. Check your internet connection.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
if (!result.updateAvailable) {
|
|
20
|
+
console.log(`Already on the latest version (v${currentVersion}).`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(`Update available: v${currentVersion} → v${result.latestVersion}\n`);
|
|
24
|
+
console.log("Installing update...\n");
|
|
25
|
+
try {
|
|
26
|
+
execSync("npm install -g @bike4mind/cli@latest", {
|
|
27
|
+
stdio: "inherit",
|
|
28
|
+
timeout: 12e4
|
|
29
|
+
});
|
|
30
|
+
console.log(`\nSuccessfully updated to v${result.latestVersion}.`);
|
|
31
|
+
} catch {
|
|
32
|
+
console.error("\nUpdate failed. Try running manually:");
|
|
33
|
+
console.error(" npm install -g @bike4mind/cli@latest");
|
|
34
|
+
console.error("\nIf you get permission errors, try:");
|
|
35
|
+
console.error(" sudo npm install -g @bike4mind/cli@latest");
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { handleUpdateCommand };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as assertPathAllowed } from "./pathValidation-Cgjh5WQO-DiCZTcq6.mjs";
|
|
3
|
+
import { existsSync, promises } from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
//#region ../../b4m-core/packages/services/dist/createFile-yQfh8uvk.mjs
|
|
6
|
+
async function createFile(params, allowedDirectories) {
|
|
7
|
+
const { path: filePath, content, createDirectories = true } = params;
|
|
8
|
+
const resolvedPath = assertPathAllowed(filePath, allowedDirectories, "create");
|
|
9
|
+
const action = existsSync(resolvedPath) ? "overwritten" : "created";
|
|
10
|
+
if (createDirectories) {
|
|
11
|
+
const dir = path.dirname(resolvedPath);
|
|
12
|
+
await promises.mkdir(dir, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
await promises.writeFile(resolvedPath, content, "utf-8");
|
|
15
|
+
const stats = await promises.stat(resolvedPath);
|
|
16
|
+
const lines = content.split("\n").length;
|
|
17
|
+
return `File ${action} successfully: ${filePath}\nSize: ${stats.size} bytes\nLines: ${lines}`;
|
|
18
|
+
}
|
|
19
|
+
const createFileTool = {
|
|
20
|
+
name: "create_file",
|
|
21
|
+
implementation: (context) => ({
|
|
22
|
+
toolFn: async (value) => {
|
|
23
|
+
const params = value;
|
|
24
|
+
const fileExists = existsSync(path.resolve(process.cwd(), path.normalize(params.path)));
|
|
25
|
+
context.logger.info(`📝 CreateFile: ${fileExists ? "Overwriting" : "Creating"} file`, {
|
|
26
|
+
path: params.path,
|
|
27
|
+
size: params.content.length
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
const result = await createFile(params, context.allowedDirectories);
|
|
31
|
+
context.logger.info("✅ CreateFile: Success", { path: params.path });
|
|
32
|
+
return result;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
context.logger.error("❌ CreateFile: Failed", error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
toolSchema: {
|
|
39
|
+
name: "create_file",
|
|
40
|
+
description: "Create a new file or overwrite an existing file with the provided content. Will create parent directories if they do not exist. Restricted to current working directory for security. Always prompts user for confirmation before writing.",
|
|
41
|
+
parameters: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
path: {
|
|
45
|
+
type: "string",
|
|
46
|
+
description: "Path where the file should be created (relative to current working directory)"
|
|
47
|
+
},
|
|
48
|
+
content: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "Content to write to the file"
|
|
51
|
+
},
|
|
52
|
+
createDirectories: {
|
|
53
|
+
type: "boolean",
|
|
54
|
+
description: "Create parent directories if they do not exist (default: true)"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
required: ["path", "content"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { createFileTool };
|