dsh-builtin-browser 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -1,106 +1,169 @@
1
- # dsh-builtin-browser (built-in shared real browser plugin for DeepSeek Harness)
1
+ <p align="center">
2
+ <img src="https://img.shields.io/github/stars/wqty123/dsh-browser?style=flat&amp;label=%E2%98%85&amp;color=08C" alt="GitHub stars">
3
+ <img src="https://img.shields.io/npm/v/dsh-builtin-browser?style=flat&amp;label=npm&amp;color=CB3837" alt="npm version">
4
+ <img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat" alt="MIT License">
5
+ <img src="https://img.shields.io/badge/DSH-Plugin-47848F?style=flat" alt="DeepSeek Harness plugin">
6
+ <img src="https://img.shields.io/badge/Windows%20%7C%20macOS%20%7C%20Linux-4493F8?style=flat-square" alt="Platforms">
7
+ </p>
2
8
 
3
- 中文 | [English](README.en.md)
9
+ <p align="center"><a href="README.md">中文</a> · English</p>
4
10
 
5
- A shared **real browser** capability plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness): install and it just works — the agent drives a real, visible browser over CDP that the human can watch and take over at any time. Human and agent operate the **very same page**.
11
+ <h3 align="center">A <b>shared real browser</b> plugin for the DeepSeek Harness ecosystem (install-and-use, human and agent on the same page)</h3>
6
12
 
7
- **Why this plugin**
13
+ <h4 align="center">The agent drives a real, visible browser the human can watch and take over at any time — both operate the <b>same page</b>.</h4>
8
14
 
9
- - **Install-and-use.** With a desktop shell the shell's embedded view is used; on plain `dsh web` the plugin **self-hosts** — it spawns its own Electron window with zero extra configuration.
10
- - **Real and visible, human-takeover friendly.** Not a headless screenshot or a relay: the user sees the page and can grab control directly.
11
- - **DOM-level driving, framework-friendly.** React/Vue controlled inputs fill reliably.
12
- - **Concurrency-safe.** Task-level browser session isolation — parallel tasks never fight over the page or pollute each other.
13
- - **Built for the real world.** CAPTCHA detection, login persistence, batch form filling, authenticated downloads, operation replay, and action restriction — all included.
15
+ ## What is this
14
16
 
15
- ## Features
17
+ `dsh-builtin-browser` adds browser capability to [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness):
16
18
 
17
- **Browser capability**
19
+ - **A real view, not a relay**: the browser is a native `WebContentsView`; the human sees every step the agent takes and can grab control at any time;
20
+ - **Install-and-use**: with a desktop shell the shell's embedded view is used; on plain `dsh web` the plugin **self-hosts** — it spawns its own Electron window with zero extra configuration;
21
+ - **One plugin, one toolset**: after install the agent automatically gets 20 `browser_*` tools (open, inspect, interact, fill forms, screenshot, download, auth management…).
18
22
 
19
- - **Real view, not a relay.** The browser is a native view (`WebContentsView`) the human can see and operate directly; the agent drives the very same page. The view is provided by the host shell; the plugin drives it.
20
- - **DOM-referenced, not coordinate-guessing.** `browser_snapshot` returns numbered interactive elements; `browser_execute` runs JS in the page (native setters for framework inputs), so interaction works on React/Vue pages.
21
- - **Multi-tab sessions.** Open URLs in parallel tabs, list/switch/close/reset, all keeping state.
22
- - **Multi-format content.** Fetch pages as html / markdown / txt / json, scoped by selector, capped by length and timeout.
23
+ In one sentence: **installing the plugin gives you a real browser that is shared with the user and drivable by the agent.**
23
24
 
