OR-326 Open the dashboard in its own window on Windows - #439
Conversation
The OpenResearch.app now hosts the dashboard in a native window (tao + wry WKWebView) instead of handing it to the user's browser. It adds a standard menu bar, save panels for downloads, a native window.confirm panel, and a Cmd+Q that flushes workspace state and shuts the server down cleanly. Pop-ups open in the system browser (http/https/mailto only). The app now prefers port 4792 so the window's localStorage survives relaunches. The Dock-click tab-focus script, its Apple-events entitlement, and the SSE client counter it relied on are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the Windows desktop app. A small GUI-subsystem OpenResearch.exe (windows/launcher) starts the orx.exe beside it as `orx app` in a hidden console, so orx and the git, shell, and agent processes it runs share one invisible console instead of each flashing a window. `orx app` shares the macOS window code in src/commands/app.rs: WebView2 window, pop-ups to the system browser, save panel, page-load reveal, and port 4792. On Windows, closing the window quits, a second launch focuses the running window (named mutex + event), and the taskbar groups the window with the Start menu shortcut. An update restart relaunches as the app on the same port. Quit on both platforms now goes through up::request_shutdown instead of a self-sent SIGTERM. An Inno Setup script builds a per-user OpenResearch-Setup.exe with a Start menu entry and a WebView2 bootstrap. CI builds it as an artifact, and release-windows-app.yml attaches it to releases once WINDOWS_APP_ENABLED is set. The icon is embedded via embed-resource. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The focus listener captured its bare HANDLE (edition 2021 disjoint capture) instead of the Send wrapper, which failed to compile on Windows. - An orx.exe away from the CLI installer's prefix, like the app's, is now Portable even when the installer's receipt exists, so it can update itself. - Single instance creates its event before the mutex; the launcher hands its foreground rights to orx.exe. - Focus requests and server readiness are ignored while quitting, and focus waits for the first load. The save dialog is owned by the window. - Telemetry counts an app start only after the instance claim. - The installer reports a failed WebView2 bootstrap and shows progress. - Icon embedding now fails the build if no resource compiler is found. - CI format-checks the launcher; the release job drops an unpinned action. - Docs: maintainer notes for the release gate, two known gaps, and wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Keep the macOS save panel free-floating: only Windows gets the window as its owner, since a parent makes rfd show a sheet on macOS. - Treat the WebView2 bootstrap as failed unless the runtime is then present. - Move the UTF-16 helper out of the single-instance module, and bind the kernel object names before the mutex call that GetLastError follows. - Docs and a dead_code reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # Cargo.lock # ui/dist/assets/index-DLDRL7rV.js # ui/dist/assets/index-UAhw--Xc.js # ui/dist/assets/index-yT9oNk64.js # ui/dist/index.html
# Conflicts: # Cargo.lock # Cargo.toml # src/commands/app.rs # src/updates.rs
|
If the dashboard never finishes loading, show the window 15 seconds after the server is up and say so on stderr; a relaunch (or a Dock click on macOS) also shows it before the page loads. The installer and uninstaller now check the app's single-instance mutex and ask the user to close it, rather than replacing files under a running app and skipping its shutdown path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| std::process::Command::new(exe.with_file_name("orx.exe")) | ||
| // WINDOWS_APP_ARG in src/commands/app.rs. | ||
| .arg("app") | ||
| .creation_flags(CREATE_NO_WINDOW) |
There was a problem hiding this comment.
Child consoles can appear. On Windows,
CREATE_NO_WINDOW starts orx.exe without an attached console; it does not create a hidden console for its children to share. When the app starts a console program such as git or an agent without the same flag, that program can open a visible console window. The update-restart spawn has the same exposure.
Prompt To Fix With AI
This is a comment left during a code review.
Path: windows/launcher/src/main.rs
Line: 18
Comment:
**Child consoles can appear.** On Windows, `CREATE_NO_WINDOW` starts `orx.exe` without an attached console; it does not create a hidden console for its children to share. When the app starts a console program such as `git` or an agent without the same flag, that program can open a visible console window. The update-restart spawn has the same exposure.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| Some(chosen) => { | ||
| // WebKit fails a download onto an existing file, and the panel | ||
| // Neither webview writes over an existing file, and the panel | ||
| // has already confirmed replacing it. | ||
| if chosen.exists() && std::fs::remove_file(&chosen).is_err() { | ||
| return false; |
There was a problem hiding this comment.
Download deletes existing file. On Windows, choosing an existing destination removes that file before the WebView saves the replacement. If the download fails or is interrupted, the original is gone too, even though the user only confirmed replacing it. Keep the original until the new download succeeds.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/app.rs
Line: 612-616
Comment:
**Download deletes existing file.** On Windows, choosing an existing destination removes that file before the WebView saves the replacement. If the download fails or is interrupted, the original is gone too, even though the user only confirmed replacing it. Keep the original until the new download succeeds.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| if not Exec(ExpandConstant('{tmp}\MicrosoftEdgeWebview2Setup.exe'), '/silent /install', '', | ||
| SW_HIDE, ewWaitUntilTerminated, ResultCode) or not WebView2Installed then | ||
| ReportMissingWebView2; | ||
| except | ||
| ReportMissingWebView2; |
There was a problem hiding this comment.
Launch offered without WebView2. If the WebView2 bootstrapper cannot be downloaded or installed, setup shows an error but still offers to launch OpenResearch. That launch cannot open the dashboard view, creating a confusing first-run failure. Suppressing the post-install launch when the runtime is missing would give users a clearer outcome.
Prompt To Fix With AI
This is a comment left during a code review.
Path: windows/OpenResearch.iss
Line: 102-106
Comment:
**Launch offered without WebView2.** If the WebView2 bootstrapper cannot be downloaded or installed, setup shows an error but still offers to launch OpenResearch. That launch cannot open the dashboard view, creating a confusing first-run failure. Suppressing the post-install launch when the runtime is missing would give users a clearer outcome.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Comments Outside DiffThese findings could not be posted inline.
|
… launch without WebView2 Move the file a download replaces aside and restore it if the download fails or is cancelled (WebView2's flyout can cancel), rather than deleting it up front. The installer no longer offers to start OpenResearch when the WebView2 Runtime is still missing, since the window could not open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 2 of the desktop app, stacked on #438 (macOS). Retarget to
mainonce #438 merges.What changes
OpenResearch.exe(windows/launcher, its own tiny crate) is a windowed program with the app icon. It starts theorx.exenext to it asorx appwithCREATE_NO_WINDOW.orxand everygit, shell and agent process it starts share that one hidden console, so none of them flashes a console window. A single windowedorx.exewould have neededCREATE_NO_WINDOWat dozens of spawn sites.orx appreuses the window code from Open the macOS app's dashboard in its own window #438 (src/commands/app.rs): pop-ups go to the browser (http/https/mailto only), downloads use a Save panel, the window appears once the dashboard has loaded, and the port is 4792. On Windows specifically:orx.exeget their icon from a resource thatembed-resourceembeds.up::request_shutdown(), aNotifythatshutdown_signalalso waits on, instead of the app sending itself SIGTERM. Windows has no SIGTERM, and the stored permit also covers a quit that arrives before the server is ready.orx.exein%LOCALAPPDATA%\Programs\OpenResearchis a Portable install and swaps itself in place. After a restart the app comes back asorx appon the same port; the new process waits for the old one before claiming the single-instance lock.windows/OpenResearch.iss): a per-user Inno Setup installer with no admin prompt, a Start-menu entry, an optional desktop shortcut, and a WebView2 bootstrap if the runtime is missing. Uninstall also removes WebView2's data folder.OpenResearch-Setup.exefrom that run'sorx.exe, and uploads it as theopenresearch-windows-installerartifact.release-windows-app.ymlattaches an installer built from each release's publishedorx.exe. It does nothing until the repo variableWINDOWS_APP_ENABLEDistrue.docs/windows.mdcovers the app.Not included
orx.exedoes today.Test plan
cargo fmt --check,cargo clippy --all-targets -D warnings,cargo test --locked(923 passed); launcher builds and passes clippywindow.confirmprompts workrequest_shutdown🤖 Generated with Claude Code