v0.4.1 — cross-session state, recording lifecycle, and batch-selection fixes
pi-agent-browser-native 0.4.1 isolates managed browser restore state per Pi transcript and hardens QA, artifact, recording, and session lifecycle behavior found during parallel real-browser dogfood.
Highlights
- Scopes upstream restore keys to both checkout generation and the full hashed Pi transcript. Concurrent chats no longer overwrite or inherit each other’s cookies or storage, while one transcript keeps continuity across fresh rotation, reload, restart, and
/resume. - Makes URL QA trustworthy by clearing diagnostics, sampling post-clear page-error residue, and waiting briefly for immediate post-load errors.
- Keeps a successful nested close terminal through later explicitly non-launching diagnostics, while failed/unknown post-close rows remain tracked unless lifecycle proves no relaunch; namespace-scoped
close --allexclusively drains matching work and clears every managed/attached/page/ref/route/trace/recording owner. - Rejects stale/future artifacts and missing/stale restart recordings. A transcript-backed namespace/session reservation index serializes explicit artifact destinations, follows lexical/symlink/hardlink/full-Unicode/platform-case aliases, mirrors upstream global cleanup, screenshot positional rules, wait precedence, final diff output, and HAR-stop paths, prevents same-call
outputPathand Electron-cleanup ordering bypasses, rejects recording starts after nested close, persists close tombstones, and reconciles direct, batch, failed-stop, script, Electron, replacement, and shutdown transitions across live state and replay. - Preserves exact
stop-pending-recordingrecovery with visible guidance when any later same-session call fails during an active recording. Same-millisecond lifecycle order survives inner and concurrent outer manifest merges, replay, and a one-entry recent window. - Prevents namespace-wide
close --allfrom deadlocking against a late same-session arrival while retaining exclusive cleanup ordering. - Warns that upstream
record startswitches to a fresh active page whose prior DOM and JavaScript state does not carry over, then tells agents to take a fresh snapshot; the wrapper also invalidates the session's prior page-scoped@e…refs (direct calls and batch steps) with a persistedpage-transitioninvalidation, so stale refs fail asstale-refuntil a fresh snapshot succeeds and batch stdin cannot reuse old refs after arecord startstep. Invalidation is attempt-scoped — upstream swaps the page before its already-active check, so a failedrecord startstill invalidates — andrecord restartwith a URL operand invalidates the same way while a plain restart keeps the page and refs. Upstream ref-resolving reads and captures (is,screenshot,highlight,scroll,frame,diff) now pass the same stale-ref guards as mutations, while literal@e…-looking operands (wait --text @e1,find text @e1 click, values of value-taking flags such as--baseline) pass through unguarded and refs after boolean flags (click --new-tab @e1,screenshot --full @e1) stay guarded; a batch that times out or returns unparseable output after executing still records the recording page-swap invalidation from its planned steps (raw batch arguments exclusively when present, stdin only otherwise, matching upstream); the stale-ref preflight and intra-batch latch scan that same upstream-exclusive step source, so raw argument-mode batches (batch "click @e1") are guarded after a recording page swap and stdin refs are not falsely rejected when raw arguments exist, and the managed-restore docs state the fail-closed truth that a checkout rename or different working directory starts a fresh restore key. Tab-pinned batch rewrites dispatch those same upstream-effective steps (never resurrecting ignored caller stdin), artifact/recording preflight and batch screenshot preparation skip upstream-ignored stdin rows, and raw-argument filtering matches upstream's exact--bailtoken so--bail=truestays a raw command. Pinned rewrites re-emit the caller's exact--bailso fail-fast batches stay fail-fast under tab pinning, and parent directories are prepared for effective raw artifact rows without rewriting raw strings. - Improves semantic select, same-page batch ref handling, no-op scroll truthfulness, Windows argv behavior, Unix socket diagnostics, passive-config isolation, exact upstream version checks, and namespaced Electron probe/cleanup replay.
- Includes the reload compatibility fix from @coreyallen in #96 and the packaged build-script fix from @selimerunkut in #100 with credit.
Validation
The exact PR head d6cde09af8d7757bbfba5a4ffaf83381bb392683 passed:
npm run verify -- pre-pr: 765 tests passed, two opt-in tests skipped, 130 packed filesnpm run verify -- real-upstream: 2/2, including same-transcript continuity, distinct-transcript isolation, passive-config precedence, and pre-spawn nested close/record rejection- deterministic real-browser dogfood, packaged Pi smoke, and startup profiling (62.3 ms median, 68.6 ms maximum, below the 250 ms budget)
- rebuilt-checkout remediation smoke: open/snapshot passed; duplicate sentinel screenshot, extra-positional screenshot reuse, and reordered/repeated-timeout wait reuse failed in preflight;
record stopverified a 49,775-byte WebM before clean close - exact-head fresh-process recording smoke: controlled tab evidence proved
record startswitches from t1 withCount: 1to a new active t2 withCount: 0; the final build made that context reset and fresh-snapshot instruction visible, then saved a verified 44,661-byte WebM and closed cleanly - exact-head recording page-swap matrix smoke (final head): failed already-active
record startstill invalidated old refs, plainrecord restartpreserved them, URL-bearingrecord restartinvalidated them, recovery snapshots restored refs, and all recordings saved before a clean close - exact-head stale-ref invalidation smoke: after
record start, a click on the pre-recording@e1failed pre-spawn asstale-refwith the exact page-transition message, a freshsnapshot -irestored refs, the fresh-ref click succeeded, andrecord stopsaved a verified 72,078-byte WebM before a clean close - exact-head Electron smoke: wrapper-owned isolated Linear launch, status, probe, explicit-session title read, cleanup, and dead/not-attached tombstone status all passed; an already-running Claude singleton failed safely with precise diagnostics and no residue
- exact-head nested lifecycle regression smoke:
record start → wait → close → record stopsucceeded in one native batch, produced one verified 15,406-byte WebM with no abandoned duplicate, kept the same managed session active, returned expectedabout:blankwithout stale pre-close mismatch guidance, then closed cleanly - prior-candidate as-shipped Pi git-source install at its immutable SHA plus an exact-clone, direct-OpenAI agent sweep: open/snapshot/interact, verified 16,882-byte screenshot, 2,621-byte HAR, and 29-byte download artifacts, profile and doctor diagnostics, validation/stale-ref/selector recovery, recording-reservation replay through
/reloadwith a verified 440,642-byte WebM stop, terminal[["close"],["stream","status"]]lifecycle and session rotation, and clean session shutdown all passed - Ubuntu Crabbox
platform-buildandbrowser-dogfood-smokefrom the release branch; the second suite reused the first suite’s dependency install
A Cloudflare AI Gateway attempt exposed upstream Pi issue #7896, where omitted strict: false made every optional tool-schema field required; direct OpenAI on the same checkout/prompt passed, so this is external and non-blocking. The configured-source lifecycle harness remained environment-blocked by missing model credentials in its isolated Pi home. The full platform doctor remained blocked by macOS SSH setup and unavailable Parallels prlctl; Ubuntu passed. These are setup blocks, not skips.
Full details: PR #108, CHANGELOG.md, and the v0.4.0...v0.4.1 comparison.
This is a GitHub release only. The npm package was not published from this machine.