Files
extension/LLM.md
T
hanzo-dev c4424826f9 release: browser-extension 1.9.24 — one evaluate rule across Chrome+Firefox
shared/evaluable.ts is the single cross-browser rule for caller-supplied
JS: pickEvaluable accepts every code-param alias (expression/code/script/
function/js); wrapEvaluable passes bare expressions through and wraps
statement bodies in an async IIFE with the trailing value auto-returned.
Both dispatch paths consume it — browser-dispatch.ts (chrome.debugger
Runtime.evaluate, which also gains the plain 'evaluate' method alias
Firefox already accepted) and background-firefox.ts, whose previous
`return (${code})` wrap was a SyntaxError on any multi-statement body
and silently returned undefined for `expr;`. The Firefox path now always
settles promises in-page and routes rejections over the __hanzo_error
channel so callers see the real page-side error.

Tests: behavioral suite for the wrapper (evaluates wrapped output, not
string-matching); revive the three suites dead since the node bridge was
deleted — parity contracts repointed at browser-dispatch.ts, the IAM
contracts updated to the HIP-0111 canonical /v1/iam/oauth/token shape,
hub-wiring trimmed to the live background.ts surface, and the node-bridge
routing suite removed with its subject. 243 passing (was 186 + 3 dead
files).
2026-07-02 21:38:18 -07:00

2.9 KiB
Raw Blame History

Hanzo Extension

Browser extension (packages/browser) that joins the shared local zapd fabric. One native primitive — no WebSocket, no localhost port, no mDNS, no CDP bridge. Ships Chrome / Firefox / Safari. Build: esbuild (src/build.js, pnpm build); tests: vitest.

Architecture (native ZAP)

extension ─connectNative("ai.hanzo.zap")─► native host ─UDS─► zapd ◄─ hanzo-mcp
  • shared/native-zap.ts — the ONE transport: connectNativeZap() opens the native port (singleton — one port; the router does evict-and-replace), registers as provider browser:<engine>/<host>/default, dispatches inbound ROUTE commands. Cross-browser (browser ∥ chrome).
  • background.ts (Chrome) — dispatch via chrome.debugger (CDP→tab; shows the "debugging this browser" banner; WebKit-incompatible). To be removed — see WXT plan.
  • background-firefox.ts — native browser.* dispatch (no banner). The correct model.
  • browser-dispatch.tschrome.debugger actuation (Chrome-only).
  • shared/evaluable.ts — the ONE evaluate rule: pickEvaluable (code-param aliases) + wrapEvaluable (bare expression passes through; statement bodies → async IIFE with the trailing value auto-returned). Both dispatch paths consume it, so Chrome and Firefox accept identical caller JS.

Wire to zapd: the binary ZAP router envelope (zap-proto/zapd/src/frame.rs); the browser↔host hop is native-messaging JSON, base64'd, quarantined in the host. Host + per-browser manifests come from zapd install-host (zap-proto/zapd).

Versioning

Patch only (X.Y.Z+1), never major. package.json is the source of truth; build.js stamps it into every manifest (chrome/firefox/safari).

Cross-platform — WXT migration (canonical plan, not yet executed)

One WebExtension codebase, every engine. WXT = build/SDK layer (build matrix, manifest gen, targets, MV3, Vite/TS); webextension-polyfill / @wxt-dev/browser = browser.* normalization. Custom (keep): shared/native-zap.ts, and the Safari SafariWebExtensionHandler.swift~/.zap/run/zapd.sock bridge. WXT builds Safari but does NOT give WebKit chrome.debugger — so dispatch must become portable browser.* (the Firefox model is already correct).

  1. Adopt WXT build matrix (chrome/firefox/safari) — replaces build.js.
  2. Collapse forks → one background.ts; delete background-firefox.ts; runtime browser adapter.
  3. Collapse dispatch → delete chrome.debugger / browser-dispatch.ts; actuate over tabs/scripting/webNavigation/browser.* (portable, no banner, Safari-capable).
  4. Transport stays per-platform: Chrome/Firefox connectNative → host → zapd.sock; Safari SafariWebExtensionHandler.swiftzapd.sock.
  5. CI guards (last; go red until 14 land): fail if chrome.debugger, the debugger permission, or background-firefox.ts appears.

Large, multi-phase — do it as a focused pass, never half-merged.