aboutsummaryrefslogtreecommitdiff
path: root/src/domains/ref-resolve.ts
AgeCommit message (Collapse)Author
2026-08-02refactor: helpers live in helper modules, not in tool filesamankumarsingh77
form.ts exported resolveAndCall and detailsOf to form-batch.ts, snapshot.ts exported buildTree and collectInteractiveTargets to ref-resolve.ts, and screenshot.ts exported captureWithCrosshair to click.ts — so importing one tool pulled in another tool's whole module. The shared halves move out: ax-tree.ts (the AX tree model, its construction and the queries over it), element-call.ts (calling a function on a resolved element, and the PageResult it returns), screenshot-capture.ts (capture, resize, crosshair overlay). Each tool file now holds its tools and its own presentation, nothing else. NavOutcome stops being exported; nothing outside navigate.ts read it. target.ts stays a module rather than folding into click.ts as planned: it is already helper-only and has its own test suite, and moving a tested pure function into a tool file is the thing this commit removes. Having one consumer is not the defect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02refactor: one door from a tool to the browseramankumarsingh77
Four routes coexisted: cdpCall, a raw client.session().call, a session held in a local and called directly, and client.evaluateJs — and five files mixed two or three of them. The CdpError-to-ToolErr mapping was hand-copied at nine sites, plus a private copy in isolated-tab.ts. domains/cdp-call.ts now owns all of it: cdpErrToToolErr, cdpCall, cdpCallOnTarget, cdpCallBrowser, evalJs. Every other file under src/domains goes through them, which also removes a pile of `if (!r.success) return err({ kind: "cdp_error", ... })` boilerplate in favour of returning the failed Result as-is. Two scanner rules keep it that way, scoped to src/domains/ so the layer that legitimately owns the session — cdp/ and client.ts — is unaffected. Scoping is new to the rule model; without it the rules fired on the transport itself. One deliberate behaviour change: a CDP timeout now surfaces as kind "timeout" rather than "cdp_error". isolated-tab.ts already did this and the other 13 sites flattened it; the shared mapper uses the honest label rather than preserving the mislabel. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02refactor(domains): strip comment noiseamankumarsingh77
Removes module banners, step markers, and comments restating the code. Keeps one-line notes for safeJs's trust boundary, the select-match null sentinels, the TUI width clamp, the single-window tab rule, the input synthesis quirks (char events, keyCode, mousemove, focus, compositor), the stale AX value, ignored-wrapper recursion, and isolated-tab routing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02fix(domains): keep element refs stable across a mutationamankumarsingh77
interactiveDiff re-assigned refs by tree position after every fill, click and select, so any element appearing or disappearing shifted the numbering and a ref the agent was still holding silently resolved to a different element — while the tools kept promising that refs survive re-renders. Refs are now carried over by backendNodeId and only genuinely new elements draw a new number. Report: docs/superpowers/reports/2026-07-26-bug-audit.md#f6 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02refactor: close the remaining unguarded type assertionsamankumarsingh77
Types the event-queue iterator's TReturn as undefined so the terminal result needs no cast; declares the isError field the pi runtime reads by duck-typing; binds socket to a local const in the daemon transport; replaces the @ts-ignore on the optional sharp import with a non-literal specifier so src/ still typechecks where sharp was not installed. Adds src/util/guards.ts as the single home for narrowing over unknown — isRecord plus scalar/array readers — and converts the two private isObject copies in cdp/types.ts and daemon/protocol.ts along with every inline `as Record<string, unknown>` in domains/js.ts and domains/render.ts. Gives Accessibility.getFullAXTree a real result schema, closing the last unvalidated CDP boundary: only nodeId is required, every object carries additionalProperties, and each AX value stays Unknown, so the tree decodes as a whole or fails as a whole rather than being filtered. Guards the five tool-result `details` readers, the daemon attach response, the persisted session state, the browser-namespace flag, and the fs errno narrowing, each feeding an already-present failure path. The daemon-transport socket binding is not a bug fix: send() runs synchronously inside sendWithTimeout's promise executor, so socket cannot be reassigned between the check and the write. It removes the assertion and makes the write immune to a later refactor that adds an await. Two assertions survive by design and are documented in the task report: the never->unknown re-widening in util/tool.ts, which the type-erased tool registry makes unavoidable, and the AsyncFunction constructor lookup in domains/js.ts, which JavaScript exposes no typed binding for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02refactor(domains): drop CDP casts, share the box-model unwrapamankumarsingh77
ref-resolve.ts and snapshot.ts had the same box-model unwrap, both using data.model! to work around an untyped response. Extracted to domains/box.ts; the typed schema makes the assertions unnecessary. Both derived the centre identically (quad corner + half the model width/height), so centreOf keeps that derivation; the shared zero-size rejection moved into boxOf, and snapshot keeps its own off-viewport (x/y < 0) filter. evalInIsolatedTab now goes through evaluateJson with the tab's own sessionId and a caller-supplied guard; both callers evaluate expressions ending in JSON.stringify, so they pass isJsonText rather than a check that checks nothing. Runtime.evaluate/callFunctionOn result casts in form.ts, forms.ts and keyboard.ts are replaced by named guards over the in-page result shapes. Runtime.callFunctionOn's params schema gained arguments/returnByValue/ awaitPromise/userGesture: four domain call sites legitimately pass them and typebox's additionalProperties:true does not widen the static type, so the params type was rejecting valid CDP fields. Params schemas are type-only (only results are compiled), so this is a compile-time widening with no runtime effect. tsc is green again for both tsconfigs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-06-29feat: address elements by stable refs across re-renders (#8)Aman Kumar
Interaction tools could only target elements by raw viewport coordinates (browser_click) or model-guessed CSS selectors (browser_fill/focus/ select_option/upload). Neither survives a re-render: on React/SPA forms, every save or edit reflows the page, so captured @(x,y) coordinates go stale and guessed selectors miss — leaving the agent to fall back to hand-rolled execute_js DOM walks and unnoticed failed saves. Add a stable ref system, mirroring Playwright MCP / browser-use: - snapshot assigns each interactive element a ref (e1, e2, …), shown as [eN] in the outline, and publishes a per-tab ref → backendNodeId map - interaction tools accept an optional `ref` that re-resolves the element at call time (via DOM.resolveNode / getBoxModel), so it stays valid across re-renders; coordinates/selectors remain as fallbacks - mutating tools append a compact diff of changed / newly-appeared (*) / removed interactive elements, so silent failed saves surface immediately - stale refs return an actionable "re-snapshot" error instead of a miss Ref map is replaced per snapshot (bounded memory); fill keeps the native _valueTracker write path so React controlled inputs still update. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>