diff options
| author | amankumarsingh77 <amankumarsingh7702@gmail.com> | 2026-07-28 21:55:55 +0530 |
|---|---|---|
| committer | Aman Kumar <145339995+amankumarsingh77@users.noreply.github.com> | 2026-08-02 19:12:46 +0530 |
| commit | 632600ec0a0a68d9327e19bd419a1ae72047955f (patch) | |
| tree | 5ef59b561d055b8f9173154c252e6d464f3a042b /scripts | |
| parent | 893a9d338ceb5d37aefece1df637c9a5888a120e (diff) | |
refactor: one door from a tool to the browser
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>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/boundary-allowlist.ts | 13 | ||||
| -rw-r--r-- | scripts/check-boundaries.ts | 9 |
2 files changed, 20 insertions, 2 deletions
diff --git a/scripts/boundary-allowlist.ts b/scripts/boundary-allowlist.ts index bb34139..512aa40 100644 --- a/scripts/boundary-allowlist.ts +++ b/scripts/boundary-allowlist.ts @@ -42,6 +42,19 @@ export const ALLOWLIST: ReadonlyArray<Exemption> = [ "renderCall is stored under a per-tool Static<S> but invoked through the erased TSchema form; the generic-correlation limit makes this unavoidable and the value is the tool's own handler, created with the same S", }, { + path: "src/domains/cdp-call.ts", + rule: "raw-cdp-call", + count: 3, + reason: + "the one door from a tool to CDP: cdpCall, cdpCallOnTarget and cdpCallBrowser each reach the session once and map CdpError to ToolErr, so no other file under src/domains needs to", + }, + { + path: "src/domains/cdp-call.ts", + rule: "raw-evaluate", + count: 1, + reason: "evalJs is the single wrapper over client.evaluateJs, for the same reason", + }, + { path: "src/domains/js.ts", rule: "trailing-cast", count: 1, diff --git a/scripts/check-boundaries.ts b/scripts/check-boundaries.ts index c438b83..7dd97e2 100644 --- a/scripts/check-boundaries.ts +++ b/scripts/check-boundaries.ts @@ -11,7 +11,8 @@ export type Violation = { readonly text: string; }; -const RULES: ReadonlyArray<{ readonly rule: string; readonly re: RegExp }> = [ +// `scope` restricts a rule to one layer: the tool layer must go through domains/cdp-call.ts, while cdp/ and client.ts are the layer that owns the session. +const RULES: ReadonlyArray<{ readonly rule: string; readonly re: RegExp; readonly scope?: RegExp }> = [ { rule: "as-any", re: /\bas\s+any\b/ }, { rule: "ts-ignore", re: /@ts-(ignore|expect-error|nocheck)/ }, { rule: "non-null-assertion", re: /[A-Za-z_$)\]]!\s*(?:[.[(;,)\]}]|$)/ }, @@ -20,6 +21,8 @@ const RULES: ReadonlyArray<{ readonly rule: string; readonly re: RegExp }> = [ { rule: "named-cast", re: /\bas\s+(?:new\s+)?[A-Z][A-Za-z0-9_]*/ }, { rule: "function-cast", re: /\bas\s+\(/ }, { rule: "trailing-cast", re: /\bas\s*$/ }, + { rule: "raw-cdp-call", re: /(?:session\(\)|\bsession)\.call(?:OnTarget|Browser)?\(/, scope: /^src\/domains\// }, + { rule: "raw-evaluate", re: /\.evaluateJs\(/, scope: /^src\/domains\// }, ]; export type SourceFile = { readonly path: string; readonly text: string }; @@ -37,8 +40,10 @@ const budgets = (exemptions: ReadonlyArray<Exemption>): Map<string, number> => { const rawHits = (files: ReadonlyArray<SourceFile>): ReadonlyArray<Violation> => { const out: Violation[] = []; for (const file of files) { + const path = normalise(file.path); for (const [i, line] of file.text.split("\n").entries()) { - for (const { rule, re } of RULES) { + for (const { rule, re, scope } of RULES) { + if (scope && !scope.test(path)) continue; if (re.test(line)) out.push({ path: file.path, line: i + 1, rule, text: line.trim() }); } } |
