Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh

Commit

The desktop app runs under tauri dev: the launcher served from the CLI's localhost stays in the window.

With no devUrl, tauri dev serves launcher/ from its own server on localhost, and the window starts there. The navigation guard knew the launcher only at tauri.localhost, so it sent the dev server's page to the browser and left the window blank. The dev server's origin now counts as the launcher's in debug builds, and the tray's way back to the launcher goes there too. Release builds are unchanged.

Claude-Session:
https://claude.ai/code/session_01MMRPpook51KPMQQRurb5kC
Claudeagent and Claudeagentcommitted Parent30d794fBrowse files
3 files+21−20/3 viewed
+19−1
132132 matches!(url.scheme(), "http" | "https") && origin(url) == origin(&server(app))
133133 }
134134
135+/// Where the bundled pages are served under `tauri dev`: with no `devUrl`
136+/// in tauri.conf.json, the Tauri CLI serves `launcher/` itself, from
137+/// localhost, and the window starts there. Unset in a release build, which
138+/// serves them from inside the app.
139+static DEV_SERVER: std::sync::OnceLock<Option<Url>> = std::sync::OnceLock::new();
140+
141+/// Notes the dev server, once, as the app starts.
142+pub fn note_dev_server(app: &AppHandle) {
143+ let dev = if cfg!(debug_assertions) { app.config().build.dev_url.clone() } else { None };
144+ let _ = DEV_SERVER.set(dev);
145+}
146+
147+pub fn dev_server() -> Option<&'static Url> {
148+ DEV_SERVER.get().and_then(Option::as_ref)
149+}
150+
135151 /// Whether a page is the launcher, bundled with the app.
136152 pub fn is_launcher(url: &Url) -> bool {
137− url.scheme() == "tauri" || (matches!(url.scheme(), "http" | "https") && url.host_str() == Some("tauri.localhost"))
153+ url.scheme() == "tauri"
154+ || (matches!(url.scheme(), "http" | "https") && url.host_str() == Some("tauri.localhost"))
155+ || dev_server().is_some_and(|dev| origin(dev) == origin(url))
138156 }
139157
140158 /// What the server's pages may call: the bridge's commands (bridge.rs).
+1−0
6666 .on_menu_event(|app, event| menu::handle(app, event.id().as_ref()))
6767 .setup(|app| {
6868 let handle = app.handle().clone();
69+ config::note_dev_server(&handle);
6970 config::load(&handle);
7071 config::allow_site(&handle)?;
7172 let hidden = settings::starts_hidden(&handle);
+1−1
9696 /// The address of the launcher page bundled with the app.
9797 pub fn launcher_url(query: &str) -> url::Url {
9898 let base = if cfg!(windows) { "http://tauri.localhost/" } else { "tauri://localhost/" };
99− let mut url = url::Url::parse(base).expect("the launcher's address is a URL");
99+ let mut url = config::dev_server().cloned().unwrap_or_else(|| url::Url::parse(base).expect("the launcher's address is a URL"));
100100 url.set_path("/index.html");
101101 if !query.is_empty() {
102102 url.set_query(Some(query));