tests/transport/storage.test.ts covers the storage half of "the pairing token survives a browser restart" (round-trip, unpair-clears, corrupted override falls back to auto). websocket.test.ts adds the transport half: a fresh WebSocketTransport instance over the same backing store reuses the persisted token with no re-pairing, plus pairWithCode/unpair coverage. "Wrong token rejected and rate-limited" was already covered (websocket.test.ts's NotPaired/RateLimited cases). docs/amo-permissions.md is the submission-ready permission justification for AMO's Notes to Reviewer field, covering every permission in manifest.json plus what was deliberately not requested and how cookie/ header data is handled. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Ed8KEmAW48v4YHdxLtqsMB
Owner: lane EXT. See ../docs/agents/AGENT-EXT.md and ../docs/05-extension-spec.md. Firefox MV3, TypeScript. Zero download logic.
Layout
src/background/transport/ Transport interface + WebSocket and native-messaging impls,
runtime picker. See docs/adr/0003 for why there are two.
src/shared/protocol/ GENERATED from ../contracts — never hand-edit.
tests/ vitest; webextension-polyfill is mocked in tests/setup.ts.
Develop
npm ci
npm run typecheck # tsc --noEmit, strict
npm test # vitest run
npm run lint # web-ext lint (AMO rules) — needs manifest.json
Build against tools/mockd over the WebSocket transport; veloxd is not required.
Transport quick start
import { createTransport } from './src/background/transport/index.js';
const t = await createTransport(); // reads the Options override; default 'auto'
t.onStateChange((s) => renderDot(s));
const rules = await t.call('capture.getRules', {});
createTransport resolves with a live, self-reconnecting transport. When veloxd is not
up yet it still resolves (WebSocket, status disconnected, retrying) — callers render the
red dot. It rejects only when the user explicitly forced native messaging and that failed.
Capture code treats every call() rejection as fail-open.