SessionManager.classifyNewTab's `initializing` branch relied on a
windowInitializing flag that start() cleared *before* the home tab's
chrome.tabs.onCreated event was dispatched (the event is asynchronous), so
the branch never ran in production and the home tab's classification was
subject to a timing race. Match the home tab by its tab id instead — the id
is already returned by ensureActiveTab and is reliable regardless of event
ordering.
Also refresh the overlay-bridge docstring: overlay.ready now makes the
background *push* the per-tab overlay state (and the Agent Window also
pushes on tab create / control-mode change), rather than a request/reply.
tool.tab_create increments pendingAgentTabCount *before* chrome.tabs.create
so the onCreated listener can tell an agent tab from a user-opened tab. When
the create failed, no onCreated event arrived and the counter leaked, so the
next tab the user opened was misclassified as agent-created — the exact
confusion the counter exists to prevent, a variant of issue #57.
handleTabCreate now releases the slot on failure via
SessionManager.releaseAgentTabPending. An abort (cancelled) is excluded: the
tab did open (and was cleaned up), so its onCreated still consumes the slot.
Added a regression test asserting that after a failed tab_create, a
user-opened tab is still classified as 'user' (not 'agent').
- session_stop: exclude tabs still tracked in agentCreatedTabs from the
release decision so a tab that failed to close is no longer mistaken for
a user tab (which previously kept the window open and leaked the tab).
- Distinguish user-created tabs from agent-created tabs in the Agent Window
via a pending-tab counter consumed by chrome.tabs.onCreated, so tabs the
user opens themselves (new-tab button / Cmd+T / open in new tab) are never
taken over by the BrowserSkill control mask.
- background overlay: decide per-tab state BEFORE showing controls
(overlayStateForTab + pushOverlayStateForTab) so a user tab receives hidden
on its first overlay.ready ping instead of flashing control then hiding.
- AgentWindowApi.ensureActiveTab now resolves with the activated/created tab
id instead of void, so SessionManager can record homeTabId. This fixes the
tsc failure flagged in review (the interface previously returned
Promise<void> while callers treated the result as number | null).
- Wire the production tabManagement.tabs / tabsQuery deps into
tool.session_stop, both in the dispatcher and in the disconnect cleanup.
They were never injected, which left the agent-tab cleanup and the
window-release path as dead code outside tests (behaviour identical to
main). Added a dispatcher-level integration test that fails without the
wiring: a surviving user tab must release the window, not close it.
Agents were stopping on popup and status copy that looked like a hard incompatibility. Keep the connection usable, reframe exit 5 as an unknown method, and ask users to upgrade instead of aborting.
Co-authored-by: Cursor <cursoragent@cursor.com>
Reject legacy JSON --output before recording starts, persist the completed Trace before writing the bundle so `bsk record stop --output <dir>` can retry after an export failure, and tell users to pass --url when https://example.com/ does not load.
Wait for DOM quiet after actions, match targets to VOM refs, and reduce
drafts into deduped state-linked Trace v3 while keeping the v2 reducer.
Co-authored-by: Cursor <cursoragent@cursor.com>
RecordedTrace validation now follows classify_value — numeric version
selects v3, otherwise v2 — so mixed pages/states and v2 envelopes with
a version field fail Schema checks before Recall import. Keep standalone
trace_step as a v2|v3 union for tools that validate a single step.
Require Trace v3 version const 3, reject mixed pages/states payloads, and
align TypeScript selection optionality with the generated schema. Trace v2
on main already records hover steps, so the frozen v2 schema must accept
them instead of dropping them during reduction.
Co-authored-by: Cursor <cursoragent@cursor.com>
Define Trace v3 wire types and generated schemas while keeping protocol
1.1 peers compatible with 1.0. Default record start still produces Trace
v2, and only an explicit trace_version=3 request enables the new shape.
Refs #90
Co-authored-by: Cursor <cursoragent@cursor.com>
The extension is now published to Edge Add-ons, but every install path
still pointed Edge users at the Chrome Web Store. Both READMEs and
AGENT_INSTALL.md now name a store per browser, and `bsk doctor` offers
both listings when no browser is connected.
Two Edge-specific gaps went with it: Edge blocks content-script injection
on its own storefront the same way Chrome does, so the borrow-confirmation
overlay must treat microsoftedge.microsoft.com/addons as non-injectable;
and the Chinese README still described the pre-install.ps1 manual Windows
setup.
Also give the DeepSeek Harness section its npm package link and the
profile-start step, so plugin users have a complete path.
Co-authored-by: Cursor <cursoragent@cursor.com>
Allow intentional input clears to remain in exported traces instead of dropping every non-redacted blank fill.
Co-authored-by: Cursor <cursoragent@cursor.com>
Tool cancellation is now cooperative end-to-end: the queue stays busy until compensation completes, cancellation is checked cooperatively across the pipeline, the fallback window is compensated too, and cleanup_failed is surfaced explicitly. Includes a gated delayed-compensation E2E test.
Add a per-browser "Control hints" switch to the popup that hides the in-page control overlay (status pill + orange glow, along with its input blocker) while the Agent controls a tab. Preference lives in chrome.storage.local (bsk_control_hints_hidden, default: shown) and is applied live in content scripts via storage.onChanged.
Both popup settings rows share a single Switch component; the hint copy lives in an info-icon tooltip.
Refs #62
chrome.tabs.captureVisibleTab reads back the window surface, which fails
outright on some Windows/Chrome combinations (Chromium
FAILURE_REASON_READBACK_FAILED: "Failed to capture tab: image readback
failed"), leaving full-tab screenshots without any working path.
Capture the full tab via CDP Page.captureScreenshot (fromSurface) when
the visible-tab capture rejects; the CDP path goes through the
renderer BeginFrame pipeline instead of the surface readback. When both
paths fail, return cdp_failed with data.reason=screenshot_capture_failed
carrying both underlying messages, and render a CLI hint that points at
the browser-side readback cause.
Refs #71
`bsk session start --no-focus` opens the Agent Window in the background
without stealing focus. The flag threads focused=false through
CLI -> daemon IPC -> tool.session_start -> chrome.windows.create; an
omitted `focused` keeps the extension default (true) so older clients
are unaffected.
Reworked onto current main so it composes with #52 window sizing:
AgentWindowApi.create / SessionManager.start (extension), start_session
(CLI) and the daemon's session start now take options objects/structs
({ size, focused }) instead of colliding positional params.
Co-authored-by: alectimison-maker <alec.timison@gmail.com>