aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorTianren Dong <tianrendong.dtr@gmail.com>2026-05-16 13:13:32 -0400
committerTianren Dong <tianrendong.dtr@gmail.com>2026-05-16 13:13:48 -0400
commitb2ca8f8c343281c0263bda4c043cbe7f0d7d442e (patch)
treec37f274c112a202af86144fd6034a8a54d7933eb /docs
parentea567819d835d4704d9fb38cd114e0e5b231759e (diff)
Revert 0.16.x and 0.17.x: restore tree to v0.15.20 state
Reverts the pairing + signed-envelopes work (0.16.0-0.16.1), the standalone daemon refactor (0.17.0-0.17.3), and assorted patches. These were unpublished from npm; this commit restores the working tree to match the v0.15.20 release so the branch tip and the npm 'latest' dist-tag are consistent again. Tags v0.16.0 through v0.17.3 are preserved as recovery anchors; the work is reachable via 'git checkout v0.17.3' if ever needed. Tree-equivalent to v0.15.20.
Diffstat (limited to 'docs')
-rw-r--r--docs/DESIGN-0.17-daemon.md106
1 files changed, 0 insertions, 106 deletions
diff --git a/docs/DESIGN-0.17-daemon.md b/docs/DESIGN-0.17-daemon.md
deleted file mode 100644
index 2e7f115..0000000
--- a/docs/DESIGN-0.17-daemon.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# pi-chrome 0.17 — standalone versioned daemon
-
-**Status:** design draft. Implementing in this same release branch.
-
-## Goals
-
-1. **Decouple the bridge from any Pi session lifecycle.** Killing a Pi session must never break Chrome control for other sessions.
-2. **Eliminate the "owner vs client" topology.** Every Pi session should be a uniform client.
-3. **Make upgrades self-healing.** When `pi update` lands a new pi-chrome version, the next session that starts must Just Work without any manual `kill` or `/chrome onboard` ritual.
-4. **No new runtime deps.** Keep the zero-deps promise.
-
-## Non-goals (deferred to 0.18)
-
-- Transport change. Stays HTTP + long-poll for 0.17. WebSocket lands separately on top of the daemon.
-- Native messaging. Not pursued; see SECURITY.md threat model rationale.
-
-## Architecture
-
-```
- ┌─────────────┐ ┌────────────────────────────┐
- │ Chrome ext │ HTTPS │ pi-chrome daemon │ ─────┐
- │ (SW polls ├────────►│ ~/.cache/pi-chrome/ │ │
- │ /next) │ │ v0.17.0/daemon.cjs │ │ stat()
- └─────────────┘ │ Listens :17318 │ │ on each
- │ Owns BridgeAuth + state │ │ accept
- └─────────────┬──────────────┘ │
- │ │
- signed /command (HTTP) │
- │ │
- ┌─────────────┴──────────────┐ │
- │ Pi session N (any version) │ ──────┘
- │ extension/index.ts as │
- │ daemon supervisor + client │
- └────────────────────────────┘
-```
-
-### Lifecycle
-
-- **First Pi session in a pi-chrome version family** spawns the daemon if no compatible one is running. Spawn is detached (`spawn(node, [daemon.cjs], { detached: true, stdio: 'ignore' })`), the parent Pi doesn't own the daemon's process group, and `unref()`'s it so Pi can exit independently.
-- **Daemon stays alive** as long as it has work to do (active extension poll, or pending peer connections). After `IDLE_SHUTDOWN_MS` (default: 10 min) of zero activity, daemon exits cleanly.
-- **Subsequent Pi sessions** at `session_start` probe `/status`:
- - Healthy + compatible version → use as-is.
- - Unresponsive or incompatible version → kill it, spawn the right-version daemon.
-- **`pi update`** changes the on-disk pi-chrome version. Next Pi session sees mismatch, kills old daemon, spawns new. **No in-process hot reload** — the old daemon's in-flight commands are allowed to drain (or time out normally) and the next request to the new daemon retries fresh.
-
-### Versioned daemon path
-
-Daemon is copied to `~/.cache/pi-chrome/<version>/daemon.cjs` on Pi session_start (idempotent, only writes if absent or shasum mismatches). Pi spawns the daemon from that path, never directly from the npm install location:
-
-- Survives `nvm use` switches.
-- Multiple pi-chrome versions can coexist on disk (the active daemon corresponds to the most recent Pi session that started). Old version dirs are garbage-collected when the daemon detects them.
-- The daemon executable is a self-contained CommonJS bundle (built at publish time, or generated by a postinstall hook). No `require()` from anywhere except `node:` builtins.
-
-### Why not ESM?
-
-CommonJS keeps the daemon a single file with no entry-point ceremony, no `package.json` next to it, no resolver surprises across Node versions. The cost is irrelevant — the daemon has no third-party deps.
-
-## Protocol (unchanged from 0.16.1)
-
-The HTTP endpoints and signed-envelope contract are byte-identical to 0.16.1. The daemon is structurally a refactor of the existing `ChromeProfileBridge` class:
-
-- `/status` (now adds `daemonPid`, `daemonStartedAt`)
-- `/next` (long-poll, signed `bridge->ext` response)
-- `/result` (signed `ext->bridge` body)
-- `/command` (signed `peer->owner` / `owner->peer`)
-- `/pair` (invite window, signed response with invite secret)
-
-The only addition is a new `/heartbeat` endpoint (cheap GET, returns `{ok:true,ts}`) used by Pi clients to keep the daemon's idle timer alive and to detect daemon health without consuming a full command round-trip.
-
-### Configuration file unchanged
-
-`~/.config/pi/chrome-bridge.json` keeps the same shape (`{protocol, bridgeId, extensionId, extensionPairKey, brokerKey}`). The daemon owns the read/write of that file; Pi clients only consult it to derive `brokerKey` for signing peer→owner requests.
-
-The cross-process `fs.watch` + `refreshIfStale` machinery becomes daemon-local — `chrome-bridge.json` is now exclusively the daemon's data file. Pi clients receive pairing state via `/status` instead of reading the file directly.
-
-## Extension changes
-
-**None.** The extension still polls `127.0.0.1:17318`. From its perspective the only thing that changed is "the process behind that port restarts itself occasionally during pi-chrome upgrades."
-
-The extension's existing version-mismatch reload path (`x-pi-chrome-version` header → `chrome.runtime.reload()`) handles its own upgrade story independently.
-
-## Pi-side client surface
-
-`extensions/chrome-profile-bridge/index.ts` is split into:
-
-1. **`bridge-client.ts`** — Pi-side talker. `BridgeClient.send(action, params, timeoutMs)` signs and posts to `/command` of the local daemon, verifies the response signature, returns the result. No long-poll loop, no HTTP server. ~200 LOC.
-2. **`daemon-supervisor.ts`** — at `session_start`: ensures daemon is running, spawns if not, registers a graceful keepalive. ~100 LOC.
-3. **`daemon.cjs`** (built artifact) — the bridge process. Internally identical to today's `ChromeProfileBridge` minus the "client mode" branch. Single self-contained file shipped in npm tarball + copied to versioned cache dir on first use.
-4. **`index.ts`** — pi-extension entry. Imports `bridge-client` and `daemon-supervisor`, registers the chrome_* tools, wires `/chrome` commands. ~500 LOC (everything else moved out).
-
-## Open questions
-
-1. **Daemon log location.** Default: `~/.cache/pi-chrome/<version>/daemon.log` (rotated at 1 MiB). Exposed via `/chrome doctor --logs`.
-2. **What happens during a takeover with in-flight Pi commands?** Old daemon dies → its in-flight `/command` returns a TCP RST to the Pi client → Pi client retries against the new daemon. Implement explicit retry-once on connection-refused/RST inside `BridgeClient.send` with a budget (5 s) before surfacing the error.
-3. **Pairing across daemon restarts.** `~/.config/pi/chrome-bridge.json` persists. New daemon `load()`s it, picks up the same `extensionPairKey`/`brokerKey`. Extension never has to re-pair across a daemon restart.
-4. **Concurrent daemon spawn race.** Two Pi sessions starting simultaneously could each try to spawn a daemon. Mitigation: spawn-then-bind, second one hits EADDRINUSE inside the daemon itself and exits cleanly; supervisor probes `/status` after spawn to confirm one is up.
-5. **Garbage-collecting old versioned dirs.** Daemon at startup deletes `~/.cache/pi-chrome/v*/` directories older than 30 days.
-
-## Migration
-
-0.16.1 → 0.17:
-- First Pi session on 0.17 detects an existing 0.16.x bridge on `:17318`, version-mismatches, kills it, spawns the 0.17 daemon. Same as the existing auto-takeover code in 0.16.1.
-- Extension picks up new bridge on next poll, sees same `expectedExtensionVersion`, no reload.
-- Pairing state in `~/.config/pi/chrome-bridge.json` is preserved across the transition.
-
-User-visible: nothing. `pi update` → next Pi session → done.