fix: sync works on Chrome-extension deployments (service worker path)#27
Draft
edwinhu wants to merge 1 commit into
Draft
fix: sync works on Chrome-extension deployments (service worker path)#27edwinhu wants to merge 1 commit into
edwinhu wants to merge 1 commit into
Conversation
`sync`/`account-sync.ts` connected to the account's background sync engine
only via the Electron `background_page.html` iframe path
(connectToBackgroundPage). On Chrome-extension deployments (Linux/omarchy,
where there is no Superhuman.app), that target doesn't exist — only the MV3
extension's service worker does — so every `sync` (and forced sync) failed
with "background_page unreachable", even though `account auth` already worked
via the extension service worker. `sync --check` only appeared to work
because it silently fell back to on-disk enumeration and never reached CDP.
Port account-sync.ts onto a backend-agnostic `SyncSession` abstraction with
two implementations, mirroring how the auth path was already ported:
- extensionSession: reaches the per-account engine as
`backgrounds[email]._accountBackground.di.get("sync")` in the single
service-worker context (via connectToSuperhumanChrome).
- electronSession: the existing `window.background` per-iframe path
(connectToBackgroundPage), preserved for the macOS/Windows desktop app.
connectSyncSession tries the extension first (the common shape on Linux) and
falls back to Electron. The freshness short-circuit, sync.start() trigger,
forceSyncBackend escalation, and _lastRunEnded poll-until-advance logic are
unchanged — only the eval context/account-selection is abstracted. Verified
live against the extension on port 9222: forced sync of both linked accounts
returns "synced" (poll cycle observed), and `sync --check` enumerates via the
extension instead of the on-disk fallback.
Tests ported to the SyncSession seam (12/12 pass); full suite 435 pass / 0
fail; tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017G6xd9S8uc7WrQcCcMr59Q
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
superhuman sync(and forced sync) failed on Chrome-extension deployments (Linux/omarchy, where there is no Superhuman.app) with:Root cause:
account-sync.tsconnected to the per-account background sync engine only via the Electronbackground_page.htmliframe path (connectToBackgroundPage). On this box Superhuman runs as the MV3 Chrome extension, which exposes aservice_worker(.../background/background_page.js) — not an Electronpageatbackground_page.html. So the matcher never found a target.Meanwhile
account authalready worked here, because it was ported to the extension service worker (connectToSuperhumanChrome/backgrounds[email]._accountBackground).sync --checkonly appeared to work because it silently fell back to on-disk enumeration and never actually reached CDP.Fix
Port
account-sync.tsonto a backend-agnosticSyncSessionabstraction, mirroring the auth path:extensionSession— reaches the engine asbackgrounds[email]._accountBackground.di.get("sync")in the single service-worker context.electronSession— the existingwindow.backgroundper-iframe path, preserved for the macOS/Windows desktop app.connectSyncSession— tries the extension first (common shape on Linux), falls back to Electron.The freshness short-circuit,
sync.start()trigger,forceSyncBackendescalation, and_lastRunEndedpoll-until-advance logic are unchanged — only the eval context / account-selection is abstracted.cmdSyncerror messages are now backend-agnostic.Verification
synced(poll cycle observed via_lastRunEndedadvancing);sync --checkenumerates via the extension instead of the on-disk fallback.bun test src/__tests__/account-sync.test.ts→ 12/12 pass (ported to theSyncSessionseam).tsc --noEmitclean.🤖 Generated with Claude Code
https://claude.ai/code/session_017G6xd9S8uc7WrQcCcMr59Q