Repository navigation
fix(hooks): prevent SessionEnd from firing twice in non-interactive mode - #22139
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a bug where the SessionEnd hook was inadvertently triggered twice during the termination of non-interactive sessions. By removing a duplicate registration, the change ensures that session cleanup processes are executed precisely once, leading to more predictable and correct application behavior, particularly in automated or script-driven environments. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request addresses a bug where the SessionEnd hook was firing twice in non-interactive mode. The cause was a duplicate registration of the cleanup hook in the non-interactive code path, while a general registration already existed for both modes. The change correctly removes this redundant registration. The fix is straightforward and effectively resolves the issue. I have no further comments or suggestions.
|
/assign |
|
Hi, thank you for this PR can you add tests please |
421e394 to
f4ca4d0
Compare
|
@Adib234 Added a unit test in gemini_cleanup.test.tsx that verifies registerCleanup is called exactly once for SessionEnd in non-interactive mode. Also rebased onto upstream/main so the branch is clean. Let me know if anything else is needed. |
6c8b74d to
e348c38
Compare
|
@Adib234 All review comments addressed in the latest commits. Tests pass locally ( |
Head branch was pushed to by a user without write access
0032c54 to
f142f00
Compare
|
@Adib234, rebased onto main, branch is clean (3 commits, 0 behind upstream). Could you re-enable auto-merge and help get a code owner to approve CI workflows? The bot and all checks are good, just needs maintainer sign-off. |
|
Can you show logs that show that SessionEnd is not fired twice in non-interactive mode? |
…ode (google-gemini#18019) The shared initialization block in main() registered a SessionEnd cleanup at line 616 for all modes. The non-interactive path then registered a second identical cleanup at line 798, causing fireSessionEndEvent to fire twice on exit. Interactive mode was unaffected (it returns before reaching line 798). Fix: remove the duplicate registration in the non-interactive path. The shared registration at line 616 already covers both modes. Fixes google-gemini#18019
f142f00 to
13685f7
Compare
|
@Adib234, Both items addressed. 1. TypeScript fix pushed Added 2. Proof that SessionEnd fires exactly once The unit test directly asserts this at the code level: How it works: mocks Local run confirming it passes: ![vitest output showing ✓ should register SessionEnd hook exactly once in non-interactive mode 13ms] Could you re-enable auto-merge and approve the 3 pending CI workflows? |
|
@Adib234 The E2E failure is macOS-specific, E2E Test (Linux) sandbox:none and sandbox:docker both passed cleanly in the same run. This PR only modifies TypeScript logic in gemini.tsx (a duplicate cleanup registration removal) with zero OS-specific code paths, so a macOS-only failure is almost certainly a pre-existing flake. Could you re-trigger the E2E? All other 25 checks pass. |
…ode (#22139) Co-authored-by: Tommaso Sciortino <[email protected]>
…ode (#22139) Co-authored-by: Tommaso Sciortino <[email protected]>
…ode (google-gemini#22139) Co-authored-by: Tommaso Sciortino <[email protected]>
…ode (google-gemini#22139) Co-authored-by: Tommaso Sciortino <[email protected]>

Summary
Removes a duplicate
SessionEndhook registration ingemini.tsxthat caused the hook to fire twice when exiting non-interactive mode.Details
main()registered aSessionEndcleanup in the shared initialization block, which runs for both interactive and non-interactive modes. The non-interactive path then registered an identical second cleanup, causingfireSessionEndEventto fire twice on exit.Interactive mode was unaffected, it calls
startInteractiveUI()and returns before reaching the duplicate registration.Related Issues
Fixes #18019
How to Validate
Configure a
SessionEndhook command and run gemini in non-interactive mode (e.g.echo "hello" | gemini). Verify the hook fires exactly once on exit.Run unit tests: npx vitest run packages/cli/src/gemini_cleanup.test.tsx
Pre-Merge Checklist