This commit is contained in:
Oleg Maslov
2026-09-02 10:14:22 +02:00
parent 0c3e2ead3b
commit b20b138fe4
771 changed files with 161561 additions and 9027 deletions

View File

@@ -1,69 +1,66 @@
# Waggle Companion · Chrome MV3 extension
# Waggle Companion - Chrome MV3 extension
The browser-side hook for Waggle OS. Lets the user save any page or selection
to their workspace memory from anywhere on the web, without leaving the tab.
Browser-side capture for Waggle OS. It saves a page selection or the current
page to personal Waggle memory without leaving the tab.
This implements **FR-1** from the 2026-05-28 addictiveness audit — closes the
"external trigger surface" rubric gap (dim 1) for the non-coder personas
whose real workflow lives in browser tabs (researcher, journalist, marketer,
writer, retired teacher).
## What it does
## What it does (v0.1.0)
- The popup shows connection status and the active memory destination.
- Save Selection and Save Page send personal imported-memory captures.
- The context menu can save selected text.
- Pairing is explicit: generate a one-time code in Waggle Settings, then enter
it in the popup. The code is single-use and expires after ten minutes.
- **Popup** — shows connection status + the active workspace memory is saving to + two buttons (save selection / save page).
- **Right-click context menu** — "Save to Waggle memory" appears on any text selection.
- **Reuses existing sidecar endpoints** — `/api/browser-ext/session-token` for local token bootstrap, `/api/browser-ext/health` for status, and `/api/memory/frames` for ingest. No new ingest logic.
The popup never makes network requests. The MV3 background worker redeems the
code and stores only the resulting scoped credential in
`chrome.storage.local.companionToken`. Legacy `sessionToken` values are deleted
and never trusted. A rejected credential is removed; captures are never replayed
or automatically re-paired.
## How to load (developer mode, local install)
## Load locally
1. Start the Waggle sidecar with one of these env vars set so its CORS layer accepts the dev extension origin:
- **Quickest (dev only):** `WAGGLE_DEV_ALLOW_ANY_EXTENSION=1` — accepts any `chrome-extension://*` origin. Never set this in production.
- **Production-shaped:** `WAGGLE_BROWSER_EXT_IDS=<your-extension-id>` (comma-separated for multiple IDs). Pin once you have the loaded extension's ID from `chrome://extensions`.
2. Open `chrome://extensions` in Chrome (or Edge, or any Chromium browser).
3. Toggle **Developer mode** on (top right).
4. Click **Load unpacked** and pick this folder (`apps/browser-ext`).
5. Copy the extension ID shown on the card.
6. Restart the sidecar with `WAGGLE_BROWSER_EXT_IDS=<that-id>` for the production-shaped path, or skip this if you used the dev escape hatch in step 1.
7. Pin the extension to the toolbar.
8. Open the popup — you should see a green dot + "Connected" + the memory destination.
1. Start Waggle with an extension allowlist:
- Development only: `WAGGLE_DEV_ALLOW_ANY_EXTENSION=1`
- Production-shaped: `WAGGLE_BROWSER_EXT_IDS=<extension-id>`
2. Open `chrome://extensions`, enable Developer mode, and choose Load unpacked.
3. Select this `apps/browser-ext` directory.
4. If using the production-shaped allowlist, copy the installed extension ID
into `WAGGLE_BROWSER_EXT_IDS` and restart Waggle.
5. In Waggle Settings -> Advanced, generate a Browser Companion code.
6. Enter that code in the extension popup.
Without either env var set, the sidecar rejects Browser Companion token bootstrap and the popup shows setup recovery copy. The extension stores the sidecar session token in `chrome.storage.local.sessionToken` after a successful bootstrap and sends it as a bearer token on save/status calls.
## What's deliberately NOT in v0.1.0
- **Side panel chat** — the Chrome side panel for asking questions about the current page. Designed for v0.2; would call `/api/chat`.
- **One-time-code pairing UX** — v0.1.0 bootstraps the local session token for an env-allowlisted extension ID. A more explicit desktop Settings pairing flow with a one-time code is future hardening.
- **Cross-browser packaging** — manifest is MV3, works on Chrome/Edge/Brave. Firefox needs a parallel manifest shape.
- **Article extraction** — page text capture is `document.body.innerText` capped at 12k chars. Reader-mode style extraction belongs server-side.
- **Icons** — using browser default. Wire in real icons when we have the brand asset.
- **Build step** — vanilla JS, no bundler. Simpler MVP; if we add typescript/react for the side panel later, add Vite then.
Never enable `WAGGLE_DEV_ALLOW_ANY_EXTENSION` in a production build.
## Files
| File | Role |
|---|---|
| `manifest.json` | MV3 manifest — permissions, action, content script, background |
| `popup.html` | Popup UI shell (dark Hive theme inline) |
| `popup.js` | Popup logic — health refresh, selection read, save dispatch |
| `content.js` | Per-page content script — extracts selection + body text on demand |
| `background.js` | Service worker — fetch wrapper to the Waggle sidecar |
| `manifest.json` | MV3 permissions, popup, content script, background worker |
| `popup.html` | Popup UI |
| `popup.js` | Pairing, health, and capture UI logic |
| `content.js` | On-demand selection and page extraction |
| `background.js` | Pairing and authenticated loopback requests |
## Sidecar contract
- `GET /api/browser-ext/session-token` -> `{ token }` for allowlisted extension origins / MV3 service-worker requests.
- `GET /api/browser-ext/health` -> `{ ok: true, version, activeWorkspaceId, activeWorkspace }` (defined in `packages/server/src/local/routes/browser-ext.ts`; `activeWorkspace` is legacy compatibility)
- `POST /api/memory/frames` — existing endpoint, body `{ content, source: 'import', importance: 'normal' | 'low' }`. Dedup runs server-side.
- `POST /api/browser-ext/pair` redeems an allowlisted extension's valid code.
- `GET /api/browser-ext/health` reports local connection and workspace state.
- `POST /api/memory/frames` accepts only `source: "import"`, personal scope,
and normal/low importance for the paired credential.
## Verification
The global desktop session token is never exposed to the extension.
After loading the unpacked extension:
1. Click the extension icon on any web page → status should read "Connected" with a green dot.
2. Select some text → "Save selection to memory" enables → click it → toast reads "Saved to Waggle memory ✓".
3. Open the Waggle desktop → Memory app → confirm the new frame appears with source `import`.
## Manual smoke test
## Roadmap (post-MVP)
1. Open the popup before pairing: it must show the code form and disable
authenticated capture.
2. Pair with a fresh Settings code: the popup must show Connected.
3. Save a selection and confirm a personal frame with source `import` appears.
4. Revoke in Settings: the next health/save request must require a new code and
must not retry the previous capture.
- v0.2 — side panel with chat about the current page (calls `/api/chat`).
- v0.3 — pre-load Waggle's "Ask about this page" agent on important pages (configurable).
- v0.4 — Firefox MV2 parallel manifest.
- v0.5 — explicit auth pairing UX (one-time code from desktop Settings).
## Deferred
- Side-panel chat about the current page.
- Firefox-specific packaging.
- Reader-mode extraction and branded icons.