Skip to content

feat(peek): get_page_view — live ref-tagged snapshot + ref-based targeting (R1)#101

Merged
harry-harish merged 2 commits into
mainfrom
feat/peek-live-page-view
Jun 20, 2026
Merged

feat(peek): get_page_view — live ref-tagged snapshot + ref-based targeting (R1)#101
harry-harish merged 2 commits into
mainfrom
feat/peek-live-page-view

Conversation

@harry-harish

@harry-harish harry-harish commented Jun 20, 2026

Copy link
Copy Markdown
Member

What

Implements R1 from the MCP token-optimization research: a new get_page_view MCP tool that returns a live, masked, ref-tagged list of interactive page elements, and ref-based targeting for the act verbs. The agent can now target a stable ref (e.g. e5) instead of authoring a CSS selector from get_dom_snapshot's ~24KB of HTML — far fewer tokens per perception, and deterministic (no selector guessing).

Spec: _context/docs/research/2026-06-20-peek-mcp-token-optimization.md + _context/docs/specs/2026-06-20-peek-live-snapshot-refs-spec.md.

How

  • snapshot.ts — self-contained MAIN-world buildPageView walker + a window.__peekRefs registry (a JS global, so rrweb never records it; replaced per snapshot; wiped on navigation).
  • action-schema.tspage_view action + optional ref on click/type/dblclick/scroll/enter (selector optional; ref-or-selector enforced at dispatch — kept optional in the schema so members stay plain objects for the discriminated union).
  • dispatcher.tsresolveElement/resolveTarget resolve ref via the registry first; a missing/detached ref returns a clear ref expired error.
  • background.tsdispatchInMainWorld runs buildPageView, masks names/values SW-side, returns compact ref-tagged lines in details; the destructive matcher now threads ref too.
  • action-handler.tspage_view intercepted before the gate, auto-allowed at effective Level ≥ 1 (read), new level-1-read approver (4 mirrors updated).
  • server.tsget_page_view tool (rides the execute_action rails; surfaces the view via response.details).

