diff options
| author | Tianren Dong <tianrendong.dtr@gmail.com> | 2026-05-16 12:56:24 -0400 |
|---|---|---|
| committer | Tianren Dong <tianrendong.dtr@gmail.com> | 2026-05-16 12:56:24 -0400 |
| commit | 43c62c2f338654394f82c86aa12b22be6a358d94 (patch) | |
| tree | f2774b2e91fe029f612d267899c8c01057168e46 | |
| parent | 2ac665ec31fe156b372540e8ac38aa42765b3001 (diff) | |
0.17.1: fix /chrome onboard stuck on 'Waiting for the extension to wake up'
0.17.0 made the daemon own the HTTP listener, but the Pi client's
bridge.status().connected still reflected the local Pi's lastSeenAt
(which is never updated in the daemon model). Onboard's connect-wait
loop spun forever even when the extension was polling the daemon.
Fix: new ChromeProfileBridge.daemonStatus() async helper that fetches
the daemon's /status. onboard, doctor, and status now query that for
the 'connected' flag instead of reading stale Pi-side state.
| -rw-r--r-- | CHANGELOG.md | 14 | ||||
| -rw-r--r-- | extensions/chrome-profile-bridge/browser-extension/manifest.json | 2 | ||||
| -rw-r--r-- | extensions/chrome-profile-bridge/index.ts | 27 | ||||
| -rw-r--r-- | package.json | 2 |
4 files changed, 39 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 99af471..5f2fed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable user-facing changes to `pi-chrome`. +## 0.17.1 — 2026-05-16 + +### Fix: `/chrome onboard` stuck on "Waiting for the extension to wake up…" + +0.17.0 made the daemon (not the Pi process) own the HTTP listener, but the Pi client's +`bridge.status().connected` still reflected the *local Pi*'s `lastSeenAt`, which never gets +updated in the daemon model. Result: onboard's connect-wait loop spun forever even when the +extension was happily polling the daemon. + +- New `ChromeProfileBridge.daemonStatus()` async method: fetches the daemon's `/status` and + returns its view (the only correct source of truth in 0.17+). +- `/chrome onboard`, `/chrome doctor`, `/chrome status` now query `daemonStatus()` for the + `connected` flag instead of reading stale Pi-side `lastSeenAt`. + ## 0.17.0 — 2026-05-16 ### Standalone daemon (no more owner-vs-client topology) diff --git a/extensions/chrome-profile-bridge/browser-extension/manifest.json b/extensions/chrome-profile-bridge/browser-extension/manifest.json index dd7d19a..98f47a5 100644 --- a/extensions/chrome-profile-bridge/browser-extension/manifest.json +++ b/extensions/chrome-profile-bridge/browser-extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Pi Chrome Connector", - "version": "0.17.0", + "version": "0.17.1", "description": "Lets Pi control tabs in Chrome via a local connector at 127.0.0.1.", "permissions": [ "tabs", diff --git a/extensions/chrome-profile-bridge/index.ts b/extensions/chrome-profile-bridge/index.ts index c20cf9a..db41ce3 100644 --- a/extensions/chrome-profile-bridge/index.ts +++ b/extensions/chrome-profile-bridge/index.ts @@ -895,6 +895,22 @@ class ChromeProfileBridge { console.warn(`pi-chrome: killed PID ${pid}; will spawn the daemon next.`); } + // Probe the daemon's /status and return its view (which is the only source of truth for + // `connected` / `lastSeenAt` in 0.17+, since the extension polls the daemon, not Pi). + async daemonStatus(timeoutMs = 1_000): Promise<Record<string, unknown> | undefined> { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeoutMs); + try { + const res = await fetch(`${this.url}/status`, { signal: controller.signal }); + if (!res.ok) return undefined; + return (await res.json()) as Record<string, unknown>; + } catch { + return undefined; + } finally { + clearTimeout(timer); + } + } + // Signed admin RPC to the daemon. Used for state mutations the daemon owns: arm-pair-window, // reset, status. Pre-pair (when the daemon has no state file), unauthenticated; once paired, // the daemon requires the broker-key envelope (same signature as /command). @@ -1453,7 +1469,7 @@ Usage rules: // the doctor command for the full 35s waiting for a response that will never come. if (!bridge.bridgeAuth.paired) { lines.push("✗ Skipping extension probe — bridge isn't paired yet. Run /chrome onboard."); - } else if (!status.connected) { + } else if (!(await bridge.daemonStatus(1_500))?.connected) { lines.push( "✗ Chrome extension hasn't polled the bridge recently.", " Fix: load the extension via /chrome onboard, keep that Chrome window open, then re-run /chrome doctor.", @@ -1744,11 +1760,13 @@ Usage rules: // poll = lastSeenAt updates = `bridge.status().connected` flips true. ctx.ui.notify("Waiting for the extension to wake up and poll the bridge…", "info"); const connectStart = Date.now(); + let connected = false; while (Date.now() - connectStart < 15_000) { - if (bridge.status().connected) break; + const ds = await bridge.daemonStatus(1_500); + if (ds && ds.connected === true) { connected = true; break; } await new Promise((r) => setTimeout(r, 500)); } - if (!bridge.status().connected) { + if (!connected) { ctx.ui.notify( [ "✗ The Chrome extension didn't poll the bridge within 15 s.", @@ -1837,7 +1855,8 @@ Usage rules: if (!bridge.bridgeAuth.paired) { return "✗ Chrome bridge not paired (run /chrome onboard)"; } - if (!bridge.status().connected) { + const ds = await bridge.daemonStatus(1_000); + if (!ds?.connected) { return "✗ Chrome extension not polling (load extension via /chrome onboard, keep Chrome open)"; } try { diff --git a/package.json b/package.json index 6b38254..1813de4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pi-chrome", - "version": "0.17.0", + "version": "0.17.1", "scripts": { "version": "node scripts/sync-manifest-version.js", "prepublishOnly": "node scripts/sync-manifest-version.js" |
