(workspaceDir, input, confirmShellCommand)
| 298 | } |
| 299 | |
| 300 | async function runShellCommand(workspaceDir, input, confirmShellCommand) { |
| 301 | if (typeof input.command !== 'string' || !input.command.trim()) { |
| 302 | throw new Error('shell_command requires a command') |
| 303 | } |
| 304 | |
| 305 | const timeoutMs = |
| 306 | Number.isInteger(input.timeout_ms) && input.timeout_ms > 0 |
| 307 | ? Math.min(input.timeout_ms, 300000) |
| 308 | : 30000 |
| 309 | |
| 310 | const approved = await confirmShellCommand(input.command) |
| 311 | if (!approved) { |
| 312 | return { |
| 313 | ok: false, |
| 314 | approved: false, |
| 315 | error: 'Shell command was not approved', |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | try { |
| 320 | const { stdout, stderr } = await execFileAsync( |
| 321 | 'powershell.exe', |
| 322 | ['-NoProfile', '-Command', input.command], |
| 323 | { |
| 324 | cwd: workspaceDir, |
| 325 | timeout: timeoutMs, |
| 326 | windowsHide: true, |
| 327 | maxBuffer: 1024 * 1024, |
| 328 | }, |
| 329 | ) |
| 330 | |
| 331 | return { |
| 332 | ok: true, |
| 333 | approved: true, |
| 334 | exitCode: 0, |
| 335 | stdout: truncateText(stdout), |
| 336 | stderr: truncateText(stderr), |
| 337 | } |
| 338 | } catch (error) { |
| 339 | return { |
| 340 | ok: false, |
| 341 | approved: true, |
| 342 | exitCode: error?.code ?? null, |
| 343 | stdout: truncateText(error?.stdout || ''), |
| 344 | stderr: truncateText(error?.stderr || error?.message || ''), |
| 345 | timedOut: Boolean(error?.killed), |
| 346 | } |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | async function walkFiles(rootDir, visitFile) { |
| 351 | const stack = [rootDir] |
no test coverage detected