- desktop: probe-then-persist server URL — scheme-less input tries https then http; a failed probe no longer saves a dead URL that would trap the next launch in a redirect to a broken address - frontend: close the create-collection modal on successful submit (backdrop stayed mounted and intercepted navigation) - frontend: reload once on service-worker controllerchange so returning users don't run a stale cached shell after a deploy - frontend: gate dashboard empty states on resource loading to stop the "No project selected" / "Create your workspace" flash - cli: resolve scheduled-job refs by name or id for jobs:run, jobs:runs, and jobs:rm, matching bucket/org resolution - cli: correct stale pk_live_/pk_test_ help text to the real prm_ format; align README command spellings and demo seed prefixes - setup: rewrite all public URL vars (auth, vite, backend) and cookie domain for the entered host — https for domains, http for IPs — with anchored full-line substitutions so stale ports/paths can't survive - docs: VITE_* vars never reach the frontend image build; the app resolves API/auth URLs same-origin at runtime, so host changes need no rebuild — noted HTTPS requirement for PWA/secure-context features Generated with [Devin](https://devin.ai) Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@primora/desktop
Tauri 2 shell around a self-hosted Primora deployment. On first run it asks for the deployment URL; after that the webview renders the same SolidJS console the server serves. Nothing is embedded — no backend, no database. The self-hosted model is preserved.
Prerequisites
- Rust (rustup) and Node.js.
- Linux webview deps:
sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
Run
npm run dev --workspace @primora/desktop # dev window (debug build)
npm run bundle --workspace @primora/desktop # release bundles → src-tauri/target/release/bundle
Notes
- Config lives at
~/.config/dev.tdvorak.primora/config.json— one field,server_url. - System tray: Show Primora, Change Server… (clears the URL, back to the connect screen), Quit. Closing the window hides to the tray; a second launch focuses the existing window (single-instance).
- The connect screen only checks that the host answers; if the URL turns out not to be a Primora deployment, use the tray's Change Server.
- macOS blocks plain-HTTP loads to non-localhost hosts (ATS). Use HTTPS, or
http://localhostfor a local deployment.
Secrets Vault
The tray menu's Secrets Vault… opens a local window (ui/vault.html) for
the CLI's encrypted vault — init, timed unlock/lock, list with copy-to-clipboard,
add/delete, .env import. Values are never displayed; copy goes straight to the
clipboard.
The desktop app does not reimplement the vault: IPC commands shell out to the
primora binary on PATH (PRIMORA_CLI overrides the binary path). One vault
file, one crypto implementation — terminal and desktop always agree. Requires
npm i -g @primora/cli; without it the window shows install instructions.
Injection and the credential broker stay CLI-only (primora inject,
primora agent).
- Deep links / push notifications: deliberately omitted — nothing needs them yet.
Auto-updates
tauri-plugin-updater checks releases/latest/download/latest.json on the
GitHub repo when the connect screen loads; if a newer signed release exists
it offers "Update & restart" — download, minisign verification, install,
relaunch. No update manifest or signature failure = silent no-op; unsigned
artifacts can never install.
Release side (already wired in .github/workflows/release.yml): the desktop
job signs updater artifacts with TAURI_SIGNING_PRIVATE_KEY (+ optional
TAURI_SIGNING_PRIVATE_KEY_PASSWORD) repo secrets, uploads the .sig
files, and the release job assembles latest.json from them. Without the
secret the build still succeeds but emits no signatures — and no manifest.
The matching public key is embedded in tauri.conf.json. The private key
lives only in repo secrets and on the maintainer's machine — regenerate with
npx tauri signer generate and update both if it is ever lost.