129 lines
3.6 KiB
JavaScript
129 lines
3.6 KiB
JavaScript
import { spawn } from 'node:child_process';
|
|
|
|
let input = '';
|
|
let held = null;
|
|
let keepAlive = null;
|
|
let descendant = null;
|
|
const counts = Object.create(null);
|
|
|
|
function response(command, data = {}) {
|
|
return JSON.stringify({
|
|
type: 'response',
|
|
id: command.id,
|
|
command: command.type,
|
|
success: true,
|
|
data,
|
|
});
|
|
}
|
|
|
|
function writeRecord(record) {
|
|
process.stdout.write(`${typeof record === 'string' ? record : JSON.stringify(record)}\n`);
|
|
}
|
|
|
|
function handle(command) {
|
|
counts[command.type] = (counts[command.type] ?? 0) + 1;
|
|
if (command.type === 'echo') {
|
|
writeRecord(response(command, { value: command.value }));
|
|
return;
|
|
}
|
|
if (command.type === 'emit_event') {
|
|
writeRecord({ type: 'agent_start', marker: command.marker });
|
|
writeRecord(response(command, { emitted: true }));
|
|
return;
|
|
}
|
|
if (command.type === 'hold') {
|
|
held = command;
|
|
return;
|
|
}
|
|
if (command.type === 'release') {
|
|
writeRecord(response(command, { order: 'first' }));
|
|
if (held) {
|
|
writeRecord(response(held, { order: 'second' }));
|
|
held = null;
|
|
}
|
|
return;
|
|
}
|
|
if (command.type === 'partial') {
|
|
const record = `${response(command, { partial: true })}\n`;
|
|
process.stdout.write(record.slice(0, 7));
|
|
setTimeout(() => process.stdout.write(record.slice(7, 19)), 5);
|
|
setTimeout(() => process.stdout.write(record.slice(19)), 10);
|
|
return;
|
|
}
|
|
if (command.type === 'malformed') {
|
|
process.stdout.write('not-json\n');
|
|
return;
|
|
}
|
|
if (command.type === 'blank') {
|
|
process.stdout.write('\n');
|
|
return;
|
|
}
|
|
if (command.type === 'invalid_utf8') {
|
|
process.stdout.write(Buffer.from([0xff, 0x0a]));
|
|
return;
|
|
}
|
|
if (command.type === 'trailing_partial') {
|
|
process.stdout.write(response(command, { partial: true }));
|
|
setTimeout(() => process.exit(0), 5);
|
|
return;
|
|
}
|
|
if (command.type === 'large') {
|
|
writeRecord(response(command, { value: 'x'.repeat(command.bytes ?? 4096) }));
|
|
return;
|
|
}
|
|
if (command.type === 'get_state' && command.fakeRetry) {
|
|
if (counts.get_state > 1) writeRecord(response(command, { attempts: counts.get_state }));
|
|
return;
|
|
}
|
|
if (command.type === 'no_response' || command.type === 'prompt') return;
|
|
if (command.type === 'stats') {
|
|
writeRecord(response(command, { counts }));
|
|
return;
|
|
}
|
|
if (command.type === 'stderr_secret') {
|
|
const secret = process.env.FAKE_PI_SECRET ?? 'missing-secret';
|
|
process.stderr.write(`${'diagnostic '.repeat(50)}\n`);
|
|
process.stderr.write(`Authorization: Bearer ${secret}\n`);
|
|
process.stderr.write(`token=${secret}\n`);
|
|
writeRecord(response(command, { wrote: true }));
|
|
return;
|
|
}
|
|
if (command.type === 'spawn_descendant') {
|
|
descendant = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)'], {
|
|
stdio: 'ignore',
|
|
windowsHide: true,
|
|
});
|
|
keepAlive = setInterval(() => {}, 1000);
|
|
writeRecord(response(command, { pid: descendant.pid }));
|
|
return;
|
|
}
|
|
if (command.type === 'crash') {
|
|
process.exit(7);
|
|
}
|
|
writeRecord({
|
|
type: 'response',
|
|
id: command.id,
|
|
command: command.type,
|
|
success: false,
|
|
error: 'unsupported fake command',
|
|
});
|
|
}
|
|
|
|
process.stdin.setEncoding('utf8');
|
|
process.stdin.on('data', (chunk) => {
|
|
input += chunk;
|
|
while (true) {
|
|
const newline = input.indexOf('\n');
|
|
if (newline === -1) break;
|
|
const line = input.slice(0, newline).replace(/\r$/, '');
|
|
input = input.slice(newline + 1);
|
|
if (line) handle(JSON.parse(line));
|
|
}
|
|
});
|
|
process.stdin.on('end', () => {
|
|
if (!keepAlive) process.exit(0);
|
|
});
|
|
process.on('exit', () => {
|
|
if (keepAlive) clearInterval(keepAlive);
|
|
});
|