2026-06-17 09:24:21 -07:00
|
|
|
|
# Hanzo Extension
|
2026-03-11 10:25:49 -07:00
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
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.
|
2026-03-11 10:25:49 -07:00
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
## Architecture (native ZAP)
|
2026-03-11 10:25:49 -07:00
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
extension ─connectNative("ai.hanzo.zap")─► native host ─UDS─► zapd ◄─ hanzo-mcp
|
2026-03-11 10:25:49 -07:00
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
- `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.
|
2026-06-16 22:03:00 -07:00
|
|
|
|
Cross-browser (`browser ∥ chrome`).
|
2026-06-17 09:24:21 -07:00
|
|
|
|
- `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.ts` — `chrome.debugger` actuation (Chrome-only).
|
2026-07-02 21:38:05 -07:00
|
|
|
|
- `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.
|
2026-05-07 21:33:02 -07:00
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
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`).
|
2026-05-07 21:33:02 -07:00
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
## 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).
|
2026-05-07 21:33:02 -07:00
|
|
|
|
|
2026-07-24 23:15:51 -07:00
|
|
|
|
## CI/CD (native — Hanzo Git, KMS, act_runner)
|
|
|
|
|
|
Git of record is `git.hanzo.ai/hanzoai/extension`; GitHub is a mirror.
|
|
|
|
|
|
- `.gitea/workflows/*` — native pipeline on `hanzo-build-linux-amd64` act_runners:
|
|
|
|
|
|
`ci.yml` (amd64 test + build), `publish.yml` (Chrome Web Store + Firefox AMO + npm).
|
|
|
|
|
|
- Secrets are **KMS only**. The pipeline logs in with the KMS machine identity
|
|
|
|
|
|
(`KMS_CLIENT_ID`/`KMS_CLIENT_SECRET`) and pulls store creds from `hanzo:/extension-publish`
|
|
|
|
|
|
(env `prod`). CR: `deploy/kms/extension-publish-kms-sync.yaml`. No store cred in
|
|
|
|
|
|
any Actions secret store.
|
|
|
|
|
|
- `.github/workflows/` mirrors + degrades gracefully: `sync.yml` pushes main+tags to
|
|
|
|
|
|
Hanzo Git; `ci.yml`/`cross-platform-e2e.yml` keep the macOS(Safari)/Windows/matrix
|
|
|
|
|
|
lanes that still need GitHub-hosted runners; `publish.yml` keeps only the GitHub
|
|
|
|
|
|
Release + the interim npm publish (store-publish removed → native). See PUBLISHING.md.
|
|
|
|
|
|
|
2026-06-17 09:24:21 -07:00
|
|
|
|
## 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.swift` → `zapd.sock`.
|
|
|
|
|
|
5. CI guards (last; go red until 1–4 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.
|