diff --git a/integration-tests/run_shell_command_file_stream.test.ts b/integration-tests/run_shell_command_file_stream.test.ts index 9fbea9499d..69a608eb71 100644 --- a/integration-tests/run_shell_command_file_stream.test.ts +++ b/integration-tests/run_shell_command_file_stream.test.ts @@ -50,25 +50,27 @@ describe('run_shell_command streaming to file regression', () => { let savedFilePath = ''; const tmpdir = path.join(rig.homeDir!, '.gemini', 'tmp'); if (fs.existsSync(tmpdir)) { - const files = fs.readdirSync(tmpdir, { - recursive: true, - withFileTypes: true, - }); - for (const file of files) { - if (file.isFile() && file.name.endsWith('.txt')) { - // In Node 20+, recursive readdir returns Dirent objects where `parentPath` is the directory path, - // but sometimes `path` is used in older Node. fallback: - const parentDir = - (file as { parentPath?: string }).parentPath ?? - (file as { path?: string }).path ?? - tmpdir; - const p = path.join(parentDir, file.name); - const stat = fs.statSync(p); - if (Date.now() - stat.mtimeMs < 60000 && stat.size >= 20000000) { - savedFilePath = p; - break; + const findFiles = (dir: string): string[] => { + let results: string[] = []; + const list = fs.readdirSync(dir, { withFileTypes: true }); + for (const file of list) { + const fullPath = path.join(dir, file.name); + if (file.isDirectory()) { + results = results.concat(findFiles(fullPath)); + } else if (file.isFile() && file.name.endsWith('.txt')) { + results.push(fullPath); } } + return results; + }; + + const files = findFiles(tmpdir); + for (const p of files) { + const stat = fs.statSync(p); + if (Date.now() - stat.mtimeMs < 60000 && stat.size >= 20000000) { + savedFilePath = p; + break; + } } } @@ -117,24 +119,36 @@ describe('run_shell_command streaming to file regression', () => { let savedFilePath = ''; const tmpdir = path.join(rig.homeDir!, '.gemini', 'tmp'); if (fs.existsSync(tmpdir)) { - const files = fs.readdirSync(tmpdir, { - recursive: true, - withFileTypes: true, - }); - for (const file of files) { - if (file.isFile() && file.name.endsWith('.txt')) { - const parentDir = - (file as { parentPath?: string }).parentPath ?? - (file as { path?: string }).path ?? - tmpdir; - const p = path.join(parentDir, file.name); - const stat = fs.statSync(p); - // Look for file >= 20MB (since we expect 50MB, but allowing margin for the bug) - if (Date.now() - stat.mtimeMs < 60000 && stat.size >= 20000000) { - savedFilePath = p; - break; + const findFiles = (dir: string): string[] => { + let results: string[] = []; + const list = fs.readdirSync(dir, { withFileTypes: true }); + for (const file of list) { + const fullPath = path.join(dir, file.name); + if (file.isDirectory()) { + results = results.concat(findFiles(fullPath)); + } else if (file.isFile() && file.name.endsWith('.txt')) { + results.push(fullPath); } } + return results; + }; + + const files = findFiles(tmpdir); + const fileStats = files.map((p) => ({ + p, + size: fs.statSync(p).size, + age: Date.now() - fs.statSync(p).mtimeMs, + })); + for (const p of files) { + const stat = fs.statSync(p); + // Look for file >= 20MB (since we expect 50MB, but allowing margin for the bug) + if (Date.now() - stat.mtimeMs < 60000 && stat.size >= 20000000) { + savedFilePath = p; + break; + } + } + if (!savedFilePath) { + console.error('Available files:', JSON.stringify(fileStats, null, 2)); } } diff --git a/packages/core/src/services/shellExecutionService.ts b/packages/core/src/services/shellExecutionService.ts index c2697a19ac..090bce19f3 100644 --- a/packages/core/src/services/shellExecutionService.ts +++ b/packages/core/src/services/shellExecutionService.ts @@ -899,7 +899,7 @@ export class ShellExecutionService { abortSignal.addEventListener('abort', abortHandler, { once: true }); - child.on('exit', (code, signal) => { + child.on('close', (code, signal) => { handleExit(code, signal); });