chore(release): v0.3.0 — internal rewrite
amankumarsingh77 amankumarsingh7702@gmal.com
Sat, 02 May 2026 16:50:13 +0530
2 files changed,
53 insertions(+),
1 deletions(-)
M
CHANGELOG.md
→
CHANGELOG.md
@@ -2,6 +2,58 @@ # Changelog
All notable changes to pi-browser-harness will be documented in this file. +## 0.3.0 — 2026-05-02 + +### Internal rewrite + +- Per-domain module split: every tool now lives in its own `src/domains/<name>.ts` file. The 1140-line `daemon.ts` and 2277-line `tools.ts` are gone; the largest single file is now `src/client.ts` at ~180 LOC. +- New transport/session/client split: `BrowserDaemon` class replaced with `createBrowserClient()` factory composing a `CdpTransport` (factory) and `CdpSession` (factory). +- All tool handlers now return `Result<T, E>`; one `defineBrowserTool` helper converts to pi's `ToolDefinition` and supplies a uniform `details` shape: `{ ok: true, ... }` on success, `{ ok: false, kind, message, ... }` on error. +- Strict TypeScript flags enabled (`noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noPropertyAccessFromIndexSignature`, `noUnusedLocals`, `noUnusedParameters`). Zero `any` in the codebase. All boundary `as` casts documented. + +### Bug fixes (predictability) + +- `browser_navigate` no longer silently creates a new tab when navigation fails; outcome is reported explicitly via `details.outcome.kind` (`"in_place"` | `"new_tab_created"`). +- Page-info cache invalidation is now automatic: the session subscribes to CDP `Page.frameNavigated` / `Page.loadEventFired` events. The 5 manual `invalidatePageInfoCache()` calls are gone. +- Dialog read no longer mutates state on `Page.javascriptDialogClosed` — the dialog persists in the buffer until `takeDialog()` is called, fixing a fast-dismiss race that dropped dialogs. +- `browser_dispatch_key` now returns `details.matched` (count of elements the synthetic event was dispatched to). Zero matches is an `invalid_state` error instead of a false success. +- `browser_http_get` timeout now covers the response body read (legacy aborted headers but `await response.text()` could hang indefinitely). +- `sharp` failures are distinguished from "sharp not installed" — actual errors no longer masked by the install hint. +- Screenshot paths use `randomUUID()` per-namespace — no more concurrent-write collisions from `Date.now() + global counter`. +- Reconnect is lazy (via `ensureAlive`) — no background reconnect, no stacked Chrome consent popups. +- WebSocket events are routed through an `AsyncIterable` bound to each connection — stale events from a previous connection can no longer leak across reconnects. +- `browser_wait_for_load` returns a typed `timeout` error if the deadline elapses (legacy returned a soft string). + +### Security fixes + +- All JS evaluation source is built via `safeJs\`...\`` (always JSON.stringify-safe). The previous `replace(/'/g, "\\'")` selector escaping (broken for backslashes, newlines, unicode quotes, `</script>`) is gone. +- `browser_run_script` now requires: + - script path inside `tmpdir()`, `cwd()`, or `BH_SCRIPT_DIR` (other paths rejected with `invalid_state`) + - a mandatory timeout (default 60s, max 600s, enforced via `Promise.race`) + - the AbortSignal is honored even if the script ignores its `signal` parameter + - source size ≤ 1 MB + - return shape validated structurally (each content item must be `{ type: "text", text: string }`) +- `browser_download` validates the directory exists and is writable before calling CDP (Chrome was silently downloading to nowhere if the dir was bogus). +- `browser_upload_file` verifies the file exists and is readable before any CDP call (prevents half-set state on the input). +- `pdfPath()` / `screenshotPath()` validate the namespace against a strict regex so a hostile namespace cannot escape `tmpdir()`. + +### Parameter renames (saved scripts must be updated) + +- `browser_click`: `clicks` → `count` +- `browser_dispatch_key`: `event` → `eventType` + +### Removed + +- The unused `tabHistory`, `screenshotDir`, and `debugClicks` fields on persisted state. +- The dead `tool_result` hook in `index.ts` for tab-history tracking (`details.targetId` was never set by any tool). +- `src/protocol.ts`, `src/renderers.ts`, `src/daemon.ts`, `src/tools.ts` (replaced by per-domain files and `client.ts`). + +### Known follow-ups + +- `browser_get_network_log` returns a structured deprecation note. The new transport routes events through an `AsyncIterable` consumed by the session manager; a synchronous `recentEvents()` API is deferred. Use `browser_execute_js` with `PerformanceObserver` or `performance.getEntries()` as a workaround. +- `browser_run_script` script binding is named `daemon` for back-compat, but the underlying object is now a `BrowserClient`. Scripts using `daemon.cdp(method, params)` should switch to `daemon.session().call(method, params)`. +- No tests added in this rewrite; that's a separate workstream. + ## [0.2.0] - 2026-05-02 ### Changed
M
package.json
→
package.json
@@ -1,6 +1,6 @@
{ "name": "pi-browser-harness", - "version": "0.2.0", + "version": "0.3.0", "description": "Browser control extension for pi — navigate, click, type, screenshot, and extract data from real Chrome via CDP", "keywords": [ "pi-package",