Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 5x 5x 5x 75x 75x 75x 75x 2x 75x 74x 75x 75x 75x 75x 74x 63x 75x 74x 8x 75x 5x 5x 5x 4x 4x 3x 1x 5x 75x 71x 71x 75x 2x 2x | import { Injectable } from '@nestjs/common';
import { spawn, ChildProcess } from 'child_process';
export interface IProcessResult {
exitCode: number | null;
stdout: string;
stderr: string;
timedOut: boolean;
}
@Injectable()
export class ProcessRunnerService {
async runProcess(
command: string,
args: string[],
cwd: string,
timeoutMs: number
): Promise<IProcessResult> {
return new Promise((resolve) => {
// With shell: true, pass the full command as a single string
// If args are provided, join them; otherwise use command as-is
const shellCommand = args.length > 0
? `${command} ${args.join(' ')}`
: command;
// Explicitly wrap in sh -c to ensure shell interpretation
// This ensures pipes and other shell operators are properly interpreted
const childProcess: ChildProcess = spawn(
'sh',
[ '-c', shellCommand ],
{
cwd,
// We're explicitly invoking sh, so no need for shell: true
shell: false,
detached: false
}
);
if (process.env.PROCESS_RUNNER_DEBUG === 'true') {
// eslint-disable-next-line no-console
console.log(
`[ProcessRunner] spawn command="${shellCommand}" cwd="${cwd}"`
);
}
// Close stdin so commands expecting EOF when run without a TTY
// (like cursor-agent in non-interactive mode) can exit gracefully.
if (childProcess.stdin) {
childProcess.stdin.end();
}
let stdout = '';
let stderr = '';
let timedOut = false;
if (childProcess.stdout) {
childProcess.stdout.on('data', (data) => {
stdout += data.toString();
});
}
if (childProcess.stderr) {
childProcess.stderr.on('data', (data) => {
stderr += data.toString();
});
}
const timeout = setTimeout(() => {
timedOut = true;
// Kill the process group to ensure all children are terminated
try {
if (childProcess.pid) {
childProcess.kill('SIGTERM');
// Give it a moment, then force kill
setTimeout(() => {
if (!childProcess.killed) {
childProcess.kill('SIGKILL');
}
}, 1000);
}
} catch {
// Ignore kill errors
}
resolve({
exitCode: null,
stdout,
stderr,
timedOut: true
});
}, timeoutMs);
childProcess.on('close', (code) => {
clearTimeout(timeout);
resolve({
exitCode: code,
stdout,
stderr,
timedOut
});
});
childProcess.on('error', () => {
clearTimeout(timeout);
resolve({
exitCode: null,
stdout,
stderr,
timedOut
});
});
});
}
}
|