From 9c3a4facebd52bfd3c16126108cf43306f0cd4da Mon Sep 17 00:00:00 2001 From: nipunrajk Date: Fri, 26 Jun 2026 15:19:34 +0530 Subject: [PATCH] feat(cdp): signal when the ref list is truncated in look() --- packages/cdp/src/actions.ts | 8 ++++++-- packages/cdp/src/snapshot.test.ts | 6 ++++-- packages/cdp/src/snapshot.ts | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/cdp/src/actions.ts b/packages/cdp/src/actions.ts index 5c17348..eb84c6c 100644 --- a/packages/cdp/src/actions.ts +++ b/packages/cdp/src/actions.ts @@ -62,7 +62,7 @@ export async function look(ctx: BrowserContext, opts: LookOptions = {}): Promise // a11y (default) const tree = await ctx.session.send<{ nodes: AXNode[] }>("Accessibility.getFullAXTree", {}); - const { refs, refMap, truncated } = compactAxTree(tree.nodes ?? []); + const { refs, refMap, truncated, truncatedCount } = compactAxTree(tree.nodes ?? []); ctx.lastRefs.clear(); for (const [k, v] of refMap) ctx.lastRefs.set(k, v); @@ -74,7 +74,11 @@ export async function look(ctx: BrowserContext, opts: LookOptions = {}): Promise filtered = refs.filter((r) => r.role.toLowerCase().includes(f) || r.name.toLowerCase().includes(f)); } const header = `${title}\n${url}\n${filtered.length} of ${refs.length} refs${truncated ? " (TRUNCATED at 200)" : ""}`; - return { snapshot, text: `${header}\n${renderRefs(filtered)}` }; + let text = `${header}\n${renderRefs(filtered)}`; + if (truncated && truncatedCount > 0) { + text += `\n… ${truncatedCount} more elements below — scroll or filter`; + } + return { snapshot, text }; } function delta(snapshot: Snapshot, summary: string): SnapshotDelta { diff --git a/packages/cdp/src/snapshot.test.ts b/packages/cdp/src/snapshot.test.ts index 9a4ff28..9d47054 100644 --- a/packages/cdp/src/snapshot.test.ts +++ b/packages/cdp/src/snapshot.test.ts @@ -56,12 +56,13 @@ const tree: AXNode[] = [ ]; describe("compactAxTree", () => { - const { refs, refMap, truncated } = compactAxTree(tree); + const { refs, refMap, truncated, truncatedCount } = compactAxTree(tree); it("keeps only interactive + named-role nodes that are not ignored and have a backend id", () => { expect(refs.map((r) => r.role)).toEqual(["button", "textbox", "checkbox", "heading"]); expect(refs.map((r) => r.name)).toEqual(["Sign in", "Email", "Remember me", "Welcome"]); expect(truncated).toBe(false); + expect(truncatedCount).toBe(0); }); it("assigns sequential ref ids from 1", () => { @@ -117,8 +118,9 @@ describe("compactAxTree truncation", () => { backendDOMNodeId: i + 1, }), ); - const { refs, truncated } = compactAxTree(many); + const { refs, truncated, truncatedCount } = compactAxTree(many); expect(refs.length).toBe(200); expect(truncated).toBe(true); + expect(truncatedCount).toBe(50); }); }); diff --git a/packages/cdp/src/snapshot.ts b/packages/cdp/src/snapshot.ts index 373f29a..78ed7bc 100644 --- a/packages/cdp/src/snapshot.ts +++ b/packages/cdp/src/snapshot.ts @@ -88,6 +88,7 @@ export interface CompactionResult { /** ref id -> resolution info needed by act/fill. */ refMap: Map; truncated: boolean; + truncatedCount: number; } /** @@ -100,6 +101,7 @@ export function compactAxTree(nodes: AXNode[]): CompactionResult { const refMap = new Map(); let counter = 0; let truncated = false; + let truncatedCount = 0; for (const node of nodes) { if (node.ignored) continue; @@ -115,7 +117,8 @@ export function compactAxTree(nodes: AXNode[]): CompactionResult { if (refs.length >= MAX_REFS) { truncated = true; - break; + truncatedCount++; + continue; } const ref = ++counter; @@ -124,7 +127,7 @@ export function compactAxTree(nodes: AXNode[]): CompactionResult { refMap.set(ref, { backendDOMNodeId: node.backendDOMNodeId, role, name }); } - return { refs, refMap, truncated }; + return { refs, refMap, truncated, truncatedCount }; } /** Render refs as compact "[ref] role \"name\" (state)" lines. */