@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,466 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import path from "path";
|
|
4
|
+
//#region ../../b4m-core/packages/services/dist/bashExecute-BTkdqlSs.mjs
|
|
5
|
+
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
6
|
+
const MAX_OUTPUT_SIZE = 100 * 1024;
|
|
7
|
+
/**
|
|
8
|
+
* Dangerous command patterns that should be blocked or warned about.
|
|
9
|
+
* These patterns are checked against the full command string.
|
|
10
|
+
*/
|
|
11
|
+
const DANGEROUS_PATTERNS = [
|
|
12
|
+
{
|
|
13
|
+
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
14
|
+
reason: "Recursive delete with path",
|
|
15
|
+
block: true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
19
|
+
reason: "Force delete without preserve root",
|
|
20
|
+
block: true
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
24
|
+
reason: "Recursive force delete on root paths",
|
|
25
|
+
block: true
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
29
|
+
reason: "Force recursive delete on root paths",
|
|
30
|
+
block: true
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pattern: /\bsudo\b/i,
|
|
34
|
+
reason: "Elevated privileges (sudo)",
|
|
35
|
+
block: true
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pattern: /\bsu\s+(-|root)/i,
|
|
39
|
+
reason: "Switch to root user",
|
|
40
|
+
block: true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: /\bchmod\s+777\b/i,
|
|
44
|
+
reason: "Overly permissive chmod",
|
|
45
|
+
block: false
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pattern: /\bchown\s+-R\s+root/i,
|
|
49
|
+
reason: "Recursive chown to root",
|
|
50
|
+
block: true
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
pattern: /\bmkfs\b/i,
|
|
54
|
+
reason: "Filesystem creation",
|
|
55
|
+
block: true
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
pattern: /\bfdisk\b/i,
|
|
59
|
+
reason: "Disk partitioning",
|
|
60
|
+
block: true
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
pattern: /\bdd\s+.*of=\/dev\//i,
|
|
64
|
+
reason: "Direct disk write",
|
|
65
|
+
block: true
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i,
|
|
69
|
+
reason: "Reverse shell attempt",
|
|
70
|
+
block: true
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
pattern: /\bcurl\s+.*\|\s*(ba)?sh/i,
|
|
74
|
+
reason: "Piping remote script to shell",
|
|
75
|
+
block: true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
pattern: /\bwget\s+.*\|\s*(ba)?sh/i,
|
|
79
|
+
reason: "Piping remote script to shell",
|
|
80
|
+
block: true
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i,
|
|
84
|
+
reason: "Fork bomb",
|
|
85
|
+
block: true
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
pattern: /\bwhile\s+true.*do.*done.*&/i,
|
|
89
|
+
reason: "Infinite loop in background",
|
|
90
|
+
block: false
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
pattern: /\/etc\/shadow/i,
|
|
94
|
+
reason: "Access to shadow file",
|
|
95
|
+
block: true
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
pattern: /\/etc\/passwd.*>/i,
|
|
99
|
+
reason: "Modifying passwd file",
|
|
100
|
+
block: true
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
pattern: /\baws\s+.*--profile\s+/i,
|
|
104
|
+
reason: "AWS profile access",
|
|
105
|
+
block: false
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
pattern: /\bhistory\s+-c\b/i,
|
|
109
|
+
reason: "Clearing shell history",
|
|
110
|
+
block: false
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
pattern: />\s*\/var\/log\//i,
|
|
114
|
+
reason: "Overwriting system logs",
|
|
115
|
+
block: true
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
pattern: />\s*\/dev\/sda/i,
|
|
119
|
+
reason: "Writing to block device",
|
|
120
|
+
block: true
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
pattern: />\s*\/dev\/null.*2>&1.*</i,
|
|
124
|
+
reason: "Potentially hiding output",
|
|
125
|
+
block: false
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
pattern: /\bexport\s+PATH\s*=\s*[^$]/i,
|
|
129
|
+
reason: "Overwriting PATH",
|
|
130
|
+
block: false
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
pattern: /\bexport\s+LD_PRELOAD/i,
|
|
134
|
+
reason: "LD_PRELOAD manipulation",
|
|
135
|
+
block: true
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
pattern: /\bkill\s+-9\s+(-1|1)\b/i,
|
|
139
|
+
reason: "Killing all processes",
|
|
140
|
+
block: true
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
pattern: /\bkillall\s+-9\b/i,
|
|
144
|
+
reason: "Force killing processes",
|
|
145
|
+
block: false
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
pattern: /\bshutdown\b/i,
|
|
149
|
+
reason: "System shutdown",
|
|
150
|
+
block: true
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
pattern: /\breboot\b/i,
|
|
154
|
+
reason: "System reboot",
|
|
155
|
+
block: true
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
pattern: /\binit\s+[06]\b/i,
|
|
159
|
+
reason: "System runlevel change",
|
|
160
|
+
block: true
|
|
161
|
+
}
|
|
162
|
+
];
|
|
163
|
+
/**
|
|
164
|
+
* Commands that are generally safe and commonly used in development
|
|
165
|
+
*/
|
|
166
|
+
const SAFE_COMMAND_PREFIXES = [
|
|
167
|
+
"ls",
|
|
168
|
+
"cat",
|
|
169
|
+
"head",
|
|
170
|
+
"tail",
|
|
171
|
+
"grep",
|
|
172
|
+
"find",
|
|
173
|
+
"echo",
|
|
174
|
+
"pwd",
|
|
175
|
+
"whoami",
|
|
176
|
+
"date",
|
|
177
|
+
"cal",
|
|
178
|
+
"wc",
|
|
179
|
+
"sort",
|
|
180
|
+
"uniq",
|
|
181
|
+
"cut",
|
|
182
|
+
"tr",
|
|
183
|
+
"sed",
|
|
184
|
+
"awk",
|
|
185
|
+
"git",
|
|
186
|
+
"npm",
|
|
187
|
+
"pnpm",
|
|
188
|
+
"yarn",
|
|
189
|
+
"node",
|
|
190
|
+
"npx",
|
|
191
|
+
"tsx",
|
|
192
|
+
"ts-node",
|
|
193
|
+
"python",
|
|
194
|
+
"python3",
|
|
195
|
+
"pip",
|
|
196
|
+
"pip3",
|
|
197
|
+
"docker",
|
|
198
|
+
"docker-compose",
|
|
199
|
+
"curl",
|
|
200
|
+
"wget",
|
|
201
|
+
"mkdir",
|
|
202
|
+
"touch",
|
|
203
|
+
"cp",
|
|
204
|
+
"mv",
|
|
205
|
+
"which",
|
|
206
|
+
"whereis",
|
|
207
|
+
"type",
|
|
208
|
+
"file",
|
|
209
|
+
"stat",
|
|
210
|
+
"env",
|
|
211
|
+
"printenv",
|
|
212
|
+
"set",
|
|
213
|
+
"man",
|
|
214
|
+
"help",
|
|
215
|
+
"info",
|
|
216
|
+
"diff",
|
|
217
|
+
"comm",
|
|
218
|
+
"cmp",
|
|
219
|
+
"tar",
|
|
220
|
+
"zip",
|
|
221
|
+
"unzip",
|
|
222
|
+
"gzip",
|
|
223
|
+
"gunzip",
|
|
224
|
+
"ssh",
|
|
225
|
+
"scp",
|
|
226
|
+
"rsync",
|
|
227
|
+
"make",
|
|
228
|
+
"cmake",
|
|
229
|
+
"cargo",
|
|
230
|
+
"go",
|
|
231
|
+
"rustc",
|
|
232
|
+
"gcc",
|
|
233
|
+
"g++",
|
|
234
|
+
"jest",
|
|
235
|
+
"vitest",
|
|
236
|
+
"mocha",
|
|
237
|
+
"pytest",
|
|
238
|
+
"eslint",
|
|
239
|
+
"prettier",
|
|
240
|
+
"tsc"
|
|
241
|
+
];
|
|
242
|
+
/**
|
|
243
|
+
* Check if a command matches any dangerous patterns
|
|
244
|
+
*/
|
|
245
|
+
function checkDangerousPatterns(command) {
|
|
246
|
+
for (const { pattern, reason, block } of DANGEROUS_PATTERNS) if (pattern.test(command)) return {
|
|
247
|
+
blocked: block,
|
|
248
|
+
reason
|
|
249
|
+
};
|
|
250
|
+
return { blocked: false };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get the base command from a command string
|
|
254
|
+
*/
|
|
255
|
+
function getBaseCommand(command) {
|
|
256
|
+
const match = command.trim().match(/^(\S+)/);
|
|
257
|
+
return match ? match[1] : "";
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Check if command starts with a safe prefix
|
|
261
|
+
*/
|
|
262
|
+
function isSafeCommandPrefix(command) {
|
|
263
|
+
const baseCommand = getBaseCommand(command);
|
|
264
|
+
return SAFE_COMMAND_PREFIXES.some((safe) => baseCommand === safe || baseCommand.endsWith(`/${safe}`));
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Execute a bash command with safety checks
|
|
268
|
+
*/
|
|
269
|
+
async function executeBashCommand(params) {
|
|
270
|
+
const { command, cwd: relativeCwd, timeout = DEFAULT_TIMEOUT_MS } = params;
|
|
271
|
+
if (!command || command.trim().length === 0) return {
|
|
272
|
+
stdout: "",
|
|
273
|
+
stderr: "Error: Command cannot be empty",
|
|
274
|
+
exitCode: 1,
|
|
275
|
+
timedOut: false,
|
|
276
|
+
blocked: true,
|
|
277
|
+
blockedReason: "Empty command"
|
|
278
|
+
};
|
|
279
|
+
const dangerCheck = checkDangerousPatterns(command);
|
|
280
|
+
if (dangerCheck.blocked) return {
|
|
281
|
+
stdout: "",
|
|
282
|
+
stderr: `Command blocked for safety: ${dangerCheck.reason}`,
|
|
283
|
+
exitCode: 1,
|
|
284
|
+
timedOut: false,
|
|
285
|
+
blocked: true,
|
|
286
|
+
blockedReason: dangerCheck.reason
|
|
287
|
+
};
|
|
288
|
+
const baseCwd = process.cwd();
|
|
289
|
+
const targetCwd = relativeCwd ? path.resolve(baseCwd, relativeCwd) : baseCwd;
|
|
290
|
+
const effectiveTimeout = Math.min(timeout, 300 * 1e3);
|
|
291
|
+
return new Promise((resolve) => {
|
|
292
|
+
let stdout = "";
|
|
293
|
+
let stderr = "";
|
|
294
|
+
let timedOut = false;
|
|
295
|
+
const proc = spawn("bash", ["-c", command], {
|
|
296
|
+
cwd: targetCwd,
|
|
297
|
+
env: {
|
|
298
|
+
...process.env,
|
|
299
|
+
NO_COLOR: "1",
|
|
300
|
+
FORCE_COLOR: "0"
|
|
301
|
+
},
|
|
302
|
+
stdio: [
|
|
303
|
+
"ignore",
|
|
304
|
+
"pipe",
|
|
305
|
+
"pipe"
|
|
306
|
+
]
|
|
307
|
+
});
|
|
308
|
+
const timeoutId = setTimeout(() => {
|
|
309
|
+
timedOut = true;
|
|
310
|
+
proc.kill("SIGTERM");
|
|
311
|
+
setTimeout(() => {
|
|
312
|
+
if (!proc.killed) proc.kill("SIGKILL");
|
|
313
|
+
}, 5e3);
|
|
314
|
+
}, effectiveTimeout);
|
|
315
|
+
proc.stdout.on("data", (data) => {
|
|
316
|
+
if (stdout.length < MAX_OUTPUT_SIZE) {
|
|
317
|
+
stdout += data.toString();
|
|
318
|
+
if (stdout.length > MAX_OUTPUT_SIZE) stdout = stdout.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
proc.stderr.on("data", (data) => {
|
|
322
|
+
if (stderr.length < MAX_OUTPUT_SIZE) {
|
|
323
|
+
stderr += data.toString();
|
|
324
|
+
if (stderr.length > MAX_OUTPUT_SIZE) stderr = stderr.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
proc.on("close", (exitCode) => {
|
|
328
|
+
clearTimeout(timeoutId);
|
|
329
|
+
resolve({
|
|
330
|
+
stdout: stdout.trim(),
|
|
331
|
+
stderr: stderr.trim(),
|
|
332
|
+
exitCode,
|
|
333
|
+
timedOut,
|
|
334
|
+
blocked: false
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
proc.on("error", (error) => {
|
|
338
|
+
clearTimeout(timeoutId);
|
|
339
|
+
resolve({
|
|
340
|
+
stdout: "",
|
|
341
|
+
stderr: `Failed to execute command: ${error.message}`,
|
|
342
|
+
exitCode: 1,
|
|
343
|
+
timedOut: false,
|
|
344
|
+
blocked: false
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Format the result for display
|
|
351
|
+
*/
|
|
352
|
+
function formatResult(result, command) {
|
|
353
|
+
const parts = [];
|
|
354
|
+
parts.push(`$ ${command}`);
|
|
355
|
+
parts.push("");
|
|
356
|
+
if (result.blocked) {
|
|
357
|
+
parts.push(`BLOCKED: ${result.blockedReason}`);
|
|
358
|
+
parts.push("");
|
|
359
|
+
parts.push("This command was blocked for safety reasons.");
|
|
360
|
+
parts.push("If you believe this is a false positive, please run the command manually.");
|
|
361
|
+
return parts.join("\n");
|
|
362
|
+
}
|
|
363
|
+
if (result.timedOut) {
|
|
364
|
+
parts.push("WARNING: Command timed out and was terminated.");
|
|
365
|
+
parts.push("");
|
|
366
|
+
}
|
|
367
|
+
if (result.stdout) parts.push(result.stdout);
|
|
368
|
+
if (result.stderr) {
|
|
369
|
+
if (result.stdout) parts.push("");
|
|
370
|
+
parts.push("STDERR:");
|
|
371
|
+
parts.push(result.stderr);
|
|
372
|
+
}
|
|
373
|
+
if (result.exitCode !== 0 && result.exitCode !== null) {
|
|
374
|
+
parts.push("");
|
|
375
|
+
parts.push(`Exit code: ${result.exitCode}`);
|
|
376
|
+
}
|
|
377
|
+
if (!result.stdout && !result.stderr && !result.timedOut) parts.push("(command completed with no output)");
|
|
378
|
+
return parts.join("\n");
|
|
379
|
+
}
|
|
380
|
+
const bashExecuteTool = {
|
|
381
|
+
name: "bash_execute",
|
|
382
|
+
implementation: (context) => ({
|
|
383
|
+
toolFn: async (value) => {
|
|
384
|
+
const params = value;
|
|
385
|
+
const isSafe = isSafeCommandPrefix(params.command);
|
|
386
|
+
context.logger.info("Bash: Executing command", {
|
|
387
|
+
command: params.command,
|
|
388
|
+
cwd: params.cwd || ".",
|
|
389
|
+
timeout: params.timeout || DEFAULT_TIMEOUT_MS,
|
|
390
|
+
isSafeCommand: isSafe
|
|
391
|
+
});
|
|
392
|
+
if (context.onStart) await context.onStart("bash_execute", {
|
|
393
|
+
command: params.command,
|
|
394
|
+
cwd: params.cwd
|
|
395
|
+
});
|
|
396
|
+
try {
|
|
397
|
+
const result = await executeBashCommand(params);
|
|
398
|
+
const formattedResult = formatResult(result, params.command);
|
|
399
|
+
context.logger.info("Bash: Command completed", {
|
|
400
|
+
exitCode: result.exitCode,
|
|
401
|
+
timedOut: result.timedOut,
|
|
402
|
+
blocked: result.blocked
|
|
403
|
+
});
|
|
404
|
+
if (context.onFinish) await context.onFinish("bash_execute", {
|
|
405
|
+
command: params.command,
|
|
406
|
+
exitCode: result.exitCode,
|
|
407
|
+
blocked: result.blocked
|
|
408
|
+
});
|
|
409
|
+
return formattedResult;
|
|
410
|
+
} catch (error) {
|
|
411
|
+
context.logger.error("Bash: Command failed", error);
|
|
412
|
+
if (context.onFinish) await context.onFinish("bash_execute", {
|
|
413
|
+
command: params.command,
|
|
414
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
415
|
+
});
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
toolSchema: {
|
|
420
|
+
name: "bash_execute",
|
|
421
|
+
description: `Execute a bash command in the terminal. Use this for running shell commands, scripts, build tools, git operations, and other CLI tasks.
|
|
422
|
+
|
|
423
|
+
SAFETY NOTES:
|
|
424
|
+
- Commands are executed in the current working directory (or specified cwd)
|
|
425
|
+
- Dangerous commands (sudo, rm -rf /, etc.) are automatically blocked
|
|
426
|
+
- Commands have a default timeout of 60 seconds (max 5 minutes)
|
|
427
|
+
- Output is limited to prevent overwhelming responses
|
|
428
|
+
- This tool ALWAYS requires user permission before execution
|
|
429
|
+
|
|
430
|
+
COMMON USE CASES:
|
|
431
|
+
- Running build commands: npm run build, make, cargo build
|
|
432
|
+
- Git operations: git status, git log, git diff
|
|
433
|
+
- Viewing system info: ls, pwd, cat, head, tail
|
|
434
|
+
- Running tests: npm test, pytest, cargo test
|
|
435
|
+
- Package management: npm install, pip install
|
|
436
|
+
- File operations: mkdir, cp, mv (with permission)
|
|
437
|
+
|
|
438
|
+
BLOCKED OPERATIONS:
|
|
439
|
+
- sudo and privilege escalation
|
|
440
|
+
- Recursive deletes on system paths
|
|
441
|
+
- Direct disk operations
|
|
442
|
+
- Fork bombs and resource exhaustion
|
|
443
|
+
- Piping remote scripts to shell`,
|
|
444
|
+
parameters: {
|
|
445
|
+
type: "object",
|
|
446
|
+
properties: {
|
|
447
|
+
command: {
|
|
448
|
+
type: "string",
|
|
449
|
+
description: "The bash command to execute. Can include pipes, redirects, and chained commands."
|
|
450
|
+
},
|
|
451
|
+
cwd: {
|
|
452
|
+
type: "string",
|
|
453
|
+
description: "Working directory for the command (optional). Can be relative or absolute path. Defaults to current directory."
|
|
454
|
+
},
|
|
455
|
+
timeout: {
|
|
456
|
+
type: "number",
|
|
457
|
+
description: "Timeout in milliseconds (optional, default: 60000, max: 300000). Command will be terminated if it exceeds this time."
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
required: ["command"]
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
})
|
|
464
|
+
};
|
|
465
|
+
//#endregion
|
|
466
|
+
export { bashExecuteTool };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-Cu9dkHxV.mjs";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { constants, existsSync, promises } from "fs";
|
|
5
|
+
import { homedir } from "os";
|
|
6
|
+
import path from "path";
|
|
7
|
+
//#region src/commands/doctorCommand.ts
|
|
8
|
+
/**
|
|
9
|
+
* External doctor command (b4m doctor)
|
|
10
|
+
* Runs diagnostic checks on the CLI installation.
|
|
11
|
+
* Runs outside the interactive CLI session.
|
|
12
|
+
*/
|
|
13
|
+
async function handleDoctorCommand() {
|
|
14
|
+
console.log("B4M CLI Doctor\n");
|
|
15
|
+
console.log("Running diagnostics...\n");
|
|
16
|
+
const results = [];
|
|
17
|
+
const nodeVersion = process.version;
|
|
18
|
+
if (parseInt(nodeVersion.slice(1).split(".")[0], 10) >= 18) results.push({
|
|
19
|
+
name: "Node.js version",
|
|
20
|
+
status: "pass",
|
|
21
|
+
message: `${nodeVersion} (>= 18 required)`
|
|
22
|
+
});
|
|
23
|
+
else results.push({
|
|
24
|
+
name: "Node.js version",
|
|
25
|
+
status: "fail",
|
|
26
|
+
message: `${nodeVersion} (>= 18 required, please upgrade)`
|
|
27
|
+
});
|
|
28
|
+
const latestVersion = await fetchLatestVersion();
|
|
29
|
+
if (latestVersion) results.push({
|
|
30
|
+
name: "NPM registry",
|
|
31
|
+
status: "pass",
|
|
32
|
+
message: `Accessible (latest: v${latestVersion})`
|
|
33
|
+
});
|
|
34
|
+
else results.push({
|
|
35
|
+
name: "NPM registry",
|
|
36
|
+
status: "fail",
|
|
37
|
+
message: "Not accessible — check your internet connection"
|
|
38
|
+
});
|
|
39
|
+
const currentVersion = version;
|
|
40
|
+
const updateResult = await forceCheckForUpdate(currentVersion);
|
|
41
|
+
if (updateResult) if (updateResult.updateAvailable) results.push({
|
|
42
|
+
name: "Version",
|
|
43
|
+
status: "warn",
|
|
44
|
+
message: `v${currentVersion} installed, v${updateResult.latestVersion} available. Run: b4m update`
|
|
45
|
+
});
|
|
46
|
+
else results.push({
|
|
47
|
+
name: "Version",
|
|
48
|
+
status: "pass",
|
|
49
|
+
message: `v${currentVersion} (latest)`
|
|
50
|
+
});
|
|
51
|
+
try {
|
|
52
|
+
const npmPrefix = execSync("npm config get prefix", {
|
|
53
|
+
encoding: "utf-8",
|
|
54
|
+
timeout: 1e4
|
|
55
|
+
}).trim();
|
|
56
|
+
try {
|
|
57
|
+
await promises.access(npmPrefix, constants.W_OK);
|
|
58
|
+
results.push({
|
|
59
|
+
name: "Global npm path",
|
|
60
|
+
status: "pass",
|
|
61
|
+
message: `${npmPrefix} (writable)`
|
|
62
|
+
});
|
|
63
|
+
} catch {
|
|
64
|
+
results.push({
|
|
65
|
+
name: "Global npm path",
|
|
66
|
+
status: "warn",
|
|
67
|
+
message: `${npmPrefix} (not writable — may need sudo for updates)`
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
results.push({
|
|
72
|
+
name: "Global npm path",
|
|
73
|
+
status: "warn",
|
|
74
|
+
message: "Could not determine npm prefix"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const configFile = path.join(homedir(), ".bike4mind", "config.json");
|
|
78
|
+
if (existsSync(configFile)) results.push({
|
|
79
|
+
name: "Config file",
|
|
80
|
+
status: "pass",
|
|
81
|
+
message: configFile
|
|
82
|
+
});
|
|
83
|
+
else results.push({
|
|
84
|
+
name: "Config file",
|
|
85
|
+
status: "warn",
|
|
86
|
+
message: `Not found at ${configFile}`
|
|
87
|
+
});
|
|
88
|
+
console.log("Results:\n");
|
|
89
|
+
for (const result of results) {
|
|
90
|
+
const icon = result.status === "pass" ? "\x1B[32m✓\x1B[0m" : result.status === "warn" ? "\x1B[33m!\x1B[0m" : "\x1B[31m✗\x1B[0m";
|
|
91
|
+
console.log(` ${icon} ${result.name}: ${result.message}`);
|
|
92
|
+
}
|
|
93
|
+
const failures = results.filter((r) => r.status === "fail");
|
|
94
|
+
const warnings = results.filter((r) => r.status === "warn");
|
|
95
|
+
console.log("");
|
|
96
|
+
if (failures.length > 0) console.log(`${failures.length} issue(s) found.`);
|
|
97
|
+
else if (warnings.length > 0) console.log(`All checks passed with ${warnings.length} warning(s).`);
|
|
98
|
+
else console.log("All checks passed.");
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { handleDoctorCommand };
|