M10 (task 2013): integrated AppImage — app self-integration (OOBE + Account toggle)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 6s
CI & Build / Python tests (push) Successful in 9s
Desktop (Tauri) / Tauri desktop (Linux) (push) Failing after 26s
CI & Build / Build & push image (push) Successful in 33s

The Linux AppImage can now install itself into the applications menu, so it behaves
like an installed app instead of a loose file.

- Rust (desktop/src-tauri/src/integration.rs): integration_status / integrate_desktop
  / unintegrate_desktop commands — detect $APPIMAGE, copy the AppImage to
  ~/Applications, write ~/.local/share/applications/thoughtsync.desktop + embedded
  icon, update-desktop-database. Registered in lib.rs.
- Frontend: withGlobalTauri exposes window.__TAURI__.core.invoke; desktop/bridge.ts
  (isDesktop + typed invoke, NO @tauri-apps/api dep -> web bundle unaffected);
  DesktopIntegrationPrompt (first-run OOBE, remembered) mounted in App.vue;
  AccountView "Desktop app" add/remove control. All desktop-guarded -> no-ops on web.
- desktop.yml: upload the .deb + .AppImage as a run artifact (continue-on-error) so
  the build is downloadable for hand-testing.

Verified by CI: ci.yml (vue-tsc) for the frontend, desktop.yml (cargo + tauri build)
for the Rust + AppImage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
This commit is contained in:
2026-07-24 13:24:20 -04:00
co-authored by Claude Opus 4.8
parent 1607c77ee5
commit 877a6a572f
8 changed files with 352 additions and 5 deletions
+38
View File
@@ -0,0 +1,38 @@
// Bridge to the Tauri desktop core. On the web build there is no Tauri runtime, so
// isDesktop() is false and none of these calls run. Uses the global injected by
// `withGlobalTauri` (tauri.conf.json), so the shared frontend needs no
// @tauri-apps/api dependency and the web bundle is unaffected.
interface TauriGlobal {
core: { invoke: <T>(cmd: string, args?: Record<string, unknown>) => Promise<T> };
}
declare global {
interface Window {
__TAURI__?: TauriGlobal;
}
}
export interface IntegrationStatus {
is_appimage: boolean;
is_integrated: boolean;
appimage_path: string | null;
}
/** True when running inside the Tauri desktop shell (vs. the web build). */
export function isDesktop(): boolean {
return typeof window !== "undefined" && !!window.__TAURI__;
}
function invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
const tauri = window.__TAURI__;
if (!tauri) return Promise.reject(new Error("Not running in the desktop app."));
return tauri.core.invoke<T>(cmd, args);
}
// Desktop (Linux AppImage) self-integration: add/remove an applications-menu entry.
export const desktop = {
integrationStatus: () => invoke<IntegrationStatus>("integration_status"),
integrate: () => invoke<IntegrationStatus>("integrate_desktop"),
unintegrate: () => invoke<IntegrationStatus>("unintegrate_desktop"),
};