24
- **Engineering capability**
25
-
26
- - **Per-task isolation.** Each DSH task (session) gets its own browser session (own tabs and history); concurrent tasks never interfere, and calls within one task reuse the same session (`browser_session` / `browser_reset_session`).
27
- - **Login persistence.** `browser_auth` exports/restores cookies, so logins survive host restarts.
28
- - **CAPTCHA / bot-detection awareness.** Cloudflare, reCAPTCHA, hCaptcha, Turnstile and generic challenges are detected automatically (`browser_challenge`, and flagged in snapshots); instead of blindly retrying, the agent asks the human to complete it in the shared window.
29
- - **Batch form filling.** `browser_fill` sets many fields in one call — matched by selector/name/label, handling controlled inputs, selects, checkboxes and radio groups, with optional submit.
30
- - **Operation history & replay.** `browser_history` records operations; `browser_replay` re-runs one step.
31
- - **Authenticated downloads.** `browser_download` fetches a URL with the session's cookies straight to a local file.
32
- - **Safety restriction.** `browser_restrict` limits which browser actions are allowed, preventing stray clicks/navigation.
33
-
34
- ## Requirements
35
-
36
- - DeepSeek Harness (dsh) with the `web` profile
37
- - **Electron runtime** (optional peer dependency): the desktop shell carries it; on plain `dsh web` the plugin must be able to locate an Electron binary (see below)
38
- - With a desktop shell (`ctx.electronViewHost`) the shell's embedded view is used; without one the plugin **self-hosts**: it spawns its own Electron window and the `browser_*` tools still work
39
-
40
- **Electron lookup order**: ① `require('electron')` (peer installed) → ② DSH install anchors → ③ `node_modules/.pnpm` virtual store → ④ `ELECTRON_PATH` env var. A clear error tells you when none is found.
41
-
42
- ### Verified versions
43
-
44
- | Component | Version |
45
- |---|---|
46
- | DeepSeek Harness (dsh) | `0.1.0-rc.5` |
47
- | Electron | `43.4.0` |
48
- | Node.js | `22.20.0` |
49
- | dsh-builtin-browser | `0.1.7` |
50
- | OS | Windows 10 (10.0.26200) |
51
-
52
- > The plugin declares `electron >= 30`; other platforms (macOS/Linux) run the same protocol but were only verified on the Windows environment above.
53
-
54
- ## Install
25
+ ## Quick start
55
26
 
56
27
  ```sh
57
- dsh plugin --profile web add dsh-builtin-browser # from npm once published
58
- # or from a checkout (one plugin, one repository):
28
+ # Option 1: install from npm (published)
29
+ dsh plugin --profile web add dsh-builtin-browser
30
+
31
+ # Option 2: install from a checkout (one plugin, one repository)
59
32
  dsh plugin --profile web add <path-to-this-repo>
60
33
  ```
61
34
 
