Merge the 0.3.2 release and keep the background-input fix under Unreleased.
Isolate idle-exit tests from release checks and automatic daemon replacement. Wait for the first remote connection to complete its native handshake before testing replacement at capacity; the replacement connection still exercises the pre-handshake case.
Keep both Unreleased changelog notes: extension reconnect call settling from main and the Windows in-place update entries from this branch.
Co-authored-by: Cursor <cursoragent@cursor.com>
Calls that fail because the extension's socket closed now carry
`reason: extension_disconnected`, so the CLI no longer tells the user to
check protocol versions. Native input keeps its unknown-outcome reason.
Co-authored-by: Cursor <cursoragent@cursor.com>
Terminate a socket's pending calls when it is replaced or closed, and register
and send under the same lock so no call can reach an abandoned socket. A call
that was already dispatched keeps its unknown-outcome contract in every wait
stage, including tab borrow. Session start is no longer retried.
Only mark heartbeat-capable extensions unresponsive, after two missed
heartbeats, and never let the mark replace a cleanup failure.
The handshake pong grace moves to a separate change.
Co-authored-by: Cursor <cursoragent@cursor.com>
The lifecycle host stopped every process started from the system TEMP
after a suite timed out, which could hit unrelated programs. Each suite
now gets its own TEMP, and only processes running from it are stopped.
Copies of bsk are removed from it afterwards so the artifact keeps logs.
Compile the `locked` test helper only where its tests run, which removes
a Windows dead-code warning.
- The daemon owns its update in one slot that its blocking steps fill
themselves. Shutdown aborts the async task but waits for those steps,
then hands the update over or undoes it, so a daemon that goes idle
while the release downloads or is checked no longer leaves the new
executable installed without a way back. A download that finishes after
shutdown began installs nothing.
- `bsk update` checks that it can start an independent daemon before
stopping a background one. Inside a Windows Job that forbids breakaway
it leaves that daemon running (`left_running`) instead of stopping a
service it could not start again.
- The installation takes the update lock and keeps it until it is
confirmed or rolled back; the flaky lock-free concurrency test is
replaced by one that takes turns through the lock.
- The Windows lifecycle host gives each suite 480 seconds, keeps its output
after a timeout, and stops daemons the suite started from test copies.
After a failed handover the previous daemon served again with its
original configuration, so a daemon started with `--port 0` was given a
new port and browsers could no longer reconnect. It now resumes on the
port it served before the handover.
- `bsk update` restarts the daemon as a process it owns. One that is not
ready in time is stopped and reaped before the previous version is
restarted, so the rollback no longer meets it holding the daemon lock.
- A handover or restart succeeds only when a daemon of the release's
version serves the original port. `--version` must print that version.
- A failed handover records a serving daemon only once the resumed one has
published daemon.json, and appends the error if it cannot serve again.
- A daemon keeps the executable path it started from, so it can update
again after a rollback on Linux, where `current_exe` then names a
deleted file.
- The update lock sits next to the installed executable, so updates from
different bsk homes are serialized through installation and rollback.
`bsk update` stopped any running daemon and started a background one in
its place. For a `--foreground` daemon that took it away from its
terminal or supervisor, and inside a host that forbids Job breakaway it
left no daemon at all.
The daemon now records in daemon.json whether its owner manages it.
`bsk update` installs the release but leaves such a daemon running and
says to restart it there; the CLI hint and `bsk doctor` give the same
steps. A background daemon is restarted on the port it served.
The outgoing daemon releases its lock, IPC endpoint and port but stays
alive until a daemon started from the new executable answers. If that
daemon exits or is not ready within 20 seconds, it puts the previous
executable back and serves again on the same port.
- Keep the previous executable on every platform until the update is
confirmed, and run the new one once before relying on it.
- Record each attempt's stage, result, error and recovery in
update-state.json, show it in `bsk doctor`, and retry a failed
version after 6 hours.
- Serialize update attempts with an update lock.
- Report new releases instead of installing them when bsk cannot write
next to its executable.
- `bsk update` installs before stopping the daemon and rolls back if the
restarted daemon does not become ready.
The expanded header already replaced a stale "s1 · clicking" line with
"reconnecting…", but the collapsed capsule and both status dots still
read the last session as live. Collapse is the form users leave on the
page, so an outage there looked like an in-progress action.
- treat reconnecting as its own chrome state so the header and capsule
dots leave the active color
- keep the capsule's session count and swap the action timer for
"reconnecting…" until the feed delivers a frame again
Rename the running executable aside instead of handing replacement to a
detached script, and exit only after the new daemon has started. A
foreground daemon reports the release and leaves the restart to its owner.
Document BSK_AUTO_UPDATE=off.
Co-authored-by: Sthreal <2066885216@qq.com>
`subscribed` is derived from whether an EventSource object exists, so it
stays true for the whole outage: the failed stream is still held until the
rebuilt one replaces it. The "connecting…" states therefore never showed
during a real failure, while the floating card, now gated on `subscribed`,
was committed for one frame with "connection lost — retrying" on every
page load that had no sessions.
- add `reconnecting` to the snapshot: set on any stream error, including
transient drops the browser retries itself, and cleared by the next
well-formed frame on the current stream
- show "reconnecting…" in the overlay and sidebar header while it is set,
in place of the last session status that could no longer be trusted
- keep the floating card hidden without sessions, as before this change
- cancel a pending reconnect whenever the stream is rebuilt, so a
thumbnail switch during the backoff is not torn down by the stale timer
- drop the extra publish per stream rebuild that only served `subscribed`
A late `bsk record stop` for an earlier recording could delete the state
of a recording that started after it, leaving the newer recording
impossible to stop from the terminal. The end of `bsk record start` and a
successful `bsk record stop` had the same unconditional cleanup, and two
concurrent starts could both pass the existence check.
Guard the state file with a lock and only remove it while it still names
the session being cleaned up.
Refs #342
If the foreground `bsk record start` process is killed and its session
later disappears, record-session.json keeps pointing at the dead session.
`bsk record stop` then fails with not_found and `bsk record start` refuses
to run until the file is removed by hand.
When record_stop reports not_found, drop the stale state and say so, so
`bsk record stop` is the recovery path its own error message promises.
Refs #342
Opening a blob: URL in a new tab during a recording (for example a PDF
preview built with URL.createObjectURL) made that tab the current
recording tab. The overlay content script is never injected into blob:
documents, so the required RECORD_STOP acknowledgement could not arrive
and every `bsk record stop` failed, losing the whole recording.
Captured steps have been flushed by the frame coordinator since iframe
support moved capture into frame agents; RECORD_STOP only clears the
record overlay. Treat it as best-effort cleanup for every tab and keep
the frame coordinator as the flush barrier. Flush failures now carry
their reason into the record_stop error instead of a bare message.
Refs #342
A target="_blank" attachment link downloads from a transient new tab, so
the clicked target never receives Page.downloadWillBegin and bsk download
timed out. Instead of matching the anchor href against every browser
download, accept the URL of a webNavigation navigation target whose source
is the clicked tab and that appears after the mouse press, and match it only
against download candidates observed after the press.
The dispatch point reuses clickResolvedTarget's existing markSent hook, so
the click pipeline and the exact-target CDP path keep their behavior.
Separate snapshot decoding from optional geometry so DOM, AX, form state and
identity checks finish before measuring the root viewport. Retain captured
content with explicit geometry gaps after that measurement times out, without
issuing projection or hover reads behind the gate. Keep post-layout identity
validation on successful reads and reject attachment changes and cancellation.
Clarify that navigation does not reset pending reads. Preserve the existing
RPC reason while exposing the command, deadline/blocked phase and process.
Validation: 2200 extension tests passed (108 skipped); 126 focused regression
tests, TypeScript, changed-file Biome checks and production build passed.
Fail in-flight calls when a browser generation is replaced, mark a silent heartbeat interval as unresponsive without dropping the socket, and allow one handshake grace after a pong.
Keep timed-out commands gated until Chrome settles them, including auto-attach configuration. Scope frame-tree deadlines to observation so navigation retains its caller budget, and give snapshot/AX captures a separate deadline.
Omit known unavailable iframe subtrees without rerouting them to the root session. Preserve viewing-only screenshots after post-capture identity verification when optional geometry times out.
Validation: 2191 extension tests passed (108 skipped); TypeScript, changed-file Biome checks, and production extension build passed.
Reset preserved popup overlays after session teardown and hide them when observed control is released on tab detachment. Keep overlay notifications best-effort so unresponsive pages cannot delay cleanup.
Cover local and remote stop, disconnect cleanup, tab activation ordering, unavailable content scripts, and unaffected tabs.
Browser preview checks exposed clipped German action labels in the collapsed help panel. Place collapsed actions on their own row and allow long labels to wrap within the panel, keeping return-control and cancel actions readable.
Follow up on iAstro's locale implementation with the four profile instruction keys added on main. Preserve per-session instance selection, exact CLI and tool calls, and reconnect guidance in every translation.
Document automatic registration and Chinese fallback behavior, exercise copied commands in all shipped locales, shorten the Portuguese update badge, and polish the German note prompt.
Keep prerequisite discovery in the canonical skill entry and move CLI setup and extension recovery guidance into the environment reference. Preserve the reference bundle layout and the original PR commits.
Carry header truncation through queued events, preserve large bodies during header-only edits, and reserve task/global capture capacity before yielding. Merge live evidence when storage indexes are stale, preserve Document rule scope, and expose incomplete field scans without claiming unique matches.
Add regression coverage and run all debugging browser suites in CI.
Preserve skill resource bundling and profile-bound workflows from main. Move CLI and DSH debugging guidance into dedicated references with explicit capture triggers, evidence handling, and network experiment boundaries.
Interrupting a command after exit could truncate its JSON and report a
parse failure. Output arriving during the drain could also extend the wait
past the execution timeout and turn a completed command into a timeout.
Only interrupt still-running children and count those matches in killFor.
Keep exited children draining, stop the execution timer on exit, and retain
the existing idle drain window and 2-second cap. An explicit AbortSignal
still cancels the caller's wait immediately during drain.
Clarify the execution timeout and separate output collection limit in the
runner options, plugin configuration and README. Preserve the existing
platform-specific cancellation grace, kill fallback and resource cleanup.
Validation: 10 regression checks failed before the fix and now pass; all
351 DSH plugin tests in 19 files pass, including real-process inherited-pipe
cleanup. Biome, Stylelint, TypeScript and git diff --check also pass.
Windows cancellation cases use simulated platforms on macOS.
Preserve the contributor's original commits and bounded settlement, pipe
cleanup, renewable output drain, and killAll/killFor fallback paths.
Reconcile the overlapping main runner fix by retaining its 1s drain grace,
referenced drain timers, cancellation timer cleanup, and listener ordering.
Keep the PR's 2s total drain cap and platform-specific kill deadlines.
Adapt the affected runner tests to the retained grace and update the
session-start regression fixture for main's prepare/start/claim lifecycle.
No unrelated feature changes.
Validation: all 345 DSH plugin tests across 19 files pass, including the
real-process inherited-pipe regression; Biome, Stylelint, TypeScript and
git diff --check pass. Windows cancellation is covered by simulated-platform
tests; no Windows host was used.
Isolate harness path tests from host environment settings and verify Windows defaults. Cover real historical LF/CRLF fixtures, custom intent, local edits, reference collisions, and exact checksum baselines.
Condense the DSH guidance while preserving its authorization boundary and recovery behavior. Keep the existing 7000-character limit after combining the PR with main's recovery instructions.
Retain successful invocation proof after failures and defer retries to turn/session boundaries or new skill invocations. Add regression coverage for sustained streaming and next-turn recovery.
Parse current durable tool results and support both session history APIs. Scan each session once, process later events incrementally, and retry recovery when services or history become available.
Cover official DSH messages, reloads, long conversations, failed reads, and explicit history access counts.
Share optional stop target parameters between browser_session and its internal
stop handler. Document exact request targeting, mutual exclusion, and default
stop retry behavior in the model-visible contract.
Add a public schema regression covering requestId, optional targets, and retry
guidance. Lifecycle execution remains unchanged.
Validation: 95 tool and stop recovery tests passed; TypeScript and formatting
checks passed. The new schema test reproduced the omission before the fix.
Route tool, overlay, archive, unload, and recovery cleanup through one lifecycle
owner and one job per request. Persist explicit stop intent before making a
session unusable; caller cancellation only ends its wait after admission.
Retain durable completion receipts independently of the current session so a
retry cannot stop another working session, even after background cleanup or
restart. Preserve failed default callers' retries across concurrent successful
waiters. Support exact request targeting and reject ambiguous stop targets.
Cover failed normal stops, queued and in-flight cancellation, concurrent entry
points, timer and disk recovery, persistence failures, anonymous starts, reused
IDs, unconfirmed replies, and completion receipt capacity accounting.
Validation: 303 plugin tests passed, including 31 stop recovery tests;
TypeScript checking, production build, and formatting passed.
Package lint was unavailable because publint is not installed in this environment.
Capture initial tab identities when creating an Agent Window and retain them
through failed startup compensation. Retry cleanup through the production
stop handler, preserving later user tabs and keeping ownership if agent tabs
still cannot close.
Separate owned starting and cleanup resources from active sessions. Publish
sessions only after initialization and claim succeed, preserve the working
current session on failure, and reject ordinary operations and captures for
resources awaiting cleanup. Recheck queued operations before execution.
Add regression coverage for production stop retries, mixed windows, delayed
claims, current-session fallback, recovery, capacity, and queued operations.
Update window API fixtures for the creation result's initial tab identities.
Validation: extension 1862 passed (103 skipped), plugin 276 passed; both
TypeScript checks and production builds passed.
Track prepared starts with stable request handles, durable plugin ownership, monotonic cancellation, and retryable cleanup. Retain delayed and failed startup resources until cleanup is confirmed, without touching other sessions.
Add regression coverage for lost replies, killed CLI processes, delayed creation, failed cleanup, restart recovery, archive and unload, capacity accounting, and reused session IDs.
Fixes#245
Preserve the streamlined skill workflow and document background support for both viewport and full-page screenshots. Keep Canvas capture guidance and remove the outdated visibility requirement for Agent full-page capture.
Add bounded request details, action evidence and before/after verification through CLI, DSH and an extension workspace. Preserve existing popup controls and add a current-task card.
Validation: Rust 710, extension 1770, DSH 242, i18n 52; typecheck, lint, production build and two real Chrome regressions passed.