(command, args, options = {})
| 152 | } |
| 153 | |
| 154 | export function spawnCapture(command, args, options = {}) { |
| 155 | return new Promise((resolve, reject) => { |
| 156 | const child = spawn(command, args, { |
| 157 | cwd: options.cwd, |
| 158 | shell: false, |
| 159 | stdio: ['pipe', 'pipe', 'pipe'], |
| 160 | }); |
| 161 | let stdout = ''; |
| 162 | let stderr = ''; |
| 163 | const timer = options.timeoutMs |
| 164 | ? setTimeout(() => { |
| 165 | child.kill('SIGTERM'); |
| 166 | reject(new Error(`Command timed out: ${command} ${args.join(' ')}`)); |
| 167 | }, options.timeoutMs) |
| 168 | : null; |
| 169 | child.stdout.on('data', (chunk) => { |
| 170 | stdout += chunk.toString(); |
| 171 | }); |
| 172 | child.stderr.on('data', (chunk) => { |
| 173 | stderr += chunk.toString(); |
| 174 | }); |
| 175 | child.on('error', (error) => { |
| 176 | if (timer) clearTimeout(timer); |
| 177 | reject(error); |
| 178 | }); |
| 179 | child.on('close', (exitCode) => { |
| 180 | if (timer) clearTimeout(timer); |
| 181 | if (exitCode !== 0 && !options.allowFailure) { |
| 182 | reject(new Error(`${command} exited ${exitCode}\n${stderr}`)); |
| 183 | return; |
| 184 | } |
| 185 | resolve({ stdout, stderr, exitCode }); |
| 186 | }); |
| 187 | if (options.input) child.stdin.end(options.input); |
| 188 | else child.stdin.end(); |
| 189 | }); |
| 190 | } |
| 191 | |
| 192 | /** |
| 193 | * Parse Claude Code JSON output (--output-format json). |
no outgoing calls
no test coverage detected