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:
@@ -43,7 +43,7 @@ describe('generateId', () => {
|
||||
});
|
||||
|
||||
describe('writeInputFiles', () => {
|
||||
it('writes initiative.md with frontmatter', () => {
|
||||
it('writes initiative.md with frontmatter', async () => {
|
||||
const initiative: Initiative = {
|
||||
id: 'init-1',
|
||||
name: 'Test Initiative',
|
||||
@@ -55,13 +55,13 @@ describe('writeInputFiles', () => {
|
||||
updatedAt: new Date('2026-01-02'),
|
||||
};
|
||||
|
||||
writeInputFiles({ agentWorkdir: testDir, initiative });
|
||||
await writeInputFiles({ agentWorkdir: testDir, initiative });
|
||||
|
||||
const filePath = join(testDir, '.cw', 'input', 'initiative.md');
|
||||
expect(existsSync(filePath)).toBe(true);
|
||||
});
|
||||
|
||||
it('writes phase.md with frontmatter', () => {
|
||||
it('writes phase.md with frontmatter', async () => {
|
||||
const phase = {
|
||||
id: 'phase-1',
|
||||
initiativeId: 'init-1',
|
||||
@@ -73,13 +73,13 @@ describe('writeInputFiles', () => {
|
||||
updatedAt: new Date(),
|
||||
} as Phase;
|
||||
|
||||
writeInputFiles({ agentWorkdir: testDir, phase });
|
||||
await writeInputFiles({ agentWorkdir: testDir, phase });
|
||||
|
||||
const filePath = join(testDir, '.cw', 'input', 'phase.md');
|
||||
expect(existsSync(filePath)).toBe(true);
|
||||
});
|
||||
|
||||
it('writes task.md with frontmatter', () => {
|
||||
it('writes task.md with frontmatter', async () => {
|
||||
const task = {
|
||||
id: 'task-1',
|
||||
name: 'Test Task',
|
||||
@@ -93,14 +93,14 @@ describe('writeInputFiles', () => {
|
||||
updatedAt: new Date(),
|
||||
} as Task;
|
||||
|
||||
writeInputFiles({ agentWorkdir: testDir, task });
|
||||
await writeInputFiles({ agentWorkdir: testDir, task });
|
||||
|
||||
const filePath = join(testDir, '.cw', 'input', 'task.md');
|
||||
expect(existsSync(filePath)).toBe(true);
|
||||
});
|
||||
|
||||
it('writes pages to pages/ subdirectory', () => {
|
||||
writeInputFiles({
|
||||
it('writes pages to pages/ subdirectory', async () => {
|
||||
await writeInputFiles({
|
||||
agentWorkdir: testDir,
|
||||
pages: [
|
||||
{ id: 'page-1', parentPageId: null, title: 'Root', content: null, sortOrder: 0 },
|
||||
@@ -112,13 +112,13 @@ describe('writeInputFiles', () => {
|
||||
expect(existsSync(join(testDir, '.cw', 'input', 'pages', 'page-2.md'))).toBe(true);
|
||||
});
|
||||
|
||||
it('handles empty options without error', () => {
|
||||
writeInputFiles({ agentWorkdir: testDir });
|
||||
it('handles empty options without error', async () => {
|
||||
await writeInputFiles({ agentWorkdir: testDir });
|
||||
expect(existsSync(join(testDir, '.cw', 'input'))).toBe(true);
|
||||
});
|
||||
|
||||
it('writes context/index.json grouping tasks by phaseId', () => {
|
||||
writeInputFiles({
|
||||
it('writes context/index.json grouping tasks by phaseId', async () => {
|
||||
await writeInputFiles({
|
||||
agentWorkdir: testDir,
|
||||
tasks: [
|
||||
{ id: 't1', name: 'Task A', phaseId: 'ph1', status: 'pending', category: 'execute', type: 'auto', priority: 'medium' } as Task,
|
||||
@@ -140,8 +140,8 @@ describe('writeInputFiles', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('does not write context/index.json when no tasks', () => {
|
||||
writeInputFiles({ agentWorkdir: testDir });
|
||||
it('does not write context/index.json when no tasks', async () => {
|
||||
await writeInputFiles({ agentWorkdir: testDir });
|
||||
expect(existsSync(join(testDir, '.cw', 'input', 'context', 'index.json'))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user