Safety / privacy

  • Destructive override holds for refs: a ref-targeted "Delete/Pay/Send" still hits the destructive-confirm banner (the matcher resolves the same ref'd element). (This was a bug an independent review caught — the destructive matcher initially bailed on ref-only actions; fixed + regression-tested.)
  • Masking (two-layer): password/email/tel and PII-autofill values (card, address, birthday, name, org), and fields marked .rr-mask/data-private/data-dd-privacy/data-peek-mask, are dropped in-page; the SW scrubs structured PII (emails, cards, tokens) from names + remaining values. Honest scope: free-text field values may still be returned (same as peek's existing recorder) — the tool description + privacy policy say so.
  • Non-mutating, audit-logged, Level 1+. selector targeting unchanged (backward-compatible).

Review + testing

Built subagent-driven + put through an independent code-quality/security review; all top findings addressed (C1 destructive-gate bypass, H1 imprecise autocomplete masking, H2 overstated masking claims, M1 clearer dispatch error, + the privacy-policy doc). 23 new unit tests; peek-extension 580 + peek-mcp 294 green; typecheck + biome + build clean. Changeset included (minor, both packages).

Follow-ups (out of scope, noted in the spec)

R2 diff-after-action, CDP getFullAXTree accurate-accname mode, structuredContent, and a real-browser e2e (the rrweb-invisibility is guaranteed by construction — __peekRefs is a JS global, not DOM).

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added on-demand live page snapshot capability (get_page_view / page_view) for Level 1+ viewing of interactive elements.
    • Actions can target elements via stable reference IDs (ref) in addition to CSS selectors, enabling more reliable click/type/scroll/enter/double-click targeting.
    • References now expire on navigation, with clear “ref expired” errors to prompt re-snapshot.
  • Privacy & Security

    • Improved masking of sensitive values (password/email/tel, PII-autofill, and privacy-marked fields/regions) in snapshots and reported details.
  • Bug Fixes

    • Improved alignment of destructive-action targeting with the chosen target (ref or selector).
  • Documentation

    • Updated the privacy policy and MCP capability docs to reflect the new live snapshot behavior.

…eting

R1 of the MCP token-optimization work. The agent perceives the live page as a
compact, masked, ref-tagged list of interactive elements and targets a ref in
execute_action/request_authorization instead of authoring a CSS selector from
get_dom_snapshot HTML — far fewer tokens per perception and deterministic.

- snapshot.ts: self-contained MAIN-world buildPageView walker + a window-global
  ref registry (rrweb-invisible; replaced per snapshot; wiped on navigation).
- action-schema.ts: page_view action + optional ref on click/type/dblclick/
  scroll/enter (selector now optional; ref-or-selector enforced at dispatch).
- dispatcher.ts: resolveElement/resolveTarget resolve ref via the registry
  first; a missing/detached ref yields a clear 'ref expired' error.
- background.ts: dispatchInMainWorld runs buildPageView, masks names/values
  SW-side (maskTextContent), returns compact ref-tagged lines in details.
- action-handler.ts: page_view intercepted before the gate, auto-allowed at
  effective Level >= 1 (read); new 'level-1-read' approver (4 mirrors updated).
- server.ts: get_page_view tool (rides the execute_action rails, surfaces the
  view via response.details).

Masking (two-layer): password/email/tel + PII-autofill values (card/address/
bday/name/org) and fields marked .rr-mask/data-private/data-dd-privacy/
data-peek-mask are dropped in-page; the SW scrubs structured PII from names +
remaining values. Free-text values may still be returned (same as the recorder).
Ref-targeted destructive actions go through the destructive-confirm override (the
matcher resolves the same ref'd element). Non-mutating, audit-logged, Level 1+.
Selector targeting unchanged. Reviewed (independent pass) + fixes applied;
23 new unit tests; 580 ext + 294 mcp green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b082cab1-7f3e-4f1a-a9d2-c80675685682

📥 Commits

Reviewing files that changed from the base of the PR and between 10e926f and 776e85a.

📒 Files selected for processing (2)
  • docs/peek/PRIVACY_POLICY.md
  • packages/peek-mcp/src/mcp/action-schema.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/peek/PRIVACY_POLICY.md
  • packages/peek-mcp/src/mcp/action-schema.ts

📝 Walkthrough

Walkthrough

Adds a new get_page_view Level-1+ read tool that walks the live DOM in MAIN-world, builds a masked ref-tagged snapshot of interactive/labeled elements, and stores stable element refs in window.__peekRefs. All existing action verbs gain optional ref targeting that resolves through the registry, with ref expired errors on stale or detached refs. A new level-1-read approver propagates through audit, protocol, and MCP layers.

Changes

get_page_view: live ref-tagged page snapshot

Layer / File(s) Summary
Action protocol contracts and approver types
packages/peek-extension/src/permissions/action-protocol.ts, packages/peek-mcp/src/mcp/action-schema.ts, packages/peek-mcp/src/mcp/host-bridge.ts, packages/peek-mcp/src/native-host/action-protocol.ts, packages/peek-mcp/src/native-host/audit.ts
Adds PageViewAction interface/schema with optional selector and bounded maxElements; makes selector optional and adds ref? to TypeAction, ScrollAction, EnterAction, and DblClickAction; extends approver union with level-1-read across all protocol and audit layers.
MAIN-world snapshot builder
packages/peek-extension/src/permissions/snapshot.ts
New buildPageView walks the DOM (optionally under a selector), filters by visibility, derives semantic roles and accessible names via ARIA/labels/content, masks password/email/tel and PII-autofill fields, respects .rr-mask and privacy-marked ancestors, assigns sequential ref IDs (e.g., e1, e2), populates window.__peekRefs registry, enforces truncation, and returns structured result.
Dispatcher ref-resolution
packages/peek-extension/src/permissions/dispatcher.ts
Adds resolveElement(ref?) that looks up elements in window.__peekRefs with isConnected guard and a new notFound(ref, selector) error helper; threads ref through click/type/scroll/enter/dblclick branches; updates resolveTarget to use the same registry lookup for destructive-element inspection so dispatch and destruction evaluate the same target.
Service worker page_view branch
packages/peek-extension/entrypoints/background.ts
Adds dedicated page_view case in dispatchInMainWorld that runs buildPageView in MAIN-world, applies maskTextContent to scrub node names and values, formats the details payload as newline-joined ref role "name" value state lines, and updates resolveTarget to pass optional ref alongside selector/nth.
Action-handler Level-1+ gate
packages/peek-extension/src/permissions/action-handler.ts
Adds a new page_view branch enforcing effectiveLevel >= 1, dispatching via dispatchInMainWorld, and returning allow/level-1-read results (never deny) while bypassing the normal destructive/confirm-token flow.
MCP server tool registration
packages/peek-mcp/src/mcp/server.ts
Registers get_page_view as a non-mutating MCP tool delegating to dispatchActTool with a page_view action; adds 'get_page_view' to exported PEEK_MCP_TOOLS alongside other read tools.
Tests
packages/peek-extension/src/__tests__/snapshot.test.ts, packages/peek-extension/src/__tests__/dispatcher.test.ts, packages/peek-extension/src/__tests__/action-handler.test.ts, packages/peek-mcp/test/action-schema.test.ts, packages/peek-mcp/test/server.test.ts, packages/peek-mcp/test/stdio-smoke.test.ts
Full Vitest coverage for buildPageView (DOM walk, ref registry, role/name derivation, sensitive masking, PII precision, truncation, selector scoping, self-contained serialization), dispatcher ref-targeting and expiry errors, handleActionRequest level gating, and MCP tool count/dispatch routing.
Documentation and changeset
.changeset/peek-live-page-view.md, docs/peek/PRIVACY_POLICY.md, packages/peek-mcp/README.md
Updates privacy policy Level 1 ("Observe") to include get_page_view with audit logging and masking rules; documents dropping password/email/tel and PII-autofill fields, respecting .rr-mask / data-private / data-dd-privacy / data-peek-mask selectors, and selector fallback; updates README tool table; adds minor-release changeset.

Sequence Diagram

sequenceDiagram
  participant Agent as AI Agent
  participant MCPServer as get_page_view MCP tool
  participant ActionHandler as action-handler
  participant SWBackground as background.ts (SW)
  participant MainWorld as buildPageView (MAIN)
  participant PeekRefs as window.__peekRefs

  Agent->>MCPServer: get_page_view sessionId maxElements?
  MCPServer->>ActionHandler: execute_action type=page_view
  ActionHandler->>ActionHandler: check effectiveLevel >= 1
  ActionHandler->>SWBackground: dispatchInMainWorld page_view
  SWBackground->>MainWorld: scripting.executeScript buildPageView
  MainWorld->>PeekRefs: create Map, populate ref→el
  MainWorld-->>SWBackground: PageViewResult nodes url title
  SWBackground->>SWBackground: maskTextContent on names/values
  SWBackground-->>ActionHandler: ok=true details
  ActionHandler-->>MCPServer: verdict=allow level-1-read details
  MCPServer-->>Agent: ref-tagged element lines

  Note over Agent,PeekRefs: Subsequent ref-targeted action
  Agent->>SWBackground: dispatchAction type=click ref=e5
  SWBackground->>PeekRefs: lookup e5
  alt ref valid and isConnected
    SWBackground->>MainWorld: click element
    MainWorld-->>SWBackground: ok=true
  else ref missing or detached
    SWBackground-->>Agent: ok=false error "ref expired e5"
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Cubenest/rrweb-stack#37: Introduces the original dispatchAction/resolveTarget element-resolution plumbing in dispatcher.ts that this PR extends with ref-registry lookup and updated destructive-element inspection.
  • Cubenest/rrweb-stack#72: Modifies dispatchAction/resolveTarget MAIN-world selector resolution in the same file, inlining element lookup — directly adjacent to this PR's ref-registry resolution additions.

Suggested reviewers

  • harish-captain
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a get_page_view feature with ref-tagged snapshots and ref-based targeting for the R1 research milestone.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/peek-live-page-view

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/peek/PRIVACY_POLICY.md`:
- Around line 72-80: The privacy policy text for the get_page_view feature
currently states it works "instead of guessing a CSS selector," which implies
CSS selectors are not used, but the actual behavior allows selectors as a
fallback. Update the wording in the "Live page snapshot (get_page_view)" section
to soften this language and indicate that refs are the preferred method when
available, while acknowledging that the action flow can still accept CSS
selectors as a fallback when a stable reference is not available. This will
align the documented policy with the actual system behavior.

In `@packages/peek-mcp/src/mcp/action-schema.ts`:
- Line 88: The EnterActionSchema has an inconsistent selector field validation
compared to other action schemas. Change the selector field in EnterActionSchema
from z.string().optional() to z.string().min(1).optional() to match the
validation pattern used in ClickActionSchema, TypeActionSchema, and
DblClickActionSchema. This ensures consistent behavior across all action schemas
by preventing empty strings from being accepted, maintaining parity with how the
dispatcher and other schemas handle selector validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cb200ae9-620c-4a73-aebc-0af57b1ffc88

📥 Commits

Reviewing files that changed from the base of the PR and between 0df2800 and 10e926f.

📒 Files selected for processing (19)
  • .changeset/peek-live-page-view.md
  • docs/peek/PRIVACY_POLICY.md
  • packages/peek-extension/entrypoints/background.ts
  • packages/peek-extension/src/__tests__/action-handler.test.ts
  • packages/peek-extension/src/__tests__/dispatcher.test.ts
  • packages/peek-extension/src/__tests__/snapshot.test.ts
  • packages/peek-extension/src/permissions/action-handler.ts
  • packages/peek-extension/src/permissions/action-protocol.ts
  • packages/peek-extension/src/permissions/dispatcher.ts
  • packages/peek-extension/src/permissions/snapshot.ts
  • packages/peek-mcp/README.md
  • packages/peek-mcp/src/mcp/action-schema.ts
  • packages/peek-mcp/src/mcp/host-bridge.ts
  • packages/peek-mcp/src/mcp/server.ts
  • packages/peek-mcp/src/native-host/action-protocol.ts
  • packages/peek-mcp/src/native-host/audit.ts
  • packages/peek-mcp/test/action-schema.test.ts
  • packages/peek-mcp/test/server.test.ts
  • packages/peek-mcp/test/stdio-smoke.test.ts

Comment thread docs/peek/PRIVACY_POLICY.md
Comment thread packages/peek-mcp/src/mcp/action-schema.ts Outdated
- action-schema: EnterActionSchema.selector now z.string().min(1).optional()
  to match Click/Type/DblClick (was .optional(), allowing ""). Consistency nit.
- PRIVACY_POLICY: soften "act on a stable reference instead of guessing a CSS
  selector" — selector targeting still works as a fallback, so phrase
  get_page_view as preferred-over, not instead-of.

294 mcp tests pass; typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
harry-harish added a commit that referenced this pull request Jun 20, 2026
Mirror the two fixes landed on the R1 base branch so the stack stays in sync
and #102 merges cleanly when retargeted to main:
- EnterActionSchema.selector -> .min(1).optional()
- PRIVACY_POLICY get_page_view wording (prefer-over, not instead-of)

303 mcp tests pass; typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: harry-harish <22562634+harry-harish@users.noreply.github.com>
@harry-harish harry-harish merged commit 2adf61f into main Jun 20, 2026
5 checks passed
@harry-harish harry-harish deleted the feat/peek-live-page-view branch June 20, 2026 07:48
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