diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index 64f5eac..712aee2 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -68,6 +68,7 @@
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3",
"vite": "^6.3.5",
+ "vite-plugin-top-level-await": "^1.6.0",
"vitest": "^3.1.1"
}
}
diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs
index 2274495..9f8e1e2 100644
--- a/apps/desktop/src-tauri/src/lib.rs
+++ b/apps/desktop/src-tauri/src/lib.rs
@@ -326,7 +326,27 @@ pub fn run() {
.manage(claude::ClaudeProcessState::default())
.manage(latex::LatexCompilerState::default())
.manage(zotero::ZoteroOAuthState::default())
- .setup(|_app| Ok(()))
+ .setup(|app| {
+ // Safety net: force-show the main window after a timeout if the
+ // frontend JS never calls `getCurrentWindow().show()`.
+ // This prevents the window from staying permanently hidden when
+ // WKWebView fails to execute JS (e.g. WebKit top-level-await bug
+ // on macOS 12). See https://bugs.webkit.org/show_bug.cgi?id=242740
+ let handle = app.handle().clone();
+ tauri::async_runtime::spawn(async move {
+ tokio::time::sleep(std::time::Duration::from_secs(8)).await;
+ if let Some(window) = handle.get_webview_window("main") {
+ if !window.is_visible().unwrap_or(true) {
+ eprintln!(
+ "[safety] Main window still hidden after 8s, force-showing"
+ );
+ let _ = window.show();
+ let _ = window.set_focus();
+ }
+ }
+ });
+ Ok(())
+ })
.invoke_handler(tauri::generate_handler![
create_new_window,
detect_editors,
diff --git a/apps/desktop/src/main.tsx b/apps/desktop/src/main.tsx
index 56d3c4f..4b278e0 100644
--- a/apps/desktop/src/main.tsx
+++ b/apps/desktop/src/main.tsx
@@ -73,10 +73,11 @@ if (isDebugWindow) {
});
} else {
// Main app window
- const { App } = await import("./App");
- ReactDOM.createRoot(rootEl).render(
-
-
- ,
- );
+ import("./App").then(({ App }) => {
+ ReactDOM.createRoot(rootEl).render(
+
+
+ ,
+ );
+ });
}
diff --git a/apps/desktop/vite.config.ts b/apps/desktop/vite.config.ts
index d0236b3..57e85b3 100644
--- a/apps/desktop/vite.config.ts
+++ b/apps/desktop/vite.config.ts
@@ -1,11 +1,12 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
+import topLevelAwait from "vite-plugin-top-level-await";
import path from "node:path";
const host = process.env.TAURI_DEV_HOST;
export default defineConfig({
- plugins: [react()],
+ plugins: [react(), topLevelAwait()],
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
@@ -35,7 +36,8 @@ export default defineConfig({
},
envPrefix: ["VITE_", "TAURI_"],
build: {
- target: "esnext",
+ target:
+ process.env.TAURI_ENV_PLATFORM === "windows" ? "chrome105" : "safari14",
minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false,
sourcemap: !!process.env.TAURI_ENV_DEBUG,
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3ed126a..f7a3245 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -184,6 +184,9 @@ importers:
vite:
specifier: ^6.3.5
version: 6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.16.9)(tsx@4.21.0)(yaml@2.8.2)
+ vite-plugin-top-level-await:
+ specifier: ^1.6.0
+ version: 1.6.0(rollup@4.59.0)(vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.16.9)(tsx@4.21.0)(yaml@2.8.2))
vitest:
specifier: ^3.1.1
version: 3.2.4(@types/debug@4.1.12)(@types/node@25.0.10)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.0.10)(typescript@5.9.3))(terser@5.16.9)(tsx@4.21.0)(yaml@2.8.2)
@@ -2555,6 +2558,15 @@ packages:
'@rolldown/pluginutils@1.0.0-beta.27':
resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+ '@rollup/plugin-virtual@3.0.2':
+ resolution: {integrity: sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: '>=4.58.0'
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@rollup/rollup-android-arm-eabi@4.59.0':
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
cpu: [arm]
@@ -2926,9 +2938,105 @@ packages:
'@speed-highlight/core@1.2.14':
resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==}
+ '@swc/core-darwin-arm64@1.15.21':
+ resolution: {integrity: sha512-SA8SFg9dp0qKRH8goWsax6bptFE2EdmPf2YRAQW9WoHGf3XKM1bX0nd5UdwxmC5hXsBUZAYf7xSciCler6/oyA==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@swc/core-darwin-x64@1.15.21':
+ resolution: {integrity: sha512-//fOVntgowz9+V90lVsNCtyyrtbHp3jWH6Rch7MXHXbcvbLmbCTmssl5DeedUWLLGiAAW1wksBdqdGYOTjaNLw==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@swc/core-linux-arm-gnueabihf@1.15.21':
+ resolution: {integrity: sha512-meNI4Sh6h9h8DvIfEc0l5URabYMSuNvyisLmG6vnoYAS43s8ON3NJR8sDHvdP7NJTrLe0q/x2XCn6yL/BeHcZg==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@swc/core-linux-arm64-gnu@1.15.21':
+ resolution: {integrity: sha512-QrXlNQnHeXqU2EzLlnsPoWEh8/GtNJLvfMiPsDhk+ht6Xv8+vhvZ5YZ/BokNWSIZiWPKLAqR0M7T92YF5tmD3g==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-arm64-musl@1.15.21':
+ resolution: {integrity: sha512-8/yGCMO333ultDaMQivE5CjO6oXDPeeg1IV4sphojPkb0Pv0i6zvcRIkgp60xDB+UxLr6VgHgt+BBgqS959E9g==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@swc/core-linux-ppc64-gnu@1.15.21':
+ resolution: {integrity: sha512-ucW0HzPx0s1dgRvcvuLSPSA/2Kk/VYTv9st8qe1Kc22Gu0Q0rH9+6TcBTmMuNIp0Xs4BPr1uBttmbO1wEGI49Q==}
+ engines: {node: '>=10'}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-s390x-gnu@1.15.21':
+ resolution: {integrity: sha512-ulTnOGc5I7YRObE/9NreAhQg94QkiR5qNhhcUZ1iFAYjzg/JGAi1ch+s/Ixe61pMIr8bfVrF0NOaB0f8wjaAfA==}
+ engines: {node: '>=10'}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-x64-gnu@1.15.21':
+ resolution: {integrity: sha512-D0RokxtM+cPvSqJIKR6uja4hbD+scI9ezo95mBhfSyLUs9wnPPl26sLp1ZPR/EXRdYm3F3S6RUtVi+8QXhT24Q==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-x64-musl@1.15.21':
+ resolution: {integrity: sha512-nER8u7VeRfmU6fMDzl1NQAbbB/G7O2avmvCOwIul1uGkZ2/acbPH+DCL9h5+0yd/coNcxMBTL6NGepIew+7C2w==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@swc/core-win32-arm64-msvc@1.15.21':
+ resolution: {integrity: sha512-+/AgNBnjYugUA8C0Do4YzymgvnGbztv7j8HKSQLvR/DQgZPoXQ2B3PqB2mTtGh/X5DhlJWiqnunN35JUgWcAeQ==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@swc/core-win32-ia32-msvc@1.15.21':
+ resolution: {integrity: sha512-IkSZj8PX/N4HcaFhMQtzmkV8YSnuNoJ0E6OvMwFiOfejPhiKXvl7CdDsn1f4/emYEIDO3fpgZW9DTaCRMDxaDA==}
+ engines: {node: '>=10'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@swc/core-win32-x64-msvc@1.15.21':
+ resolution: {integrity: sha512-zUyWso7OOENB6e1N1hNuNn8vbvLsTdKQ5WKLgt/JcBNfJhKy/6jmBmqI3GXk/MyvQKd5SLvP7A0F36p7TeDqvw==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@swc/core@1.15.21':
+ resolution: {integrity: sha512-fkk7NJcBscrR3/F8jiqlMptRHP650NxqDnspBMrRe5d8xOoCy9MLL5kOBLFXjFLfMo3KQQHhk+/jUULOMlR1uQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@swc/helpers': '>=0.5.17'
+ peerDependenciesMeta:
+ '@swc/helpers':
+ optional: true
+
+ '@swc/counter@0.1.3':
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+
'@swc/helpers@0.5.15':
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
+ '@swc/types@0.1.26':
+ resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==}
+
+ '@swc/wasm@1.15.21':
+ resolution: {integrity: sha512-AVomFdpE9LiB8Q0dNo1UqpqGut//Q7HJNyyCzyHsywHSUM/1pKfzywIjdha4WipgjyOPebYb93pTDBUn2iWvVA==}
+
'@tailwindcss/node@4.1.18':
resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
@@ -6253,6 +6361,10 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
validate-npm-package-name@7.0.2:
resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==}
engines: {node: ^20.17.0 || >=22.9.0}
@@ -6281,6 +6393,11 @@ packages:
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
+ vite-plugin-top-level-await@1.6.0:
+ resolution: {integrity: sha512-bNhUreLamTIkoulCR9aDXbTbhLk6n1YE8NJUTTxl5RYskNRtzOR0ASzSjBVRtNdjIfngDXo11qOsybGLNsrdww==}
+ peerDependencies:
+ vite: '>=2.8'
+
vite@6.4.1:
resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
@@ -9245,6 +9362,10 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.27': {}
+ '@rollup/plugin-virtual@3.0.2(rollup@4.59.0)':
+ optionalDependencies:
+ rollup: 4.59.0
+
'@rollup/rollup-android-arm-eabi@4.59.0':
optional: true
@@ -9669,10 +9790,72 @@ snapshots:
'@speed-highlight/core@1.2.14': {}
+ '@swc/core-darwin-arm64@1.15.21':
+ optional: true
+
+ '@swc/core-darwin-x64@1.15.21':
+ optional: true
+
+ '@swc/core-linux-arm-gnueabihf@1.15.21':
+ optional: true
+
+ '@swc/core-linux-arm64-gnu@1.15.21':
+ optional: true
+
+ '@swc/core-linux-arm64-musl@1.15.21':
+ optional: true
+
+ '@swc/core-linux-ppc64-gnu@1.15.21':
+ optional: true
+
+ '@swc/core-linux-s390x-gnu@1.15.21':
+ optional: true
+
+ '@swc/core-linux-x64-gnu@1.15.21':
+ optional: true
+
+ '@swc/core-linux-x64-musl@1.15.21':
+ optional: true
+
+ '@swc/core-win32-arm64-msvc@1.15.21':
+ optional: true
+
+ '@swc/core-win32-ia32-msvc@1.15.21':
+ optional: true
+
+ '@swc/core-win32-x64-msvc@1.15.21':
+ optional: true
+
+ '@swc/core@1.15.21':
+ dependencies:
+ '@swc/counter': 0.1.3
+ '@swc/types': 0.1.26
+ optionalDependencies:
+ '@swc/core-darwin-arm64': 1.15.21
+ '@swc/core-darwin-x64': 1.15.21
+ '@swc/core-linux-arm-gnueabihf': 1.15.21
+ '@swc/core-linux-arm64-gnu': 1.15.21
+ '@swc/core-linux-arm64-musl': 1.15.21
+ '@swc/core-linux-ppc64-gnu': 1.15.21
+ '@swc/core-linux-s390x-gnu': 1.15.21
+ '@swc/core-linux-x64-gnu': 1.15.21
+ '@swc/core-linux-x64-musl': 1.15.21
+ '@swc/core-win32-arm64-msvc': 1.15.21
+ '@swc/core-win32-ia32-msvc': 1.15.21
+ '@swc/core-win32-x64-msvc': 1.15.21
+
+ '@swc/counter@0.1.3': {}
+
'@swc/helpers@0.5.15':
dependencies:
tslib: 2.8.1
+ '@swc/types@0.1.26':
+ dependencies:
+ '@swc/counter': 0.1.3
+
+ '@swc/wasm@1.15.21': {}
+
'@tailwindcss/node@4.1.18':
dependencies:
'@jridgewell/remapping': 2.3.5
@@ -13697,6 +13880,8 @@ snapshots:
util-deprecate@1.0.2: {}
+ uuid@10.0.0: {}
+
validate-npm-package-name@7.0.2: {}
vary@1.1.2: {}
@@ -13746,6 +13931,17 @@ snapshots:
- tsx
- yaml
+ vite-plugin-top-level-await@1.6.0(rollup@4.59.0)(vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.16.9)(tsx@4.21.0)(yaml@2.8.2)):
+ dependencies:
+ '@rollup/plugin-virtual': 3.0.2(rollup@4.59.0)
+ '@swc/core': 1.15.21
+ '@swc/wasm': 1.15.21
+ uuid: 10.0.0
+ vite: 6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.16.9)(tsx@4.21.0)(yaml@2.8.2)
+ transitivePeerDependencies:
+ - '@swc/helpers'
+ - rollup
+
vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.16.9)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12