Repository navigation
Conversation
Dock > Quit, AppleScript quit and logout send kAEQuitApplication, which AppKit answers with terminate: on the spot. tao has no applicationShouldTerminate:, so ExitRequested never fires: running agents are killed without the busy-turn prompt and nothing the ⌘Q path saves first is saved. Install a handler for the event after launch that calls window::request_quit instead.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: 🔵 Low · up to
|
What changed
On macOS, quitting from the Dock (right-click > Quit), from AppleScript (
osascript -e 'quit app "MonoCode"'), or at logout / restart now goes through the same quit flow as ⌘Q: the busy-turn prompt when agents are running, and the workspace save before exit.src-tauri/src/macos.rs: newroute_quit_event(). It installs a handler for the core Quit Apple Event ('aevt'/'quit') withNSAppleEventManager; the handler callswindow::request_quit. The handler object is kept alive in athread_local, the same wayDockMenuTargetis, because the event manager does not retain it.src-tauri/src/lib.rs: call it fromRunEvent::Ready, next torequest_badge_authorization.Why
⌘Q, the tray's Quit and
app.exit()all reachwindow::request_quit: the app menu's Quit is a custom item (menu.rs,"quit" => crate::window::request_quit(app)), andRunEvent::ExitRequestedwith an exit code calls it too. That function polls every window for running turns, asks once if anything is busy, waits for each window to persist its workspace (quit_commit/quit_ready), and only then callsconfirm_quit.The Quit Apple Event never reaches any of that. The Dock, AppleScript and loginwindow all send
kAEQuitApplication, and AppKit's default handler for it calls-[NSApplication terminate:]directly. tao's app delegate does not implementapplicationShouldTerminate:, so nothing can say no: AppKit goes straight toapplicationWillTerminate:, which tao turns intoLoopDestroyed→RunEvent::Exit.ExitRequestedis never emitted, soprevent_exit()andrequest_quitnever run.RunEvent::Exitreaps the harness and PTY children, so running agents are killed without the prompt, and the windows never getquit_commit, so whatever the ⌘Q path would have saved first is lost.Neither tauri nor tao exposes a hook for this (no
applicationShouldTerminate:, no Apple Event callback), so the handler is installed directly. Two details:finishLaunching, andsetEventHandler:replaces whatever was registered before, so a handler set insetupwould be overwritten.RunEvent::Readyis emitted from tao'sapplicationDidFinishLaunching:, which is after that.request_quit.Behaviour at logout / restart: the handler returns right away, and the app quits once the normal flow finishes. With nothing running that is the poll (≤ 2 s) plus the commit (≤ 10 s,
COMMIT_TIMEOUT), thenconfirm_quitexits. With a turn running the app shows the same "agents are still running" dialog as ⌘Q and stays open until it is answered; if it is never answered, macOS cancels the logout and names the app, as it does for any app with an unsaved-changes prompt. The app does not hang:CONFIRM_TIMEOUTabandons the unanswered quit and a later Quit starts a fresh one.Related: #1012 also deals with state lost at macOS restart (it saves window geometry on move/resize). It touches a different arm of the
RunEventmatch and does not conflict; with this change, logout also reachesconfirm_quit→app.exit, so the window-state plugin's exit save runs too.UI
No visual change. Dock > Quit and
osascript … quitnow show the same quit confirmation as ⌘Q when agents are running.Validation
In
src-tauri:cargo fmt --check: cleancargo clippy --workspace --all-targets -- -D warnings: cleancargo test: 655 passed, 1 ignored. (On one earlier runharness::tests::omp_accepts_rpc_capable_binary_and_rejects_other_namesfailed; it passes on its own on unmodifiedmainand on the rerun, and this change does not touchharness.rs.)No unit test: the change is Objective-C glue that only does something when AppKit dispatches a real Apple Event, and
request_quit's state machine already has its own tests inwindow.rs.Checked by hand on macOS in a downstream fork that carries the same code: Dock > Quit and
osascript -e 'quit app "…"'both go through the same flow as ⌘Q (the busy-turn prompt when a turn is running, quitting without a prompt when idle), and the live transcripts are saved. I did not test logout / restart by hand; the behaviour described above comes from reading the code.Checklist
npm run check(check:rust; no web files changed)Summary by CodeRabbit