62
- This links the plugin, adds `dsh-builtin-browser` to the profile's bundle layer, and mounts:
63
-
64
- | Row | Subpath | Role |
65
- |---|---|---|
66
- | `browser` | `dsh-builtin-browser/browser` | `ctx.browser` capability seam (always mounted) |
67
- | `browser-electron` | `dsh-builtin-browser/browser-electron` | Electron CDP provider (needs `electronViewHost`) |
68
- | `tool-browser` | `dsh-builtin-browser/tool-browser` | `browser_*` model-facing tools |
69
-
70
- The provider and tools are gated on `ctx.get('electronViewHost')` being present, so a composition without a desktop shell simply keeps the seam and nothing else.
35
+ After install the agent can use the browser tools, e.g.:
36
+
37
+ | What you want | Tool | Notes |
38
+ | --- | --- | --- |
39
+ | Open a page | `browser_open` | Opens a URL and returns a numbered snapshot |
40
+ | Understand a page | `browser_snapshot` | Numbered inventory of inputs/buttons/links to target |
41
+ | Operate a page | `browser_execute` | Runs JS in the page (native setters, framework-friendly) |
42
+ | Fill a form | `browser_fill` | Fills many fields in one call, optional submit |
43
+ | See the page | `browser_screenshot` | PNG capture, optionally saved for a vision model |
44
+
45
+ See the full list in [Tool reference](#tool-reference).
46
+
47
+ ## Main features
48
+
49
+ <table>
50
+ <tr>
51
+ <td width="50%" valign="top">
52
+ <h3>Shared real browser</h3>
53
+ <p>A native view, not a headless screenshot. Human and agent operate the same page: the user sees every step and can take over; the agent drives the very window in front of the user.</p>
54
+ </td>
55
+ <td width="50%" valign="top">
56
+ <h3>DOM-level driving, framework-friendly</h3>
57
+ <p><code>browser_snapshot</code> returns numbered interactive elements; <code>browser_execute</code> runs JS in the page (native setters + input/change events for controlled inputs), so React/Vue pages work reliably.</p>
58
+ </td>
59
+ </tr>
60
+ <tr>
61
+ <td width="50%" valign="top">
62
+ <h3>Multi-tab sessions</h3>
63
+ <p>Open URLs in parallel tabs; list/switch/close/reset tabs while each session keeps its own state.</p>
64
+ </td>
65
+ <td width="50%" valign="top">
66
+ <h3>Multi-format content</h3>
67
+ <p>Fetch pages as html / markdown / txt / json, scoped by CSS selector, capped by character limit and timeout.</p>
68
+ </td>
69
+ </tr>
70
+ <tr>
71
+ <td width="50%" valign="top">
72
+ <h3>Per-task session isolation</h3>
73
+ <p>Each DSH task (session) gets its own browser session (own tabs and history); concurrent tasks never fight over the page or pollute each other. Calls within one task reuse the same session.</p>
74
+ </td>
75
+ <td width="50%" valign="top">
76
+ <h3>Login persistence</h3>
77
+ <p><code>browser_auth</code> exports/restores cookies so logins survive host restarts; self-hosted cookies are also persisted to disk.</p>
78
+ </td>
79
+ </tr>
80
+ <tr>
81
+ <td width="50%" valign="top">
82
+ <h3>CAPTCHA / bot-detection awareness</h3>
83
+ <p>Detects Cloudflare, reCAPTCHA, hCaptcha, Turnstile and generic challenges (<code>browser_challenge</code>, also flagged in snapshots); instead of retrying blindly, the agent asks the human to complete it in the shared window.</p>
84
+ </td>
85
+ <td width="50%" valign="top">
86
+ <h3>Batch form filling</h3>
87
+ <p><code>browser_fill</code> fills many fields at once — matched by selector/name/label, handling controlled inputs, selects, checkboxes and radio groups, with optional submit; one failing field never aborts the rest.</p>
88
+ </td>
89
+ </tr>
90
+ <tr>
91
+ <td width="50%" valign="top">
92
+ <h3>Operation history &amp; replay</h3>
93
+ <p><code>browser_history</code> logs operations (open/execute/click/type/fill/download/auth); <code>browser_replay</code> re-runs one step by sequence number.</p>
94
+ </td>
95
+ <td width="50%" valign="top">
96
+ <h3>Authenticated downloads</h3>
97
+ <p><code>browser_download</code> fetches a file in the page context with the session's cookies and writes it to disk — content behind login works too.</p>
98
+ </td>
99
+ </tr>
100
+ <tr>
101
+ <td width="50%" valign="top">
102
+ <h3>Safety restriction</h3>
103
+ <p><code>browser_restrict</code> limits which browser actions are allowed (allow-list) to prevent stray clicks/navigation; read-only tools (snapshot/content/screenshot) are never blocked.</p>
104
+ </td>
105
+ <td width="50%" valign="top">
106
+ <h3>Screenshot, save and read</h3>
107
+ <p><code>browser_screenshot</code> supports <code>savePath</code> to write the PNG to disk, ready for vision models (modlens etc.) to locate elements visually.</p>
108
+ </td>
109
+ </tr>
110
+ </table>
111
+
112
+ ## Why this plugin
113
+
114
+ - **Install-and-use, zero config**: no desktop shell or extra startup step required; on plain `dsh web` it self-hosts an Electron window and the `browser_*` tools just work.
115
+ - **Human-in-the-loop, non-interfering**: the user sees and can take over every agent action; per-task isolation gives each parallel task its own tabs and history.
116
+ - **Built for the real world**: CAPTCHA detection, login persistence, batch form filling, authenticated downloads, operation replay, action restriction — real-browser automation that is actually reliable.
117
+ - **Testable, replaceable architecture**: the provider talks to Electron through the `ElectronBrowserViewHost` seam, so a future headless relay provider can serve remote deployments without touching the tool layer.
118
+
119
+ ## Tool reference
120
+
121
+ | Tool | Purpose | Guard |
122
+ | --- | --- | --- |
123
+ | `browser_open` | Open a URL (optionally in a new tab); returns a page snapshot | ✅ |
124
+ | `browser_snapshot` | Numbered inventory of interactive elements (inputs/buttons/links) | – |
125
+ | `browser_execute` | Run JS in the page; args arrive as `arguments[0..n]` | ✅ |
126
+ | `browser_content` | Fetch the page as html / markdown / txt / json (selector, maxChars, timeoutMs) | – |
127
+ | `browser_click` | Click at viewport coordinates (for vision-located targets) | ✅ |
128
+ | `browser_type` | Type text into the focused element (CDP `Input.insertText`) | ✅ |
129
+ | `browser_fill` | Batch form fill (selector/name/label matching, controlled inputs, selects, checkbox/radio, optional submit) | ✅ |
130
+ | `browser_screenshot` | PNG capture, optional `fullPage` and `savePath` | – |
131
+ | `browser_list_tabs` | List the session's tabs | – |
132
+ | `browser_switch_tab` | Switch to a tab by id (also switches the visible view when self-hosted) | ✅ |
133
+ | `browser_close_tab` | Close a tab by id; closing the active tab activates the next | – |
134
+ | `browser_reset` | Close all tabs of this task, back to one blank tab | ✅ |
135
+ | `browser_session` | Show this task's browser session and tabs | – |
136
+ | `browser_reset_session` | Close and rebuild this task's browser session | ✅ |
137
+ | `browser_history` | Operation log (newest last), with per-step success/error and result summary | – |
138
+ | `browser_replay` | Replay one step by sequence number (navigate/execute/click/type) | ✅ |
139
+ | `browser_download` | Download a URL with session cookies to a local file (256 MB cap) | ✅ |
140
+ | `browser_auth` | Export/restore cookies (login persistence, self-hosted) | ✅ |
141
+ | `browser_challenge` | Detect a human-verification challenge (CAPTCHA / Cloudflare / reCAPTCHA / hCaptcha / Turnstile) | – |
142
+ | `browser_restrict` | Restrict allowed browser actions (allow-list; empty list lifts it) | – |
143
+
144
+ > "Guard" column: ✅ actions are governed by the `browser_restrict` allow-list; read-only tools (snapshot/content/screenshot/list_tabs/session/challenge/history) are never blocked.
145
+
146
+ ### Operating discipline (click/fill)
147
+
148
+ - **Prefer DOM semantics over coordinates**: submit forms with `form.requestSubmit()`; click with `element.click()`; coordinate clicks are the last resort.
149
+ - **Target the right element**: pages often have hidden duplicates (e.g. mobile buttons); filter visible elements with `browser_execute` (`getBoundingClientRect()` w/h > 0, `getComputedStyle` not `display:none`), then take coordinates.
150
+ - **Click right after taking coordinates**: do not insert other operations in between (filling/scrolling moves elements and invalidates old coordinates).
151
+ - **Verify before clicking**: use `document.elementFromPoint(x, y)` to confirm the coordinate hits the intended element (button/link), then perform the real click.
152
+ - **DPR awareness**: CDP input uses CSS pixels; on high-DPI screens calibrate with `elementFromPoint` instead of guessing coordinates.
71
153
 
72
154
  ## Configuration
73
155
 
74
- The plugin mounts through `cordis.patch.yml`; per-row config:
156
+ The plugin mounts through `cordis.patch.yml` (three rows); per-row config:
75
157
 
76
158
  | Row | Key | Type | Default | Description |
77
- |---|---|---|---|---|
159
+ | --- | --- | --- | --- | --- |
78
160
  | `browser-electron` | `viewHost` | object | required | `ElectronBrowserViewHost` supplied by the host shell (typically `!!js ctx.get('electronViewHost')`) |
79
- | `browser-electron` | `httpOnly` | boolean | `true` | Allow HTTP(S) navigation only; other protocols (e.g. `file:`/`data:`) are rejected (`BROWSER_NAVIGATION_BLOCKED`) |
161
+ | `browser-electron` | `httpOnly` | boolean | `true` | Allow HTTP(S) navigation only; other protocols (e.g. `file:`/`data:`) rejected (`BROWSER_NAVIGATION_BLOCKED`) |
80
162
  | `browser-electron` | `snapshotMaxElements` | number | `60` | Max snapshot elements before truncation |
81
163
  | `browser-electron` | `contentMaxChars` | number | `100000` | Default content character cap |
82
164
  | `tool-browser` | `timeoutMs` | number | `60000` | Cooperative tool timeout (ms) |
83
165
  | `tool-browser` | `tabTools` | boolean | `true` | Register tab-management tools (`browser_list_tabs` etc.) |
84
166
 
85
- ## Tools
86
-
87
- | Tool | Purpose |
88
- |---|---|
89
- | `browser_open` | Open a URL (optionally a new tab); returns a snapshot |
90
- | `browser_snapshot` | Numbered inventory of interactive elements (inputs/buttons/links) |
91
- | `browser_execute` | Run JS in the page; args arrive as `arguments[0..n]` |
92
- | `browser_content` | Fetch the page as html / markdown / txt / json (selector, maxChars, timeoutMs) |
93
- | `browser_screenshot` | PNG capture, optional `fullPage` |
94
- | `browser_list_tabs` / `browser_switch_tab` / `browser_close_tab` / `browser_reset` | Multi-tab session management |
95
-
96
- ### Interaction discipline (clicking / filling forms)
97
-
98
- - **Prefer DOM semantics over coordinates**: submit forms with `form.requestSubmit()`, click with `element.click()`; coordinate clicks are the last resort.
99
- - **Target the right element**: pages often carry hidden copies (e.g. mobile buttons). Use `browser_execute` to filter visible elements (`getBoundingClientRect()` with width/height > 0, computed style not `display:none`) before reading coordinates.
100
- - **Click immediately after reading coordinates**: do not interleave other actions (filling, scrolling moves elements; stale coordinates fail instantly).
101
- - **Verify the hit before clicking**: `document.elementFromPoint(x, y)` confirms the coordinate actually lands on the target button/link before issuing a real click.
102
- - **Mind DPR**: CDP input uses CSS pixels; on high-DPI screens, calibrate with `elementFromPoint` instead of blind coordinate tries.
103
-
104
167
  ## How it works
105
168
 
106
169
  ```
@@ -111,20 +174,73 @@ agent (browser_* tools)
111
174
  → WebContentsView + webContents.debugger (CDP)
112
175
  ```
113
176
 
114
- The provider is Electron-agnostic by construction: it operates through the `ElectronBrowserViewHost` seam (create/destroy/show views, `sendCommand`), which a real shell implements with Electron objects. The same seam lets a future relay provider (headless Chromium screenshot stream) serve remote deployments without touching the tools.
177
+ - **Seam** (`browser` row): provides the `ctx.browser` service — provider registration, session lifecycle, error codes — decoupled from any implementation.
178
+ - **Provider** (`browser-electron` row): operates views through the `ElectronBrowserViewHost` seam (create/destroy/show, `sendCommand`), implemented with real Electron objects by the shell.
179
+ - **Tools** (`tool-browser` row): the 20 model-facing `browser_*` tools, maintaining one browser session per calling task (DSH session).
180
+
181
+ **Self-hosted mode**: without a desktop shell, the plugin spawns its own Electron child process (`host-main.js`) and drives it over loopback TCP JSON-RPC (window title `dsh-browser`). The child auto-restarts after a crash; screenshots prefer Electron's native `capturePage` (CDP capture can hang with multiple views in the window); the plugin automatically picks the **newest** Electron in the environment (33.x has a compositor defect; ≥ 40 recommended).
182
+
183
+ **Electron lookup order**: ① `require('electron')` (peer dependency) → ② `ELECTRON_PATH` (explicit override) → ③ the newest among DSH install anchors and pnpm virtual stores. A clear error tells you when none is found.
115
184
 
116
185
  ## Division of labor with the desktop shell
117
186
 
118
- The browser's **visible view**, the **browser column layout**, and the **column-to-view alignment** belong to the host shell (e.g. dsh's `apps/desktop`), not this plugin. This plugin only consumes the shell-provided `electronViewHost` and owns the seam, provider, and tools. Installing the plugin without a matching shell leaves the capability disabled.
187
+ The browser's **visible view**, the **browser column layout**, and the **column-to-view alignment** belong to the host shell (e.g. dsh's `apps/desktop`), not this plugin. This plugin consumes the shell-provided `electronViewHost` and owns the seam, provider, and tools. Without a shell the plugin **self-hosts** and everything still works.
188
+
189
+ ## Requirements
190
+
191
+ - DeepSeek Harness (dsh) with the `web` profile
192
+ - **Electron runtime** (optional peer dependency): the desktop shell carries it; on plain `dsh web` the plugin locates an Electron binary automatically (see above; ≥ 40 recommended)
193
+
194
+ ### Verified versions
195
+
196
+ | Component | Version |
197
+ | --- | --- |
198
+ | DeepSeek Harness (dsh) | `0.1.0-rc.5` |
199
+ | Electron | `43.4.0` (≥ 40 recommended; 33.x has a compositor defect) |
200
+ | Node.js | `22.20.0` |
201
+ | dsh-builtin-browser | `0.1.11` |
202
+ | OS | Windows 10 (10.0.26200) |
203
+
204
+ > The plugin declares `electron >= 30`; other platforms (macOS/Linux) run the same protocol but were only verified on the Windows environment above.
119
205
 
