fix(stage-tamagotchi): add renewable click-through lease for window interactivity - #2455
Conversation
…nteractivity Split from moeru-ai#2278. When the renderer sets click-through mode (setIgnoreMouseEvents(true)), a crashed, unresponsive, or navigating renderer previously left the main window permanently unclickable, because nothing restored input on the main-process side. createWindowService now tracks a renewable lease: the renderer must keep invoking setIgnoreMouseEvents(true) periodically (via the new useWindowInteractivityLease composable) or the main process restores mouse input automatically after 2s. It also restores input immediately on 'closed', 'render-process-gone', 'unresponsive', and 'did-start-navigation'. Windows that manage their own click-through state outside this flow (caption, desktop-overlay) opt out via `manageWindowInteractivity: false` so navigation recovery doesn't fight their explicit state. Also simplifies `withHashRoute()` by dropping the unused `query` option and removes a `did-start-navigation` listener cleanup in `location.ts` that fought the new window-level listener registered above. Rebased onto current main: kept moeru-ai#2288's `setWindowAlwaysOnTop` helper in `windows/shared/window.ts` and its use in caption window setup rather than the direct `setAlwaysOnTop` calls from the original branch, since the helper already handles per-platform always-on-top levels. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8f33b4926
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| import { resizeWindowByDelta, setWindowAlwaysOnTop } from '../../windows/shared/window' | ||
|
|
||
| export function createWindowService(params: { context: ReturnType<typeof createContext>['context'], window: BrowserWindow }) { | ||
| const mouseInputLeaseDuration = 2000 |
There was a problem hiding this comment.
Document the lease timing relationship
mouseInputLeaseDuration and the renderer's mouseInputLeaseRenewInterval form one cross-process timing contract, but neither constant documents that renewals must precede expiration. If either value changes independently, click-through can expire between heartbeats and make the window intercept clicks. Document the relationship beside both constants, or define it once in a shared contract.
AGENTS.md reference: AGENTS.md:L317-L319
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 618c25a: documented the cross-process timing contract at both constants (mouseInputLeaseDuration in window.ts, mouseInputLeaseRenewInterval in the composable), noting renewal must happen strictly more often than expiration.
⏳ Approval required for deploying to Cloudflare Workers (Preview) for stage-web.
Hey, maintainers, kindly take some time to review and approve this deployment when you are available. Thank you! 🙏 |
… contract mouseInputLeaseDuration (main) and mouseInputLeaseRenewInterval (renderer) form one timing contract, but neither constant documented that renewal must happen strictly more often than expiration. Changing either value independently could let click-through lapse between renewals and make the window intercept clicks it should pass through. Addresses Codex review feedback on moeru-ai#2455. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Split off #2278 per maintainer feedback ("Too big, split.").
setIgnoreMouseEvents(true)), a crashed, unresponsive, or navigating renderer previously left the main window permanently unclickable, because nothing restored input on the main-process side.createWindowServicenow tracks a renewable lease: the renderer must keep invokingsetIgnoreMouseEvents(true)periodically (via the newuseWindowInteractivityLeasecomposable) or the main process restores mouse input automatically after 2s. It also restores input immediately onclosed,render-process-gone,unresponsive, anddid-start-navigation.manageWindowInteractivity: falseso navigation recovery doesn't fight their explicit state.withHashRoute()by dropping the unusedqueryoption, and removes adid-start-navigationlistener cleanup inlocation.tsthat fought the new window-level listener.Rebased onto current
main: kept #2288'ssetWindowAlwaysOnTophelper inwindows/shared/window.tsand its use in caption window setup rather than the directsetAlwaysOnTopcalls from the original branch, since the helper already handles per-platform always-on-top levels.Test plan
pnpm -F @proj-airi/stage-tamagotchi typecheckpnpm exec eslinton the touched filespnpm -F @proj-airi/stage-tamagotchi exec vitest runonlocation.test.ts,caption/index.test.ts,use-window-interactivity-lease.test.ts,window-interactivity.test.ts(15 passed)🤖 Generated with Claude Code