Tools & The Execution Engine

const BashToolDefinition: ToolDefinition = { name: 'BashTool', description: 'Execute shell commands with streaming output', inputSchema: z.object({ command: z.string(), timeout: z.number().optional().default(30000), description: z.string().optional(), sandbox: z.boolean().optional(), shellExecutable: z.string().optional() }), async checkPermissions(input, context, permContext) { const { command, sandbox } = input; const parsed = ShellParser.parse(command, process.env); const baseCommand = parsed[0]; const FORBIDDEN = ['find', 'grep', 'cat', 'head', 'tail', 'ls']; if (FORBIDDEN.includes(baseCommand) && !permContext.mode.includes('bypass')) { return { behavior: 'deny', message: `Use dedicated tools instead of ${baseCommand}` }; } const DANGEROUS = ['rm', 'dd', 'mkfs', 'fdisk', 'kill']; if (DANGEROUS.some(cmd => command.includes(cmd))) { return { behavior: 'ask', message: 'This command could be dangerous', ruleSuggestions: [`BashTool(${baseCommand}/*)`] }; } if (sandbox === true) { const SANDBOX_SAFE = ['echo', 'pwd', 'env', 'date', 'which']; if (SANDBOX_SAFE.includes(baseCommand)) { return { behavior: 'allow' }; } } return await super.checkPermissions(input, context, permContext); }, async *call(input, context) { const { command, timeout, sandbox = false } = input; yield { type: 'progress', toolUseID: context.currentToolUseId, data: { status: 'Preparing command execution...', command: command.substring(0, 100), sandbox } }; const execOptions = { cwd: context.cwd, env: { ...process.env, CLAUDE_CODE: 'true' }, timeout, maxBuffer: 10 * 1024 * 1024, killSignal: 'SIGTERM' }; if (sandbox && process.platform === 'darwin') { const profile = this.generateSandboxProfile(); const sandboxedCommand = `sandbox-exec -p '${profile}' ${command}`; return yield* this.executeCommand(sandboxedCommand, execOptions, context); } yield* this.executeCommand(command, execOptions, context); }, async *executeCommand(command, options, context) { const startTime = Date.now(); const child = spawn('bash', ['-c', command], options); let stdout = ''; let stderr = ''; let outputSize = 0; const MAX_OUTPUT = 1024 * 1024; child.stdout.on('data', (chunk) => { const text = chunk.toString(); stdout += text; outputSize += chunk.length; if (outputSize < MAX_OUTPUT) { context.yieldProgress({ type: 'stdout', data: text, partial: true }); } }); child.stderr.on('data', (chunk) => { const text = chunk.toString(); stderr += text; outputSize += chunk.length; if (outputSize < MAX_OUTPUT) { context.yieldProgress({ type: 'stderr', data: text, partial: true }); } }); const result = await new Promise((resolve, reject) => { child.on('error', reject); child.on('exit', (code, signal) => { resolve({ exitCode: code, signal, stdout: stdout.substring(0, MAX_OUTPUT), stderr: stderr.substring(0, MAX_OUTPUT), truncated: outputSize > MAX_OUTPUT, duration: Date.now() - startTime }); }); context.abortController.signal.addEventListener('abort', () => { child.kill('SIGTERM'); }); }); yield { type: 'result', data: result }; }, generateSandboxProfile(): string { return ` (version 1) (deny default) (allow process-exec (literal "/bin/bash")) (allow process-exec (literal "/usr/bin/env")) (allow file-read*) (deny file-write*) (deny network*) (allow sysctl-read) `; }, async *handleGitCommit(args, context) { const [status, diff, log] = await Promise.all([ this.runCommand('git status --porcelain'), this.runCommand('git diff --cached'), this.runCommand('git log -5 --oneline') ]); yield { type: 'progress', toolUseID: context.currentToolUseId, data: { status: 'Analyzing changes...', files: status.split('\\n').length - 1 } }; const commitAnalysis = await this.analyzeChangesForCommit( status, diff, context ); const commitCommand = `git commit -m "$(cat <<'EOF' ${commitAnalysis.message} Co-authored-by: Claude claude@anthropic.com EOF )"`; yield* this.executeCommand(commitCommand, {}, context); }, mapToolResultToToolResultBlockParam(result, toolUseId) { const output = []; if (result.stdout) { output.push(`stdout:\\n${result.stdout}`); } if (result.stderr) { output.push(`stderr:\\n${result.stderr}`); } output.push(`Exit code: ${result.exitCode}`); if (result.truncated) { output.push('\\n(Output truncated due to size limits)'); } return [{ type: 'text', text: output.join('\\n\\n') }]; }, isReadOnly: false };

Accueil - Wiki
Copyright © 2011-2025 iteam. Current version is 2.144.0. UTC+08:00, 2025-06-07 07:30
浙ICP备14020137号-1 $Carte des visiteurs$