fix: Convert sync file I/O to async in agent spawn path to unblock event loop
writeInputFiles, spawnDetached, and diagnostic writes now use fs/promises (mkdir, writeFile) instead of mkdirSync/writeFileSync. File writes in writeInputFiles are batched with Promise.all. openSync/closeSync for child process stdio FDs remain sync as spawn() requires the FDs immediately.
This commit is contained in:
@@ -57,7 +57,7 @@ export class CassetteProcessManager extends ProcessManager {
|
||||
this.replayWorkerPath = new URL('./replay-worker.mjs', import.meta.url).pathname;
|
||||
}
|
||||
|
||||
override spawnDetached(
|
||||
override async spawnDetached(
|
||||
agentId: string,
|
||||
agentName: string,
|
||||
command: string,
|
||||
@@ -68,7 +68,7 @@ export class CassetteProcessManager extends ProcessManager {
|
||||
prompt?: string,
|
||||
onEvent?: (event: StreamEvent) => void,
|
||||
onRawContent?: (content: string) => void,
|
||||
): { pid: number; outputFilePath: string; tailer: FileTailer } {
|
||||
): Promise<{ pid: number; outputFilePath: string; tailer: FileTailer }> {
|
||||
const key: CassetteKey = {
|
||||
normalizedPrompt: normalizePrompt(prompt ?? '', this._workspaceRoot),
|
||||
providerName,
|
||||
@@ -80,7 +80,7 @@ export class CassetteProcessManager extends ProcessManager {
|
||||
const existing = this.cassetteMode !== 'record' ? this.store.find(key) : null;
|
||||
|
||||
if (existing) {
|
||||
const result = this.replayFromCassette(agentId, agentName, cwd, env, providerName, existing, onEvent, onRawContent);
|
||||
const result = await this.replayFromCassette(agentId, agentName, cwd, env, providerName, existing, onEvent, onRawContent);
|
||||
this.pendingReplays.set(result.pid, { cassette: existing, agentCwd: cwd });
|
||||
return result;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export class CassetteProcessManager extends ProcessManager {
|
||||
|
||||
// auto or record: run the real agent and record the cassette on completion.
|
||||
console.log(`[cassette] recording new cassette for agent '${agentName}' (${providerName})`);
|
||||
const result = super.spawnDetached(agentId, agentName, command, args, cwd, env, providerName, prompt, onEvent, onRawContent);
|
||||
const result = await super.spawnDetached(agentId, agentName, command, args, cwd, env, providerName, prompt, onEvent, onRawContent);
|
||||
this.pendingRecordings.set(result.pid, { key, outputFilePath: result.outputFilePath, agentCwd: cwd });
|
||||
return result;
|
||||
}
|
||||
@@ -230,7 +230,7 @@ export class CassetteProcessManager extends ProcessManager {
|
||||
}
|
||||
}
|
||||
|
||||
private replayFromCassette(
|
||||
private async replayFromCassette(
|
||||
agentId: string,
|
||||
agentName: string,
|
||||
cwd: string,
|
||||
@@ -239,7 +239,7 @@ export class CassetteProcessManager extends ProcessManager {
|
||||
cassette: CassetteEntry,
|
||||
onEvent?: (event: StreamEvent) => void,
|
||||
onRawContent?: (content: string) => void,
|
||||
): { pid: number; outputFilePath: string; tailer: FileTailer } {
|
||||
): Promise<{ pid: number; outputFilePath: string; tailer: FileTailer }> {
|
||||
console.log(`[cassette] replaying cassette for agent '${agentName}' (${cassette.recording.jsonlLines.length} lines)`);
|
||||
|
||||
return super.spawnDetached(
|
||||
|
||||
Reference in New Issue
Block a user