diff --git a/.env.desktop.example b/.env.desktop.example new file mode 100644 index 0000000..b90a162 --- /dev/null +++ b/.env.desktop.example @@ -0,0 +1,13 @@ +# Desktop build (`deno task desktop`). Copy to `.env.desktop`. +# +# QUANTUM_TARGET=desktop switches vite.config.ts to the Deno adapter, whose +# `.deno-deploy/server.ts` output `deno desktop` packages. The rest is the local +# runtime config the packaged app boots with (until the first-launch mode screen +# lands — tasks 2.2/7.1). + +QUANTUM_TARGET=desktop +QUANTUM_MODE=local +DB_PATH=./data/desktop-spike.db + +# Omit to hit the first-launch /welcome screen instead of seeding a name. +QUANTUM_LOCAL_DISPLAY_NAME=Graham diff --git a/.gitignore b/.gitignore index 3c586ad..99a4938 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,13 @@ Thumbs.db .env.* !.env.example !.env.localmode.example +!.env.desktop.example !.env.test +# deno desktop build output +/.deno-deploy +/quantum/ + # Vite vite.config.js.timestamp-* vite.config.ts.timestamp-* diff --git a/deno.json b/deno.json index 680f775..fe32c33 100644 --- a/deno.json +++ b/deno.json @@ -11,7 +11,8 @@ "dev:local": "deno run --env-file=.env.localmode --unstable-cron -A npm:vite dev", "build": "deno run -A npm:vite build", "start": "deno run --env-file --unstable-cron -A build/index.js", - "desktop": "deno desktop --unstable-cron -A .", + "desktop:build": "deno run -A --env-file=.env.desktop npm:vite build", + "desktop": "deno desktop --env-file=.env.desktop --unstable-cron --no-check -A .", "check": "deno run -A npm:@sveltejs/kit/svelte-kit sync && deno run -A npm:svelte-check --tsconfig ./tsconfig.json", "test": "deno test -A src", "fmt": "deno fmt", diff --git a/deno.lock b/deno.lock index e215dd9..a540cb9 100644 --- a/deno.lock +++ b/deno.lock @@ -5,6 +5,7 @@ "npm:@atproto/jwk-jose@~0.2.4": "0.2.4", "npm:@atproto/oauth-client-node@~0.4.8": "0.4.8", "npm:@atproto/oauth-types@~0.7.5": "0.7.5", + "npm:@deno/svelte-adapter@~0.2.1": "0.2.1_@sveltejs+kit@2.69.2__@sveltejs+vite-plugin-svelte@7.2.0___svelte@5.56.4___vite@8.1.4____@types+node@26.1.1___@types+node@26.1.1__svelte@5.56.4__typescript@6.0.3__vite@8.1.4___@types+node@26.1.1__@types+node@26.1.1", "npm:@fontsource-variable/inter@^5.2.8": "5.2.8", "npm:@modelcontextprotocol/sdk@1.29.0": "1.29.0_zod@3.25.76", "npm:@modelcontextprotocol/sdk@^1.29.0": "1.29.0_zod@3.25.76", @@ -209,6 +210,19 @@ "zod" ] }, + "@deno/experimental-route-config@0.0.5": { + "integrity": "sha512-0PN4qij3sC3Qm8WbiOBGlOQz8WtB0AENGkzsTHOYyPenf40iW7OGFid8QT3L8lGApnz3t6ufET0c2XgagV8Jjw==", + "dependencies": [ + "urlpattern-polyfill" + ] + }, + "@deno/svelte-adapter@0.2.1_@sveltejs+kit@2.69.2__@sveltejs+vite-plugin-svelte@7.2.0___svelte@5.56.4___vite@8.1.4____@types+node@26.1.1___@types+node@26.1.1__svelte@5.56.4__typescript@6.0.3__vite@8.1.4___@types+node@26.1.1__@types+node@26.1.1": { + "integrity": "sha512-jVdTaq9FwuYpOehCsiVmSNz4D/8FzewNSk6apvt1dNonp+MtJm/x5dV2xHVpiHesby2Nw/is7NcBU2NX2PArVQ==", + "dependencies": [ + "@deno/experimental-route-config", + "@sveltejs/kit" + ] + }, "@emnapi/core@1.11.1": { "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "dependencies": [ @@ -1502,6 +1516,9 @@ "unpipe@1.0.0": { "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, + "urlpattern-polyfill@10.1.0": { + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==" + }, "vary@1.1.2": { "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, @@ -1562,6 +1579,7 @@ "npm:@atproto/jwk-jose@~0.2.4", "npm:@atproto/oauth-client-node@~0.4.8", "npm:@atproto/oauth-types@~0.7.5", + "npm:@deno/svelte-adapter@~0.2.1", "npm:@fontsource-variable/inter@^5.2.8", "npm:@modelcontextprotocol/sdk@^1.29.0", "npm:@sveltejs/adapter-node@^5.5.0", diff --git a/openspec/changes/add-desktop-local-remote-modes/tasks.md b/openspec/changes/add-desktop-local-remote-modes/tasks.md index e45f72f..37a1515 100644 --- a/openspec/changes/add-desktop-local-remote-modes/tasks.md +++ b/openspec/changes/add-desktop-local-remote-modes/tasks.md @@ -15,9 +15,22 @@ fixed-port `Deno.serve` works in the packaged binary, else publish the per-launch URL via `agent.json`. Still needs the binary to settle that sub-question. -- [ ] 1.3 **Packaging sanity.** Confirm `deno desktop` (2.9.x) auto-detects this - SvelteKit project and produces a runnable Windows binary from the existing - build, with the webview backend, before building mode logic on top. +- [~] 1.3 **Packaging sanity.** Confirm `deno desktop` (2.9.x) auto-detects this + SvelteKit project and produces a runnable Windows binary from the existing + build, with the webview backend, before building mode logic on top. — Bundling + now works (finding chain, all resolved in code): (1) detection needs a + `svelte.config.js` — without it `deno desktop` sees generic Vite and tries to + embed a nonexistent `dist/`; added a detection stub (SvelteKit ignores it, + uses the inline vite config, but the file makes `deno desktop` detect + SvelteKit). (2) SvelteKit support wants the Deno adapter's + `.deno-deploy/server.ts`, not adapter-node's `build/`; added + `@deno/svelte-adapter`, selected via `QUANTUM_TARGET=desktop` in + vite.config.ts (server/container stays adapter-node). (3) the Deno adapter's + generated `handler.ts` type-skews against `@sveltejs/kit@2.69.2` + (`RouteParam.matcher`), so compile needs `--no-check`. Result: + `deno task desktop` compiles `quantum.dll`, pulls the laufey webview backend, + and bundles (exit 0). **REMAINING: launch the window on a real display** and + confirm the app renders in local mode — that's the live check (with Graham). ## 2. Build and mode plumbing diff --git a/package.json b/package.json index dbb649e..d797391 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "zod": "^3.25.76" }, "devDependencies": { + "@deno/svelte-adapter": "^0.2.1", "@sveltejs/adapter-node": "^5.5.0", "@sveltejs/kit": "^2.63.0", "@sveltejs/vite-plugin-svelte": "^7.1.2", diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..6e41c0f --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,19 @@ +import adapterNode from "@sveltejs/adapter-node"; +import adapterDeno from "@deno/svelte-adapter"; +import process from "node:process"; + +// Detection stub for `deno desktop` (add-desktop-local-remote-modes). +// +// SvelteKit itself IGNORES this file — the real config is passed inline to the +// `sveltekit()` plugin in vite.config.ts, and SvelteKit warns that this file is +// ignored. But `deno desktop` detects the framework as SvelteKit by this file's +// presence; without it, it falls back to generic Vite and tries to embed a +// nonexistent `dist/`. The adapter here mirrors vite.config.ts so the two never +// drift if SvelteKit ever starts reading this file. +const adapter = process.env.QUANTUM_TARGET === "desktop" + ? adapterDeno() + : adapterNode(); + +export default { + kit: { adapter }, +}; diff --git a/vite.config.ts b/vite.config.ts index 27de72d..6cca4d1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,16 @@ -import adapter from "@sveltejs/adapter-node"; +import adapterNode from "@sveltejs/adapter-node"; +import adapterDeno from "@deno/svelte-adapter"; import { sveltekit } from "@sveltejs/kit/vite"; import { defineConfig } from "vite"; +import process from "node:process"; + +// The server/container deployment uses adapter-node (run under Deno via +// `deno task start`). The `deno desktop` build sets QUANTUM_TARGET=desktop and +// uses the Deno Deploy adapter, whose `.deno-deploy/server.ts` output is what +// `deno desktop` detects and packages (add-desktop-local-remote-modes). +const adapter = process.env.QUANTUM_TARGET === "desktop" + ? adapterDeno() + : adapterNode(); export default defineConfig({ plugins: [ @@ -11,8 +21,7 @@ export default defineConfig({ filename.split(/[/\\]/).includes("node_modules") ? undefined : true, }, - // adapter-node output runs under Deno in production (deno task start) - adapter: adapter(), + adapter, }), ], });