All plugins

DSH / BUNDLE / CLIENT-UI

dsh-agent-browser

v0.1.0guanhaisen / dsh-agent-browser0ae65b5492

InstallableBundlesUI & client pluginsCommunity · Topic auto-analysisWeb UI

Overview

dsh-agent-browser

Agent-driven control of the DSH right-Sidebar browser: read page content, act on it, size the viewport, and take screenshots from model tools (Desktop only)

README / EN

Package documentation

Registry summary

Agent-driven control of the DSH right-Sidebar browser: read page content, act on it, size the viewport, and take screenshots from model tools (Desktop only)

dsh.pub verifies the pinned bundle contract, runtime facts, and distribution semantics. The complete README remains in the source repository.

Read the full README on GitHub

LIMITATIONS

Known limitations

- **Desktop only**, as above. - **Mounted tabs only.** A tab that is open but not yet mounted cannot be driven; the tool says so and asks you to click that tab once. (In practice tabs mount as soon as they are opened or restored.) Setting a viewport is the exception: it is stored and applied when the tab mounts. - **Opening a tab needs this Conversation's Sidebar to have a surface.** The Session-addressed open is a silent no-op for a Session whose Sidebar store has never been adopted, so `browser_navigate` without a `tabId` can fail with "not created" in a Conversation that has never shown its right Sidebar. Open that Conversation's Sidebar once and retry. Navigating an existing tab is unaffected. - **`shortcuts.register` requires a `defaults` map.** Omitting it throws during `apply()`, which takes down the entire client half — the Inspect provider included — and surfaces only as `web boot: … did not activate`. This plugin ships `defaults: {}`; `test/apply-check.cjs` guards the shape so the outage cannot come back silently. - **The menu item reads `sessionId` from a standard slot prop.** It falls back to the enclosing `[data-sidebar-right-session]` only if a future shell stops providing it, so the control keeps working either way. - **The tab menu is a right-click menu, not a "⋯" button.** The kit's tab strip has no overflow button; the menu is opened by the tab's `onContextMenu` handler. `Modal` is deliberately **not** used for the custom-size form: the kit dismisses the menu on any `pointerdown` outside its own element, and `Modal` portals to `document.body`, so a portaled dialog would destroy itself on first click. The form renders inline and stops pointer events instead. - **`jsx(type, props, key)` takes the React KEY third — not children.** This plugin shipped a bug from exactly that: labels were passed as the third argument, which compiles and renders *empty* buttons (the live menu showed six blank rows). Children always go in `props.children`. `test/apply-check.cjs` asserts every menu item carries a non-empty label. - **A `store` handle can only mount under one slot scope.** Declaring `store` on a registration makes the renderer bind `useStore`/`actions`, but the same handle cannot be mounted under two different scopes — this plugin needs its state in both a session-scoped slot (the tab menu) and a root-scoped one (Settings → General), and doing so throws `store handle mounted under … is already mounted under scope …`. So the store is passed as a plain prop and the components subscribe with `React.useSyncExternalStore` directly. The snapshot must be identity-stable; `test/apply-check.cjs` asserts the components declare no `store` handle. - **A screenshot that cannot be delivered still answers.** If no attachment store is mounted, or the store refuses the image (an oversized capture, for instance), the result drops the bytes and explains why in `note` rather than failing the call. - **Every guest call is bounded by the plugin's own budget.** 6 s for reads and actions, 15 s for a screenshot, and 1 s for the identity probe every method makes. Electron's `executeJavaScript`, `capturePage` and `loadURL` accept no abort signal and no timeout, so an unresponsive renderer never settles; racing a timer is the only bound the plugin controls. Awaiting them bare is what made a stalled page cost a fixed 60 s per call (the Inspect channel's default timeout) — eight of those cost one agent about eight minutes. The budget is not configurable: the Client half cannot read plugin configuration, so it is a constant rather than a setting, and `clientInspectTimeoutMs` still governs the outer channel. - **`browser_tabs` shares one deadline across the whole listing.** Each tab needs its own identity probe, so a Session full of stalled tabs could otherwise cost one full budget per tab — an unbounded answer to the question that is supposed to be the cheap w