Skip to content

fix(proxy): forward content-frame API calls + errors to chrome shell#2

Open
andylbrummer wants to merge 2 commits into
mainfrom
fix/proxy-ui-content-shell-bridge
Open

fix(proxy): forward content-frame API calls + errors to chrome shell#2
andylbrummer wants to merge 2 commits into
mainfrom
fix/proxy-ui-content-shell-bridge

Conversation

@andylbrummer

Copy link
Copy Markdown
Member

Problem

The proxy UI tabs (Network, Errors) and their badges stopped updating with the page's real API calls and front-end errors.

Root cause: the always-wrap shell model (injector.go BuildShellDocument, default for top-level navigations) renders a page as a chrome shell wrapping the real page in a content <iframe>. The indicator UI runs in the shell frame, but:

  • api-tracker.js wraps fetch/XHR per-frame → app calls land in the content frame's callBuffer.
  • core.js error capture runs only in the content frame (__isContent gate at init) → JS/console errors land in the content frame's buffers.

The shell's own buffers stayed empty, so getCalls() / getDeduplicatedErrors() / getStats() — which feed the tabs + badges via the 1s poll — saw nothing.

Fix

Content frames forward each captured call/error up to the shell via the existing same-origin cross-frame idiom (frames.js window.parent.__devtool_*):

  • api-tracker.jsaddCall forwards to shell.__devtool_api_ingest when role==='content'; new terminal ingest sink; chrome stops recording its own WS/screenshot fetches as Network noise.
  • core.jsforwardErrorToShell + ingestForwardedError; forward at the js/console/warn buffer pushes; window.__devtool_errors_ingest export.

Shell ingest pushes into the shell's own buffers, so getCalls / getDeduplicatedErrors / getStats / audits all work unchanged. No loop (shell is terminal). Backward compatible — standalone (no-shell) pages keep local capture; forward is gated on role==='content'.

Verification

Opt-in headless-Chrome regression test (bridge_live_test.go, AGNT_LIVE_BRIDGE=1). A content-frame fetch + uncaught throw + console.error all surface in the shell frame:

{"role":"chrome","urls":["…/api/data"],"stats":{"jsErrorCount":1,"consoleErrorCount":1,"totalCount":2}}

Normal suite green (go test ./internal/proxy/...); live test skips unless gated.

🤖 Generated with Claude Code

andylbrummer and others added 2 commits June 27, 2026 18:33
The always-wrap shell model renders a top-level navigation as a chrome
shell wrapping the real page in a content <iframe>. The indicator UI runs
in the shell, but fetch/XHR capture (api-tracker.js) and error capture
(core.js, content-only) happen in the content frame. The shell's own
buffers stayed empty, so the Network and Errors tabs (and their badges)
never updated with the page's real traffic.

Content frames now forward each captured call/error up to the shell via
same-origin window.parent.__devtool_*_ingest (the existing frames.js
cross-frame idiom). Shell-side terminal ingest sinks push into the shell's
own buffers, so getCalls / getDeduplicatedErrors / getStats / audits all
work unchanged. Chrome stops recording its own WS/screenshot traffic as
Network noise. Standalone (no-shell) pages keep local capture — forward
is gated on role==='content'.

Verified end-to-end in headless Chrome (AGNT_LIVE_BRIDGE=1): a content
fetch + uncaught throw + console.error all surface in the shell frame's
buffers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMry6m6QXTdc8Xbecqmzid
Document that shell-side ingestForwardedError intentionally skips the
consolidated error stream — harmless today (no shell consumer reads
getConsolidated*), but a future consumer must wire it in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMry6m6QXTdc8Xbecqmzid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant