>_EXECUTIVE SUMMARY
zpwrchrome is a single-author Chrome MV3 extension built around the
MRU (most-recently-used) tab primitive. The service worker tracks
tab activation in chrome.storage.session across windows;
the toolbar popup renders 12 categories with
fzf fuzzy filtering; a Tampermonkey-equivalent userscript engine
runs in Chrome's native USER_SCRIPT world via
chrome.userScripts; and a frecency-ranked
chrome.history search replaces Chrome's built-in
chrome://history page on Cmd+Y.
6,959 JS lines + 1,104 CSS lines + 22,708 test lines · 54 commands · 19 message handlers · 2948 tests passing.
~SUBSYSTEM BREAKDOWN
Every JS surface in the repo, by role. Pure helpers in lib/util.js + lib/fzf.js carry zero chrome.* references so they unit-test headless and so scripts/build-modal.mjs can inline them into the content-script modal between UTIL_INLINE_START/END and FZF_INLINE_START/END markers.
Service worker
background.js— 3,727 lines
MV3 SW. Cross-window MRU tracker, command dispatcher, popup/modal message API, userscript registration, scenes, history, pass + identity fill, segmented downloads, full-page screenshot.
Popup
popup.html— 46 linespopup.css— 601 linespopup.js— 1,221 lines
Cyberpunk HUD toolbar action. 12 categories (incl. PASS + TECH), fzf filter, keyboard nav, opens via Alt+T / Cmd+Y (history) / Cmd+P (pass) / Cmd+K (tech).
Modal (content script)
modal/content.template.js— 930 lines
Shadow-DOM overlay matching the popup category set. Dormant by default after v0.4.16 — Cmd+E now opens the toolbar popup directly.
Page-theme injector (content script)
modal/cyber-theme.js— 0 lineslib/cyber-theme-css.js— 0 linesscripts-manager/theme-injector.html— 0 lines
document_start content script. Reads chrome.storage.local["theme.injector"]; paints arbitrary pages with the strykelang HUD palette. Knobs: intensity (subtle/medium/full), dark mode (color-scheme + AUI / generic white-card overrides, no filter:invert), forceMono (icon-font carriers exempted), scanlines. Per-host block/allowlist.
Reader mode (on-demand content script)
modal/reader-mode.js— 0 lineslib/reader-mode-css.js— 0 linesscripts-manager/reader-mode.html— 0 lines
document_idle content script. Heuristic article extraction (largest <article> → <main> → densest paragraph cluster outside noise containers); clone sanitized (script/style/iframe/form/inline-handlers stripped); rendered in a fixed overlay with the strykelang palette. Four themes × three font families; A−/A+ live bumpers; Esc closes.
Turn off the lights (on-demand content script)
modal/lights-off.js— 0 lineslib/lights-off-css.js— 0 linesscripts-manager/lights-off.html— 0 lines
document_idle content script. Toggle messages from the SW. Full-viewport overlay at z-index 2147483646; every visible <video> + its ancestor chain lifted to z-index 2147483647 + position:relative. Click overlay or Esc undims and restores the original z-index / position values tagged on each touched element.
JSON viewer (content script)
modal/json-viewer.js— 0 lineslib/json-format.js— 0 lines
document_end content script. Auto-detects JSON-served pages, replaces <pre> with a collapsible tree. RFC 6901 pointer copy, prettyPrint / minify toggles, clipboard with execCommand fallback for non-secure contexts.
User-Agent switcher
modal/cyber-theme.js (n/a)— 0 linesscripts-manager/ua-switcher.html— 0 lineslib/ua-presets.js— 0 lines
16 vendor-shipped UA presets across 6 families plus a custom field. Backed by a single chrome.declarativeNetRequest dynamic rule (id 1001) that rewrites the User-Agent request header.
Find-in-all-tabs
scripts-manager/find-all.html— 0 lineslib/find-snippet.js— 0 lines
Parallel innerText scrape across every open http(s) tab capped at 200 KB / tab. fzf-fuzzy filter; Enter activates the chosen tab and scrolls to the match via window.find().
Pure helpers
lib/util.js— 208 lineslib/fzf.js— 130 lines
Zero chrome.* refs. MRU stack semantics, hostname parse, jump-index resolution, scenes, opener-tree, domain-hue, frecency, fzf scorer. Unit-tested headless.
Userscript engine
lib/userscript.js— 189 lineslib/gm-shim.js— 95 lines
Tampermonkey-equivalent: @metadata parser, match-pattern validator, GM_* shim (getValue/setValue/openInTab/setClipboard/notification/fire-beacon).
Userscript dashboard
scripts-manager/manager.html— 244 linesscripts-manager/manager.js— 459 linesscripts-manager/manager.css— 503 lines
Options-page editor — installed/log/settings/utilities/help tabs, sortable table, monaco-free CodeMirror-free plain textarea editor, fire-log ring buffer reader.
Download queue UI
scripts-manager/downloads.html— 0 linesscripts-manager/downloads.js— 0 linesscripts-manager/downloads.css— 0 lines
Live segmented-download queue. Subscribes to host push events (id=0 dl.progress) for ~5/s updates while active, falls back to polling. Re-hydrates from chrome.storage.local snapshot mirror so the queue paints instantly across SW restarts. Pause / resume / cancel per-row + bulk; speed + ETA + per-job segment count.
#TOP FILES BY SIZE
Sorted descending. modal/content.template.js is the source; modal/content.js is generated (fonts + fzf + util inlined) and excluded from this table.
| Path | Lines | Bytes |
|---|---|---|
background.js | 3,727 | 152,518 |
popup.js | 1,221 | 50,053 |
tests/dl-integration.test.js | 1,025 | 52,864 |
modal/content.template.js | 930 | 37,419 |
popup.css | 601 | 18,689 |
tests/static.test.js | 561 | 26,240 |
tests/logic.test.js | 555 | 22,613 |
scripts-manager/manager.css | 503 | 16,708 |
scripts-manager/manager.js | 459 | 17,230 |
tests/pass-entry-format.test.js | 409 | 17,942 |
tests/userscript.test.js | 369 | 13,025 |
tests/pass-integration.test.js | 355 | 17,965 |
tests/quality.test.js | 352 | 17,665 |
tests/modal.test.js | 299 | 16,097 |
tests/identity-tokens.test.js | 280 | 14,417 |
%ARCHITECTURE
Three processes, six storage planes. Chrome hosts the extension; the extension's SW (one process) talks to a Rust native messaging host (one process per request, plus detached download worker processes that outlive their parent). All persistent state lives in chrome.storage or on the filesystem under ~/.cache/zpwrchrome/ — nothing relies on the SW staying alive.
Cyan edges = in-process chrome.* calls. Magenta edges = native messaging RPC (stdio, length-prefixed JSON, one round-trip per process). Pink edges = filesystem I/O performed by the detached worker process. Dashed = process-spawn or asynchronous (worker doesn't await parent; SW doesn't await worker).
@EXECUTION PIPELINE
Three persistence stores: chrome.storage.session for MRU (survives SW restart, not browser restart), chrome.storage.local for scenes / userscripts / GM bags / fire log, and the Chrome-managed chrome.history + chrome.sessions APIs for browsing history and recently-closed tabs.
chrome.tabs events background.js (SW) chrome.storage onActivated ────────────▶ pushMru / dropFromMru ────────▶ .session onRemoved (MRU array) onReplaced .local command dispatcher scenes message API (popup/modal) userscripts userscripts registration fire-log ring history-list (frecency) GM bags │ │ runtime.sendMessage / tabs.sendMessage ▼ popup.html/.js modal/content.js (shadow DOM) ─────────────── ───────────────────────────── 12 categories 10 categories (dormant since v0.4.16) fzf filter 10 categories keyboard nav same protocol kinds scripts-manager/manager.html ──────────────────────────── Tampermonkey-style dashboard 4 tabs · sortable table · firelog reader
&MESSAGE PROTOCOL
19 message kinds handled by the service worker. Popup sends 18 kinds; modal sends 19. tests/protocol.test.js guards against orphans on either side.
activatepopup/modal → SW. Switch to a tab by id + focus its window.close-tabpopup/modal → SW. Close an open tab; refresh.gm:deleteValueuserscript shim → SW. Per-script chrome.storage.local bag delete.gm:fireuserscript shim → SW. Beacon appended to the fire log at script load.gm:getValueuserscript shim → SW. Per-script chrome.storage.local bag read.gm:listValuesuserscript shim → SW. List keys in the per-script bag.gm:notificationuserscript shim → SW. chrome.notifications.create proxy.gm:openInTabuserscript shim → SW. chrome.tabs.create proxy (also used by history-row Enter in the modal).gm:setClipboarduserscript shim → SW. Inject navigator.clipboard.writeText() into the active tab.gm:setValueuserscript shim → SW. Per-script chrome.storage.local bag write.history-deletepopup/modal → SW. chrome.history.deleteUrl for every visit of a URL.history-listpopup/modal → SW. chrome.history.search up to 5000 results, frecency-sorted before return.listpopup/modal → SW. Returns MRU tab list + 25 most-recently-closed sessions.open-scripts-managermodal → SW. Opens scripts-manager/manager.html in a new tab.restorepopup/modal → SW. Restore a closed session by sessionId.scenes-deletepopup/modal → SW. Drop a scene by slug.scenes-listpopup/modal → SW. Returns persisted scenes from chrome.storage.local.scenes-restorepopup/modal → SW. Open a new window populated from a scene by slug.scenes-savepopup/modal → SW. Snapshot the active window's tabs as a named scene.
$KEYBOARD COMMANDS
Chrome MV3 caps commands with default-suggested keys at 4; everything else is user-bound at chrome://extensions/shortcuts. Currently 4 default-keyed (_execute_action=Alt+T, switch-previous-tab=Command+E, open-history=Command+Y, pass-fill=Command+Shift+L), 50 user-bound, 54 total.
%POPUP CATEGORIES
The popup (popup.html/popup.css/popup.js) renders 12 categories with fzf scoring against title + host. Each category is jumpable via Cmd+1..Cmd+0 (where Cmd+0 = History, the 10th slot). The modal mirrors the same list since v0.4.15.
- All Tabs⌘1
- Current Window⌘2
- Pinned⌘3
- Audible⌘4
- Muted⌘5
- Recently Closed⌘6
- Scenes⌘7
- Tree (by opener)⌘8
- Minimap⌘9
- History⌘0
- Pass⌘P
- Tech⌘K
^HISTORY — FRECENCY FORMULA
chrome.history.search({ text: "", maxResults: 5000, startTime: 0 }) returns visits in lastVisitTime-desc order, which over-promotes one-off pages. background.js:history-list re-ranks by frecency before returning to popup/modal. Each result carries its frecency field forward so the fzf sort uses it as a tiebreaker.
// lib/util.js — pure, unit-tested, inlined into modal via UTIL_INLINE export function frecencyScore(item, nowMs = Date.now()) { if (!item) return 0; const visits = (item.visitCount || 0) + 2 * (item.typedCount || 0); if (visits <= 0) return 0; const last = item.lastVisitTime || 0; if (last <= 0) return visits; const hoursAgo = Math.max(0, (nowMs - last) / 3_600_000); return visits / (hoursAgo + 2); }
!PERMISSIONS
18 declared. tests/static.test.js enforces every declared permission is actually used in background.js or popup.js — no dead permissions.
*TESTS
Plain node:test. Zero dependencies. 2948 cases across 181 files in ~1s. CI matrix: Node 20 + 22 on ubuntu-latest.
| File | Tests | Lines |
|---|---|---|
tests/background.test.js | 28 | 203 |
tests/build-scene-restorable.test.js | 12 | 76 |
tests/build.test.js | 21 | 143 |
tests/buildscene-slugify-edge.test.js | 15 | 88 |
tests/buildscene-timing.test.js | 11 | 98 |
tests/ci.test.js | 11 | 73 |
tests/close-tabs-more.test.js | 16 | 98 |
tests/commands.test.js | 22 | 161 |
tests/configure-world.test.js | 12 | 93 |
tests/copy-helpers.test.js | 14 | 87 |
tests/cyber-theme-css.test.js | 26 | 246 |
tests/dispatch-popup.test.js | 16 | 97 |
tests/dispatch-tab-ops.test.js | 12 | 65 |
tests/dl-batch.test.js | 14 | 98 |
tests/dl-integration.test.js | 88 | 1,025 |
tests/dl-postcommands.test.js | 25 | 191 |
tests/docs-index.test.js | 16 | 83 |
tests/domain-hue-distribution.test.js | 11 | 115 |
tests/domain-hue-unit.test.js | 12 | 86 |
tests/expand-match-unit.test.js | 15 | 84 |
tests/find-snippet.test.js | 12 | 119 |
tests/fire-log-handlers.test.js | 12 | 78 |
tests/firelog-init.test.js | 17 | 113 |
tests/flatten-tree-deep-iterative.test.js | 4 | 78 |
tests/flatten-tree-unit-more.test.js | 12 | 82 |
tests/frecency-edge-unit.test.js | 12 | 73 |
tests/frecency-extremes.test.js | 11 | 115 |
tests/fuzz-adversarial.test.js | 17 | 217 |
tests/fuzz-fzf.test.js | 10 | 180 |
tests/fuzz-monte-carlo-scenes.test.js | 7 | 161 |
tests/fuzz-userscript.test.js | 12 | 201 |
tests/fuzz-util.test.js | 12 | 214 |
tests/fzf-constants.test.js | 10 | 91 |
tests/fzf-highlight-integration.test.js | 11 | 144 |
tests/fzf-highlight-more.test.js | 14 | 88 |
tests/fzf-match-edge.test.js | 14 | 87 |
tests/fzf-more.test.js | 14 | 96 |
tests/fzf-position-more.test.js | 12 | 64 |
tests/fzf-stability.test.js | 13 | 123 |
tests/fzf.test.js | 20 | 129 |
tests/gen-pipeline.test.js | 15 | 90 |
tests/gm-background.test.js | 15 | 99 |
tests/gm-shim-aliases.test.js | 14 | 125 |
tests/gm-shim-open-tab.test.js | 12 | 55 |
tests/gm-shim.test.js | 18 | 108 |
tests/handlers-async.test.js | 2 | 65 |
tests/highlight-bounds.test.js | 11 | 91 |
tests/history-handlers.test.js | 17 | 105 |
tests/identity-tokens.test.js | 35 | 280 |
tests/include-pattern-more.test.js | 16 | 107 |
tests/include-pattern-unit.test.js | 15 | 76 |
tests/init-nav-logger.test.js | 12 | 80 |
tests/json-format.test.js | 20 | 180 |
tests/lib-exports.test.js | 3 | 59 |
tests/lights-off-css.test.js | 13 | 132 |
tests/list-handler-detail.test.js | 12 | 81 |
tests/logic-hostname.test.js | 18 | 90 |
tests/logic-more.test.js | 19 | 120 |
tests/logic-tree-more.test.js | 14 | 98 |
tests/logic.test.js | 75 | 555 |
tests/manager-banner-refresh.test.js | 14 | 85 |
tests/manager-chrome-ext.test.js | 11 | 58 |
tests/manager-css.test.js | 18 | 94 |
tests/manager-editor-keys.test.js | 12 | 68 |
tests/manager-editor-meta.test.js | 14 | 82 |
tests/manager-editor.test.js | 22 | 119 |
tests/manager-firelog.test.js | 17 | 91 |
tests/manager-formatters.test.js | 12 | 67 |
tests/manager-import-export-more.test.js | 14 | 84 |
tests/manager-log-live.test.js | 13 | 71 |
tests/manager-row-actions.test.js | 18 | 92 |
tests/manager-sort-filter.test.js | 16 | 86 |
tests/manager-table.test.js | 18 | 107 |
tests/manager-utilities.test.js | 17 | 94 |
tests/manager.test.js | 36 | 223 |
tests/manifest-commands-meta.test.js | 20 | 149 |
tests/manifest-extended.test.js | 19 | 106 |
tests/manifest-icons-commands.test.js | 14 | 97 |
tests/manifest-permissions-more.test.js | 15 | 83 |
tests/match-pattern-flow.test.js | 10 | 124 |
tests/match-pattern-unit.test.js | 15 | 84 |
tests/matchPatternToRegex-schemes.test.js | 15 | 111 |
tests/modal-built.test.js | 22 | 127 |
tests/modal-close-teardown.test.js | 14 | 81 |
tests/modal-handle-delete.test.js | 12 | 73 |
tests/modal-hold.test.js | 23 | 138 |
tests/modal-html-a11y.test.js | 12 | 73 |
tests/modal-message.test.js | 16 | 86 |
tests/modal-refresh-chain.test.js | 14 | 78 |
tests/modal-template-css.test.js | 16 | 86 |
tests/modal-template.test.js | 37 | 203 |
tests/modal-wire-scene.test.js | 11 | 66 |
tests/modal-wire.test.js | 20 | 109 |
tests/modal.test.js | 27 | 299 |
tests/mru-invariants.test.js | 12 | 123 |
tests/mru-realistic-session.test.js | 11 | 113 |
tests/mru-session.test.js | 16 | 105 |
tests/mru-step-large-delta.test.js | 7 | 56 |
tests/mru-step-unit.test.js | 14 | 70 |
tests/mru-switch-step.test.js | 14 | 96 |
tests/mru-wire.test.js | 18 | 120 |
tests/nav-fallback.test.js | 20 | 103 |
tests/package-description-drift.test.js | 2 | 39 |
tests/parity-extended.test.js | 16 | 113 |
tests/parity.test.js | 17 | 127 |
tests/parse-metadata-more.test.js | 15 | 114 |
tests/parseMetadata-duplicate-keys.test.js | 13 | 131 |
tests/pass-entry-format.test.js | 50 | 409 |
tests/pass-integration.test.js | 35 | 355 |
tests/popup-activate.test.js | 18 | 103 |
tests/popup-css.test.js | 18 | 105 |
tests/popup-escape-html.test.js | 6 | 64 |
tests/popup-history-delete-key.test.js | 12 | 69 |
tests/popup-html.test.js | 13 | 77 |
tests/popup-interaction.test.js | 18 | 100 |
tests/popup-keys.test.js | 21 | 122 |
tests/popup-lifecycle.test.js | 15 | 93 |
tests/popup-list.test.js | 18 | 104 |
tests/popup-minimap-render.test.js | 14 | 77 |
tests/popup-minimap.test.js | 15 | 86 |
tests/popup-refresh-first.test.js | 14 | 82 |
tests/popup-render-cats-more.test.js | 12 | 71 |
tests/popup-render-list-more.test.js | 18 | 109 |
tests/popup-render.test.js | 21 | 111 |
tests/popup-scene-form-more.test.js | 11 | 62 |
tests/popup-time-fmt-behavior.test.js | 3 | 52 |
tests/popup-time-static.test.js | 12 | 75 |
tests/popup-tree-kill.test.js | 10 | 64 |
tests/popup-ui.test.js | 28 | 157 |
tests/popup.test.js | 20 | 123 |
tests/processes-api-detect.test.js | 3 | 31 |
tests/processes-handlers.test.js | 6 | 68 |
tests/processes.test.js | 4 | 41 |
tests/protocol-extended.test.js | 18 | 116 |
tests/protocol.test.js | 7 | 89 |
tests/quality.test.js | 17 | 352 |
tests/reader-mode-css.test.js | 15 | 153 |
tests/readme.test.js | 11 | 98 |
tests/report-html.test.js | 27 | 187 |
tests/resolve-boundary.test.js | 16 | 85 |
tests/scene-crud-composition.test.js | 11 | 124 |
tests/scene-restore-open.test.js | 12 | 75 |
tests/scenes-handlers.test.js | 18 | 116 |
tests/scenes-restore.test.js | 21 | 140 |
tests/screenshot.test.js | 15 | 179 |
tests/scripts-save.test.js | 22 | 136 |
tests/scripts-storage.test.js | 16 | 103 |
tests/scripts-toggle-storage.test.js | 13 | 83 |
tests/sessions-restore.test.js | 14 | 95 |
tests/single-tab-ops.test.js | 19 | 105 |
tests/static.test.js | 41 | 561 |
tests/stress-memory-scale.test.js | 11 | 170 |
tests/stress-pathological-fzf.test.js | 15 | 139 |
tests/stress-timing-budgets.test.js | 11 | 167 |
tests/sync-failure-paths.test.js | 14 | 81 |
tests/sync-register.test.js | 20 | 112 |
tests/sync.test.js | 30 | 185 |
tests/tab-batch-extended.test.js | 16 | 102 |
tests/tab-ops.test.js | 29 | 175 |
tests/tabs-mru-listeners.test.js | 12 | 71 |
tests/theme-extended.test.js | 14 | 85 |
tests/theme-images.test.js | 14 | 80 |
tests/theme.test.js | 12 | 167 |
tests/totp.test.js | 16 | 185 |
tests/ua-presets.test.js | 12 | 99 |
tests/userscript-edge.test.js | 16 | 101 |
tests/userscript-id-edge.test.js | 15 | 86 |
tests/userscript-malformed-r4.test.js | 8 | 94 |
tests/userscript-more.test.js | 16 | 112 |
tests/userscript-parse-edge.test.js | 12 | 116 |
tests/userscript-real-world.test.js | 14 | 215 |
tests/userscript-regex-more.test.js | 18 | 107 |
tests/userscript-roundtrip.test.js | 12 | 144 |
tests/userscript.test.js | 37 | 369 |
tests/util-buildtree-edge.test.js | 11 | 135 |
tests/util-flatten-collapsed-shapes.test.js | 11 | 86 |
tests/util-frecency-more.test.js | 14 | 77 |
tests/util-large-scale.test.js | 10 | 128 |
tests/util-mru-cap-edge.test.js | 10 | 63 |
tests/validate-userscript-unit.test.js | 13 | 87 |
tests/wappalyzer-engine.test.js | 19 | 200 |
TOTAL | 2948 | 22,708 |
?KEY DESIGN DECISIONS
Service worker, not background page
MV3 requires an event-driven SW. State lives in chrome.storage.session (MRU) and chrome.storage.local (scenes, userscripts, GM bags, dl.snapshot mirror) — never in module-level globals.
No build step
Zero npm dependencies at runtime. No bundler, no transpiler. Pure ES modules in the SW; popup ships as a regular extension page; modal pre-builds via scripts/build-modal.sh inlining fonts + lib/fzf.js + lib/util.js into a single content-script file.
Native messaging host in Rust, not JS
pass + gpg can't run inside the SW (MV3 has no shell). One long-lived Rust process per Chrome session multiplexes pass + dl channels over the same length-prefixed JSON port (4-byte LE len, ≤1 MiB/msg per spec). Single install.sh writes the NM manifest for Chrome/Chromium/Brave/Edge on macOS+Linux.
Vendored Rust HTTP client, not aria2
ureq + rustls compiled into the host gives portable HTTP/HTTPS with Range support — no aria2 or curl binary on PATH. Pure-Rust TLS works on macOS aarch64 + Linux x86_64/aarch64 with no system OpenSSL dependency. Future-proof against OS TLS API churn.
Segmented download via Range, file pre-allocated
HEAD probe + 4-way parallel Range GETs. Destination file pre-allocated to total size via set_len so segment threads never collide on disk writes. downloaded_in_seg counter tracks per-segment progress so a mid-stream connection drop resumes via Range from the correct offset rather than restarting the segment.
Cookie + UA forwarded for logged-in URLs
chrome.cookies.getAll(url) → Cookie header on every HEAD + GET. Without this, downloads behind a login (paywalls, GitHub private releases, session-piggybacked S3 URLs) silently 401 / 403. UA forwarded too so servers that key on UA (GitHub release filtering, browser-detection paywalls) behave identically to a regular browser download.
Clipboard auto-clear matches <code>pass -c</code>
45 s setTimeout on copy. Fail-open: if the SW dies before the timer fires the clipboard stays, which is the conservative direction (worst case the user sees their password longer; never accidentally clobbers a later copy they made).
fzf scorer ported from audio-haxor
Same constants — boundary=9, camel=7, gap-start=-3, match=16. Visual parity () across MenkeTechnologies' tools.
Closed shadow DOM for the modal
Host-page CSS can never leak in. Fonts inlined as base64 data: URIs so strict host-page font-src CSP can't block them.
Window-capture keydown for the modal
window.addEventListener("keydown", h, true) + stopImmediatePropagation beats Vimium / cVim / any other extension that listens on document.
Frecency for History
visitCount + 2*typedCount over hoursAgo+2. Typed visits weigh 2x (deliberate). Linear decay: ~57x weight to 1h-ago vs 1w-ago.
Default-key ceiling = 4
Chrome MV3 hard cap. Currently 3 used (Alt+T popup, Cmd+E switch-previous-tab, Cmd+Y history). Everything else binds at chrome://extensions/shortcuts.
Pure helpers in lib/util.js
Zero chrome.* refs so they unit-test in plain Node and so they can also be inlined into the content-script modal via UTIL_INLINE_START/END markers + scripts/build-modal.mjs.
Pure helpers in zpwrchrome-host/src/extensions/
Filename sanitization, unique_dest_path collision handling, subseq search scorer, OTP otpauth extractor — all fns with no I/O. cargo test exercises them directly. Integration tests stand up a std::net HTTP/1.1 fixture with Range support to drive the detached worker process end-to-end, with cookie-gate + retry-recovery + cancel paths.