From d54d8e9e2dfbd31358b1f48e17338d74f5d270c0 Mon Sep 17 00:00:00 2001 From: amankumarsingh77 Date: Mon, 27 Jul 2026 23:37:04 +0530 Subject: fix(domains): restore fail-closed focus check in browser_type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopting isFocusProbe inverted the safety default: the guard was ANDed into the condition gating the check, so a probe result the guard rejected skipped the check and fell through to Input.insertText — text typed into nothing, silently, which is the exact failure the block exists to prevent. The guard now feeds a value that defaults to { ok: false }, so a rejected shape produces the error instead of bypassing it. The other four guard adoptions (isFillResult, isFocusResult, isSelectResult, isPageResult) were already fail-closed: each feeds a value whose rejection lands on a pre-existing error branch. Also assert x/y in the box centre test — the fields snapshot's off-viewport filter reads — and wrap the zero-size message to the surrounding width. Co-Authored-By: Claude Opus 5 (1M context) --- src/domains/box.ts | 5 ++++- src/domains/keyboard.ts | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/domains/box.ts b/src/domains/box.ts index 7b12e82..e013f70 100644 --- a/src/domains/box.ts +++ b/src/domains/box.ts @@ -41,7 +41,10 @@ export const boxOf = async ( return err({ kind: "invalid_state", message: "DOM.getBoxModel returned an incomplete content quad" }); } if (model.width <= 0 || model.height <= 0) { - return err({ kind: "invalid_state", message: "element has a zero-size box and cannot be clicked" }); + return err({ + kind: "invalid_state", + message: "element has a zero-size box and cannot be clicked", + }); } return ok(centreOf(model)); }; diff --git a/src/domains/keyboard.ts b/src/domains/keyboard.ts index 21681c5..6722ffb 100644 --- a/src/domains/keyboard.ts +++ b/src/domains/keyboard.ts @@ -27,10 +27,6 @@ export const typeTool = defineBrowserTool({ ], parameters: TypeArgs, async handler(args, { client }): Promise> { - // Guard against silent text loss: Input.insertText succeeds regardless of - // whether an editable element is focused, so without this check typed text - // can vanish into the void with no error. Fail loudly with an actionable - // message instead. IIFE starts with "(" so evaluateJs returns it directly. const focused = await client.evaluateJs(safeJs` (() => { const el = document.activeElement; @@ -39,8 +35,8 @@ export const typeTool = defineBrowserTool({ return { ok, tag: el ? el.tagName : null }; })() `); - if (focused.success && isFocusProbe(focused.data)) { - const f = focused.data; + if (focused.success) { + const f: FocusProbe = isFocusProbe(focused.data) ? focused.data : { ok: false, tag: null }; if (!f.ok) { return err({ kind: "invalid_state", -- cgit v1.2.3