Skip to content

Commit 66c4638

Browse files
committed
fix(gemini-adapter): handle stdout close events
Addressed the Gemini CLI streaming regression where readline could emit a close event without any lines, leaving iterators waiting forever. Added a close handler that emits cancelled/error metadata for aborted runs and always pushes the DONE sentinel before cleanup detaches the listener, and updated the spawn cleanup helper to remove the new handler safely. Verified via npm run test --workspace examples.
1 parent 5d3ec46 commit 66c4638

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

packages/gemini-adapter/src/index.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,22 @@ export class GeminiAdapter implements HeadlessCoder {
247247
}
248248
};
249249
rl.on('line', handleLine);
250+
const handleClose = () => {
251+
if (finished) return;
252+
finished = true;
253+
if (active.aborted) {
254+
const reason = active.abortReason ?? 'Interrupted';
255+
push({
256+
type: 'cancelled',
257+
provider: CODER_NAME,
258+
ts: now(),
259+
originalItem: { reason },
260+
});
261+
push(interruptedErrorEvent(reason));
262+
}
263+
push(DONE);
264+
};
265+
rl.once('close', handleClose);
250266

251267
const onExit = (code: number | null) => {
252268
if (finished) return;
@@ -287,7 +303,7 @@ export class GeminiAdapter implements HeadlessCoder {
287303
yield entry;
288304
}
289305
} finally {
290-
cleanup(handleLine, rl);
306+
cleanup(handleLine, rl, handleClose);
291307
if (!finished && !active.aborted) {
292308
this.abortChild(state, 'Stream closed');
293309
}
@@ -363,11 +379,18 @@ export class GeminiAdapter implements HeadlessCoder {
363379
return {
364380
child,
365381
active,
366-
cleanup: (lineHandler?: (line: string) => void, rl?: readline.Interface) => {
382+
cleanup: (
383+
lineHandler?: (line: string) => void,
384+
rl?: readline.Interface,
385+
closeHandler?: () => void,
386+
) => {
367387
stopExternal();
368388
this.clearKillTimers(active);
369389
if (lineHandler && rl) {
370390
rl.off('line', lineHandler);
391+
if (closeHandler) {
392+
rl.off('close', closeHandler);
393+
}
371394
rl.close();
372395
}
373396
destroyChildStreams(child);

0 commit comments

Comments
 (0)