local-browser-bridge 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +724 -0
- package/dist/package.json +61 -0
- package/dist/src/browser/chrome.d.ts +19 -0
- package/dist/src/browser/chrome.js +778 -0
- package/dist/src/browser/index.d.ts +3 -0
- package/dist/src/browser/index.js +25 -0
- package/dist/src/browser/safari.d.ts +41 -0
- package/dist/src/browser/safari.js +827 -0
- package/dist/src/browser-attach-ux-helper.d.ts +39 -0
- package/dist/src/browser-attach-ux-helper.js +157 -0
- package/dist/src/capabilities.d.ts +3 -0
- package/dist/src/capabilities.js +182 -0
- package/dist/src/chrome-relay-error-helper.d.ts +19 -0
- package/dist/src/chrome-relay-error-helper.js +78 -0
- package/dist/src/chrome-relay-helper-cli.d.ts +2 -0
- package/dist/src/chrome-relay-helper-cli.js +97 -0
- package/dist/src/chrome-relay-helper.d.ts +29 -0
- package/dist/src/chrome-relay-helper.js +151 -0
- package/dist/src/chrome-relay-state.d.ts +23 -0
- package/dist/src/chrome-relay-state.js +108 -0
- package/dist/src/claude-code.d.ts +20 -0
- package/dist/src/claude-code.js +66 -0
- package/dist/src/cli-reference-adapter.d.ts +13 -0
- package/dist/src/cli-reference-adapter.js +48 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.js +200 -0
- package/dist/src/codex.d.ts +17 -0
- package/dist/src/codex.js +25 -0
- package/dist/src/connection-ux.d.ts +61 -0
- package/dist/src/connection-ux.js +256 -0
- package/dist/src/errors.d.ts +12 -0
- package/dist/src/errors.js +58 -0
- package/dist/src/http-reference-adapter.d.ts +34 -0
- package/dist/src/http-reference-adapter.js +61 -0
- package/dist/src/http.d.ts +3 -0
- package/dist/src/http.js +161 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.js +43 -0
- package/dist/src/mcp-stdio.d.ts +2 -0
- package/dist/src/mcp-stdio.js +10 -0
- package/dist/src/mcp.d.ts +25 -0
- package/dist/src/mcp.js +483 -0
- package/dist/src/reference-adapter.d.ts +32 -0
- package/dist/src/reference-adapter.js +42 -0
- package/dist/src/service/attach-service.d.ts +28 -0
- package/dist/src/service/attach-service.js +272 -0
- package/dist/src/session-metadata.d.ts +4 -0
- package/dist/src/session-metadata.js +88 -0
- package/dist/src/store/session-store.d.ts +14 -0
- package/dist/src/store/session-store.js +52 -0
- package/dist/src/target.d.ts +9 -0
- package/dist/src/target.js +61 -0
- package/dist/src/types.d.ts +397 -0
- package/dist/src/types.js +2 -0
- package/dist/tests/attach-service.test.d.ts +1 -0
- package/dist/tests/attach-service.test.js +1367 -0
- package/dist/tests/browser-attach-ux-helper.test.d.ts +1 -0
- package/dist/tests/browser-attach-ux-helper.test.js +139 -0
- package/dist/tests/chrome-relay-error-helper.test.d.ts +1 -0
- package/dist/tests/chrome-relay-error-helper.test.js +67 -0
- package/dist/tests/chrome-relay-helper.test.d.ts +1 -0
- package/dist/tests/chrome-relay-helper.test.js +142 -0
- package/dist/tests/chrome-relay-state-schema.test.d.ts +1 -0
- package/dist/tests/chrome-relay-state-schema.test.js +96 -0
- package/dist/tests/claude-code-wrapper.test.d.ts +1 -0
- package/dist/tests/claude-code-wrapper.test.js +170 -0
- package/dist/tests/codex.test.d.ts +1 -0
- package/dist/tests/codex.test.js +210 -0
- package/dist/tests/demo-client-smoke.test.d.ts +1 -0
- package/dist/tests/demo-client-smoke.test.js +405 -0
- package/dist/tests/docs-fixtures.test.d.ts +1 -0
- package/dist/tests/docs-fixtures.test.js +255 -0
- package/dist/tests/doctor-connect-wrapper.test.d.ts +1 -0
- package/dist/tests/doctor-connect-wrapper.test.js +62 -0
- package/dist/tests/fixtures/doctor-connect-cli-stub.d.ts +1 -0
- package/dist/tests/fixtures/doctor-connect-cli-stub.js +93 -0
- package/dist/tests/fixtures/public-root-cli-stub.d.ts +210 -0
- package/dist/tests/fixtures/public-root-cli-stub.js +143 -0
- package/dist/tests/fixtures/public-root-consumer.js +67 -0
- package/dist/tests/mcp.test.d.ts +1 -0
- package/dist/tests/mcp.test.js +345 -0
- package/dist/tests/public-consumer-helpers.test.d.ts +1 -0
- package/dist/tests/public-consumer-helpers.test.js +33 -0
- package/dist/tests/public-package-git-consumption.test.d.ts +1 -0
- package/dist/tests/public-package-git-consumption.test.js +56 -0
- package/dist/tests/public-root-consumer-smoke.test.d.ts +1 -0
- package/dist/tests/public-root-consumer-smoke.test.js +214 -0
- package/dist/tests/reference-adapter.test.d.ts +1 -0
- package/dist/tests/reference-adapter.test.js +220 -0
- package/dist/tests/transport-reference-adapters.test.d.ts +1 -0
- package/dist/tests/transport-reference-adapters.test.js +214 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
# local-browser-bridge
|
|
2
|
+
|
|
3
|
+
Reusable, agent-agnostic local browser bridge for AI clients, developer tools, and scripts.
|
|
4
|
+
|
|
5
|
+
`local-browser-bridge` is a small TypeScript/Node product that exposes a user's real local browser state through two consumer-neutral surfaces:
|
|
6
|
+
|
|
7
|
+
- a JSON CLI for local scripts, shells, and coding agents
|
|
8
|
+
- a local HTTP JSON API for editor plugins, desktop apps, daemon processes, or other clients
|
|
9
|
+
|
|
10
|
+
The project started as `safari-attach-tool`, but the product surface is now intentionally broader than any one consumer or agent runtime.
|
|
11
|
+
|
|
12
|
+
## Implementation status
|
|
13
|
+
|
|
14
|
+
The toolkit contract in this repo is feature-complete for the v1 bridge surface.
|
|
15
|
+
Safari remains actionable in v1, and Chrome/Chromium remains read-only in v1.
|
|
16
|
+
Downstream consumer integration, including adapter wiring for consumers such as OpenClaw, remains integration work outside this repo.
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
If you are new to the repo, start here:
|
|
21
|
+
|
|
22
|
+
- **Understand the toolkit surface first:** [src/index.ts](src/index.ts) is the shared consumer entrypoint. It re-exports the transport-neutral helper surface plus the reference CLI/HTTP adapters used by downstream runtimes and clients.
|
|
23
|
+
- **Use the contract artifacts as the source of truth:** start with [docs/agent-integration-contract.md](docs/agent-integration-contract.md), then the machine-readable schemas in [schema/capabilities.schema.json](schema/capabilities.schema.json) and [schema/chrome-relay-error.schema.json](schema/chrome-relay-error.schema.json), plus the example payloads in [examples/](examples/).
|
|
24
|
+
- **Pick a transport only at the edge:** the toolkit exposes the same bridge contract through the JSON CLI and the local HTTP API. Choose whichever fits your runtime; neither is the privileged path.
|
|
25
|
+
- **Copy from runnable consumers when wiring a client:** use [examples/clients/http-consumer.ts](examples/clients/http-consumer.ts), [examples/clients/cli-consumer.ts](examples/clients/cli-consumer.ts), the CLI-shell wrapper at [examples/clients/doctor-connect-wrapper.ts](examples/clients/doctor-connect-wrapper.ts), the Codex-style wrapper at [examples/clients/codex-consumer.ts](examples/clients/codex-consumer.ts), the Claude Code-style wrapper at [examples/clients/claude-code-tool.ts](examples/clients/claude-code-tool.ts), and the end-to-end demo at [examples/clients/http-node.ts](examples/clients/http-node.ts).
|
|
26
|
+
- **Treat consumer wrappers as convenience only:** Codex-facing helpers such as `normalizeCodexRoute(...)`, `connectCodexViaCli(...)`, and `connectCodexViaHttp(...)` stay on top of the same agent-agnostic adapter/reference layer.
|
|
27
|
+
|
|
28
|
+
## Canonical artifacts and docs
|
|
29
|
+
|
|
30
|
+
Use these artifacts as the canonical sources for product intent, integration behavior, consumer guidance, and the Chrome relay error contract:
|
|
31
|
+
|
|
32
|
+
- [PRD.md](PRD.md) - product requirements and direction
|
|
33
|
+
- [docs/universal-toolkit-summary.md](docs/universal-toolkit-summary.md) - short progress summary of the shared-toolkit direction and where to start
|
|
34
|
+
- [docs/agent-integration-contract.md](docs/agent-integration-contract.md) - transport-neutral integration contract
|
|
35
|
+
- [docs/adapter-patterns.md](docs/adapter-patterns.md) - canonical runtime-neutral adapter patterns for shared consumers
|
|
36
|
+
- [docs/consuming-the-bridge.md](docs/consuming-the-bridge.md) - consumer implementation guidance
|
|
37
|
+
- [src/index.ts](src/index.ts) - shared helper/reference-adapter entrypoint for consumers importing the toolkit as code
|
|
38
|
+
- [schema/capabilities.schema.json](schema/capabilities.schema.json) - stable capabilities contract schema
|
|
39
|
+
- [schema/chrome-relay-error.schema.json](schema/chrome-relay-error.schema.json) - Chrome relay error schema
|
|
40
|
+
- [examples/error.chrome-relay-share-required.example.json](examples/error.chrome-relay-share-required.example.json) - Chrome relay share-required example
|
|
41
|
+
|
|
42
|
+
## What this product is
|
|
43
|
+
|
|
44
|
+
`local-browser-bridge` is:
|
|
45
|
+
|
|
46
|
+
- **agent-agnostic**: Claude Code, Codex, AWOS, custom scripts, or any other client can consume the same contract
|
|
47
|
+
- **local-first**: it runs on the user's machine and exposes only local CLI and local HTTP transports
|
|
48
|
+
- **bridge-first**: the stable product artifact is the browser/session contract, not a single browser-specific script
|
|
49
|
+
- **Safari actionable in v1**: Safari on macOS is the first actionable adapter and sets the quality bar for the contract
|
|
50
|
+
- **Chrome/Chromium read-only in v1**: Chrome participates through the same contract, but action flows are intentionally unavailable in this phase
|
|
51
|
+
|
|
52
|
+
The canonical product requirements document lives in [PRD.md](PRD.md).
|
|
53
|
+
The short direction summary lives in [docs/product-direction.md](docs/product-direction.md).
|
|
54
|
+
The primary agent/client integration contract lives in [docs/agent-integration-contract.md](docs/agent-integration-contract.md).
|
|
55
|
+
The canonical runtime-neutral adapter patterns live in [docs/adapter-patterns.md](docs/adapter-patterns.md).
|
|
56
|
+
The client-consumption guide lives in [docs/consuming-the-bridge.md](docs/consuming-the-bridge.md).
|
|
57
|
+
For OpenClaw/browser-style consumer wiring specifically, see [docs/openclaw-style-consumer-integration.md](docs/openclaw-style-consumer-integration.md).
|
|
58
|
+
For the next-step OpenClaw adapter shape, see [docs/openclaw-adapter-draft.md](docs/openclaw-adapter-draft.md).
|
|
59
|
+
|
|
60
|
+
## Stable contract
|
|
61
|
+
|
|
62
|
+
The bridge has a stable additive contract that clients should key off directly:
|
|
63
|
+
|
|
64
|
+
- `schemaVersion = 1`
|
|
65
|
+
- `kind = "safari-actionable" | "chrome-readonly"`
|
|
66
|
+
|
|
67
|
+
Those fields appear in:
|
|
68
|
+
|
|
69
|
+
- the bridge capabilities payload (`capabilities.schemaVersion`, `capabilities.browsers[*].kind`)
|
|
70
|
+
- every saved/returned session payload (`session.schemaVersion`, `session.kind`)
|
|
71
|
+
|
|
72
|
+
### Contract guidance for clients
|
|
73
|
+
|
|
74
|
+
Treat the contract as follows:
|
|
75
|
+
|
|
76
|
+
- **Use `schemaVersion` for compatibility gates.** Current stable value is `1`.
|
|
77
|
+
- **Use `kind` as the top-level behavior switch.**
|
|
78
|
+
- `safari-actionable` means the saved/current session is expected to support action flows.
|
|
79
|
+
- `chrome-readonly` means inspection and saved-session resume may work, but runtime tab actions are intentionally unavailable in this phase.
|
|
80
|
+
- **Use `session.capabilities` for exact per-session checks** before showing or calling `activate`, `navigate`, or `screenshot`.
|
|
81
|
+
- **Use `session.attach` plus `session.semantics` for trust and UX labeling.**
|
|
82
|
+
- Direct Chrome sessions represent a saved browser tab reference.
|
|
83
|
+
- Relay Chrome sessions represent the last explicitly shared tab only.
|
|
84
|
+
- **Use `session.status.state` for quick UX labeling**:
|
|
85
|
+
- `actionable`
|
|
86
|
+
- `read-only`
|
|
87
|
+
- **Do not infer actionability from browser name alone.** Consume `kind`, `status`, and `capabilities` instead.
|
|
88
|
+
|
|
89
|
+
The machine-readable schema is in [schema/capabilities.schema.json](schema/capabilities.schema.json).
|
|
90
|
+
|
|
91
|
+
## Current browser behavior
|
|
92
|
+
|
|
93
|
+
### Safari: actionable
|
|
94
|
+
|
|
95
|
+
Safari on macOS is the primary adapter. It uses `osascript`/JXA plus `screencapture`; it is not a browser-native automation/debugging stack.
|
|
96
|
+
|
|
97
|
+
Current Safari behavior:
|
|
98
|
+
|
|
99
|
+
- inspect front tab / selected tab / tab list
|
|
100
|
+
- attach and persist sessions
|
|
101
|
+
- resume saved sessions after tab movement via fallback matching strategies
|
|
102
|
+
- activate a target or saved session
|
|
103
|
+
- navigate a target or saved session
|
|
104
|
+
- capture screenshots
|
|
105
|
+
|
|
106
|
+
Safari sessions are emitted as:
|
|
107
|
+
|
|
108
|
+
- `kind: "safari-actionable"`
|
|
109
|
+
- `status.state: "actionable"`
|
|
110
|
+
- session capabilities with `activate`, `navigate`, and `screenshot` set to `true`
|
|
111
|
+
|
|
112
|
+
### Chrome/Chromium: read-only
|
|
113
|
+
|
|
114
|
+
Chrome/Chromium is exposed through the same bridge contract, but in this phase it is deliberately honest and read-only.
|
|
115
|
+
|
|
116
|
+
Current Chrome/Chromium behavior:
|
|
117
|
+
|
|
118
|
+
- inspect front tab / selected tab / tab list when a local DevTools HTTP endpoint is already discoverable
|
|
119
|
+
- attach and persist sessions
|
|
120
|
+
- resume saved sessions in read-only mode when the same inspectable target can still be matched
|
|
121
|
+
- **no** runtime `activate`, `navigate`, or `screenshot`
|
|
122
|
+
|
|
123
|
+
Chrome sessions are emitted as:
|
|
124
|
+
|
|
125
|
+
- `kind: "chrome-readonly"`
|
|
126
|
+
- `status.state: "read-only"`
|
|
127
|
+
- session capabilities with `activate`, `navigate`, and `screenshot` set to `false`
|
|
128
|
+
|
|
129
|
+
## Features
|
|
130
|
+
|
|
131
|
+
- Inspect the current front tab
|
|
132
|
+
- Inspect an explicit tab by indexes or by signature
|
|
133
|
+
- List visible tabs with stable-ish identity metadata
|
|
134
|
+
- Attach and persist sessions locally
|
|
135
|
+
- Persist self-describing sessions with stable `schemaVersion` and `kind` metadata
|
|
136
|
+
- Resume saved sessions even after tabs move
|
|
137
|
+
- Return a machine-readable capabilities contract for clients and tools
|
|
138
|
+
- Report diagnostics about local browser/runtime constraints independently from capabilities
|
|
139
|
+
- Expose all supported functionality through both CLI and local HTTP
|
|
140
|
+
|
|
141
|
+
## Requirements
|
|
142
|
+
|
|
143
|
+
- macOS with Safari installed for Safari support
|
|
144
|
+
- Node.js 20+
|
|
145
|
+
- `osascript`
|
|
146
|
+
- `screencapture`
|
|
147
|
+
|
|
148
|
+
## Install
|
|
149
|
+
|
|
150
|
+
Build a local checkout:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm install
|
|
154
|
+
npm run build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Run the CLI from a built repo checkout:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npm run cli -- --help
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Install from git as a dependency or from another local project:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm install <git-url>#<commit-ish>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The package uses `prepare`, so a git install builds `dist/` during installation and exposes the same stable root helper surface plus declarations through `local-browser-bridge`.
|
|
170
|
+
After install, the package exposes these executable names:
|
|
171
|
+
|
|
172
|
+
- `local-browser-bridge`
|
|
173
|
+
- `local-browser-bridge-mcp`
|
|
174
|
+
- `local-browser-bridge-chrome-relay`
|
|
175
|
+
- `safari-attach-tool` (compatibility alias for `local-browser-bridge`)
|
|
176
|
+
|
|
177
|
+
For the route-first connection flow, use the published `local-browser-bridge` bin. `npm run cli -- ...` is the repo-checkout convenience entrypoint for the same CLI during local development.
|
|
178
|
+
|
|
179
|
+
## MCP stdio RC
|
|
180
|
+
|
|
181
|
+
This repo now includes a minimal MCP stdio release-candidate surface for Claude Code and generic MCP clients.
|
|
182
|
+
|
|
183
|
+
Current MCP tools:
|
|
184
|
+
|
|
185
|
+
- `browser_doctor(route, sessionId?)`
|
|
186
|
+
- `browser_tabs(route)`
|
|
187
|
+
- `browser_connect(route, sessionId?)`
|
|
188
|
+
|
|
189
|
+
`browser_tabs` is available for Safari and `chrome-direct`.
|
|
190
|
+
For `chrome-relay`, `browser_tabs` returns a structured non-error blocked result because relay is shared-tab scoped to the currently shared tab rather than browser-wide.
|
|
191
|
+
Runtime action tools such as `activate`, `navigate`, or `screenshot` are intentionally not part of this RC MCP surface.
|
|
192
|
+
|
|
193
|
+
Each MCP tool result now also includes the same additive top-level branching fields without removing the older tool-specific fields:
|
|
194
|
+
|
|
195
|
+
- `outcome`: `success | blocked | unsupported | error`
|
|
196
|
+
- `status`: stable high-level state such as `ready`, `connected`, `listed`, `blocked`, `unsupported`, or `failed`
|
|
197
|
+
- `category`: compact tool/result category such as `route-ready`, `session-connected`, `tab-list`, or `shared-tab-scope`
|
|
198
|
+
- `reason`: optional `{ code, message, retryable?, userActionRequired? }`
|
|
199
|
+
|
|
200
|
+
Tiny copy-paste branching example for agents or client wrappers:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
const payload = result.structuredContent;
|
|
204
|
+
|
|
205
|
+
if (payload.outcome === "success") {
|
|
206
|
+
// Safe to continue: use payload.envelope/session/tabs as appropriate.
|
|
207
|
+
} else if (payload.outcome === "blocked") {
|
|
208
|
+
// Ask the user to do the nextStep or surface payload.reason/prompt.
|
|
209
|
+
} else if (payload.outcome === "unsupported") {
|
|
210
|
+
// Pick a different route/tool. Example: browser_tabs + chrome-relay.
|
|
211
|
+
} else {
|
|
212
|
+
// Real error: inspect payload.reason or payload.error.
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Build and run the stdio server from this repo checkout:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm install
|
|
220
|
+
npm run build
|
|
221
|
+
npm run mcp
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Equivalent direct repo-checkout command after `npm run build`:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
node ./dist/src/mcp-stdio.js
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Installed dependency usage from a consumer project:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
./node_modules/.bin/local-browser-bridge-mcp
|
|
234
|
+
# or, if the bin is already on PATH
|
|
235
|
+
local-browser-bridge-mcp
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Claude Code setup
|
|
239
|
+
|
|
240
|
+
Copy-paste example file:
|
|
241
|
+
|
|
242
|
+
- [examples/mcp/claude-code.installed-package.mcp.json](examples/mcp/claude-code.installed-package.mcp.json)
|
|
243
|
+
|
|
244
|
+
Project-local `.mcp.json` in a consumer project that installed `local-browser-bridge`:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"mcpServers": {
|
|
249
|
+
"local-browser-bridge": {
|
|
250
|
+
"command": "./node_modules/.bin/local-browser-bridge-mcp"
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
If the binary is already on `PATH`, you can shorten that to:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"mcpServers": {
|
|
261
|
+
"local-browser-bridge": {
|
|
262
|
+
"command": "local-browser-bridge-mcp"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Generic MCP client setup
|
|
269
|
+
|
|
270
|
+
Copy-paste example file:
|
|
271
|
+
|
|
272
|
+
- [examples/mcp/generic-stdio.repo-checkout.json](examples/mcp/generic-stdio.repo-checkout.json)
|
|
273
|
+
|
|
274
|
+
Most stdio MCP clients accept the same `command` plus `args` shape. This form is useful when you want the config to point at a built checkout directly:
|
|
275
|
+
|
|
276
|
+
```json
|
|
277
|
+
{
|
|
278
|
+
"mcpServers": {
|
|
279
|
+
"local-browser-bridge": {
|
|
280
|
+
"command": "node",
|
|
281
|
+
"args": [
|
|
282
|
+
"/ABSOLUTE/PATH/TO/local-browser-bridge/dist/src/mcp-stdio.js"
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Quick inspector smoke test:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
npx @modelcontextprotocol/inspector node /ABSOLUTE/PATH/TO/local-browser-bridge/dist/src/mcp-stdio.js
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Quick installed-binary smoke test:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
test -x ./node_modules/.bin/local-browser-bridge-mcp
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Quick repo-checkout smoke test:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
test -f ./dist/src/mcp-stdio.js
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Tool result notes:
|
|
308
|
+
|
|
309
|
+
- results include `structuredContent` JSON plus a text mirror for client compatibility
|
|
310
|
+
- `browser_doctor` keeps blockers explicit without pretending the route is connected
|
|
311
|
+
- `browser_connect` keeps read-only and shared-tab scope explicit in `truth` and `envelope`
|
|
312
|
+
- unsupported runtime actions stay explicit in `truth.unsupportedRuntimeActions`
|
|
313
|
+
|
|
314
|
+
## Consumer surfaces and examples
|
|
315
|
+
|
|
316
|
+
### CLI
|
|
317
|
+
|
|
318
|
+
Primary binary:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
local-browser-bridge --help
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Compatibility alias:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
safari-attach-tool --help
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Common commands:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
npm run cli -- capabilities
|
|
334
|
+
npm run cli -- capabilities --browser safari
|
|
335
|
+
npm run cli -- capabilities --browser chrome
|
|
336
|
+
npm run cli -- diagnostics --browser safari
|
|
337
|
+
npm run cli -- front-tab --browser safari
|
|
338
|
+
npm run cli -- tabs --browser safari
|
|
339
|
+
npm run cli -- attach --browser safari --window-index 1 --tab-index 2
|
|
340
|
+
npm run cli -- sessions
|
|
341
|
+
npm run cli -- session --id <session-id>
|
|
342
|
+
npm run cli -- resume --id <session-id>
|
|
343
|
+
npm run cli -- session-activate --id <session-id>
|
|
344
|
+
npm run cli -- session-navigate --id <session-id> --url https://example.com/next
|
|
345
|
+
npm run cli -- session-screenshot --id <session-id> --output .tmp/session.png
|
|
346
|
+
npm run cli -- serve --host 127.0.0.1 --port 3000
|
|
347
|
+
npm run mcp
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Commands:
|
|
351
|
+
|
|
352
|
+
- `front-tab [--browser safari|chrome]`
|
|
353
|
+
- `tab [--browser safari|chrome] (--window-index <n> --tab-index <n> | --signature <sig>)`
|
|
354
|
+
- `tabs [--browser safari|chrome]`
|
|
355
|
+
- `attach [--browser safari|chrome] [target flags]`
|
|
356
|
+
- `activate [--browser safari|chrome] [target flags]`
|
|
357
|
+
- `navigate [--browser safari|chrome] [target flags] --url <url>`
|
|
358
|
+
- `screenshot [--browser safari|chrome] [target flags] [--output <path>]`
|
|
359
|
+
- `capabilities [--browser safari|chrome]`
|
|
360
|
+
- `diagnostics [--browser safari|chrome]` (includes Safari `preflight.inspect|automation|screenshot` readiness when available)
|
|
361
|
+
- `sessions`
|
|
362
|
+
- `session --id <session-id>`
|
|
363
|
+
- `resume --id <session-id>`
|
|
364
|
+
- `session-activate --id <session-id>`
|
|
365
|
+
- `session-navigate --id <session-id> --url <url>`
|
|
366
|
+
- `session-screenshot --id <session-id> [--output <path>]`
|
|
367
|
+
- `serve [--host 127.0.0.1] [--port 3000]`
|
|
368
|
+
|
|
369
|
+
### Local HTTP API
|
|
370
|
+
|
|
371
|
+
Start the server:
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
npm run serve -- --host 127.0.0.1 --port 3000
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Health:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
curl http://127.0.0.1:3000/health
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Capabilities:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
curl "http://127.0.0.1:3000/v1/capabilities"
|
|
387
|
+
curl "http://127.0.0.1:3000/v1/capabilities?browser=safari"
|
|
388
|
+
curl "http://127.0.0.1:3000/v1/capabilities?browser=chrome"
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Inspection and actions:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
curl "http://127.0.0.1:3000/v1/front-tab?browser=safari"
|
|
395
|
+
curl "http://127.0.0.1:3000/v1/tabs?browser=safari"
|
|
396
|
+
curl "http://127.0.0.1:3000/v1/tab?browser=safari&windowIndex=1&tabIndex=2"
|
|
397
|
+
|
|
398
|
+
curl -X POST http://127.0.0.1:3000/v1/attach \
|
|
399
|
+
-H "content-type: application/json" \
|
|
400
|
+
-d '{"browser":"safari","target":{"windowIndex":1,"tabIndex":2}}'
|
|
401
|
+
|
|
402
|
+
curl -X POST http://127.0.0.1:3000/v1/sessions/<session-id>/resume
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
See [docs/consuming-the-bridge.md](docs/consuming-the-bridge.md) for fuller CLI and HTTP examples, including the practical HTTP consumer demo at [examples/clients/http-node.ts](examples/clients/http-node.ts).
|
|
406
|
+
For runtime-neutral wrapper patterns across OpenClaw, AWOS, Codex, Claude Code, and custom consumers, including copyable minimal adapter skeletons built on the shared helper surface, see [docs/adapter-patterns.md](docs/adapter-patterns.md).
|
|
407
|
+
If you are importing the toolkit directly instead of shelling out or calling HTTP, start from [src/index.ts](src/index.ts), which re-exports the shared helpers plus the CLI/HTTP reference adapters used in [examples/clients/cli-consumer.ts](examples/clients/cli-consumer.ts), [examples/clients/http-consumer.ts](examples/clients/http-consumer.ts), and [examples/clients/codex-consumer.ts](examples/clients/codex-consumer.ts).
|
|
408
|
+
|
|
409
|
+
If you want the smallest route-first shell wrapper instead of importing helpers, start from [examples/clients/doctor-connect-wrapper.ts](examples/clients/doctor-connect-wrapper.ts). It shells out to `local-browser-bridge doctor --route ...` and `local-browser-bridge connect --route ...`, then returns one concise wrapper JSON result while preserving additive top-level `outcome` / `status` / `category` / `reason` branching fields and keeping Safari actionable, `chrome-direct` read-only, and `chrome-relay` read-only plus shared-tab scoped.
|
|
410
|
+
|
|
411
|
+
For a thin Codex-facing wrapper that still uses the same shared/public toolkit surface, use `normalizeCodexRoute(...)`, `connectCodexViaCli(...)`, or `connectCodexViaHttp(...)` from the package root, then copy from [examples/clients/codex-consumer.ts](examples/clients/codex-consumer.ts).
|
|
412
|
+
For a thin Claude Code-facing wrapper that still uses the same shared/public toolkit surface, use `normalizeClaudeCodeRoute(...)` and `prepareClaudeCodeRoute(...)` from the package root, then copy from [examples/clients/claude-code-tool.ts](examples/clients/claude-code-tool.ts).
|
|
413
|
+
|
|
414
|
+
Quick copy-paste run for the shell wrapper:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
npm install
|
|
418
|
+
npm run build
|
|
419
|
+
node --experimental-strip-types examples/clients/doctor-connect-wrapper.ts safari
|
|
420
|
+
node --experimental-strip-types examples/clients/doctor-connect-wrapper.ts chrome-relay
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Installed-package equivalent once the dependency is present on `PATH` or in `node_modules/.bin`:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
local-browser-bridge doctor --route safari
|
|
427
|
+
local-browser-bridge connect --route safari
|
|
428
|
+
local-browser-bridge doctor --route chrome-relay
|
|
429
|
+
local-browser-bridge connect --route chrome-relay
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Quick copy-paste run for the demo:
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
npm install
|
|
436
|
+
npm run build
|
|
437
|
+
|
|
438
|
+
# terminal 1
|
|
439
|
+
npm run serve
|
|
440
|
+
|
|
441
|
+
# terminal 2
|
|
442
|
+
npx tsx examples/clients/http-node.ts safari
|
|
443
|
+
# or: npx tsx examples/clients/http-node.ts chrome-direct
|
|
444
|
+
# or: npx tsx examples/clients/http-node.ts chrome-relay
|
|
445
|
+
|
|
446
|
+
# optional: resume a saved session for the selected path
|
|
447
|
+
LOCAL_BROWSER_BRIDGE_SESSION_ID=<session-id> npx tsx examples/clients/http-node.ts chrome-relay
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
The demo fetches `/v1/capabilities` plus `/v1/diagnostics`, then renders different consumer-facing labels and prompts for Safari actionable, Chrome direct read-only, and Chrome relay read-only. It keeps Chrome direct and relay explicit and does not silently fall back between them.
|
|
451
|
+
|
|
452
|
+
## Capability payload example
|
|
453
|
+
|
|
454
|
+
Reference fixture: [examples/capabilities.example.json](examples/capabilities.example.json)
|
|
455
|
+
|
|
456
|
+
```json
|
|
457
|
+
{
|
|
458
|
+
"capabilities": {
|
|
459
|
+
"schemaVersion": 1,
|
|
460
|
+
"schema": {
|
|
461
|
+
"path": "schema/capabilities.schema.json",
|
|
462
|
+
"version": "1.0.0"
|
|
463
|
+
},
|
|
464
|
+
"product": {
|
|
465
|
+
"name": "local-browser-bridge",
|
|
466
|
+
"displayName": "local-browser-bridge",
|
|
467
|
+
"summary": "Reusable, agent-agnostic local browser bridge with honest capability signaling. Safari is actionable; Chrome/Chromium is read-only in v1."
|
|
468
|
+
},
|
|
469
|
+
"targeting": {
|
|
470
|
+
"modes": ["front", "indexed", "signature"]
|
|
471
|
+
},
|
|
472
|
+
"browsers": [
|
|
473
|
+
{
|
|
474
|
+
"kind": "safari-actionable",
|
|
475
|
+
"browser": "safari",
|
|
476
|
+
"maturity": "primary",
|
|
477
|
+
"attachModes": [
|
|
478
|
+
{
|
|
479
|
+
"mode": "direct",
|
|
480
|
+
"source": "user-browser",
|
|
481
|
+
"scope": "browser",
|
|
482
|
+
"supported": true,
|
|
483
|
+
"readiness": "ready"
|
|
484
|
+
}
|
|
485
|
+
],
|
|
486
|
+
"operations": {
|
|
487
|
+
"attach": true,
|
|
488
|
+
"resumeSession": true,
|
|
489
|
+
"activate": true,
|
|
490
|
+
"navigate": true,
|
|
491
|
+
"screenshot": true
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"kind": "chrome-readonly",
|
|
496
|
+
"browser": "chrome",
|
|
497
|
+
"maturity": "experimental-readonly",
|
|
498
|
+
"attachModes": [
|
|
499
|
+
{
|
|
500
|
+
"mode": "direct",
|
|
501
|
+
"source": "user-browser",
|
|
502
|
+
"scope": "browser",
|
|
503
|
+
"supported": true,
|
|
504
|
+
"readiness": "degraded"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"mode": "relay",
|
|
508
|
+
"source": "extension-relay",
|
|
509
|
+
"scope": "tab",
|
|
510
|
+
"supported": true,
|
|
511
|
+
"readiness": "unavailable"
|
|
512
|
+
}
|
|
513
|
+
],
|
|
514
|
+
"operations": {
|
|
515
|
+
"attach": true,
|
|
516
|
+
"resumeSession": true,
|
|
517
|
+
"activate": false,
|
|
518
|
+
"navigate": false,
|
|
519
|
+
"screenshot": false
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
]
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Session payload examples
|
|
528
|
+
|
|
529
|
+
Reference fixtures:
|
|
530
|
+
|
|
531
|
+
- [examples/session.safari-actionable.example.json](examples/session.safari-actionable.example.json)
|
|
532
|
+
- [examples/session.chrome-readonly.example.json](examples/session.chrome-readonly.example.json)
|
|
533
|
+
- [examples/session.chrome-relay-readonly.example.json](examples/session.chrome-relay-readonly.example.json)
|
|
534
|
+
- [examples/error.chrome-relay-share-required.example.json](examples/error.chrome-relay-share-required.example.json)
|
|
535
|
+
|
|
536
|
+
Chrome relay failure contract artifacts:
|
|
537
|
+
|
|
538
|
+
- [schema/chrome-relay-error.schema.json](schema/chrome-relay-error.schema.json)
|
|
539
|
+
- [docs/consuming-the-bridge.md](docs/consuming-the-bridge.md)
|
|
540
|
+
|
|
541
|
+
### Safari session example
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"session": {
|
|
546
|
+
"schemaVersion": 1,
|
|
547
|
+
"kind": "safari-actionable",
|
|
548
|
+
"browser": "safari",
|
|
549
|
+
"attach": {
|
|
550
|
+
"mode": "direct",
|
|
551
|
+
"source": "user-browser",
|
|
552
|
+
"scope": "browser"
|
|
553
|
+
},
|
|
554
|
+
"semantics": {
|
|
555
|
+
"inspect": "browser-tabs",
|
|
556
|
+
"list": "saved-session",
|
|
557
|
+
"resume": "saved-browser-target",
|
|
558
|
+
"tabReference": {
|
|
559
|
+
"windowIndex": "browser-position",
|
|
560
|
+
"tabIndex": "browser-position"
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
"status": {
|
|
564
|
+
"state": "actionable",
|
|
565
|
+
"canAct": true
|
|
566
|
+
},
|
|
567
|
+
"capabilities": {
|
|
568
|
+
"resume": true,
|
|
569
|
+
"activate": true,
|
|
570
|
+
"navigate": true,
|
|
571
|
+
"screenshot": true
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### Chrome session example
|
|
578
|
+
|
|
579
|
+
```json
|
|
580
|
+
{
|
|
581
|
+
"session": {
|
|
582
|
+
"schemaVersion": 1,
|
|
583
|
+
"kind": "chrome-readonly",
|
|
584
|
+
"browser": "chrome",
|
|
585
|
+
"attach": {
|
|
586
|
+
"mode": "direct",
|
|
587
|
+
"source": "user-browser",
|
|
588
|
+
"scope": "browser"
|
|
589
|
+
},
|
|
590
|
+
"semantics": {
|
|
591
|
+
"inspect": "browser-tabs",
|
|
592
|
+
"list": "saved-session",
|
|
593
|
+
"resume": "saved-browser-target",
|
|
594
|
+
"tabReference": {
|
|
595
|
+
"windowIndex": "browser-position",
|
|
596
|
+
"tabIndex": "browser-position"
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
"status": {
|
|
600
|
+
"state": "read-only",
|
|
601
|
+
"canAct": false
|
|
602
|
+
},
|
|
603
|
+
"capabilities": {
|
|
604
|
+
"resume": true,
|
|
605
|
+
"activate": false,
|
|
606
|
+
"navigate": false,
|
|
607
|
+
"screenshot": false
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
## Error shape
|
|
614
|
+
|
|
615
|
+
CLI stderr and HTTP errors share the same machine-readable structure:
|
|
616
|
+
|
|
617
|
+
```json
|
|
618
|
+
{
|
|
619
|
+
"error": {
|
|
620
|
+
"code": "missing_url",
|
|
621
|
+
"message": "--url is required.",
|
|
622
|
+
"statusCode": 400
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
## Constraints
|
|
628
|
+
|
|
629
|
+
### Safari/macOS constraints
|
|
630
|
+
|
|
631
|
+
- Safari diagnostics now include a machine-readable `preflight` section so clients can distinguish attach/action readiness before calling attach, activate, navigate, or screenshot.
|
|
632
|
+
- Browser capability descriptors may now include additive `attachModes` metadata, and sessions may now include additive `attach` metadata so clients can distinguish direct user-browser attach from future extension relay attach without changing `kind`.
|
|
633
|
+
- Sessions now also include additive `semantics` metadata so clients can render truthful inspect/list/resume UX, especially for relay-scoped Chrome sessions.
|
|
634
|
+
- Chrome diagnostics now include a machine-readable `attach.direct` / `attach.relay` section with per-mode readiness, state, and blockers. Relay uses a local probe when available, and a minimal read-only relay attach can now create a session for the currently shared tab.
|
|
635
|
+
- When Safari has open windows but zero inspectable tabs, `front-tab`/tab resolution now returns `browser_no_tabs` instead of a generic availability error, matching the `preflight` blocker and empty `tabs` list.
|
|
636
|
+
- Safari access depends on Apple Events permission.
|
|
637
|
+
- Screenshots depend on Screen Recording permission.
|
|
638
|
+
- Activation, navigation, and screenshots visibly focus Safari.
|
|
639
|
+
- Session matching is heuristic, based on signature/url/title plus fallback indexes.
|
|
640
|
+
- If multiple tabs share the same URL/title, the first visible match may win.
|
|
641
|
+
|
|
642
|
+
### Chrome/Chromium constraints
|
|
643
|
+
|
|
644
|
+
- Inspection currently requires an already-running local DevTools HTTP endpoint.
|
|
645
|
+
- The adapter is intentionally read-only in this phase.
|
|
646
|
+
- Diagnostics enumerate attempted endpoint discovery sources when inspection is unavailable.
|
|
647
|
+
- Relay diagnostics can optionally consume a local JSON probe from `LOCAL_BROWSER_BRIDGE_CHROME_RELAY_STATE_PATH`, `./.local-browser-bridge/chrome-relay-state.json`, or `~/.local-browser-bridge/chrome-relay-state.json`.
|
|
648
|
+
- Relay probe states distinguish extension missing, disconnected, user-click/share required, no-shared-tab, and expired-scope cases. When a shared tab is present, `attach.mode = relay` can create a read-only Chrome session for that tab.
|
|
649
|
+
- Chrome relay sessions are saved shared-tab references. They do not make `/v1/tab` or `/v1/tabs` relay-aware, and their `tab.windowIndex` / `tab.tabIndex` should be treated as synthetic shared-tab placeholders.
|
|
650
|
+
- Relay attach/resume failures reuse the same shared-tab-scoped `error.details` contract over CLI and HTTP. Consumers should branch on the returned relay metadata rather than guessing or silently falling back between direct and relay paths.
|
|
651
|
+
|
|
652
|
+
### Chrome relay probe
|
|
653
|
+
|
|
654
|
+
If you have a local extension/helper that can write relay state, point the bridge at a JSON file:
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
export LOCAL_BROWSER_BRIDGE_CHROME_RELAY_STATE_PATH="$PWD/.local-browser-bridge/chrome-relay-state.json"
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Producer contract and field guidance:
|
|
661
|
+
|
|
662
|
+
- [docs/chrome-relay-producer-contract.md](docs/chrome-relay-producer-contract.md)
|
|
663
|
+
|
|
664
|
+
Reference helper for local simulation:
|
|
665
|
+
|
|
666
|
+
```bash
|
|
667
|
+
npm run build
|
|
668
|
+
|
|
669
|
+
# defaults to ./.local-browser-bridge/chrome-relay-state.json unless --output or
|
|
670
|
+
# LOCAL_BROWSER_BRIDGE_CHROME_RELAY_STATE_PATH is set
|
|
671
|
+
npx local-browser-bridge-chrome-relay extension-missing
|
|
672
|
+
npx local-browser-bridge-chrome-relay disconnected
|
|
673
|
+
npx local-browser-bridge-chrome-relay click-required
|
|
674
|
+
npx local-browser-bridge-chrome-relay share-required
|
|
675
|
+
npx local-browser-bridge-chrome-relay shared-tab --tab-id relay-42 --title "Shared Docs" --url https://example.com/docs
|
|
676
|
+
npx local-browser-bridge-chrome-relay expired-share --tab-id relay-42 --url https://example.com/docs
|
|
677
|
+
npx local-browser-bridge-chrome-relay clear-shared-tab
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
The helper reuses the bridge's relay validator before writing and replaces the full JSON snapshot through a temp-file rename, matching the producer contract's overwrite model.
|
|
681
|
+
|
|
682
|
+
Example probe payload:
|
|
683
|
+
|
|
684
|
+
```json
|
|
685
|
+
{
|
|
686
|
+
"version": "1.1.0",
|
|
687
|
+
"updatedAt": "2026-03-28T11:00:00.000Z",
|
|
688
|
+
"extensionInstalled": true,
|
|
689
|
+
"connected": true,
|
|
690
|
+
"shareRequired": false,
|
|
691
|
+
"userGestureRequired": false,
|
|
692
|
+
"sharedTab": {
|
|
693
|
+
"id": "tab-123",
|
|
694
|
+
"title": "Relay Example",
|
|
695
|
+
"url": "https://example.com/shared"
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
If the probe reports a currently shared tab, `attach.relay.ready` becomes `true` and you can explicitly request relay attach with `--attach-mode relay` or `{ "attach": { "mode": "relay" } }`. Relay sessions stay `chrome-readonly`, are scoped to that one shared tab, and may carry truthful `resumable`, `resumeRequiresUserGesture`, `expiresAt`, and `trustedAt` metadata when the probe provides it. On successful saved-session resume, use the returned session as the fresh source of relay metadata for that currently shared tab. Saved relay sessions should be presented as "resume against the currently shared tab" rather than as general Chrome browser sessions.
|
|
701
|
+
|
|
702
|
+
If relay attach or relay resume fails, CLI stderr JSON and HTTP error responses now stay aligned through additive `error.details` metadata. Consumers can branch on `error.details.context.operation` plus `error.details.relay.branch` rather than inferring UX only from status codes or free-form text. The package root now re-exports two stable consumer utilities from `src/index.ts`: the narrower relay helper from `src/chrome-relay-error-helper.ts` and the broader attach/resume UX helper from `src/browser-attach-ux-helper.ts`. The sample HTTP client uses that public helper entrypoint directly.
|
|
703
|
+
|
|
704
|
+
## Contract files
|
|
705
|
+
|
|
706
|
+
- Canonical PRD: `PRD.md`
|
|
707
|
+
- Direction summary: `docs/product-direction.md`
|
|
708
|
+
- Consumer guide: `docs/consuming-the-bridge.md`
|
|
709
|
+
- Relay producer guide: `docs/chrome-relay-producer-contract.md`
|
|
710
|
+
- Relay state schema: `schema/chrome-relay-state.schema.json`
|
|
711
|
+
- Capabilities schema: `schema/capabilities.schema.json`
|
|
712
|
+
- Example fixtures: `examples/*.json`
|
|
713
|
+
- Runtime capability payloads: CLI `capabilities` and HTTP `GET /v1/capabilities`
|
|
714
|
+
|
|
715
|
+
## Storage
|
|
716
|
+
|
|
717
|
+
- Sessions: `.data/sessions.json`
|
|
718
|
+
- Screenshots: `.data/screenshots/*.png`
|
|
719
|
+
|
|
720
|
+
## Validation
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
npm test
|
|
724
|
+
```
|