// ZPWRCHROME — ENGINEERING REPORT

Manifest V3 Chrome extension · cross-window MRU · 54 keyboard commands · 12-category fzf-scored popup · chrome.userScripts Tampermonkey-equivalent · frecency-ranked history search

>_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.

6,959
JS Lines
1,104
CSS Lines
54
Keyboard Commands
2948
Tests Passing
12
Popup Categories
19
Message Kinds
39
Dispatch Handlers
18
Permissions
15
Pure Helpers
356
Repo Files
4
Default-Keyed
v0.21.4
Version

Source distribution — 31,061 total lines

JS · 6,959 lines · 22.4%
Tests · 22,708 lines · 73.1%
CSS · 1,104 lines · 3.6%
HTML · 290 lines · 0.9%

~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 lines
  • popup.css — 601 lines
  • popup.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 lines
  • lib/cyber-theme-css.js — 0 lines
  • scripts-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 lines
  • lib/reader-mode-css.js — 0 lines
  • scripts-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 lines
  • lib/lights-off-css.js — 0 lines
  • scripts-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 lines
  • lib/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 lines
  • scripts-manager/ua-switcher.html — 0 lines
  • lib/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 lines
  • lib/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 lines
  • lib/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 lines
  • lib/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 lines
  • scripts-manager/manager.js — 459 lines
  • scripts-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 lines
  • scripts-manager/downloads.js — 0 lines
  • scripts-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.

PathLinesBytes
background.js3,727152,518
popup.js1,22150,053
tests/dl-integration.test.js1,02552,864
modal/content.template.js93037,419
popup.css60118,689
tests/static.test.js56126,240
tests/logic.test.js55522,613
scripts-manager/manager.css50316,708
scripts-manager/manager.js45917,230
tests/pass-entry-format.test.js40917,942
tests/userscript.test.js36913,025
tests/pass-integration.test.js35517,965
tests/quality.test.js35217,665
tests/modal.test.js29916,097
tests/identity-tokens.test.js28014,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.

