| Age | Commit message (Collapse) | Author |
|
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>
|
|
Both were documented and inert.
--browser-debug-clicks was registered as a flag and never read; the only
real switch was the undocumented BH_DEBUG_CLICKS env var. The flag now
feeds util/debug.ts, which the click tool consults, and the env var keeps
working as an equivalent.
BU_CDP_WS was read in the client and handed to transport.connect(), but
the daemon transport discards that argument and always dials the daemon
socket — and the daemon's own discovery never looked at the variable, so
setting it did nothing. The override now lives in discoverEndpoint, which
is what both processes go through, and the client's redundant read is
gone. The variable must be set before the daemon spawns.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The scanner banned as any, as {, as unknown as, non-null assertions and
ts-ignore, but said nothing about `as SomeNamedType` — so a new cast over
CDP or JSON data could be added and CI would stay green, which is the exact
regression the refactor exists to prevent. It also could not see a cast
whose target type sits on the following line.
Adds named-cast, function-cast and trailing-cast. All six surviving
assertions in src/ are now visible to the scanner and individually
exempted with a stated reason, so the allowlist is the complete inventory.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The tool gate ran access() on DAEMON_SOCKET_PATH, which on Windows is the named
pipe \\.\pipe\pi-browser-daemon. Named pipes are not filesystem entries, so
access() always fails there and every browser_* call returned "Browser harness
not initialized" no matter how healthy the daemon was. spawn.ts already skipped
the identical check for this reason; that knowledge is now one shared
daemonSocketMayExist() used by both call sites, with platform and path as
parameters so the branch is testable off-platform.
Report: docs/superpowers/reports/2026-07-26-bug-audit.md#f1
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
A clean tsc does not prove the absence of casts. This scans src/ for
as any, ts-ignore, non-null assertions, inline object casts, and double
casts, wired into a new npm run check that CI runs as a single step.
The escape hatch is an external allowlist module rather than an inline
comment marker: comments are not used in this codebase, and an entry
carries a count, so adding a new cast to an already-exempted file still
fails until someone raises a number that shows up in the diff. Exactly
one exemption is needed today, for the dynamic sharp import.
scripts/ was gitignored wholesale, so the two new files are un-ignored
individually and everything else dropped there stays ignored.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
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>
|
|
Ten sites cast or implicitly typed JSON.parse output; JSON.parse("null")
would have satisfied all of them. parseJson returns a Result and validates
against a typebox schema. js.ts keeps unknown — user script output has no
fixed shape. daemon/bridge.ts assigned JSON.parse straight to CdpRawMessage
with no guard at all; it now uses isCdpRawMessage like the transport does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|