Files
browser/manifest.ts
T
pastilhasandClaude Opus 5 52934f52dc browser, extracted from the platform — extension, relay and all
Your own Chrome, driven from Officer. Not a headless one: it attaches to the browser you are already
signed into, which is the whole difference from /scrape, and /scrape stays behind in the platform.

The relay is a sidecar now, and that is the point. It was a second Bun.serve inside the platform
process on its own port, which is exactly why it was switched off on 2026-08-13 — "the platform serves
one port". A sidecar is a process allowed its own listeners, so the objection stops applying instead of
being argued with.

The boundary across it is deliberately small: two questions, who is connected and what tabs they have,
because only those live in memory on the relay side. Screenshots, evaluation and navigation still go
straight down cdp.ts's own WebSocket to the relay's /cdp endpoint, exactly as before — routing page
bytes through the platform would be work for nothing.

Three normally-breaking changes taken now because now they are free, each already recommended in a
comment by whoever switched the relay off. Its own signing key instead of borrowing getKey('jwt'). Its
own table instead of the platform's user_integrations. And the port kept at 18792 on purpose, because
the port is an input to the token HMAC as well as an address — moving it fails every pairing silently,
and the extension blames the address. user_integrations held zero browser-relay rows, checked in
Postgres rather than assumed, so there was nothing to unpair.

The screen became panels. BrowserScreen.tsx rendered TabList and TabPreview through appType: null
placeholders; both components were already self-contained and took no props, so the screen had nothing
to pass and simply went.

Not tested end to end — no browser has been paired since the move, and that needs a Chrome and a
person. BLOCKERS.md says so rather than the commit implying otherwise.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:04:09 +00:00

49 lines
2.4 KiB
TypeScript

import type { PluginManifest } from '@@/plugins/manifest';
// Browser — your own Chrome, driven from Officer, through an extension you install yourself.
//
// Extracted 2026-08-21, having been switched off since 2026-08-13. It was never a scraper: it attaches to
// the browser the person is already using, with their sessions, their logins and their tabs. That is the
// whole difference from `/scrape`, which stays in the platform and launches a headless chromium that
// knows nobody.
//
// extension/ the Chrome extension — the half that runs in the browser
// sidecar/ the relay it connects to, on a FIXED port, plus the CDP bridge
// api/ pairing, status, and the target verbs
// db/ one table: the salt each pairing's token is derived from
// web/ the tab list and preview panels
//
// ── Why the relay is a sidecar ──
//
// It listens on its own port, which is why it was switched off: the platform serves one. A sidecar is a
// process with its own listeners, so the objection disappears rather than being argued with.
export const manifest: PluginManifest = {
publisher: 'officerdev',
version: '1.0.0',
platform: '>=1.0.0',
label: 'Browser',
summary: 'Drive your own browser from Officer — your tabs, your sessions, your logins',
icon: 'Globe',
color: '#38bdf8',
permissions: [
{
key: 'browser-relay',
label: 'Browser',
description: 'Pair a browser and drive its tabs — screenshots, navigation, evaluated scripts',
// NOT owner-only, unlike desktop, and the difference is real: every route here is scoped by the
// caller's own pairing. A member pairs THEIR browser, and the relay resolves an extension's token
// to the account that minted it — so two accounts on one server drive two different browsers.
//
// That is also why this is not the platform's `browser` permission, which is `kind: 'execution'`
// and covers `/scrape`. Those are different things wearing the same word: one runs a headless
// chromium as the owner, this one attaches to whoever is holding the keyboard.
},
],
// Nothing to declare. The extension is installed by the person, into their own browser, and the relay
// is Bun — there is no host binary in the path at all. Chrome itself is deliberately NOT declared: it
// does not have to be on this machine, and on a remote pairing it is not.
};