CHROME (host browser) Service Worker (MV3) background.js · 1 process commands · NM bridge · context menus Popup (toolbar) popup.html · 12 categories downloads strip + clipboard banner Extension pages scripts-manager/* · pass / manager / dl theme / lights / ua / find / settings Content scripts modal/{content,cyber-theme,lights-off,json-viewer}.js pass-fill / userscripts / screenshot probe chrome.* APIs tabs / windows / scripting downloads / contextMenus notifications / sessions history / commands cookies webRequest · userScripts action.setBadgeText runtime.sendNativeMessage chrome.storage .session → MRU stack .local → dl.settings, dl.rules, dl.snapshot, scenes, scripts, zpc.diag .local → pass.settings Web pages N user tabs login forms (pass) link/media targets scrollable bodies (screenshot src) NATIVE HOST (Rust) zpwrchrome-host crates.io · v0.9.6 one process per NM message stdio: length-prefixed JSON Extension actions dl.{add,list,pause,resume,cancel} dl.{clear,openDir,openFile,writeFile} otp · search · echo Detached workers --dl-worker (one per gid) setsid + close FD ≥ 3 ureq+rustls · Range requests FILESYSTEM (~) ~/.cache/zpwrchrome/dl/ gid_NNNNNN.json (one per download) next_gid (monotonic counter) worker.log (detached worker out) host.log (every NM invocation) Authoritative download state — survives SW restart, browser restart ~/Downloads/ User-configured (settings.downloadDir) Falls through: downloadDir → lastDir → default_download_dir() (host) Per-download bytes (segmented HTTP) + screenshots (dl.writeFile) ~/.password-store/ browserpass-compatible GPG-encrypted *.gpg entries Read by host actions: list / fetch / tree / search / otp Powers pass-fill keystroke + autofill badge sendNativeMessage (stdio framed JSON) HTTP segments → file state files (read/write/atomic rename) gpg decrypt

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.

$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.

7
Switching / popup
9
Jump
6
Single-tab ops
7
Batch tab ops
6
Scenes
1
Userscripts

%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.

^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.

tabs tabGroups sessions bookmarks history storage scripting userScripts webNavigation clipboardWrite nativeMessaging contextMenus notifications cookies webRequest webRequestAuthProvider downloads declarativeNetRequestWithHostAccess

*TESTS

Plain node:test. Zero dependencies. 2948 cases across 181 files in ~1s. CI matrix: Node 20 + 22 on ubuntu-latest.

FileTestsLines
tests/background.test.js28203
tests/build-scene-restorable.test.js1276
tests/build.test.js21143
tests/buildscene-slugify-edge.test.js1588
tests/buildscene-timing.test.js1198
tests/ci.test.js1173
tests/close-tabs-more.test.js1698
tests/commands.test.js22161
tests/configure-world.test.js1293
tests/copy-helpers.test.js1487
tests/cyber-theme-css.test.js26246
tests/dispatch-popup.test.js1697
tests/dispatch-tab-ops.test.js1265
tests/dl-batch.test.js1498
tests/dl-integration.test.js881,025
tests/dl-postcommands.test.js25191
tests/docs-index.test.js1683
tests/domain-hue-distribution.test.js11115
tests/domain-hue-unit.test.js1286
tests/expand-match-unit.test.js1584
tests/find-snippet.test.js12119
tests/fire-log-handlers.test.js1278
tests/firelog-init.test.js17113
tests/flatten-tree-deep-iterative.test.js478
tests/flatten-tree-unit-more.test.js1282
tests/frecency-edge-unit.test.js1273
tests/frecency-extremes.test.js11115
tests/fuzz-adversarial.test.js17217
tests/fuzz-fzf.test.js10180
tests/fuzz-monte-carlo-scenes.test.js7161
tests/fuzz-userscript.test.js12201
tests/fuzz-util.test.js12214
tests/fzf-constants.test.js1091
tests/fzf-highlight-integration.test.js11144
tests/fzf-highlight-more.test.js1488
tests/fzf-match-edge.test.js1487
tests/fzf-more.test.js1496
tests/fzf-position-more.test.js1264
tests/fzf-stability.test.js13123
tests/fzf.test.js20129
tests/gen-pipeline.test.js1590
tests/gm-background.test.js1599
tests/gm-shim-aliases.test.js14125
tests/gm-shim-open-tab.test.js1255
tests/gm-shim.test.js18108
tests/handlers-async.test.js265
tests/highlight-bounds.test.js1191
tests/history-handlers.test.js17105
tests/identity-tokens.test.js35280
tests/include-pattern-more.test.js16107
tests/include-pattern-unit.test.js1576
tests/init-nav-logger.test.js1280
tests/json-format.test.js20180
tests/lib-exports.test.js359
tests/lights-off-css.test.js13132
tests/list-handler-detail.test.js1281
tests/logic-hostname.test.js1890
tests/logic-more.test.js19120
tests/logic-tree-more.test.js1498
tests/logic.test.js75555
tests/manager-banner-refresh.test.js1485
tests/manager-chrome-ext.test.js1158
tests/manager-css.test.js1894
tests/manager-editor-keys.test.js1268
tests/manager-editor-meta.test.js1482
tests/manager-editor.test.js22119
tests/manager-firelog.test.js1791
tests/manager-formatters.test.js1267
tests/manager-import-export-more.test.js1484
tests/manager-log-live.test.js1371
tests/manager-row-actions.test.js1892
tests/manager-sort-filter.test.js1686
tests/manager-table.test.js18107
tests/manager-utilities.test.js1794
tests/manager.test.js36223
tests/manifest-commands-meta.test.js20149
tests/manifest-extended.test.js19106
tests/manifest-icons-commands.test.js1497
tests/manifest-permissions-more.test.js1583
tests/match-pattern-flow.test.js10124
tests/match-pattern-unit.test.js1584
tests/matchPatternToRegex-schemes.test.js15111
tests/modal-built.test.js22127
tests/modal-close-teardown.test.js1481
tests/modal-handle-delete.test.js1273
tests/modal-hold.test.js23138
tests/modal-html-a11y.test.js1273
tests/modal-message.test.js1686
tests/modal-refresh-chain.test.js1478
tests/modal-template-css.test.js1686
tests/modal-template.test.js37203
tests/modal-wire-scene.test.js1166
tests/modal-wire.test.js20109
tests/modal.test.js27299
tests/mru-invariants.test.js12123
tests/mru-realistic-session.test.js11113
tests/mru-session.test.js16105
tests/mru-step-large-delta.test.js756
tests/mru-step-unit.test.js1470
tests/mru-switch-step.test.js1496
tests/mru-wire.test.js18120
tests/nav-fallback.test.js20103
tests/package-description-drift.test.js239
tests/parity-extended.test.js16113
tests/parity.test.js17127
tests/parse-metadata-more.test.js15114
tests/parseMetadata-duplicate-keys.test.js13131
tests/pass-entry-format.test.js50409
tests/pass-integration.test.js35355
tests/popup-activate.test.js18103
tests/popup-css.test.js18105
tests/popup-escape-html.test.js664
tests/popup-history-delete-key.test.js1269
tests/popup-html.test.js1377
tests/popup-interaction.test.js18100
tests/popup-keys.test.js21122
tests/popup-lifecycle.test.js1593
tests/popup-list.test.js18104
tests/popup-minimap-render.test.js1477
tests/popup-minimap.test.js1586
tests/popup-refresh-first.test.js1482
tests/popup-render-cats-more.test.js1271
tests/popup-render-list-more.test.js18109
tests/popup-render.test.js21111
tests/popup-scene-form-more.test.js1162
tests/popup-time-fmt-behavior.test.js352
tests/popup-time-static.test.js1275
tests/popup-tree-kill.test.js1064
tests/popup-ui.test.js28157
tests/popup.test.js20123
tests/processes-api-detect.test.js331
tests/processes-handlers.test.js668
tests/processes.test.js441
tests/protocol-extended.test.js18116
tests/protocol.test.js789
tests/quality.test.js17352
tests/reader-mode-css.test.js15153
tests/readme.test.js1198
tests/report-html.test.js27187
tests/resolve-boundary.test.js1685
tests/scene-crud-composition.test.js11124
tests/scene-restore-open.test.js1275
tests/scenes-handlers.test.js18116
tests/scenes-restore.test.js21140
tests/screenshot.test.js15179
tests/scripts-save.test.js22136
tests/scripts-storage.test.js16103
tests/scripts-toggle-storage.test.js1383
tests/sessions-restore.test.js1495
tests/single-tab-ops.test.js19105
tests/static.test.js41561
tests/stress-memory-scale.test.js11170
tests/stress-pathological-fzf.test.js15139
tests/stress-timing-budgets.test.js11167
tests/sync-failure-paths.test.js1481
tests/sync-register.test.js20112
tests/sync.test.js30185
tests/tab-batch-extended.test.js16102
tests/tab-ops.test.js29175
tests/tabs-mru-listeners.test.js1271
tests/theme-extended.test.js1485
tests/theme-images.test.js1480
tests/theme.test.js12167
tests/totp.test.js16185
tests/ua-presets.test.js1299
tests/userscript-edge.test.js16101
tests/userscript-id-edge.test.js1586
tests/userscript-malformed-r4.test.js894
tests/userscript-more.test.js16112
tests/userscript-parse-edge.test.js12116
tests/userscript-real-world.test.js14215
tests/userscript-regex-more.test.js18107
tests/userscript-roundtrip.test.js12144
tests/userscript.test.js37369
tests/util-buildtree-edge.test.js11135
tests/util-flatten-collapsed-shapes.test.js1186
tests/util-frecency-more.test.js1477
tests/util-large-scale.test.js10128
tests/util-mru-cap-edge.test.js1063
tests/validate-userscript-unit.test.js1387
tests/wappalyzer-engine.test.js19200
TOTAL294822,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.