dsh-builtin-browser 0.1.15 → 0.1.17
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 +71 -21
- package/README.md +71 -21
- package/docs/README.md +1 -1
- package/docs/architecture.md +8 -5
- package/docs/tool-reference.md +22 -9
- package/docs/user-guide.md +16 -10
- package/lib/browser/runtime.d.ts +42 -8
- package/lib/browser/runtime.js +58 -6
- package/lib/browser/types.d.ts +267 -8
- package/lib/browser-electron/entry.d.ts +15 -5
- package/lib/browser-electron/entry.js +13 -5
- package/lib/browser-electron/host-main.d.ts +13 -4
- package/lib/browser-electron/host-main.js +686 -93
- package/lib/browser-electron/provider.d.ts +192 -18
- package/lib/browser-electron/provider.js +1063 -61
- package/lib/browser-electron/remote-host.d.ts +32 -2
- package/lib/browser-electron/remote-host.js +309 -49
- package/lib/index.d.ts +6 -6
- package/lib/index.js +4 -4
- package/lib/tool-browser/index.d.ts +4 -4
- package/lib/tool-browser/index.js +706 -79
- package/package.json +5 -4
- package/src/browser/runtime.ts +111 -10
- package/src/browser/types.ts +278 -8
- package/src/browser-electron/entry.ts +81 -63
- package/src/browser-electron/host-main.ts +635 -81
- package/src/browser-electron/provider.ts +1217 -58
- package/src/browser-electron/remote-host.ts +319 -50
- package/src/index.ts +21 -6
- package/src/tool-browser/index.ts +1528 -885
- package/src/types/electron-shim.d.ts +20 -0
package/README.en.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
| --- | --- |
|
|
19
19
|
| Why a shared real browser, and how it differs from headless approaches | [Why a shared real browser](docs/why-browser.md) |
|
|
20
20
|
| Installation, configuration, day-to-day use | [User guide](docs/user-guide.md) |
|
|
21
|
-
| All
|
|
21
|
+
| All 33 tools: parameters, output, examples | [Tool reference](docs/tool-reference.md) |
|
|
22
22
|
| How the seam / provider / tools layers and self-hosting work | [Architecture](docs/architecture.md) |
|
|
23
23
|
| Documentation index and README split | [Docs index](docs/README.md) |
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
- **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;
|
|
30
30
|
- **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;
|
|
31
|
-
- **One plugin, one toolset**: after install the agent automatically gets
|
|
31
|
+
- **One plugin, one toolset**: after install the agent automatically gets 33 `browser_*` tools (open, a11y tree, wait, semantic/coordinate interaction, scroll, back/forward, batch and single-control form filling, keys, structured scraping, screenshot, download, auth management…).
|
|
32
32
|
|
|
33
33
|
In one sentence: **installing the plugin gives you a real browser that is shared with the user and drivable by the agent.**
|
|
34
34
|
|
|
@@ -131,13 +131,26 @@ See the full list in [Tool reference](#tool-reference).
|
|
|
131
131
|
| Tool | Purpose | Guard |
|
|
132
132
|
| --- | --- | --- |
|
|
133
133
|
| `browser_open` | Open a URL (optionally in a new tab); returns a page snapshot | ✅ |
|
|
134
|
-
| `
|
|
134
|
+
| `browser_wait` | Wait for page load (optional expected URL / CSS selector), returns readiness | – |
|
|
135
|
+
| `browser_snapshot` | Numbered inventory of interactive elements (inputs/buttons/links; pierces same-origin iframes and Shadow DOM) | – |
|
|
136
|
+
| `browser_a11y` | Accessibility tree: semantic role/name/value/states + coordinates per interactive node (pierces same-origin iframes and Shadow DOM) | – |
|
|
135
137
|
| `browser_execute` | Run JS in the page; args arrive as `arguments[0..n]` | ✅ |
|
|
136
138
|
| `browser_content` | Fetch the page as html / markdown / txt / json (selector, maxChars, timeoutMs) | – |
|
|
137
|
-
| `browser_click` | Click
|
|
138
|
-
| `browser_type` | Type text
|
|
139
|
+
| `browser_click` | Click a semantic target (`target`: css/text/xpath, scrolls into view and clicks center) or viewport coordinates (vision-located) | ✅ |
|
|
140
|
+
| `browser_type` | Type text (optionally focusing a `target` element first; CDP `Input.insertText`) | ✅ |
|
|
141
|
+
| `browser_key` | Press a named key (Enter/Tab/arrows/Home/End…) | ✅ |
|
|
142
|
+
| `browser_scroll` | Scroll the page (pixel deltas / selector / top-bottom) | ✅ |
|
|
143
|
+
| `browser_back` | One step back in page history (no-op at the start) | ✅ |
|
|
144
|
+
| `browser_forward` | One step forward in page history (no-op at the end) | ✅ |
|
|
145
|
+
| `browser_refresh` | Reload the current page (like a browser refresh button) | ✅ |
|
|
139
146
|
| `browser_fill` | Batch form fill (selector/name/label matching, controlled inputs, selects, checkbox/radio, optional submit) | ✅ |
|
|
140
|
-
| `
|
|
147
|
+
| `browser_set_value` | Set one control's value (`target`-located; native setter + input/change, React-controlled friendly) | ✅ |
|
|
148
|
+
| `browser_check` | Check/uncheck a checkbox or radio (`target`-located) | ✅ |
|
|
149
|
+
| `browser_select` | Select an option of a `<select>` by value/text/index (`target`-located) | ✅ |
|
|
150
|
+
| `browser_clear` | Clear an input/textarea/contenteditable, or uncheck (`target`-located) | ✅ |
|
|
151
|
+
| `browser_get_value` | Read an element's current value for verification (`target`-located) | – |
|
|
152
|
+
| `browser_scrape` | Structured extraction: container selector + field map (`selector@attr`), static CSS only, CSP-safe | – |
|
|
153
|
+
| `browser_screenshot` | Capture, optional `fullPage`, `savePath`, JPEG (`format`/`quality`) and scaling (`maxWidth`/`maxHeight`) | – |
|
|
141
154
|
| `browser_list_tabs` | List the session's tabs | – |
|
|
142
155
|
| `browser_switch_tab` | Switch to a tab by id (also switches the visible view when self-hosted) | ✅ |
|
|
143
156
|
| `browser_close_tab` | Close a tab by id; closing the active tab activates the next | – |
|
|
@@ -146,13 +159,24 @@ See the full list in [Tool reference](#tool-reference).
|
|
|
146
159
|
| `browser_reset_session` | Close and rebuild this task's browser session | ✅ |
|
|
147
160
|
| `browser_history` | Operation log (newest last), with per-step success/error and result summary | – |
|
|
148
161
|
| `browser_replay` | Replay one step by sequence number (navigate/execute/click/type) | ✅ |
|
|
149
|
-
| `browser_download` | Download
|
|
162
|
+
| `browser_download` | Download an HTTP(S) URL with session cookies to a local file (absolute `savePath`, 256 MB cap) | ✅ |
|
|
150
163
|
| `browser_auth` | Export/restore cookies (login persistence, self-hosted) | ✅ |
|
|
151
164
|
| `browser_challenge` | Detect a human-verification challenge (CAPTCHA / Cloudflare / reCAPTCHA / hCaptcha / Turnstile) | – |
|
|
152
|
-
| `browser_restrict` | Restrict allowed browser actions (allow-list; empty list lifts it) | – |
|
|
165
|
+
| `browser_restrict` | Restrict allowed browser actions (allow-list; empty list lifts it). **Soft guardrail** — the model can lift it itself; not a security boundary | – |
|
|
153
166
|
|
|
154
167
|
> "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.
|
|
155
168
|
|
|
169
|
+
### Waiting for the page
|
|
170
|
+
|
|
171
|
+
- **After `browser_open`, before `browser_snapshot`, call `browser_wait` on slow sites**: pass `url` (what you opened) and an optional `selector`, and wait for `ready: true` — otherwise you snapshot the old document or a white screen.
|
|
172
|
+
- **Content you cannot see may live in an iframe / Shadow DOM**: snapshots and the a11y tree pierce same-origin iframes and shadow roots and mark them `(iframe)`; coordinates are always top-document, so `browser_click` works directly. DOM selectors are frame-scoped — reach them via `iframe.contentDocument` in `browser_execute`.
|
|
173
|
+
|
|
174
|
+
### Semantic targets and the a11y tree
|
|
175
|
+
|
|
176
|
+
- **`browser_a11y` is the best way to understand a page**: every interactive node carries its semantic role (button/textbox/checkbox…), accessible name, current value, states (enabled/checked/expanded…) and coordinates — click/type them directly.
|
|
177
|
+
- **`browser_click`/`browser_type` accept a `target`**: `{by: css|text|xpath, value, index?}` — `text` matches an element's own visible text (exact first, then contains, deepest preferred); clicks scroll the element to the viewport center first; typing focuses it first.
|
|
178
|
+
- **Use the single-control tools for one field** (`browser_set_value`/`browser_check`/`browser_select`/`browser_clear`/`browser_get_value`), `browser_fill` for batches, and `browser_scrape` for structured list extraction.
|
|
179
|
+
|
|
156
180
|
### Operating discipline (click/fill)
|
|
157
181
|
|
|
158
182
|
- **Prefer DOM semantics over coordinates**: submit forms with `form.requestSubmit()`; click with `element.click()`; coordinate clicks are the last resort.
|
|
@@ -171,6 +195,7 @@ The plugin mounts through `cordis.patch.yml` (three rows); per-row config:
|
|
|
171
195
|
| `browser-electron` | `httpOnly` | boolean | `true` | Allow HTTP(S) navigation only; other protocols (e.g. `file:`/`data:`) rejected (`BROWSER_NAVIGATION_BLOCKED`) |
|
|
172
196
|
| `browser-electron` | `snapshotMaxElements` | number | `60` | Max snapshot elements before truncation |
|
|
173
197
|
| `browser-electron` | `contentMaxChars` | number | `100000` | Default content character cap |
|
|
198
|
+
| `browser-electron` | `downloadDir` | string | `~/Downloads` | Confine `browser_download` save paths to this directory (stops a prompt-injected agent writing arbitrary paths); defaults to the OS Downloads folder, override for a sandbox dir |
|
|
174
199
|
| `tool-browser` | `timeoutMs` | number | `60000` | Cooperative tool timeout (ms) |
|
|
175
200
|
| `tool-browser` | `tabTools` | boolean | `true` | Register tab-management tools (`browser_list_tabs` etc.) |
|
|
176
201
|
|
|
@@ -186,11 +211,13 @@ agent (browser_* tools)
|
|
|
186
211
|
|
|
187
212
|
- **Seam** (`browser` row): provides the `ctx.browser` service — provider registration, session lifecycle, error codes — decoupled from any implementation.
|
|
188
213
|
- **Provider** (`browser-electron` row): operates views through the `ElectronBrowserViewHost` seam (create/destroy/show, `sendCommand`), implemented with real Electron objects by the shell.
|
|
189
|
-
- **Tools** (`tool-browser` row): the
|
|
214
|
+
- **Tools** (`tool-browser` row): the 33 model-facing `browser_*` tools, maintaining one browser session per calling task (DSH session).
|
|
215
|
+
|
|
216
|
+
**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. The RPC is authenticated with a random per-spawn token delivered over **both stdin and an environment variable** — on Windows the Electron GUI process never receives piped stdin, so the env fallback keeps the handshake reliable. 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; 44+ downloads its binary on first use, needs network).
|
|
190
217
|
|
|
191
|
-
**
|
|
218
|
+
**The self-hosted browser IS a real browser**: every task (DSH session) gets its **own browser window** with a full toolbar — address bar, back/forward/reload buttons, and a tab strip (new/switch/close tabs). A human can use it exactly like Chrome: type a URL in the address bar (https:// is added automatically), click tabs, open new ones. Keyboard focus follows your clicks — **click the address bar to type, click the page to interact** (Windows focus routing; fixes the case where clicks did not move focus and the address bar could not receive typed URLs). Human and agent actions feed the **same session model** (same tabs, history, and navigation); the window title always shows the task label plus the page title/URL, and views follow the window size on resize. A window closes automatically with its session when the task ends.
|
|
192
219
|
|
|
193
|
-
**Electron lookup order**: ① `require('electron')` (peer dependency)
|
|
220
|
+
**Electron lookup order**: ① the current process IS Electron (DSH Desktop main process) → reuse the host binary directly; ② walk the process ancestry for the host's Electron binary (covers hosts that run the plugin in a child Node process, e.g. DSH Desktop; PowerShell CIM on Windows, last resort only); ③ `require('electron')` (peer dependency); ④ `ELECTRON_PATH` (explicit override); ⑤ the newest among DSH install anchors and pnpm virtual stores. **Zero extra install on DSH Desktop**; when nothing is found a clear error tells you what to do (including the per-profile install command).
|
|
194
221
|
|
|
195
222
|
## Division of labor with the desktop shell
|
|
196
223
|
|
|
@@ -198,42 +225,48 @@ The browser's **visible view**, the **browser column layout**, and the **column-
|
|
|
198
225
|
|
|
199
226
|
## Requirements
|
|
200
227
|
|
|
201
|
-
- DeepSeek Harness (dsh) with the `web`
|
|
202
|
-
- **Electron runtime** (optional peer dependency):
|
|
228
|
+
- DeepSeek Harness (dsh) with the matching profile (`web` / `desktop`, etc.)
|
|
229
|
+
- **Electron runtime** (optional peer dependency):
|
|
230
|
+
- **DSH Desktop**: the host itself runs on Electron — the plugin reuses the host binary automatically, **zero extra install**;
|
|
231
|
+
- **plain `dsh web` self-hosted**: an Electron binary is required and located automatically (see above; ≥ 40 recommended; 44+ downloads its binary on first use, needs network)
|
|
203
232
|
|
|
204
233
|
### Verified versions
|
|
205
234
|
|
|
206
235
|
| Component | Version |
|
|
207
236
|
| --- | --- |
|
|
208
|
-
| DeepSeek Harness (dsh) | `0.1.0-rc.
|
|
209
|
-
| Electron | `
|
|
237
|
+
| DeepSeek Harness (dsh) | `0.1.1-rc.2` (peer range `^0.1.1-rc.2`) |
|
|
238
|
+
| Electron | `44.0.0` (≥ 40 recommended; 33.x has a compositor defect) |
|
|
210
239
|
| Node.js | `22.20.0` |
|
|
211
|
-
| dsh-builtin-browser | `0.1.
|
|
240
|
+
| dsh-builtin-browser | `0.1.17` |
|
|
212
241
|
| OS | Windows 10 (10.0.26200) |
|
|
213
242
|
|
|
214
243
|
> The plugin declares `electron >= 30`; it has **only been verified on Windows** (macOS/Linux untested, not yet promised).
|
|
215
244
|
|
|
216
245
|
## Known limitations
|
|
217
246
|
|
|
218
|
-
-
|
|
247
|
+
- JPEG screenshots are available only on the self-hosted native path (`capturePage` `toJPEG`); the desktop shell's CDP fallback stays PNG (CDP JPEG hangs on Electron 43).
|
|
219
248
|
- 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.
|
|
220
249
|
- `fullPage` capture is flaky under software compositing on some hosts.
|
|
221
250
|
- CAPTCHA cannot be solved automatically: snapshots flag detected challenges; ask the human to complete it in the shared window instead of retrying.
|
|
222
251
|
- Private mode (`privateMode`) is not implemented: it needs Electron session partitioning, which is host-layer territory; this plugin does not promise it.
|
|
223
|
-
- `browser_download` fetches in the page context (keeps logins) and is subject to same-origin/CORS constraints; single files are capped at 256 MB.
|
|
252
|
+
- `browser_download` fetches in the page context (keeps logins) and is subject to same-origin/CORS constraints; HTTP(S) targets only; `savePath` must be absolute (default confined to `~/Downloads`, override with `downloadDir`); single files are capped at 256 MB (streamed with a Content-Length early reject) and are written by the browser child itself (temp file + atomic rename).
|
|
253
|
+
- The self-hosted browser's cookies are stored in plaintext on disk (Electron default); deployments that need encrypted-at-rest should integrate a system keychain / DPAPI at the host layer.
|
|
254
|
+
- `browser_restrict` is a **soft guardrail** against accidental actions, not a security boundary: the model can lift it itself.
|
|
255
|
+
- Popups (`window.open` / `target=_blank`) are re-routed into the current tab instead of opening untracked native windows, so the tab/session model stays intact.
|
|
224
256
|
- 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.
|
|
225
257
|
- 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.
|
|
258
|
+
- Electron 44+ downloads its binary (~100 MB) on the first window open and needs network; it is never needed again afterwards. If detection runs without network, pre-install a binary and point `ELECTRON_PATH` at it.
|
|
226
259
|
- This plugin contains no browser-column UI — that is host-shell territory; do not treat "browser column" as a plugin feature.
|
|
227
260
|
|
|
228
261
|
## Development
|
|
229
262
|
|
|
230
263
|
```sh
|
|
231
264
|
# Type-check + build (lib/)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
# Functional tests: start a local page server + Electron probe (see repo test scripts)
|
|
265
|
+
npm run build
|
|
235
266
|
```
|
|
236
267
|
|
|
268
|
+
> Run tests: `npm test` (= `tsc -p tsconfig.json` + `node --test "tests/*.test.mjs"`; fake-host tests, no Electron needed).
|
|
269
|
+
|
|
237
270
|
Code layout:
|
|
238
271
|
|
|
239
272
|
| Directory | Responsibility |
|
|
@@ -243,6 +276,23 @@ Code layout:
|
|
|
243
276
|
| `src/tool-browser/` | Model-facing `browser_*` tools |
|
|
244
277
|
| `src/types/` | Electron ambient types (shim; no hard electron type dependency) |
|
|
245
278
|
|
|
279
|
+
## Update history
|
|
280
|
+
|
|
281
|
+
> Round-by-round development and fixes (full detail in [CHANGELOG.md](CHANGELOG.md)). Published as of **0.1.16** (tag `v0.1.16`).
|
|
282
|
+
|
|
283
|
+
| Round | Date | Content |
|
|
284
|
+
| --- | --- | --- |
|
|
285
|
+
| 1 | 2026-08-18 | **Security & robustness**: random-token RPC auth + single connection; download admission (HTTP(S) only, absolute path, `downloadDir`-confined) with streamed caps (Content-Length early reject, 256 MB max); CDP timeout interrupts and click/type timeout key-release recovery; per-task sessions/allow-lists with agent-lifecycle auto-close; history redaction (typed text, replay/execute args not leaked); popup re-routing into the tab |
|
|
286
|
+
| 2 | 2026-08 | **Feature completion + tests + CI**: window title shows the task; flicker-free showView; snapshots/a11y pierce same-origin iframes & Shadow DOM; new `browser_wait`/`scroll`/`back`/`forward`/`key` tools; real `available()` probe; child-side downloads (temp file + atomic rename); constrained Electron lookup; JPEG/scaled screenshots; snapshot perf; test suite + CI |
|
|
287
|
+
| 3 | 2026-08 | **browser-bridge parity + review fixes**: `browser_a11y` a11y tree; 6 form-control tools (`browser_set_value`/`check`/`select`/`clear`/`get_value`/`refresh`); semantic `target` (css/text/xpath); `browser_scrape` structured extraction; independent BrowserWindow + real toolbar (address bar, back/forward/reload, tab strip) routed back into the session model; tool count **20 → 33**; CI switched to npm (no lockfile → pnpm cache broken), README corrections |
|
|
288
|
+
| 4 | 2026-08 | **DSH 0.1.1-rc.2 alignment + review fixes**: peer floor `^0.1.1-rc.2`; fixed `browser_type` dropping text with a target, `browser_key` Space missing CDP `text`, keyUp failure sticking a key, `browser_wait` same-origin URL mis-match, `.part` rename residue, `snapshotMaxElements`/`contentMaxChars` config wiring, missing type exports; 3 regression tests |
|
|
289
|
+
| 5 | 2026-08 | **Electron 44 compatibility**: `available()` is now side-effect free (no more triggering Electron 44 lazy download); `flushAuth` cookie-domain build fix |
|
|
290
|
+
| 6 | 2026-08 | **Windows handshake & tab lookup**: the Electron GUI process never receives piped stdin → RPC token now flows over **stdin + env var**; `browser_switch_tab`/`browser_close_tab` locate tabs across sessions (`locateTab`), `browser_close_tab` no longer fakes success, unknown ids error with the session's actual tab list |
|
|
291
|
+
| 7 | 2026-08 | **Toolbar interaction (Windows focus routing)**: keyboard input only reaches the focused view and the page view grabbed it, so the address bar could not receive input → added `wireFocusRouting` (clicking a view focuses it) + window refocus restores the last-clicked view; verified with real OS input probes |
|
|
292
|
+
| **0.1.16** | 2026-08-26 | **Release**: all seven rounds ship as **0.1.16** (build clean, 21/21 tests pass, `v0.1.16`) |
|
|
293
|
+
| 8 | 2026-08-27 | **DSH Desktop host-Electron reuse**: running inside an Electron process reuses the host binary directly; when the host runs the plugin in a child Node process, walk the process ancestry to find the host's Electron (PowerShell CIM on Windows, last resort only) — **DSH Desktop works with zero install**; error now hints per active profile; electron shim completed to fix the CI typecheck; docs updated |
|
|
294
|
+
| **0.1.17** | 2026-08-27 | **Release**: round 8 ships as **0.1.17** (build clean, 21/21 tests pass) |
|
|
295
|
+
|
|
246
296
|
## Acknowledgements
|
|
247
297
|
|
|
248
298
|
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.
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
| --- | --- |
|
|
19
19
|
| 了解插件为什么存在、与无头方案的区别 | [为什么做共享真实浏览器](docs/why-browser.md) |
|
|
20
20
|
| 安装、配置与日常使用 | [用户指南](docs/user-guide.md) |
|
|
21
|
-
| 全部
|
|
21
|
+
| 全部 33 个工具的参数、输出与示例 | [工具参考](docs/tool-reference.md) |
|
|
22
22
|
| 了解 seam / provider / 工具三层与自托管实现 | [架构说明](docs/architecture.md) |
|
|
23
23
|
| 查看全部文档与 README 分工 | [文档索引](docs/README.md) |
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
- **真实视图,而非转播**:浏览器是原生 `WebContentsView`,用户直接看到 agent 在做什么,随时可以上手接管;
|
|
30
30
|
- **装好即用**:有桌面外壳时嵌入外壳视图;纯 `dsh web` 也能**自托管**——插件自己拉起一个 Electron 窗口,不需要任何额外配置;
|
|
31
|
-
- **一插件即一套工具**:安装后 agent 自动获得
|
|
31
|
+
- **一插件即一套工具**:安装后 agent 自动获得 33 个 `browser_*` 工具(打开、查看、无障碍树、等待、语义/坐标操作、滚动、回退、批量/单控件填表、按键、结构化提取、截图、下载、登录态管理……)。
|
|
32
32
|
|
|
33
33
|
一句话:**安装插件 = 获得一个与用户共享、可被 agent 驱动的真实浏览器。**
|
|
34
34
|
|
|
@@ -131,13 +131,26 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
131
131
|
| 工具 | 用途 | 守卫 |
|
|
132
132
|
| --- | --- | --- |
|
|
133
133
|
| `browser_open` | 打开 URL(可选新标签),返回页面快照 | ✅ |
|
|
134
|
-
| `
|
|
134
|
+
| `browser_wait` | 等待页面加载完成(可选期望 URL / CSS 选择器),返回是否就绪 | – |
|
|
135
|
+
| `browser_snapshot` | 交互元素(输入框/按钮/链接)带编号清单(穿透同源 iframe 与 Shadow DOM) | – |
|
|
136
|
+
| `browser_a11y` | 无障碍树:每个交互节点的语义角色/名称/值/状态 + 坐标(穿透同源 iframe 与 Shadow DOM) | – |
|
|
135
137
|
| `browser_execute` | 在页面执行 JS;参数以 `arguments[0..n]` 传入 | ✅ |
|
|
136
138
|
| `browser_content` | 以 html / markdown / txt / json 抓取页面(selector、maxChars、timeoutMs) | – |
|
|
137
|
-
| `browser_click` |
|
|
138
|
-
| `browser_type` |
|
|
139
|
+
| `browser_click` | 点击:语义目标(`target`: css/text/xpath,滚动到元素并点中心)或视口坐标(配合截图视觉定位) | ✅ |
|
|
140
|
+
| `browser_type` | 输入文本(可先按 `target` 聚焦元素;CDP `Input.insertText`) | ✅ |
|
|
141
|
+
| `browser_key` | 按命名按键(Enter/Tab/方向键/Home/End 等) | ✅ |
|
|
142
|
+
| `browser_scroll` | 滚动页面(像素增量 / 选择器定位 / 顶部底部) | ✅ |
|
|
143
|
+
| `browser_back` | 页面历史后退一步(无前项时为空操作) | ✅ |
|
|
144
|
+
| `browser_forward` | 页面历史前进一步(无后项时为空操作) | ✅ |
|
|
145
|
+
| `browser_refresh` | 刷新当前页(等价浏览器的刷新按钮) | ✅ |
|
|
139
146
|
| `browser_fill` | 批量填充表单(选择器/名称/标签匹配,受控输入、下拉、单选/复选,可选提交) | ✅ |
|
|
140
|
-
| `
|
|
147
|
+
| `browser_set_value` | 单个控件设值(按 `target` 定位;原生 setter + input/change,React 受控输入可用) | ✅ |
|
|
148
|
+
| `browser_check` | 勾选/取消勾选 checkbox 或 radio(按 `target` 定位) | ✅ |
|
|
149
|
+
| `browser_select` | 选中 `<select>` 的某个选项(按值/文本/索引,按 `target` 定位) | ✅ |
|
|
150
|
+
| `browser_clear` | 清空输入/文本域/contenteditable,或取消勾选(按 `target` 定位) | ✅ |
|
|
151
|
+
| `browser_get_value` | 读取元素当前值(操作后验证用;按 `target` 定位) | – |
|
|
152
|
+
| `browser_scrape` | 结构化提取:容器选择器 + 字段映射(`选择器[@属性]`),静态 CSS 查询、CSP 安全 | – |
|
|
153
|
+
| `browser_screenshot` | 截图,可选 `fullPage`、`savePath`、JPEG(`format`/`quality`)与缩放(`maxWidth`/`maxHeight`) | – |
|
|
141
154
|
| `browser_list_tabs` | 当前会话的标签列表 | – |
|
|
142
155
|
| `browser_switch_tab` | 按 id 切换标签(自托管下同步切换可见视图) | ✅ |
|
|
143
156
|
| `browser_close_tab` | 按 id 关闭标签;关闭活动标签后激活下一个 | – |
|
|
@@ -146,13 +159,24 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
146
159
|
| `browser_reset_session` | 关闭并重建本任务的浏览器会话 | ✅ |
|
|
147
160
|
| `browser_history` | 操作日志(最新在后),含成功/失败与结果摘要 | – |
|
|
148
161
|
| `browser_replay` | 按序号回放某一步(navigate/execute/click/type) | ✅ |
|
|
149
|
-
| `browser_download` | 带会话 cookie 下载 URL 到本地文件(
|
|
162
|
+
| `browser_download` | 带会话 cookie 下载 HTTP(S) URL 到本地文件(`savePath` 必须绝对路径,上限 256MB) | ✅ |
|
|
150
163
|
| `browser_auth` | 导出/恢复 cookie(登录态持久化,自托管可用) | ✅ |
|
|
151
164
|
| `browser_challenge` | 检测人机验证(CAPTCHA / Cloudflare / reCAPTCHA / hCaptcha / Turnstile) | – |
|
|
152
|
-
| `browser_restrict` | 限制允许的浏览器动作(白名单;空列表解除) | – |
|
|
165
|
+
| `browser_restrict` | 限制允许的浏览器动作(白名单;空列表解除)。**软护栏**,模型可自行解除,非安全边界 | – |
|
|
153
166
|
|
|
154
167
|
> 「守卫」列:打 ✅ 的动作受 `browser_restrict` 白名单约束;只读工具(snapshot/content/screenshot/list_tabs/session/challenge/history)永不拦截。
|
|
155
168
|
|
|
169
|
+
### 等待页面就绪
|
|
170
|
+
|
|
171
|
+
- **`browser_open` 之后、`browser_snapshot` 之前,慢站点请先 `browser_wait`**:传 `url`(你打开的地址)与可选的 `selector`,等它返回 `ready: true` 再拍照——否则拍到的是旧页面或白屏。
|
|
172
|
+
- 页面里看不到的内容先想 iframe / Shadow DOM:快照与无障碍树会穿透同源 iframe 与 shadow root 并标注 `(iframe)`,坐标始终是顶层文档坐标,可直接用 `browser_click`;DOM 选择器则是 frame 作用域的,需用 `browser_execute` 经 `iframe.contentDocument` 访问。
|
|
173
|
+
|
|
174
|
+
### 语义定位(`target`)与无障碍树
|
|
175
|
+
|
|
176
|
+
- **`browser_a11y` 是理解页面的首选**:它返回每个交互节点的语义角色(button/textbox/checkbox…)、可访问名称、当前值、状态(enabled/checked/expanded…)与坐标,比编号快照更能说明“这是什么、能做什么”;拿到坐标后可直接 `browser_click`/`browser_type`。
|
|
177
|
+
- **`browser_click`/`browser_type` 支持 `target` 定位**:`{by: css|text|xpath, value, index?}`——`text` 按元素自身可见文本匹配(精确优先、退化包含、最深元素优先);点击会把元素滚动到视口中央再点;输入会先聚焦该元素。
|
|
178
|
+
- **单控件操作用 `browser_set_value`/`browser_check`/`browser_select`/`browser_clear`/`browser_get_value`**,批量用 `browser_fill`,列表页结构化抓取用 `browser_scrape`。
|
|
179
|
+
|
|
156
180
|
### 操作纪律(点击/填表)
|
|
157
181
|
|
|
158
182
|
- **优先用 DOM 语义而非坐标**:表单提交优先 `form.requestSubmit()`;点击优先 `element.click()`;坐标点击是最后手段。
|
|
@@ -171,6 +195,7 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
171
195
|
| `browser-electron` | `httpOnly` | 布尔 | `true` | 仅允许 HTTP(S) 导航;其余协议(如 `file:`/`data:`)拒绝(`BROWSER_NAVIGATION_BLOCKED`) |
|
|
172
196
|
| `browser-electron` | `snapshotMaxElements` | 数字 | `60` | 快照最多收录的交互元素数,超出截断 |
|
|
173
197
|
| `browser-electron` | `contentMaxChars` | 数字 | `100000` | 内容抓取默认字符上限 |
|
|
198
|
+
| `browser-electron` | `downloadDir` | 字符串 | `~/Downloads` | 限定 `browser_download` 保存路径必须位于该目录内(防 agent 写任意路径);默认收敛到系统下载目录,可改为沙箱目录 |
|
|
174
199
|
| `tool-browser` | `timeoutMs` | 数字 | `60000` | 工具协作超时(ms) |
|
|
175
200
|
| `tool-browser` | `tabTools` | 布尔 | `true` | 是否注册标签管理工具(`browser_list_tabs` 等) |
|
|
176
201
|
|
|
@@ -186,11 +211,13 @@ agent (browser_* 工具)
|
|
|
186
211
|
|
|
187
212
|
- **seam 层**(`browser` 行)提供 `ctx.browser` 服务:provider 注册、会话生命周期、错误码,与具体实现解耦;
|
|
188
213
|
- **provider 层**(`browser-electron` 行)通过 `ElectronBrowserViewHost` 接缝操作视图(创建/销毁/显示/`sendCommand`),由真实外壳用 Electron 对象实现;
|
|
189
|
-
- **工具层**(`tool-browser` 行)提供模型侧的
|
|
214
|
+
- **工具层**(`tool-browser` 行)提供模型侧的 33 个 `browser_*` 工具,按调用方任务(DSH 会话)维护独立的浏览器会话。
|
|
215
|
+
|
|
216
|
+
**自托管模式**:没有桌面外壳时,插件自己拉起一个 Electron 子进程(`host-main.js`),通过本机 TCP JSON-RPC 驱动。RPC 带随机 token 认证,token 经 **stdin + 环境变量双通道**传递——Windows 上 Electron 是 GUI 子系统进程、收不到 piped stdin,环境变量兜底保证握手稳定。子进程崩溃会自动重启;截图优先走 Electron 原生 `capturePage`(CDP 截图在多视图下会挂起),并自动选择环境中**最新版本**的 Electron(33.x 有合成器缺陷,建议 ≥ 40;44+ 首次使用自动下载二进制,需联网)。
|
|
190
217
|
|
|
191
|
-
|
|
218
|
+
**自托管浏览器就是一台真正的浏览器**:每个任务(DSH 会话)拥有**独立的浏览器窗口**,窗口自带完整工具栏——地址栏、后退/前进/刷新按钮、标签条(新建/切换/关闭标签)。人可以直接像用 Chrome 一样使用它:在地址栏输入网址(自动补 `https://`)、点标签切换页面、开新标签;键盘焦点跟随点击——**点地址栏即可输入、点页面即可操作**(Windows 焦点路由,修复了点击不转移焦点导致地址栏无法输入的问题)。agent 与人的操作都汇入**同一个会话模型**(同一套标签、历史与导航),窗口标题实时显示当前任务标识与页面标题/URL,窗口缩放时视图自动跟随。任务结束后窗口随会话自动关闭。
|
|
192
219
|
|
|
193
|
-
**Electron 定位顺序**:① `require('electron')`(peer 依赖)→
|
|
220
|
+
**Electron 定位顺序**:① 插件运行在 Electron 进程内(DSH Desktop 主进程)时直接复用宿主二进制 → ② 进程祖先树中的宿主 Electron 二进制(DSH Desktop 把插件跑在子 Node 进程时的兜底)→ ③ `require('electron')`(peer 依赖)→ ④ `ELECTRON_PATH`(显式覆盖)→ ⑤ DSH 安装锚点与 pnpm 虚拟仓库中**版本最新**者。**DSH Desktop 上零额外安装**;找不到时工具会报清晰的错误提示(含按当前 profile 的安装命令)。
|
|
194
221
|
|
|
195
222
|
## 与桌面外壳的分工
|
|
196
223
|
|
|
@@ -198,42 +225,48 @@ agent (browser_* 工具)
|
|
|
198
225
|
|
|
199
226
|
## 环境要求
|
|
200
227
|
|
|
201
|
-
- DeepSeek Harness(dsh)
|
|
202
|
-
- **Electron 运行时**(可选 peer 依赖)
|
|
228
|
+
- DeepSeek Harness(dsh),已安装对应 profile(`web` / `desktop` 等)
|
|
229
|
+
- **Electron 运行时**(可选 peer 依赖):
|
|
230
|
+
- **DSH Desktop**:宿主本身基于 Electron,**插件自动复用宿主二进制,零额外安装**;
|
|
231
|
+
- **纯 `dsh web` 自托管**:需要 Electron 二进制,插件自动定位(见上,建议 ≥ 40;44+ 首次使用自动下载,需网络)
|
|
203
232
|
|
|
204
233
|
### 验证过的版本
|
|
205
234
|
|
|
206
235
|
| 组件 | 版本 |
|
|
207
236
|
| --- | --- |
|
|
208
|
-
| DeepSeek Harness(dsh) | `0.1.0-rc.
|
|
209
|
-
| Electron | `
|
|
237
|
+
| DeepSeek Harness(dsh) | `0.1.1-rc.2`(peer 声明 `^0.1.1-rc.2`) |
|
|
238
|
+
| Electron | `44.0.0`(推荐 ≥ 40;33.x 存在合成器缺陷) |
|
|
210
239
|
| Node.js | `22.20.0` |
|
|
211
|
-
| dsh-builtin-browser | `0.1.
|
|
240
|
+
| dsh-builtin-browser | `0.1.17` |
|
|
212
241
|
| 操作系统 | Windows 10 (10.0.26200) |
|
|
213
242
|
|
|
214
243
|
> 插件声明 `electron >= 30`;**当前仅在 Windows 环境实测**(macOS/Linux 未验证,暂不承诺)。
|
|
215
244
|
|
|
216
245
|
## 已知限制
|
|
217
246
|
|
|
218
|
-
-
|
|
247
|
+
- JPEG 截图仅自托管原生路径可用(`capturePage` 的 `toJPEG`);桌面壳的 CDP 回退路径仍为 PNG(CDP JPEG 在 Electron 43 上挂起)。
|
|
219
248
|
- 自托管截图优先走 Electron 原生 `capturePage`(CDP `captureScreenshot` 在多视图下会挂起);截图前自动把目标标签置顶。
|
|
220
249
|
- 部分主机在软件合成下 `fullPage` 截图不稳定。
|
|
221
250
|
- 人机验证(CAPTCHA)无法自动解决:快照会标注检测到的挑战,此时应请用户在共享窗口中人工完成,而不是反复重试。
|
|
222
251
|
- 无痕模式(`privateMode`)未实现:它需要 Electron 的 session 分区能力,属于宿主层,本插件不承诺。
|
|
223
|
-
- `browser_download` 在页面上下文内 `fetch`(带登录态),受同源/CORS
|
|
252
|
+
- `browser_download` 在页面上下文内 `fetch`(带登录态),受同源/CORS 约束;仅允许 HTTP(S) 目标;`savePath` 必须为绝对路径(默认限定在 `~/Downloads`,可用 `downloadDir` 覆盖);单文件上限 256MB(流式限流,按 Content-Length 提前拒绝),文件由浏览器子进程直接落盘(临时文件 + 原子改名)。
|
|
253
|
+
- 自托管浏览器的 cookie 在磁盘上以明文存储(Electron 默认行为);需要加密落盘的部署应在宿主层接入系统钥匙串 / DPAPI。
|
|
254
|
+
- `browser_restrict` 是防误操作的**软护栏**,不是安全边界:模型可以自行解除白名单。
|
|
255
|
+
- 页面弹窗(`window.open` / `target=_blank`)会被重定向到当前标签页内打开,不创建独立窗口,以免破坏标签/会话模型。
|
|
224
256
|
- `browser_auth` 的 cookie 往返不保留 `hostOnly`/`sameSite` 字段(host-only cookie 恢复后变成 domain cookie);仅自托管浏览器可用。
|
|
225
257
|
- 自托管浏览器子进程崩溃后会自动重启,但崩溃前已打开的会话视图已失效,调用 `browser_reset_session` 重建即可。
|
|
258
|
+
- Electron 44+ 首次打开浏览器窗口时会自动下载二进制(约 100MB,需网络);之后不再需要。若探测时网络不可用,可预装 `ELECTRON_PATH` 指定的二进制。
|
|
226
259
|
- 本插件不含浏览器列 UI——那是宿主外壳的配套,别把"浏览器列"当成插件能力。
|
|
227
260
|
|
|
228
261
|
## 开发
|
|
229
262
|
|
|
230
263
|
```sh
|
|
231
264
|
# 类型检查 + 构建(lib/)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
# 功能测试:启动本地页面服务器 + Electron probe(见仓库测试脚本)
|
|
265
|
+
npm run build
|
|
235
266
|
```
|
|
236
267
|
|
|
268
|
+
> 运行测试: `npm test`(= `tsc -p tsconfig.json` + `node --test "tests/*.test.mjs"`,假 host 测试,无需 Electron)。
|
|
269
|
+
|
|
237
270
|
代码结构:
|
|
238
271
|
|
|
239
272
|
| 目录 | 职责 |
|
|
@@ -243,6 +276,23 @@ pnpm run build
|
|
|
243
276
|
| `src/tool-browser/` | 模型侧 `browser_*` 工具 |
|
|
244
277
|
| `src/types/` | electron 环境类型(shim,避免强制依赖 electron 类型) |
|
|
245
278
|
|
|
279
|
+
## 更新记录
|
|
280
|
+
|
|
281
|
+
> 按轮次记录的开发与修复历程(完整明细见 [CHANGELOG.md](CHANGELOG.md))。**0.1.16** 起随版本发布(tag `v0.1.16`)。
|
|
282
|
+
|
|
283
|
+
| 轮次 | 日期 | 内容 |
|
|
284
|
+
| --- | --- | --- |
|
|
285
|
+
| 第一轮 | 2026-08-18 | **安全与健壮性修复**:RPC 随机 token 认证 + 单连接强制;下载准入(仅 HTTP(S)、绝对路径、`downloadDir` 限定)与流式限流(Content-Length 提前拒绝,256MB 上限);CDP 超时打断与 click/type 超时松键恢复;会话/白名单改为每任务作用域并随 agent 生命周期自动关闭;操作历史脱敏(输入文本、replay/execute 参数不泄露);弹窗重定向回标签页 |
|
|
286
|
+
| 第二轮 | 2026-08 | **功能补全 + 测试 + CI**:窗口标题显示任务标识、showView 无闪烁;快照/无障碍树穿透同源 iframe 与 Shadow DOM;新增 `browser_wait`/`scroll`/`back`/`forward`/`key` 工具;真实 `available()` 探测;下载改由子进程直接落盘(临时文件 + 原子改名);Electron 定位收敛;JPEG/缩放截图;快照性能优化;新增测试套件与 CI |
|
|
287
|
+
| 第三轮 | 2026-08 | **对标 browser-bridge 的功能 + 审查修复**:`browser_a11y` 无障碍树;表单控件 6 件套(`browser_set_value`/`check`/`select`/`clear`/`get_value`/`refresh`);语义定位 `target`(css/text/xpath);`browser_scrape` 结构化提取;独立 BrowserWindow + 真实工具栏(地址栏/后退/前进/刷新/标签条),工具栏操作路由回会话模型;工具总数 **20 → 33**;CI 改 npm(无 lockfile 不兼容 pnpm cache)、README 修正等审查项 |
|
|
288
|
+
| 第四轮 | 2026-08 | **DSH 0.1.1-rc.2 对齐 + 复查修复**:peer 下限对齐 `^0.1.1-rc.2`;修复 `browser_type` 带 target 丢文本、`browser_key` 空格缺 CDP `text`、keyUp 失败卡键、`browser_wait` URL 同源误匹配、download `.part` rename 残留、`snapshotMaxElements`/`contentMaxChars` 配置接线、导出类型补齐;新增 3 个回归测试 |
|
|
289
|
+
| 第五轮 | 2026-08 | **Electron 44 兼容**:`available()` 改为无副作用探测(不再触发 Electron 44 懒下载);`flushAuth` cookie-domain 构建错误修复 |
|
|
290
|
+
| 第六轮 | 2026-08 | **Windows 握手与标签定位**:Electron GUI 进程收不到 piped stdin → RPC token 改 **stdin + 环境变量双通道**;`browser_switch_tab`/`browser_close_tab` 跨会话按 id 定位(`locateTab`),`browser_close_tab` 不再静默假成功,未知 id 报错附带现有标签列表 |
|
|
291
|
+
| 第七轮 | 2026-08 | **工具栏交互(Windows 焦点路由)**:键盘输入只进有焦点的 view,页面 view 抢占焦点导致地址栏无法输入 → 新增 `wireFocusRouting`(点击即聚焦该 view)+ 窗口 refocus 恢复上次点击的 view;真机 OS 输入探针验证 |
|
|
292
|
+
| **0.1.16** | 2026-08-26 | **发布**:以上七轮全部随 **0.1.16** 发布(构建零错误、21 项测试全绿,`v0.1.16`) |
|
|
293
|
+
| 第八轮 | 2026-08-27 | **DSH Desktop 宿主 Electron 复用**:插件运行在 Electron 进程内直接复用宿主二进制;插件跑在宿主子 Node 进程时沿进程祖先树找到宿主 Electron 兜底(Windows 用 PowerShell CIM,仅最后手段)——DSH Desktop **零安装开箱可用**;报错按当前 profile 动态提示;补齐 electron shim 修复 CI 类型检查;文档同步 |
|
|
294
|
+
| **0.1.17** | 2026-08-27 | **发布**:第八轮修复随 **0.1.17** 发布(构建零错误、21 项测试全绿) |
|
|
295
|
+
|
|
246
296
|
## 特别感谢
|
|
247
297
|
|
|
248
298
|
特别感谢 [DeepSeek Harness 原始仓库](https://github.com/deepseek-ai/deepseek-harness) 与 DeepSeek AI 团队:本插件的 seam、工具运行时与插件体系都构建在这个项目之上。
|
package/docs/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| --- | --- |
|
|
7
7
|
| 了解插件为什么存在、与无头方案的区别 | [为什么做共享真实浏览器](why-browser.md) |
|
|
8
8
|
| 安装、配置、日常使用与常见问题 | [用户指南](user-guide.md) |
|
|
9
|
-
| 全部
|
|
9
|
+
| 全部 25 个工具的参数、输出与示例 | [工具参考](tool-reference.md) |
|
|
10
10
|
| 了解 seam / provider / 工具三层与自托管实现 | [架构说明](architecture.md) |
|
|
11
11
|
| 回到项目首页 | [README](../README.md) |
|
|
12
12
|
|
package/docs/architecture.md
CHANGED
|
@@ -37,11 +37,13 @@ agent (browser_* 工具)
|
|
|
37
37
|
|
|
38
38
|
### 工具层(`src/tool-browser/`)
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
25 个 `browser_*` 工具,按**调用方任务**(`exec.agent.id`)维护独立浏览器会话:
|
|
41
41
|
|
|
42
42
|
- 会话缓存 `sessionsByTask`:同一任务复用同一会话,并发首开去重;
|
|
43
43
|
- `browser_reset_session` 关闭本任务会话并遗忘映射(即使 close 抛错也清除,下次调用重建);
|
|
44
|
-
-
|
|
44
|
+
- 会话生命周期绑定 agent 作用域 ctx:agent(DSH 会话)销毁时自动关闭对应浏览器会话,任务结束后不再泄漏窗口/视图;
|
|
45
|
+
- 会话/开启动态/白名单都是**每插件实例(每 context)作用域**的,多 context 互不共享、互不污染;
|
|
46
|
+
- `browser_restrict` 维护本实例白名单,守卫所有非只读工具;
|
|
45
47
|
- 输出 schema 与返回值严格一致(DSH 运行时会校验,`additionalProperties: false` 下多一个字段都会报错)。
|
|
46
48
|
|
|
47
49
|
## 自托管实现(纯 `dsh web`)
|
|
@@ -57,9 +59,10 @@ RemoteElectronViewHost ──TCP JSON-RPC──▶ host-main.js
|
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
- **协议**:本机 loopback TCP,每行一个 JSON(`{ id, op, ... }` ↔ `{ id, ok, result|err }`);
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
62
|
+
- **认证**:每次 spawn 生成随机 token(经 `--rpc-token` 传入),子进程首条消息必须回传该 token(`hello`);服务端只接受**一个**连接,其余连接直接断开——本机其他进程无法伪冒子进程或注入回复;
|
|
63
|
+
- **Electron 定位**:① 插件运行在 Electron 进程内(DSH Desktop 主进程)时直接复用宿主二进制(`process.execPath`);② 进程祖先树中的宿主 Electron 二进制(DSH Desktop 把插件跑在子 Node 进程时的兜底,Windows 用 PowerShell CIM 查询,仅在其它路径全部落空时才执行)→ ③ peer 依赖 → ④ `ELECTRON_PATH` → ⑤ 锚点与 pnpm store 中**版本最新**者(33.x 有合成器缺陷,建议 ≥ 40);
|
|
64
|
+
- **稳健性**:子进程/套接字都有 `error` 监听(否则未捕获事件会炸掉整个 DSH 进程);子进程退出自动重启;物化失败可重试;下载仅限 HTTP(S)、`savePath` 必须绝对路径(默认限定 `~/Downloads`,可配置 `downloadDir` 覆盖)、流式限流 + Content-Length 提前拒绝、256MB 上限与 60s 超时,文件由**子进程直接落盘**(临时文件 + rename,不再经 RPC 传 base64);cookie 导出/恢复有 30s 超时;
|
|
65
|
+
- **视图可见性**:多标签/多会话时,`showView` 隐藏其他视图并把目标视图置顶(remove+re-add),确保用户看到的是活动标签;目标是当前可见视图时**跳过** remove/re-add(否则每次操作都闪烁);窗口标题实时显示当前可见会话的任务标识 + 页面标题/URL(`showView` 携带会话 label,子进程读 `getTitle`/`getURL`);窗口 resize 时视图 bounds 自动跟随;
|
|
63
66
|
- **孤儿防护**:父进程断开时子进程自动退出,不留僵尸窗口;
|
|
64
67
|
- **cookie 落盘**:子进程使用独立 userData 目录(`<DSH_HOME>/dsh-builtin-browser-host`),登录态跨重启保留(另有 `browser_auth` 手动导出/恢复)。
|
|
65
68
|
|
package/docs/tool-reference.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# 工具参考
|
|
2
2
|
|
|
3
|
-
全部
|
|
3
|
+
全部 33 个 `browser_*` 工具。守卫列:✅ 表示该动作受 `browser_restrict` 白名单约束;只读工具永不拦截。
|
|
4
4
|
|
|
5
5
|
## 页面与导航
|
|
6
6
|
|
|
7
7
|
| 工具 | 参数 | 输出 | 守卫 | 说明 |
|
|
8
8
|
| --- | --- | --- | --- | --- |
|
|
9
9
|
| `browser_open` | `url`(必填), `newTab?` | 快照(url/title/elements/truncated/challenge) | ✅ | 打开 URL,返回带编号元素的快照;`newTab: true` 在新标签打开 |
|
|
10
|
-
| `
|
|
10
|
+
| `browser_wait` | `timeoutMs?`, `url?`, `selector?` | `{ ready, reason }` | – | 等待页面加载完成(可选期望 URL / CSS 选择器);未就绪不抛错,返回原因 |
|
|
11
|
+
| `browser_snapshot` | – | 快照 | – | 交互元素(输入框/按钮/链接)编号清单,供定位与点击;穿透同源 iframe 与 Shadow DOM,iframe 内元素标注 `frame` |
|
|
12
|
+
| `browser_a11y` | `includeHidden?`, `maxNodes?`(10-5000,默认 500) | `{ url, title?, count, nodes[], truncated }` | – | 无障碍树:每个交互节点的 `role`/`name`/`value`/`states`/`depth`/`tag`/坐标;优先 Chrome `computedRole`/`computedName`,穿透同源 iframe 与 Shadow DOM;坐标可直接喂 `browser_click`/`browser_type` |
|
|
11
13
|
| `browser_content` | `format`(html/markdown/txt/json,必填), `selector?`, `maxChars?`, `timeoutMs?` | `{ content, truncated }` | – | 抓取页面内容;`selector` 限定区域 |
|
|
12
14
|
| `browser_challenge` | – | `{ blocked, kind?, reason?, hint? }` | – | 检测人机验证(CAPTCHA/Cloudflare/reCAPTCHA/hCaptcha/Turnstile);阻塞时请用户处理 |
|
|
13
15
|
|
|
@@ -16,9 +18,20 @@
|
|
|
16
18
|
| 工具 | 参数 | 输出 | 守卫 | 说明 |
|
|
17
19
|
| --- | --- | --- | --- | --- |
|
|
18
20
|
| `browser_execute` | `script`(必填), `args?` | `{ ok, value? / exception? }` | ✅ | 在页面执行 JS;脚本以 `return` 开头或作为表达式;`args` 以 `arguments[0..n]` 传入 |
|
|
19
|
-
| `browser_click` | `x
|
|
20
|
-
| `browser_type` | `text`(必填) | `{ typed }` | ✅ |
|
|
21
|
+
| `browser_click` | `target?`(css/text/xpath), `x?`, `y?`(target 与坐标二选一) | `{ clicked }` | ✅ | 语义目标点击:按 `target` 定位、滚动到视口中央再点中心;或视口坐标点击(配合截图做视觉定位) |
|
|
22
|
+
| `browser_type` | `text`(必填), `target?` | `{ typed }` | ✅ | 输入文本;传 `target` 先聚焦该元素(CDP `Input.insertText`) |
|
|
23
|
+
| `browser_key` | `key`(必填,枚举) | `{ pressed }` | ✅ | 按命名按键:Enter/Tab/Escape/Backspace/Delete/方向键/Home/End/PageUp/PageDown/Space |
|
|
24
|
+
| `browser_scroll` | `deltaX?`, `deltaY?`, `selector?`, `toTop?`, `toBottom?` | `{ scrolled }` | ✅ | 滚动页面:像素增量 / 选择器定位 / 顶部底部 |
|
|
25
|
+
| `browser_back` | – | `{ back }` | ✅ | 页面历史后退一步(无前项时为空操作) |
|
|
26
|
+
| `browser_forward` | – | `{ forward }` | ✅ | 页面历史前进一步(无后项时为空操作) |
|
|
27
|
+
| `browser_refresh` | – | `{ refreshed }` | ✅ | 刷新当前页(等价浏览器刷新按钮) |
|
|
21
28
|
| `browser_fill` | `fields`(必填,数组), `submit?` | `{ fields[], submitted }` | ✅ | 批量填表;字段按 `selector`/`name`/`label`/`placeholder` 匹配,值支持字符串/数字/布尔;单个字段失败不影响其余;`submit: true` 提交表单 |
|
|
29
|
+
| `browser_set_value` | `target`(必填), `value`(必填) | `{ method, value }` | ✅ | 单个控件设值(按 css/text/xpath 定位);原生 setter + input/change,React 受控输入可用;select 按值/文本 |
|
|
30
|
+
| `browser_check` | `target`(必填), `checked?` | `{ checked }` | ✅ | 勾选/取消勾选 checkbox 或 radio(按 target 定位) |
|
|
31
|
+
| `browser_select` | `target`(必填), `optionValue?`/`optionText?`/`optionIndex?`(三选一) | `{ value, text }` | ✅ | 选中 `<select>` 的某个选项(按 target 定位) |
|
|
32
|
+
| `browser_clear` | `target`(必填) | `{ cleared }` | ✅ | 清空输入/文本域/contenteditable,或取消勾选 checkbox/radio |
|
|
33
|
+
| `browser_get_value` | `target`(必填) | `{ value?, checked?, selectedText? }` | – | 读取元素当前值,用于操作后验证 |
|
|
34
|
+
| `browser_scrape` | `item`(必填), `fields`(必填,映射), `timeoutMs?` | `{ count, items[] }` | – | 结构化提取:容器选择器 + 字段映射(如 `{"title": "h3", "url": "a@href"}`);静态 CSS 查询、不执行任意代码、CSP 安全;等待 item 出现(默认 5s) |
|
|
22
35
|
|
|
23
36
|
## 标签与会话
|
|
24
37
|
|
|
@@ -36,27 +49,27 @@
|
|
|
36
49
|
| 工具 | 参数 | 输出 | 守卫 | 说明 |
|
|
37
50
|
| --- | --- | --- | --- | --- |
|
|
38
51
|
| `browser_history` | – | `{ entries[] }` | – | 操作日志(最新在后),含 seq/action/ok/params/result/error |
|
|
39
|
-
| `browser_replay` | `seq`(必填) | `{ replayed }` | ✅ | 按序号回放某一步(navigate/execute/click/type) |
|
|
40
|
-
| `browser_download` | `url`(必填), `savePath`(必填) | `{ path }` | ✅ | 带会话 cookie 下载到本地(
|
|
52
|
+
| `browser_replay` | `seq`(必填) | `{ replayed }` | ✅ | 按序号回放某一步(navigate/execute/click/type/scroll/key) |
|
|
53
|
+
| `browser_download` | `url`(必填), `savePath`(必填) | `{ path }` | ✅ | 带会话 cookie 下载到本地(仅 http(s);`savePath` 必须为绝对路径,默认限定在 `~/Downloads`,可用 `downloadDir` 覆盖;上限 256MB,受 CORS 约束;由子进程直接落盘) |
|
|
41
54
|
|
|
42
55
|
## 登录态与安全
|
|
43
56
|
|
|
44
57
|
| 工具 | 参数 | 输出 | 守卫 | 说明 |
|
|
45
58
|
| --- | --- | --- | --- | --- |
|
|
46
59
|
| `browser_auth` | `action`(flush/restore,必填), `cookies?` | `{ cookies[]? / restored? }` | ✅ | 导出/恢复 cookie(自托管可用);flush 返回 cookie 列表,restore 带列表写回 |
|
|
47
|
-
| `browser_restrict` | `allowed?` | `{ restrictedTo[] }` | – |
|
|
60
|
+
| `browser_restrict` | `allowed?` | `{ restrictedTo[] }` | – | 设置动作白名单;空列表解除;未知工具名报错。**软护栏**——模型可自行解除,非安全边界 |
|
|
48
61
|
|
|
49
62
|
## 截图
|
|
50
63
|
|
|
51
64
|
| 工具 | 参数 | 输出 | 守卫 | 说明 |
|
|
52
65
|
| --- | --- | --- | --- | --- |
|
|
53
|
-
| `browser_screenshot` | `fullPage?`, `savePath?` | `{ dataUrl, path? }` | – | PNG
|
|
66
|
+
| `browser_screenshot` | `fullPage?`, `savePath?`, `format?`(png/jpeg), `quality?`, `maxWidth?`, `maxHeight?` | `{ dataUrl, path? }` | – | 截图;PNG 默认,JPEG 仅自托管原生路径;`maxWidth`/`maxHeight` 等比缩放降低视觉模型开销;`savePath` 落盘供视觉模型读取 |
|
|
54
67
|
|
|
55
68
|
## 常用组合
|
|
56
69
|
|
|
57
70
|
**调研一个网站**
|
|
58
71
|
```
|
|
59
|
-
browser_open https://site → browser_content format=markdown → browser_snapshot → 逐页浏览
|
|
72
|
+
browser_open https://site → browser_wait(url=...) → browser_content format=markdown → browser_snapshot → 逐页浏览
|
|
60
73
|
```
|
|
61
74
|
|
|
62
75
|
**登录并下载文件**
|
package/docs/user-guide.md
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## 环境要求
|
|
4
4
|
|
|
5
|
-
- DeepSeek Harness(dsh)
|
|
6
|
-
- **Electron 运行时**(可选 peer 依赖)
|
|
5
|
+
- DeepSeek Harness(dsh),已安装对应 profile(`web` / `desktop` 等)
|
|
6
|
+
- **Electron 运行时**(可选 peer 依赖):
|
|
7
|
+
- **DSH Desktop**:宿主本身基于 Electron,**插件自动复用宿主二进制,零额外安装**;
|
|
8
|
+
- **纯 `dsh web` 自托管**:需要 Electron 二进制,插件自动定位(建议 ≥ 40,33.x 存在截图合成器缺陷;44+ 首次使用自动下载,需网络),找不到时按下文 FAQ 安装即可。
|
|
7
9
|
|
|
8
10
|
## 安装
|
|
9
11
|
|
|
10
12
|
```sh
|
|
11
|
-
# 从 npm 安装(已发布)
|
|
13
|
+
# 从 npm 安装(已发布);`--profile` 换成你实际使用的 profile(DSH Desktop 为 `desktop`)
|
|
12
14
|
dsh plugin --profile web add dsh-builtin-browser
|
|
13
15
|
|
|
14
16
|
# 或从源码目录(独立仓库,一插件一仓库)
|
|
@@ -33,6 +35,7 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
33
35
|
| `browser-electron` | `httpOnly` | 布尔 | `true` | 仅允许 HTTP(S) 导航;`file:`/`data:` 等拒绝 |
|
|
34
36
|
| `browser-electron` | `snapshotMaxElements` | 数字 | `60` | 快照最多收录的交互元素数 |
|
|
35
37
|
| `browser-electron` | `contentMaxChars` | 数字 | `100000` | 内容抓取默认字符上限 |
|
|
38
|
+
| `browser-electron` | `downloadDir` | 字符串 | `~/Downloads` | 限定 `browser_download` 保存路径必须位于该目录内;默认收敛到系统下载目录,可改沙箱目录 |
|
|
36
39
|
| `tool-browser` | `timeoutMs` | 数字 | `60000` | 工具协作超时(ms) |
|
|
37
40
|
| `tool-browser` | `tabTools` | 布尔 | `true` | 是否注册标签管理工具 |
|
|
38
41
|
|
|
@@ -40,11 +43,12 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
40
43
|
|
|
41
44
|
```
|
|
42
45
|
1. browser_open 打开 https://example.com
|
|
43
|
-
2.
|
|
46
|
+
2. 慢站点先 browser_wait(url=…) 等页面就绪,再 browser_snapshot 查看可交互元素
|
|
44
47
|
3. 需要填表时用 browser_fill(按 name/label/placeholder 匹配,一次填多个字段)
|
|
45
|
-
4. 需要截图确认时用 browser_screenshot(可 savePath
|
|
46
|
-
5.
|
|
47
|
-
6.
|
|
48
|
+
4. 需要截图确认时用 browser_screenshot(可 savePath 存文件,大页面用 maxWidth 缩小)
|
|
49
|
+
5. 需要滚动/回退/按键时用 browser_scroll / browser_back / browser_forward / browser_key
|
|
50
|
+
6. 遇到验证码(browser_challenge 或快照标注 CHALLENGE)时,停下请用户处理
|
|
51
|
+
7. 每次操作后告知用户你在页面上做了什么
|
|
48
52
|
```
|
|
49
53
|
|
|
50
54
|
## 操作纪律
|
|
@@ -70,7 +74,9 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
70
74
|
能。插件自托管:自己拉起 Electron 窗口,无需桌面外壳。
|
|
71
75
|
|
|
72
76
|
**Q:找不到 Electron?**
|
|
73
|
-
插件按顺序自动定位:① peer 依赖 `require('electron')`
|
|
77
|
+
插件按顺序自动定位:① 插件运行在 Electron 进程内(DSH Desktop 主进程)时直接复用宿主二进制 → ② 进程祖先树中的宿主 Electron 二进制(DSH Desktop 把插件跑在子 Node 进程时的兜底)→ ③ peer 依赖 `require('electron')`(仅二进制已就绪时)→ ④ `ELECTRON_PATH` 环境变量 → ⑤ DSH 锚点与 pnpm 虚拟仓库中版本最新者。
|
|
78
|
+
|
|
79
|
+
DSH Desktop 上①②任一命中即开箱可用,无需任何安装。纯 `dsh web` 下全部落空时,报错会给出指引:可 `dsh plugin --profile <你的-profile> add electron`(DSH Desktop 的 profile 是 `desktop`)或设置 `ELECTRON_PATH`。
|
|
74
80
|
|
|
75
81
|
**Q:截图失败或挂起?**
|
|
76
82
|
确保 Electron ≥ 40(33.x 有合成器缺陷)。自托管截图优先走原生 `capturePage`,多视图/窗口未激活时自动兜底到 CDP。
|
|
@@ -79,10 +85,10 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
79
85
|
窗口标题为 `dsh-browser`(自托管)。若子进程崩溃会自动重启;重启后旧会话失效,调用 `browser_reset_session` 重建。
|
|
80
86
|
|
|
81
87
|
**Q:下载报 CORS 错误?**
|
|
82
|
-
`browser_download` 在页面上下文内 `fetch`,受同源/CORS
|
|
88
|
+
`browser_download` 在页面上下文内 `fetch`,受同源/CORS 约束;跨域文件请先在同源页面内操作,或直接请求用户提供。仅支持 HTTP(S) URL;`savePath` 必须为绝对路径(配置 `downloadDir` 后限定在该目录内)。
|
|
83
89
|
|
|
84
90
|
**Q:如何禁止 agent 乱点?**
|
|
85
|
-
`browser_restrict` 设置白名单(如只允许 `browser_snapshot`/`browser_content`)
|
|
91
|
+
`browser_restrict` 设置白名单(如只允许 `browser_snapshot`/`browser_content`);传空列表解除。注意它是防误操作的**软护栏**,模型可自行解除,不是安全边界。
|
|
86
92
|
|
|
87
93
|
## 故障排查
|
|
88
94
|
|