From fe00d3361dece3d35f788d3eeb1c750eedbf6294 Mon Sep 17 00:00:00 2001 From: Aman Kumar <145339995+amankumarsingh77@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:59:58 +0530 Subject: feat: add forms domain and durable window binding (v0.9.0) (#14) - Add forms domain with a universal field setter that auto-detects element type and fires framework-compatible input events (React native-setter trick) - Add window-binding helper to capture and bind the real Chrome windowId as the session's durable window identity on every new-window code path - Wire supporting changes across CDP session/ownership, client, navigate, isolated-tab, prompt, and state - Add manual tests for forms and window binding - Bump version 0.8.3 -> 0.9.0 Co-authored-by: Claude Opus 4.8 (1M context) --- src/index.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src/index.ts') diff --git a/src/index.ts b/src/index.ts index d5f3435..7109ea0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -109,9 +109,10 @@ export default function browserHarnessExtension(pi: ExtensionAPI): void { if (!client) { const transport = createDaemonTransport(state.namespace); - const initialOwnership: { ownedTargetIds?: ReadonlyArray; harnessWindowTargetId?: string } = {}; + const initialOwnership: { ownedTargetIds?: ReadonlyArray; harnessWindowTargetId?: string; harnessWindowId?: number } = {}; if (state.ownedTargetIds !== undefined) initialOwnership.ownedTargetIds = state.ownedTargetIds; if (state.harnessWindowTargetId !== undefined) initialOwnership.harnessWindowTargetId = state.harnessWindowTargetId; + if (state.harnessWindowId !== undefined) initialOwnership.harnessWindowId = state.harnessWindowId; client = createBrowserClient({ namespace: state.namespace, @@ -124,6 +125,9 @@ export default function browserHarnessExtension(pi: ExtensionAPI): void { ...(snap.harnessWindowTargetId !== undefined ? { harnessWindowTargetId: snap.harnessWindowTargetId } : {}), + ...(snap.harnessWindowId !== undefined + ? { harnessWindowId: snap.harnessWindowId } + : {}), }; // Ownership changes can fire from CDP events at any time, // including after session replacement when pi's ctx is stale. @@ -147,20 +151,27 @@ export default function browserHarnessExtension(pi: ExtensionAPI): void { }); pi.on("session_shutdown", async () => { - persistState(pi, state); if (client) { try { // Detach from the page target (removes the "Chrome is being controlled" // banner) but keep the transport alive for the next session. await client.detach(); + // Close every tab this session opened so no stale harness tabs linger + // in the user's browser between sessions. This also clears the persisted + // ownership + window binding via onOwnershipChange, so the next session + // starts with a fresh dedicated window rather than reattaching to leftovers. + await client.closeOwnedTabs(); } catch (e) { - console.warn("[pi-browser-harness] client.detach() failed during shutdown:", e); + console.warn("[pi-browser-harness] browser teardown failed during shutdown:", e); } // ponytail: keep the transport alive across sessions. // Do NOT call client.stop() or null out client — the daemon connection // persists and eliminates the per-session "Allow Remote Debugging" prompt. // Only Chrome restart or daemon death triggers a new prompt. } + // Persist last — closeOwnedTabs mutates `state` through onOwnershipChange, + // so this captures the cleared ownership set. + persistState(pi, state); await cleanupTempDirs(); }); -- cgit v1.2.3