120
206
  ## Known limitations
121
207
 
122
208
  - Screenshots are PNG-only (CDP JPEG hangs on Electron 43); JPEG awaits a non-CDP conversion path.
209
+ - Self-hosted captures prefer Electron's native `capturePage` (CDP `captureScreenshot` can hang with multiple views in the window); the target tab is raised before capturing.
123
210
  - `fullPage` capture is flaky under software compositing on some hosts.
124
- - Session lifecycle is plugin-level (one session shared by the model), not per-agent yet.
211
+ - CAPTCHA cannot be solved automatically: snapshots flag detected challenges; ask the human to complete it in the shared window instead of retrying.
125
212
  - Private mode (`privateMode`) is not implemented: it needs Electron session partitioning, which is host-layer territory; this plugin does not promise it.
213
+ - `browser_download` fetches in the page context (keeps logins) and is subject to same-origin/CORS constraints; single files are capped at 256 MB.
214
+ - The `browser_auth` cookie round-trip does not preserve `hostOnly`/`sameSite` (host-only cookies come back as domain cookies); it is available on the self-hosted browser only.
215
+ - After a self-hosted child crash the browser host restarts automatically, but sessions opened before the crash are gone — call `browser_reset_session` to rebuild.
126
216
  - This plugin contains no browser-column UI — that is host-shell territory; do not treat "browser column" as a plugin feature.
