(
signal: AbortSignal,
updateOutput?: (output: string) => void,
)
| 96 | } |
| 97 | |
| 98 | async execute( |
| 99 | signal: AbortSignal, |
| 100 | updateOutput?: (output: string) => void, |
| 101 | ): Promise<ToolResult> { |
| 102 | const strippedCommand = stripShellWrapper(this.params.command); |
| 103 | |
| 104 | if (signal.aborted) { |
| 105 | return { |
| 106 | llmContent: 'Command was cancelled by user before it could start.', |
| 107 | returnDisplay: 'Command cancelled by user.', |
| 108 | }; |
| 109 | } |
| 110 | |
| 111 | const isWindows = os.platform() === 'win32'; |
| 112 | const tempFileName = `shell_pgrep_${crypto |
| 113 | .randomBytes(6) |
| 114 | .toString('hex')}.tmp`; |
| 115 | const tempFilePath = path.join(os.tmpdir(), tempFileName); |
| 116 | |
| 117 | try { |
| 118 | // pgrep is not available on Windows, so we can't get background PIDs |
| 119 | const commandToExecute = isWindows |
| 120 | ? strippedCommand |
| 121 | : (() => { |
| 122 | // wrap command to append subprocess pids (via pgrep) to temporary file |
| 123 | let command = strippedCommand.trim(); |
| 124 | if (!command.endsWith('&')) command += ';'; |
| 125 | return `{ ${command} }; __code=$?; pgrep -g 0 >${tempFilePath} 2>&1; exit $__code;`; |
| 126 | })(); |
| 127 | |
| 128 | const cwd = path.resolve( |
| 129 | this.config.getTargetDir(), |
| 130 | this.params.directory || '', |
| 131 | ); |
| 132 | |
| 133 | let cumulativeStdout = ''; |
| 134 | let cumulativeStderr = ''; |
| 135 | |
| 136 | let lastUpdateTime = Date.now(); |
| 137 | let isBinaryStream = false; |
| 138 | |
| 139 | const { result: resultPromise } = ShellExecutionService.execute( |
| 140 | commandToExecute, |
| 141 | cwd, |
| 142 | (event: ShellOutputEvent) => { |
| 143 | if (!updateOutput) { |
| 144 | return; |
| 145 | } |
| 146 | |
| 147 | let currentDisplayOutput = ''; |
| 148 | let shouldUpdate = false; |
| 149 | |
| 150 | switch (event.type) { |
| 151 | case 'data': |
| 152 | if (isBinaryStream) break; // Don't process text if we are in binary mode |
| 153 | if (event.stream === 'stdout') { |
| 154 | cumulativeStdout += event.chunk; |
| 155 | } else { |
nothing calls this directly
no test coverage detected