heph-pwa: mobile app (PWA mirror of heph-tui) + hub static serving #8

Merged
eblume merged 7 commits from feature/heph-pwa-mobile into main 2026-06-04 17:50:48 -07:00
3 changed files with 22 additions and 11 deletions
Showing only changes of commit 0036c1a284 - Show all commits

fix(hephd): supervise the ⌘' popover in server mode too; PWA defaults hub to its origin

Popover supervision was gated to Mode::Local, so running the store-owning
daemon in server mode (now needed to host heph-pwa) silently dropped the
desktop quick-capture popover. Server mode is local + an HTTP hub and owns the
same store/socket, so it should drive the popover too; broaden the guard to
Local | Server (client, a thin proxy, still opts out).

Also: when the PWA shell is served from the hub, default the hub URL to its own
origin so the app is zero-config on first open (Settings still overrides). Bump
the service-worker cache to v2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Erich Blume 2026-06-04 17:13:28 -07:00

View file

@ -231,14 +231,17 @@ async fn main() -> Result<()> {
tracing::info!(socket = %socket.display(), mode = ?cli.mode, "hephd listening");
// macOS local mode: supervise the global quick-capture popover (⌘'). hephd
// already runs as a `gui/$uid` LaunchAgent, so its child inherits the Aqua
// session the hotkey/GUI need — no separate launch agent. Opt-in via
// HEPH_QUICKADD=1 (the installed plist sets it) so dev/test runs that spawn a
// local daemon never pop a window. The helper self-exits when this daemon
// goes away, so killing hephd (even `kill -9`) leaves nothing behind.
// macOS store-owning modes: supervise the global quick-capture popover (⌘').
// hephd already runs as a `gui/$uid` LaunchAgent, so its child inherits the
// Aqua session the hotkey/GUI need — no separate launch agent. Both `local`
// and `server` own the local store on the device (server is local + an HTTP
// hub), so both should drive the desktop popover; only `client` (a thin
// remote proxy) does not. Opt-in via HEPH_QUICKADD=1 (the installed plist
// sets it) so dev/test runs that spawn a daemon never pop a window. The
// helper self-exits when this daemon goes away, so killing hephd (even
// `kill -9`) leaves nothing behind.
#[cfg(target_os = "macos")]
if cli.mode == Mode::Local && quickadd_enabled() {
if matches!(cli.mode, Mode::Local | Mode::Server) && quickadd_enabled() {
spawn_quickadd_supervisor(socket.clone());
}

View file

@ -8,12 +8,20 @@
const SETTINGS_KEY = "heph-pwa:settings";
export function loadSettings() {
let s = {};
try {
const s = JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}");
return { baseUrl: s.baseUrl || "", token: s.token || "" };
s = JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}");
} catch {
return { baseUrl: "", token: "" };
s = {};
}
let baseUrl = s.baseUrl || "";
// Served from the hub? Default the hub URL to our own origin so the app is
// zero-config out of the box (the Settings screen still lets you override,
// e.g. when the shell is hosted separately from the hub).
if (!baseUrl && typeof location !== "undefined" && /^https?:/.test(location.origin)) {
baseUrl = location.origin;
}
return { baseUrl, token: s.token || "" };
}
export function saveSettings(settings) {

View file

@ -1,7 +1,7 @@
// Service worker: cache the app shell so heph launches offline. Data is never
// cached — every /rpc call must hit the live hub (and POSTs aren't cacheable
// anyway). Bump CACHE when shell assets change to evict the old set.
const CACHE = "heph-pwa-v1";
const CACHE = "heph-pwa-v2";
const SHELL = [
"./",
"./index.html",