Repository navigation
shell: a hosted module may refuse a close and ask first (makepad#65) - #186
Merged
Merged
Conversation
makepad#65 gave AppModule a close-veto hook (close_requested -> CloseDecision, ModuleCloseAction::Confirmed). The shell dropped a module instance at once, so closing an in-process Terminal SIGHUPed its running jobs without asking. - request_close asks a live instance first. Allow: torn down as before. Veto: the tile and instance stay, the tile comes to the front so its question shows, and the root's uid is remembered (module_host CloseGate). - A ModuleCloseAction::Confirmed from a pending root's uid tears that instance down; from any other uid it is ignored. A cancel emits nothing. - Quit (the shell menu's Quit, Cmd+Q / QuitRequested, the window's close button) asks every instance and waits while any refuses; it quits when the last one confirms. A termination signal, a crash or a fault never asks. A later close of one app abandons a waiting quit. - A module that panics while answering is contained and let go; a failed instance no longer holds a quit. - The assistant's close tool says the app is asking; a Recents swipe on a refusing app opens it instead of staying on Recents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chrislearn
pushed a commit
to chrislearn/OctoSense
that referenced
this pull request
Oct 8, 2026
) A process client's close sent CloseRequested and Kill back to back, so closing a process Terminal's tile (the macOS default hosting) still ended its running jobs without asking. Stacked on OctoSense-org#186, which did the same for in-process modules. - process_close.rs: a pure close state machine per process client. An app that says WmRequest::AsksBeforeClose (makepad feat/wm-close-refused) is asked with CloseRequested alone; its tile and process stay. Its answer is its own WmRequest::Close (yes: closed at once, without asking back), CloseRefused (it is asking the person: no deadline, the tile comes to the front) or an exit. - Fallback for an app that does not answer: a second close of the same tile while the first is unanswered ends it at once (a repeat within 0.5 s is the same click); left alone it is ended after 5 s. A refusal is never a licence to hang: every close asks again, a live app re-answers at once, a frozen one falls to the fallback. So an app that is visibly asking is never killed, and a hung one is always closable. - An app that never declared closes exactly as before (CloseRequested + Kill, the tile leaves at once), so apps without the new words, and a Terminal from an older makepad, lose nothing. - Shell quit (menu, Cmd+Q, the window's close, /quit) asks declared apps the same way and waits while any module or app is deciding; it goes when the last says yes. A second quit forces unanswered apps. A termination signal or a crash still asks nobody. - The words are read off the wire by their exact text, so this works with the current makepad pin; on_wm_request gains a catch-all arm so a repin to the new variants compiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ymote
added a commit
that referenced
this pull request
Oct 9, 2026
App Hub #186 admits WebAssembly components when the manifest requires wasm-components-v1, validates their imports (only the WASI packages a host scopes to the app) and tells reviewers what each reaches. With the store on it, a component shipped as a system app goes through admission, and the new service test calls it as the app's script would: typed JSON, the instance's state from one request to the next, no folder without storage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 9, 2026
ymote
added a commit
that referenced
this pull request
Oct 10, 2026
App Hub #191 repins App Hub to the same runtime, and with the budget gate gone a runaway app tool handler still fails at once (a captured-error sink catches the per-evaluation limit); net alone hands an isolate its network module. It also brings #186 (components under wasm-components-v1), #188 (wasi:http and octosense:host admission) and Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #185, the makepad
bcb0583brepin. Review and merge that first, then retarget this PR tomain. Part of #179, the Phase 1 item "hosted close path skips the running-job confirmation".Problem
makepad#65 gave
AppModulea close-veto hook:close_requested(cx, root) -> CloseDecisionandModuleCloseAction::Confirmed. The shell still dropped a module instance at once. So closing an in-process Terminal tile, or quitting OctoSense, sent SIGHUP to its running jobs without asking.Design
module_host::CloseGate(owned byModuleHost) tracks each pending close asclient → root widget_uid, plus whether a quit is waiting.ModuleHost::ask_closecallsclose_requestedoutside the isolate undercontain_outside, as the executor calls are. A panic there is contained and treated as Allow.teardownandrelease_failedforget the instance's pending mark.App::request_close, which the tile close button, Super+W, the bar, Alt+F4, the assistant'sclosetool and a Recents swipe all go through:activate_clientso the tile comes to the front with its question. It logsasks before closing.handle_actions: aModuleCloseAction::Confirmedfrom a pending root's uid callsremove_client. A Confirmed from any other uid is ignored. A cancel emits nothing, so nothing changes.Event::QuitRequested(Cmd+Q,/quit) andEvent::WindowCloseRequested(the window's close button,/close) callask_before_quit.shell_handle_eventcallscx.quit()once the last refusing instance confirms, or fails.QuitReason::Signal, a crash and a module fault never ask.closetool answers "asks the person before closing". A Recents swipe on an app that refuses opens that app instead of staying on Recents.Tests
crates/shell/src/module_close_tests.rs, 11 new tests:CloseGate:ModuleHost, with real probe instances:close_requestedis let go.Results:
cd phone && cargo test --locked --features mobile-apps -p octosense-shell: 595 passed (584 + 11).... --features mobile-apps,app-terminal -p octosense-shell terminal: 14 passed.cargo check --locked -p octosense: ok.Instrument evidence (macOS)
The run was
MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8471 octosense --module terminal --test-action launch-terminal, release build, with a tempOCTOSENSE_HOME,OCTOSENSE_APP_DATAandOCTOS_APP_CORE_DIR.sleep 300, then click the tile's close buttonterminal (client 1) asks before closingsleepare still there/quitquit waits: clients [1]/close?w=0{"ok":1,"refused":1}and the same promptclient 1 confirmed its close, thenterminal.1 torn down. The tile is gone,sleephas ended and the shell stays up, because the earlier waiting quit was droppedsleep 301,/quit, then Enterclient 2 confirmed its close, thenevery instance confirmed; quitting. The shell exits andsleephas endedNo panics in the log.
Not covered here
native-apps.jsonhosting). Only--module terminal, or aterminal: Moduleline, hosts it in-process, which is where this change applies.request_closestill sendsWmEvent::CloseRequestedandKillback to back. The process terminal's veto onCloseRequestedis therefore overridden, and its jobs still end without asking. This is the same gap makepad#65 notes for the in-tree WM. Fixing it needs the shell to wait for the app's answer, or for its exit, before it kills. That should be a separate change.🤖 Generated with Claude Code