aboutsummaryrefslogtreecommitdiff
path: root/CHANGELOG.md
AgeCommit message (Collapse)Author
2026-10-14fix(setup): skip local-browser precondition for every remote targetIgor Soarez
The pre-flight check only skipped isBrowserRunning() when BU_CDP_HTTP was set, so a machine with no local browser failed /browser-setup with 'No browser instance running' before discovery ever dialed the built-in castle default. Resolve the target the same way discovery does and skip the local-process check whenever it resolves remote — env var, /browser-target choice, or default. A resolved local target still requires a local browser, and an unreachable remote still fails loudly in step 4.
2026-10-12fix(daemon): let pi exit after a session has connected to the daemon (#40)Aman Kumar
The client's daemon socket is kept open across sessions by design; in pi -p it was the last handle keeping Node alive, so a run that had connected to the browser hung after its answer. Unref the socket; in-flight requests hold their own timers. Fixes #39 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12fix: browser_download no longer hijacks the user's own downloads (#33)Uttkarsh
Browser.setDownloadBehavior was sent without a browserContextId, so the override applied to the user's default context and outlived the session. browser_download now takes restore:true, tracks the override this process set, and a clean session shutdown restores Chrome's default with a bounded call that is skipped when the browser is already gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11refactor: remove duplicate browser prompt instructions (#35)Patrick Barattin
Remove browser instruction text repeated across tool descriptions, parameter schemas, tool guidelines and the global browser prompt. Tool names, schemas, handlers and concurrency are unchanged; shared recovery and ownership guidance is now available before and after the browser connects, and the prompt names which tools are serialized versus observations. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11fix(daemon): stop importing typebox in the daemon process (#38)Aman Kumar
pi installs packages with dev and peer dependencies omitted and supplies typebox only to the extension host. The daemon is a separate Node process whose import graph reached typebox via src/cdp/discovery.ts, so from a pi-managed install it crashed with "Cannot find module 'typebox'" before binding its socket. Parse /json/version with the package's own guards, and add a test that keeps every package reachable from the daemon a runtime dependency. Fixes #34 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11fix: append browser state to the session only when it changes (#37)Aman Kumar
persistState appended a browser-harness-state entry on every ownership callback, session_tree and shutdown, so the append-only session file and Pi Web's "+N custom" chain grew without bound. A snapshot is now written only when it differs from the last one persisted or restored. Fixes #26 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11fix(daemon): resolve tsx from the filesystem when Node's resolver cannot see ↵PhysicistLeon
node_modules (#28) Inside a Bun-compiled pi binary (pi.exe), createRequire().resolve("tsx/cli") is rooted at the embedded virtual filesystem and cannot see the extension's real node_modules, so browser_setup failed instantly. The resolver result is now checked on disk and, when it fails, the tsx CLI is found by walking up the node_modules chain. Under Bun the daemon runs on `node` from PATH (process.execPath is the pi binary itself); PI_BROWSER_NODE overrides it. Fixes #27 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09feat: add per-tab request headers (#30)astarring
Expose explicit set and clear tools so environment-routed pages can be opened without leaking header values or carrying headers across unrelated browsing. Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com Co-authored-by: zouzhigang <zouzhigang@bytedance.com>
2026-08-13chore(release): 0.11.1 (#24)Uttkarsh
2026-08-06fix: accept Windows script paths and start the daemon from a real install (#23)Aman Kumar
Two independent Windows/production defects reported in #22. browser_run_script rejected every absolute path on Windows. The allowed-root check compared with a hardcoded `${root}/`, but path.resolve returns backslash-separated paths there, so a file inside os.tmpdir() was refused even though the rejection message listed tmpdir as allowed. Decide containment with path.relative instead: it is separator-agnostic and carries each platform's own case rules, so it also accepts a differing drive-letter case that a path.sep patch would still reject. Escapes via `..` and sibling directories sharing the root's name prefix stay rejected, as before. The daemon could not start under `npm omit=dev`: it is spawned through tsx, which was declared only as a dev dependency. Moving tsx to dependencies is not enough on its own — pi installs extensions into one flat hoisted tree, so tsx lands beside the package and the fixed <pkg>/node_modules/.bin/tsx lookup still misses, falling through to an `npx tsx` that resolves against the wrong cwd and dies against stdio: "ignore". Resolve the CLI entry with Node's own resolver, which walks up to the hoisted copy. That removes the shell entirely, and with it the Windows .cmd shim, windowsVerbatimArguments, and the manual quoting that paths containing spaces needed. Both fixes live in platform-branching code, so their tests are registered in the three-OS CI matrix that already exists for that purpose — a Linux-only run cannot exercise either one.
2026-08-06fix: reconnect to Chrome only on explicit browser demand (#18)Uttkarsh
* fix: reconnect to Chrome only on browser demand * fix(daemon): gate stale CDP bridge reconnect attempts * Harden bridge reconnect lifecycle against stale socket callbacks * fix(daemon): handle stale attempt failures without deferred settlement * test: align waitFor assertions and stale-socket case labels * fix(daemon): re-check socket after connect wait in handleRequest Restores the post-wait re-check from the original PR branch (dropped during the main rebase merge); TypeScript needs the local narrowing before send. * fix(daemon): reject in-flight requests when an open connection drops `failCurrentAttempt` delegated callback rejection to `settleAttempt`, but an attempt that reached `open` had already settled, so the close path returned early and never answered its in-flight requests. They hung until the 10s command timeout instead of failing immediately, which the on-demand reconnect change had promised to preserve. Reject the attempt's callbacks directly in `failCurrentAttempt`, before the close handler notifies clients. Move the connection-lifecycle tests out of test/manual/ — which nothing runs — into test/daemon/, where `npm test` picks them up, and convert the hand-rolled pass/fail counters to node:test. Adds a case covering the drop path above; it fails without the fix. --------- Co-authored-by: Hermes Subagent <hermes-subagent@example.com> Co-authored-by: Hermes Agent <agent@example.com> Co-authored-by: uttkarsh-26 <uttkarsh@users.noreply.github.com> Co-authored-by: amankumarsingh77 <amankumarsingh7702@gmail.com>
2026-08-02chore(release): 0.11.0amankumarsingh77
Breaking: the deep-research skill, command, and subagent are gone. Also carries the 0.10.3 fixes, which were tagged but never published. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02docs: record the new contract and the two knobs that now workamankumarsingh77
ARCHITECTURE.md: the layer map gains domains/cdp-call.ts as the single door and the helper-module/tool-module split; the "cdpCall vs session.call" section is replaced, since snapshot.ts no longer mixes styles — it swallows failures through cdpCall instead of around it. Rule 1 now says tool files export only tools, rule 7 names the enforced scanner rules, and the two 250-line exceptions are recorded as largely settled (snapshot 477 to 256, form 409 to 283). Also notes the one honest gap: session.attach and session.windowId perform CDP calls the rules do not match. README: BU_CDP_WS carries its daemon-restart caveat, BH_DEBUG_CLICKS is documented as the flag's equivalent, and the tool count matches the registry (38 to 40). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02feat!: remove the deep-research featureamankumarsingh77
The harness ships browser tools; orchestrating a multi-agent research workflow on top of them is the agent's job, not this extension's. Drops the skill, the /deep-research command, and the web-search-researcher subagent config. browser_web_search and browser_read_page are untouched — the two tests that covered their pure parsers move to test/domains/, where the test glob still picks them up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26chore: release 0.10.3amankumarsingh77
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26chore: release 0.10.2amankumarsingh77
Also resyncs package-lock.json, which was left at 0.9.0 by the 0.10.0 and 0.10.1 bumps. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26fix: kill leaked Chrome processes on profile seed failureamankumarsingh77
When a profile is pinned and ProcessSingleton fails to delegate, the spawned Chrome process starts a full second browser instance. The sentinel never appeared, but the spawned process was never killed (detached + unref'd + reference discarded), accumulating zombie browsers that consume RAM. Three changes: - Store child process ref and expose kill() on ProfileWindowHandle. Call kill() when the sentinel doesn't appear within the timeout. - Only clear profileContextId when the browser UUID changes (Chrome mints a fresh UUID on every launch), avoiding unnecessary re-spawns. - Don't clear profileContextId in setProfilePin when the pin hasn't changed, preventing gratuitous re-spawns on session_start.
2026-07-25chore: update 0.10.0 release dateamankumarsingh77
2026-07-25feat: pin the agent to a chosen browser profile (#16)Aman Kumar
* feat: pin the agent to a chosen browser profile (#15) Harness tabs were created with a bare Target.createTarget, which places them in Chrome's defaultBrowserContextId — and that value follows window focus. Which profile the agent acted as therefore depended on which browser window the user last clicked, so the same task could run as a work account on one run and a personal account on the next. /browser-profile lists the connected browser's profiles as "Name (email)" and pins one to ~/.pi/agent/browser-harness.json, so the choice outlives the session. The same picker appears on first browser_setup when nothing is pinned; with no interactive UI, or on cancel, setup continues with a note and the previous behavior. Chrome offers no direct route to another profile: Target.createTarget rejects a foreign browserContextId, and openerId does not inherit the opener's context. The window is opened through the browser's own command line (--profile-directory, handed to the running browser by Chromium's ProcessSingleton) and identified by a unique file:// sentinel page, since a bare about:blank#token argument is discarded. Further tabs come from window.open evaluated with userGesture: true — the only CDP-reachable way to place a tab in a non-default browser context — correlated by a unique token so concurrent isolated tabs stay distinct. A failed handshake is reported, never silently redirected to another profile. All four tab-creation sites now funnel through cdp/target-factory, so open_urls and the isolated tabs behind web_search / read_page cannot run with a different profile's cookies than the visible tabs. Also fixed along the way: snap Chromium is discovered, Windows uses %LOCALAPPDATA%, browsers launched with an explicit --user-data-dir are found, the running browser is chosen by ranking candidates against the connected user-data-dir rather than taking the first process found, and an installed-but-closed browser no longer reads as running. CI runs the profile suites and a real-browser end-to-end test on ubuntu, macOS, and Windows — profile discovery is the one part of the harness whose behavior genuinely differs per OS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: single-flight harness window creation Isolated tabs run concurrently (browser_read_page is registered unserialized), so several could each find "no harness window" and create one — two blank windows before this feature, two LAUNCHED profile windows after it. ensureHarnessWindow now shares one in-flight creation per client. Sharing introduces a second hazard: freshlyCreated is a claim on the seed tab, and if every waiter received it, they would all drive the same tab. Only the caller that started the creation keeps the claim; the rest open their own tab beside it. Covered by test/manual/profile-concurrency-test.ts (five concurrent isolated tabs, pinned and unpinned: distinct targets, one window, correct profile), wired into CI on Linux only — the coordination is pure JS and identical across platforms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: tilde expansion differs by purpose on Windows CI on windows-latest caught this: join("~", "x") yields "~\x" there, and expandTilde only handled "~/". The two uses are not the same, so they no longer share a helper. The agent dir stays byte-compatible with pi's own expandTildePath ("~/" only, every platform) — being more lenient would put the pin file somewhere pi never looks. $CHROME_USER_DATA_DIR is ours to interpret, so it accepts "~\" as well, which is what a Windows user would type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24docs: add 0.8.3 and 0.9.0 changelog entriesamankumarsingh77
The changelog stopped at 0.8.1 while npm was on 0.8.3 and main had already bumped to 0.9.0. Backfills the 0.8.3 stale-socket fix and documents the 0.9.0 cycle: web_search / read_page / deep-research, the forms domain and durable window binding, the Windows daemon fix (#7), Brave + channel support and stale DevToolsActivePort discovery (#4), and the removed footer status chip (#10). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05fix: make dispatch_key fire legacy keyCode handlers and tighten execute_js ↵Aman Kumar
IIFE wrap (#9) - browser_dispatch_key now sets keyCode/which on the synthesized KeyboardEvent (both ref and selector paths) so handlers checking e.keyCode === 13 fire. - browser_execute_js IIFE auto-wrap triggers only when the source starts with a return statement, not on any substring "return " (which silently produced undefined for bare expressions). - browser_fill guidelines point at dispatch_key for tag-input submission and the snapshot+click recipe for custom dropdowns. Bump to 0.8.1. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21release: v0.6.0 — per-tab isolation, Unix socket daemon, on-demand init (#6)Aman Kumar
* feat: Unix socket daemon with auto-reconnect for persistent Chrome CDP Eliminates the 'Allow Remote Debugging' Chrome prompt that appeared on every pi session by multiplexing pi instances through a single persistent daemon process. Key additions: - Unix socket IPC (net.createServer + readline JSON framing) - CdpBridge with ID multiplexer + event router - DaemonTransport implementing CdpTransport interface - Auto-spawn with ensureDaemon() (lazy, checks socket) Fixes since initial implementation: - Bridge auto-reconnects to Chrome with exponential backoff (1s-60s). Previously the bridge tried once at startup and permanently failed if Chrome wasn't ready — causing 'Chrome not connected' on every browser tool call. - Daemon spawn uses project-local tsx binary instead of global --import flag, fixing silent spawn failure (ERR_MODULE_NOT_FOUND). - Stale ctx crash: persistState in onOwnershipChange wrapped in try/catch to prevent CDP event consumer crashes. 49 test assertions across 4 test files. Zero TypeScript errors. * feat: on-demand browser initialization Browser daemon no longer auto-starts on session_start. Instead: - session_start creates the client lazily but does NOT connect or spawn the daemon. Zero Chrome prompts for non-browser pi sessions. - Browser tool wrapper checks for daemon socket before each call. Socket missing → clear error: 'Run /browser-setup first'. Socket exists → proceeds silently (daemon already running). - /browser-setup is the explicit, one-time init point. It spawns the daemon and connects to Chrome only when the user opts in. - SKILL.md updated with Connection Setup instructions telling agents to direct users to /browser-setup when socket is missing. * fix: checkChromeRunning on macOS — match by substring not exact ps -A -o comm= returns full executable paths on modern macOS (e.g. /Applications/Google Chrome.app/Contents/MacOS/Google Chrome), not the basename. The old exact-match check (browserProcesses.includes(l)) never matched, causing false 'No browser instance running' errors. Changed to substring includes() with helper/renderer/crashpad filtering. * feat: browser_setup as agent-callable tool The agent can now self-recover from 'Browser harness not initialized' errors by calling browser_setup directly — no user mediation needed. - Extracted shared performSetup() from the slash command into setup.ts - Created src/domains/setup.ts with ensureAlive:false to bypass the socket guard (this tool IS the setup, can't require itself) - Registered browser_setup in the tool registry - Updated SKILL.md: agent calls browser_setup directly, not ask user - Removed stale test/manual/spawn-test.ts * release: v0.6.0 — per-tab isolation, Unix socket daemon, on-demand init
2026-05-07release: v0.5.0 — browser_console tool for JS error/console diagnosticsamankumarsingh77
2026-05-06release: v0.4.0 — accessibility snapshot, network capture, snapshot-first ↵amankumarsingh77
prompts Adds two new tools and pivots the agent's default workflow away from screenshots toward structured page data. browser_snapshot — CDP accessibility tree (roles, names, states, hierarchy) with click coordinates @(x,y) attached to every interactive element via DOM.getBoxModel (parallel, 1.5s aggregate budget). Pass directly to browser_click — no screenshot round-trip. Optional includeScreenshot:true for visual confirmation. format:"json" returns a slim structure with full box per node. browser_network_requests — replaces the deprecated browser_get_network_log placeholder. Filters by urlPattern (substring or /regex/), method, status, resource type, recency. Optional response-body capture under a 5s aggregate budget with 50KB per-body cap. Buffer is page-scoped (cleared on tab switch), 500 records/tab, with a bufferOverflowed flag on drain. CDP plumbing: in-process aggregator in src/cdp/network-buffer.ts wired into the existing single-consumer event loop. Accessibility domain enabled alongside Page/DOM/Runtime/Network on every attach. Ctrl+O expand/collapse on three tools' renderResult — browser_snapshot, browser_network_requests, browser_execute_js. Compact-by-default views with keyHint("app.tools.expand") that respects user keybinding remaps. Tool prompts pivoted snapshot-first: browser_screenshot is documented as LAST RESORT for visual verification only; browser_snapshot is the default for understanding pages; browser_execute_js is the default for surgical reads. browser_click and browser_open_urls guidance follows. SKILL.md collapsed from ~342 to ~53 lines — keeping only what isn't already in tool prompts: the decision tree, connection rules, browser_run_script daemon bindings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05release: v0.3.2 — parallel tool execution, scroll fixes, TUI crash fixamankumarsingh77
- Add async mutex for auto-serialization of mutation tools - Observation tools can run in parallel with mutations - Fix scroll deltaY sign convention (positive=down per W3C) - Add Page.bringToFront before scroll to prevent silent drops - Fix screenshot TUI crash on long file paths (truncateToWidth)
2026-05-02release: v0.3.1 — audit fixes for list_tabs IDs, switch_tab prefix ↵amankumarsingh77
matching, download auto-mkdir, session recovery, docs updates Bug fixes: - list_tabs: show full 32-char targetIds (was truncated to 8 chars) - switch_tab: prefix matching fallback for hex prefixes >= 8 chars - download: auto-create directory with mkdir -p - ensureAlive: Runtime.evaluate probe to recover from crashed page targets Docs: - dispatch_key: clarify DOM-only event behavior - navigate: warn about Google anti-bot limitation - network_log: update deprecated promptSnippet - SKILL.md: document actual daemon API (evaluateJs, pageInfo, session.call) - SKILL.md: add troubleshooting for sharp/maxDim and Google navigation - sharp: add to optionalDependencies for screenshot maxDim auto-resize
2026-05-02chore: address final-review minors — surface event-consumer crashes, ↵amankumarsingh77
document IIFE-wrap heuristic, log shutdown failures, fix CHANGELOG file-size claim Five tweaks from the whole-implementation review: - session.ts: log unexpected event-consumer rejections instead of silent swallow - client.ts: comment the return-substring IIFE-wrap false-positive case - transport.ts: comment that ws.onclose post-open settle is no-op-by-design - index.ts: log client.stop() failures during shutdown - CHANGELOG.md: correct largest-file claim (transport.ts and client.ts are ~220 each, not "client.ts at ~180") Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02chore(release): v0.3.0 — internal rewriteamankumarsingh77
2026-05-02perf: v0.2.0 — event-based waitForLoad, fast ensureAlive, JPEG ↵amankumarsingh77
screenshots, page info caching 5 performance optimizations (14-36% faster end-to-end, output quality unchanged): - fast ensureAlive(): WS state check instead of CDP roundtrip (96% faster per-call) - event-based waitForLoad(): CDP load events instead of 300ms polling (99.5% faster for loaded tabs) - JPEG screenshot support: 29-49% smaller files, faster CDP transfer - page info caching: 1s TTL eliminates redundant evaluateJS calls - parallel domain enables: Promise.all instead of sequential await in switchTab() Benchmark: 3622ms vs 4243ms baseline on 3-tab navigation + screenshot task.
2026-05-02chore: prepare v0.1.0 releaseamankumarsingh77
- Add hero image for pi package gallery - Update CHANGELOG with release date - Update README with npm install instructions - Add assets/ to npm package files - Add CONTRIBUTING.md and GitHub templates - Add CI workflow for typecheck and pack validation
2026-04-29Initial release: pi-browser-harnessamankumarsingh77
Browser control extension for pi — 20 browser_* tools for navigating, clicking, typing, screenshotting, and extracting data from real Chrome via CDP. Includes self-extending harness (register_tool/remove_tool), guided /browser-setup, session persistence, and custom TUI renderers.