@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.
Files changed (85) hide show
  1. package/bin/bike4mind-cli.mjs +6 -6
  2. package/dist/BubblewrapRuntime-BHbtqvLx.mjs +72 -0
  3. package/dist/ConfigStore-CllM6jOf.mjs +8614 -0
  4. package/dist/ImageStore-DaKT_Ew8.mjs +202 -0
  5. package/dist/ProxyManager-Dl2nFk-A.mjs +259 -0
  6. package/dist/ProxyManager-kiOD1X8-.mjs +3 -0
  7. package/dist/SandboxOrchestrator-BEW3rqYi.mjs +159 -0
  8. package/dist/SandboxOrchestrator-CHZgSR3P.mjs +3 -0
  9. package/dist/SandboxRuntimeAdapter-C1B4t20N.mjs +57 -0
  10. package/dist/SandboxRuntimeAdapter-D7UAG13n.mjs +3 -0
  11. package/dist/SeatbeltRuntime-D4m0VOcD.mjs +116 -0
  12. package/dist/StderrViolationParser-D0afQ3-1.mjs +70 -0
  13. package/dist/ViolationLogStore-CZl35HcA.mjs +96 -0
  14. package/dist/bashExecute-BTkdqlSs-5foM20Lb.mjs +466 -0
  15. package/dist/commands/doctorCommand.mjs +101 -0
  16. package/dist/commands/headlessCommand.mjs +319 -0
  17. package/dist/commands/mcpCommand.mjs +218 -0
  18. package/dist/commands/updateCommand.mjs +40 -0
  19. package/dist/createFile-yQfh8uvk-I-yM5DxC.mjs +63 -0
  20. package/dist/deleteFile-DKHfnyny-G3b1Kj2T.mjs +66 -0
  21. package/dist/globFiles-D1en6joM-8jekiXdX.mjs +100 -0
  22. package/dist/grepSearch-aMamoBn_-DCJcY8JS.mjs +173 -0
  23. package/dist/index.mjs +6722 -0
  24. package/dist/pathValidation-Cgjh5WQO-DiCZTcq6.mjs +63 -0
  25. package/dist/store-Dw1nZX2Y.mjs +128 -0
  26. package/dist/store-nZExNOWX.mjs +3 -0
  27. package/dist/terminalSetup-rmr1P8KF.mjs +254 -0
  28. package/dist/tools-C6M5aW8W.mjs +20907 -0
  29. package/dist/treeSitterEngine-DCSXcm_3.mjs +309 -0
  30. package/dist/types-DBEjF9YS.mjs +59 -0
  31. package/dist/types-DK3P88Px.mjs +3 -0
  32. package/dist/updateChecker-Cu9dkHxV.mjs +120 -0
  33. package/package.json +10 -10
  34. package/dist/BubblewrapRuntime-PMIOLWKR.js +0 -71
  35. package/dist/HydrationEngine-YL2HWJ3V.js +0 -9
  36. package/dist/ImageStore-MMUOUPI2.js +0 -224
  37. package/dist/ProxyManager-HEB4TLVX.js +0 -7
  38. package/dist/SandboxOrchestrator-UIJ5GYBB.js +0 -8
  39. package/dist/SandboxRuntimeAdapter-FQ56MAB2.js +0 -13
  40. package/dist/SeatbeltRuntime-EE3TTLEP.js +0 -98
  41. package/dist/StderrViolationParser-7OYPM2DJ.js +0 -59
  42. package/dist/ViolationLogStore-RIIUVURH.js +0 -104
  43. package/dist/artifactExtractor-R7DIP2XO.js +0 -180
  44. package/dist/bashExecute-GLGLD3JD.js +0 -379
  45. package/dist/chunk-4BIBE3J7.js +0 -48
  46. package/dist/chunk-5LZS5CVJ.js +0 -161
  47. package/dist/chunk-BDQBOLYG.js +0 -120
  48. package/dist/chunk-BPFEGDC7.js +0 -192
  49. package/dist/chunk-EPIYC3LA.js +0 -13770
  50. package/dist/chunk-G4ZGEQFT.js +0 -250
  51. package/dist/chunk-GQGOWACU.js +0 -770
  52. package/dist/chunk-J6ZBI6TI.js +0 -1079
  53. package/dist/chunk-JW3JRHH7.js +0 -12433
  54. package/dist/chunk-KQAMBXAW.js +0 -163
  55. package/dist/chunk-KUVV2NAB.js +0 -19125
  56. package/dist/chunk-LTLJRF6I.js +0 -44
  57. package/dist/chunk-PFBYGCOW.js +0 -449
  58. package/dist/chunk-QWB6ZYY4.js +0 -48
  59. package/dist/chunk-SGPRXN4C.js +0 -245
  60. package/dist/chunk-UZUHPHZC.js +0 -95
  61. package/dist/chunk-WBE7SQUB.js +0 -241
  62. package/dist/chunk-Y4WOJJM3.js +0 -147
  63. package/dist/commands/doctorCommand.js +0 -87
  64. package/dist/commands/headlessCommand.js +0 -380
  65. package/dist/commands/mcpCommand.js +0 -203
  66. package/dist/commands/updateCommand.js +0 -42
  67. package/dist/create-C4VEEEYR.js +0 -12
  68. package/dist/createFile-6PSPLW6R.js +0 -71
  69. package/dist/deleteFile-AUSRLWIK.js +0 -73
  70. package/dist/formatConverter-5QEJDW24.js +0 -7
  71. package/dist/globFiles-TSRN64N2.js +0 -120
  72. package/dist/grepSearch-634XWZOJ.js +0 -216
  73. package/dist/index.js +0 -6779
  74. package/dist/llmMarkdownGenerator-Z6NB26TT.js +0 -371
  75. package/dist/markdownGenerator-SK2ZQQL4.js +0 -269
  76. package/dist/mementoService-N4IM6QAC.js +0 -12
  77. package/dist/notificationDeduplicator-HUC53NEW.js +0 -9
  78. package/dist/src-F4KZCAA2.js +0 -319
  79. package/dist/src-ISX322I7.js +0 -1101
  80. package/dist/store-CAB6BV3P.js +0 -11
  81. package/dist/subtractCredits-D4KEM6VU.js +0 -12
  82. package/dist/terminalSetup-C5FHMLC3.js +0 -214
  83. package/dist/treeSitterEngine-4SGFQDY3.js +0 -330
  84. package/dist/types-KB5NP6T4.js +0 -7
  85. 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 };