Skip to content

0.2.0 — one browser tab per session

Choose a tag to compare

@imroc imroc released this 14 Sep 06:13
· 5 commits to main since this release

Breaking: every DSH session now gets its own tab in the shared browser. 0.1.x owned a single page for the whole host, so two conversations trampled each other's page.

What changed

  • One Chrome, one tab per session. A session's tab is created on its first browser_panel_* call (or from the panel's open button) and is activated once at creation — a Chrome target that was never activated silently discards every injected input event for the rest of its life.
  • The profile stays shared, on purpose. Sessions are isolated in page state, not in identity: log in once (SSO, QR, 2FA, CAPTCHA) and every session is authenticated.
  • Tools follow the caller. Handlers take the session from their execution context, so tool names and parameters are unchanged, and one session can never steer another's page. A call without an owning session is an error rather than a silent fallback to a shared page.
  • The panel lives in the session page. A fixed 浏览器 / Browser tab in the session's view strip renders that session's browser; the sidebar entry became a host-wide overview (rows per session tab, pending take-over badge, per-row teardown). The root-scoped canvas panel is gone.
  • Streaming follows the human. Chrome streams only the active tab, so the session whose panel is actually being watched owns the real screencast and every other attached session is served by polled captures (~7 fps, optimizeForSpeed). A fresh panel is always seeded a frame.
  • Take-over is per session. Two sessions can wait on a person at the same time, and a request is delivered only to the panel of its own session.
  • Closing is explicit. browser_panel_close, the panel's 结束并清理, or the session being disposed close that session's tab. Unmounting the panel hands the foreground back and never closes anything.
  • Idle reaping is lossless. After idleShutdownMinutes (default 10, 0 disables) the browser stops; the next call reopens each session at its last URL, already authenticated.

Upgrading

No configuration change is required. Two behaviour notes: browser_panel_close now closes the calling session's tab instead of stopping the whole browser (there is no stop-everything tool any more), and browser_panel_navigate's newTab replaces this session's tab. A new pollFrameMs (default 140) tunes the fallback stream for panels that do not hold the foreground.

Verification

43-check standalone smoke suite (node test/smoke.mjs) covering per-session isolation and real input delivery — two sessions get two tabs, tabs do not steer each other, click-then-type really lands in the field, the focus gate is asserted, panel input reaches its own session only, the watched session owns the screencast while the other is polled, a panel reconnect survives, and a login survives a browser restart. Plus a live install check: tools bound to the calling session, a logged-in page coming back after the upgrade, and /open + /close touching exactly one session.