feat(schema,engine,desktop): browser broker — wire contract, webview executor, code-mode execute tool for claude/pi (CODE-267) - #188
Conversation
CODE-267 feat(schema,engine,desktop): browser broker — wire contract, desktop webview executor, code-mode execute tool for claude/pi
目标Agent 自动化 Phase B-1:paseo 式 daemon broker——agent 经 code-mode 前提事实(2026-07-17 实勘)
TasksWire(
Engine
桌面执行端
安全与默认值
验收
风险
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38e3923d2f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Greptile SummaryThis PR adds a browser broker so code-mode agents can drive the same desktop browser tabs the user sees. The main changes are:
Confidence Score: 4/5Mostly safe, with one contained reliability issue to fix before merging. Broker routing, schema, host channel, and desktop executor changes are scoped and covered by tests. The REPL execution path lacks bounds, so one bad browser execute call can hang the affected live session or daemon path. packages/engine/src/browser/repl-host.ts
What T-Rex did
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Agent as Agent code-mode execute tool
participant Engine as Engine BrowserReplHost/Broker
participant Hub as Transport Hub
participant Desktop as Desktop BrowserHostChannel
participant Webview as Visible Electron webview
Agent->>Engine: "browser.* JS call"
Engine->>Engine: dispatch(op,args), mint commandId
Engine->>Hub: browser.command(commandId, op, args)
Hub->>Desktop: targeted delivery to active browser host
Desktop->>Webview: execute store/webview operation
Webview-->>Desktop: operation result / screenshot / error
Desktop->>Hub: browser.command.result(commandId, result)
Hub->>Engine: forward settlement
Engine-->>Agent: resolve execute result
alt host disconnects or times out
Hub->>Engine: browser.host.detached(hostId)
Engine-->>Agent: closed-code error result
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Agent as Agent code-mode execute tool
participant Engine as Engine BrowserReplHost/Broker
participant Hub as Transport Hub
participant Desktop as Desktop BrowserHostChannel
participant Webview as Visible Electron webview
Agent->>Engine: "browser.* JS call"
Engine->>Engine: dispatch(op,args), mint commandId
Engine->>Hub: browser.command(commandId, op, args)
Hub->>Desktop: targeted delivery to active browser host
Desktop->>Webview: execute store/webview operation
Webview-->>Desktop: operation result / screenshot / error
Desktop->>Hub: browser.command.result(commandId, result)
Hub->>Engine: forward settlement
Engine-->>Agent: resolve execute result
alt host disconnects or times out
Hub->>Engine: browser.host.detached(hostId)
Engine-->>Agent: closed-code error result
end
Reviews (1): Last reviewed commit: "test(desktop): browser broker end-to-end..." | Re-trigger Greptile |
Summary
Phase B-1 of the in-app browser roadmap (CODE-267), stacked on #181 (CODE-266 multi-tab panel — its tab store is this feature's execution surface). Agents get a single code-mode
executetool driving the SAME browser tabs the user sees, per CODE-33's locked code-mode decision.browserdomain (packages/schema/src/wire/browser.ts+src/browser.ts):browser.host.register(client-minted capability, mirrors terminal attachments), Hub-synthesizedbrowser.host.detached,browser.host.changedbroadcast, daemon→hostbrowser.command/browser.command.result(closed op enum + closed error codes withretryable), and the client-sidebrowser.execute/browser.executedpair (used by the E2E now, by the B-2 stdio bridge later).browser.host.registersucceeds becomes THE single active host (last registration wins — commands have side effects and are never fanned out);browser.commandframes are delivered only there; disconnect synthesizesbrowser.host.detached(guarded by hostId so a stale drop can't clear a newer host).BrowserBrokerService(engine): pending-map correlation by daemon-mintedcommandId, 15 s timeout, fail-all on host detach/supersede/shutdown, availability broadcasts.dispatchnever rejects — every failure is a closed-code result.client-coreBrowserHostChannelregisters via the workbench hookuseBrowserHostRegistration(re-registers per connection generation); the renderer executor drives the CODE-266 tab store (open/select/close/navigate) and live webviews (executeJavaScriptsnapshot with@eNmarker-attribute refs capped at 200, click/type with stale-ref discipline,capturePagescreenshots, evaluate). Screenshot results are attached as real image content blocks.packages/engine/src/browser/repl-host.ts, reviving the sky-mcp skeleton): persistentnode:vmcontext exposing abrowsernamespace + captured console; behavior discipline is embedded in the tool description. claude-code hosts it as an in-process MCP server (createSdkMcpServer, approvals ride the existingcanUseToolflow); pi hosts it viacustomTools(TypeBox).EngineDeps.browserToolsEnabled, daemon env gateLINKCODE_BROWSER_TOOLS=1. The Settings toggle is a follow-up; host registration itself is ungated (harmless).Verification
pnpm -F @linkcode/desktop e2e:browser-broker(PASS): isolated daemon (wire 38) + real desktop; a raw wire client executestabs.open→ the desktop executor opens a visible tab and returns the tab list;tab.clickwithout a snapshot →stale-ref; desktop quit →host-unavailableinstead of a hang.LINKCODE_BROWSER_TOOLS=1drivingbrowser.*end-to-end (needs a signed-in claude), and a pi smoke. pi has no per-call approval seam — known limitation, gate-guarded.Linear: CODE-267