127
217
 
218
+ ## Development
219
+
220
+ ```sh
221
+ # Type-check + build (lib/)
222
+ pnpm run build
223
+
224
+ # Functional tests: start a local page server + Electron probe (see repo test scripts)
225
+ ```
226
+
227
+ Code layout:
228
+
229
+ | Directory | Responsibility |
230
+ | --- | --- |
231
+ | `src/browser/` | The `ctx.browser` seam and all request/result types |
232
+ | `src/browser-electron/` | Electron CDP provider, self-hosted child (`host-main.ts`), RPC layer |
233
+ | `src/tool-browser/` | Model-facing `browser_*` tools |
234
+ | `src/types/` | Electron ambient types (shim; no hard electron type dependency) |
235
+
236
+ ## Acknowledgements
237
+
238
+ Special thanks to the [DeepSeek Harness repository](https://github.com/deepseek-ai/deepseek-harness) and the DeepSeek AI team: the seam, the tool runtime, and the plugin system this plugin builds on all come from that project.
239
+
240
+ Thanks as well to [Cordis](https://github.com/cordiverse/cordis) for the plugin foundation, and to everyone in the community who discussed, tested, gave feedback, and built plugins.
241
+
128
242
  ## License
129
243
 
130
- MIT
244
+ MIT License, see [LICENSE](LICENSE).
245
+
246
+ > This project is a community plugin for DeepSeek Harness, not an official DeepSeek product.