Commands
--timeout 120000 because the e2e suite launches real browsers. The harness kills every Chrome it started in a finally block; if a test crashes hard, pgrep -fl remote-debugging-port shows leftovers.
Test fixtures
test-apps/ is served by test-apps/server.ts and provides deterministic pages: a form page, a debug page with console noise, exceptions, timers and a source-mapped script, an iframe page, a second page for navigation, a service worker, a manifest, a JSON API with configurable latency, a download endpoint and a WebSocket echo. The e2e suites drive the real companion through the MCP client against these pages in both modes.
Adding a tool
- Register it with
tool(ctx, name, description, zodShape, handler)in the right module undercompanion/src/tools.tsorcompanion/src/devtools/. The wrapper handles the per-agent context, the disabled-tool policy and result normalisation. - Write the description for the agent: what it does, when to use it, what to call instead. Descriptions are the agent’s only manual.
- Add an example to
companion/test/docs-examples.tsand runbun run docs:tools; the generator validates every example against the schema and fails on mismatch. - Cover it in
companion/test/e2e.test.tsordevtools.e2e.test.ts.
Docs site
The docs are a Mintlify site indocs/. Hand-written pages are MDX; docs/tools/** is generated. Preview locally with:
bunx mint broken-links. Deploy by connecting the repository in the Mintlify dashboard with docs as the docs path.
Conventions
- TypeScript with erasable syntax only (no parameter properties, no enums), so Bun runs the source directly.
- One zod (v4) across the project; the MCP SDK’s nested copy is deduplicated by the lockfile.
- Conventional commit messages.
- UI in the extension is vanilla HTML, CSS and TypeScript with design tokens for light and dark themes; no framework.
