- `bsk session start --width <px> --height <px>` opens the Agent Window
with the given outer size (chrome.windows.create)
- new `bsk window resize --session <id> --width <px> --height <px>`
resizes the Agent Window at runtime (chrome.windows.update)
- both validated on CLI, daemon and extension sides (100..=7680 CSS px)
- protocol: new tool.window_resize method (BrowserMutation) and
optional width/height on tool.session_start params; schemas regenerated
`bsk install-skill --all` installed the bundled skill into every supported harness directory (detected or not), creating junk paths like ~/.claude/skills on machines without those harnesses. --all now targets detected harnesses only and errors with guidance when none are found; --harness remains the explicit override. The --yes non-interactive branch shares the same detected-only logic.
* feat(request-help): add BSK_REQUEST_HELP=off to disable blocking help requests
* style(extension): format HelpOutcome union per biome
* docs(skill): condense BSK_REQUEST_HELP section
Add a popup launcher + action-recording panel that builds a copyable
`bsk record start` prompt, add `--browser` targeting, and default `--url`
to https://example.com/ when omitted. Drop the popup browser-alias field.
Move the reaper's silence timeout and scan cadence into DaemonConfig
(defaulting to the existing 60s/15s constants) with a
`with_browser_liveness` builder, so tests can drive the task in
sub-second windows.
Add an integration test that runs a real daemon and asserts a silent
heartbeat-capable browser — and its sessions — get reaped, while a
legacy browser that never heartbeated is left untouched.
Co-authored-by: Cursor <cursoragent@cursor.com>
Only reap browsers that have sent at least one `system.heartbeat`.
A pre-heartbeat extension never opts in, so it is never dropped on
silence and keeps relying on socket-close detection exactly as before.
This removes a backward-compat regression where a new daemon paired
with an old extension would wrongly reap a live-but-idle connection
and then report `no_browser_connected` on the next command.
- Add a `heartbeat_seen` flag to `BrowserClient`, set when a heartbeat
event arrives, and exclude never-heartbeated clients from
`stale_browsers`.
- Cover both the opt-in and the legacy-survivor cases in unit tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
After a long idle the service worker is only revived on its next
keepalive-alarm tick (up to 30s away), so the previous 5s wait made
the first command after idle fail with `no_browser_connected` even
though the extension was about to reconnect.
- Raise the daemon's `EXTENSION_CONNECT_WAIT` (used by `session.start`)
to 35s so it comfortably covers one alarm period plus handshake slack.
- Bump the CLI `session start` IPC timeout to that window plus slack so
it never gives up before the daemon answers, and print a one-line
"waiting for browser extension to connect…" hint when it actually
waits.
- Keep `bsk status` / `browsers` on their own short 5s wait so quick
informational commands are not slowed down.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce a `system.heartbeat` protocol event and use it as a
liveness signal on the daemon side.
- Track `last_seen` per connected browser, bumped on every inbound
WS frame (tool response, event, ping/pong, or heartbeat).
- Add a reaper task that drops any browser silent past a 60s window
and purges its sessions, mirroring the WS disconnect cleanup. This
releases half-open connections left behind when the OS resumes from
sleep and kills the service worker without delivering a close frame,
so the daemon no longer pins a phantom "connected" browser and can
idle-exit normally.
- Wire the reaper into both the foreground daemon and the test/embed
entry point, aborting it on shutdown.
Co-authored-by: Cursor <cursoragent@cursor.com>
Capture user actions in the Agent Window and export a record-only
trace (pages[] + navigate/click/fill/select/press steps with target
descriptors). Adds the record overlay UI aligned with the control
overlay, and wires record start/stop/await through CLI, daemon,
protocol, and extension.
Add `bsk network` as a sibling of the `console` command from #7,
reading the buffered network responses / failures for a tab. Fills the
remaining half of the request in #2 (console landed in #7; network did
not).
Mirrors the console command's conventions exactly:
bsk network --session <id> [--tab-id N] [--since C]
[--limit N] [--max-text-chars N]
The extension enables `Network` on attach (best-effort) and buffers
`responseReceived` / `loadingFailed` events per tab with a monotonic
sequence, correlating them to `requestWillBeSent` for method/URL. Reads
are cursor-paginated (`since` -> `next_since`) and bounded (`limit`,
`max_text_chars`) for agent-context safety, same as console. Entries
carry the real HTTP status code (response) or the CDP failure reason
(failure) — things `performance.getEntriesByType('resource')` can't
give.
Classified read-only (pass-through under the pending-interrupt gate);
defaults to the Agent Window's active tab.
Wires bsk-protocol (Method + params/result/entry structs + schema),
bsk-cli (network subcommand + daemon dispatch allow-list) and the
extension (handler + dispatcher route), with unit / parse / IPC tests
paralleling the console command.
Refs #2.
The daemon dispatched inbound `session.window_closed` and
`session.user_interrupt` events using only the payload — the sending
browser's identity was never checked against the session's owner.
Any connected extension could therefore emit window_closed with
another browser's session_id to tear down its session (forgetting it,
dropping its tool queue + interrupt marker), or emit user_interrupt
to cancel every inflight tool of another browser's session and arm
its interrupt marker. This is a cross-tenant integrity/DoS hole that
is exploitable even between two legitimate extensions, independent of
the (separately tracked) WS Origin allow-list gap.
Thread the sender's BrowserId (already in scope as `client.id` in
handle_inbound_text) into both handlers and ignore the event when the
named session is live and owned by a different browser. A session
that is already gone is left to the existing no-op forget path.
Adds four ownership tests (owner honoured / non-owner ignored for each
event); updated two existing tests for the new signature. Full bsk
suite green (165 lib + integration), no new clippy warnings.
Co-Authored-By: Claude <noreply@anthropic.com>