MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / execute

Method execute

src/tools/shell/bash.ts:21–74  ·  view source on GitHub ↗
(args: z.infer<typeof ArgsSchema>, ctx: ToolContext)

Source from the content-addressed store, hash-verified

19 argsSchema = ArgsSchema;
20
21 async execute(args: z.infer<typeof ArgsSchema>, ctx: ToolContext): Promise<ToolResult> {
22 const cmd = args.command.trim();
23 if (!cmd) return { content: '[ERROR] Empty command', isError: true };
24
25 // Permission check
26 const permReq = { tool: 'shell', operation: cmd, description: args.description };
27 const decision = ctx.permissions.evaluate(permReq);
28 if (decision === 'deny') {
29 return { content: `[PERMISSION_DENIED] Command blocked by policy: ${cmd}\nIf you really need this, ask the user to add an allow rule.`, isError: true };
30 }
31 if (decision === 'ask') {
32 ctx.emit({ type: 'permission-request', tool: 'shell', operation: cmd, description: args.description });
33 const answer = await ctx.askUser(
34 `Run: ${cmd}${args.description ? `\n (${args.description})` : ''}`,
35 ['yes', 'no', 'always'],
36 );
37 if (answer === 'no') {
38 return { content: `[USER_REJECTED] User declined to run: ${cmd}`, isError: true };
39 }
40 if (answer === 'always') {
41 ctx.permissions.rememberDecision(permReq, 'allow', 'pattern');
42 }
43 }
44
45 const timeoutMs = (args.timeout_seconds ?? 120) * 1000;
46
47 // Auto-snapshot: if the wiring is present and this command pattern is destructive,
48 // take a git stash first so /undo can roll back. Best-effort — never blocks on
49 // failure, but the failure IS surfaced in the result so the user knows /undo
50 // is unavailable for this command.
51 let snapshotWarning: string | null = null;
52 if (ctx.snapshotService) {
53 const snapshot = await import('../../safety/snapshot.js');
54 const check = snapshot.isDestructiveBash(cmd);
55 if (check.destructive) {
56 try {
57 ctx.snapshotService.takeSnapshot(
58 `before bash: ${check.label} (${cmd.slice(0, 80)})`,
59 ctx.currentTurn ?? 0,
60 );
61 } catch (e: any) {
62 // Snapshot failure is non-fatal — log, surface to the user, and proceed.
63 logger.warn('Auto-snapshot before bash failed (continuing)', { err: e?.message });
64 snapshotWarning = '⚠ snapshot failed — /undo unavailable for this command';
65 }
66 }
67 }
68
69 const result = await this.runCommand(cmd, ctx, timeoutMs);
70 if (snapshotWarning) {
71 return { ...result, content: `${snapshotWarning}\n${result.content}` };
72 }
73 return result;
74 }
75
76 private runCommand(cmd: string, ctx: ToolContext, timeoutMs: number): Promise<ToolResult> {
77 return new Promise(resolve => {

Callers

nothing calls this directly

Calls 7

runCommandMethod · 0.95
evaluateMethod · 0.80
rememberDecisionMethod · 0.80
takeSnapshotMethod · 0.80
warnMethod · 0.80
emitMethod · 0.45
askUserMethod · 0.45

Tested by

no test coverage detected