dsh-builtin-browser 0.1.18 → 0.1.20
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 +20 -7
- package/README.md +20 -7
- package/docs/architecture.md +2 -2
- package/docs/user-guide.md +3 -3
- package/lib/browser-electron/host-main.js +8 -0
- package/lib/browser-electron/remote-host.d.ts +76 -1
- package/lib/browser-electron/remote-host.js +294 -123
- package/package.json +13 -1
- package/src/browser-electron/host-main.ts +8 -0
- package/src/browser-electron/remote-host.ts +315 -115
package/README.en.md
CHANGED
|
@@ -213,11 +213,11 @@ agent (browser_* tools)
|
|
|
213
213
|
- **Provider** (`browser-electron` row): operates views through the `ElectronBrowserViewHost` seam (create/destroy/show, `sendCommand`), implemented with real Electron objects by the shell.
|
|
214
214
|
- **Tools** (`tool-browser` row): the 33 model-facing `browser_*` tools, maintaining one browser session per calling task (DSH session).
|
|
215
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).
|
|
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; the plugin prefers its own bundled electron package — packaged app executables (e.g. DSH Desktop.exe) are never reused as the spawnable binary, which would launch the app itself and exit immediately; 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).
|
|
217
217
|
|
|
218
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.
|
|
219
219
|
|
|
220
|
-
**Electron lookup order**: ① the
|
|
220
|
+
**Electron lookup order**: ① `ELECTRON_PATH` (explicit override, wins first) → ② the electron package bundled with the plugin (filesystem-only probe, never triggers the 44+ lazy download; covers both node_modules and pnpm-store layouts) → ③ the newest among DSH install anchors and pnpm virtual stores → ④ reuse the host binary when the current process is a **bare** Electron (dev mode) → ⑤ walk the process ancestry for a **bare** Electron host (PowerShell CIM on Windows, last resort only). **Packaged apps (e.g. `DSH Desktop.exe`) are never reused** — they cannot be spawned with a script argument, and misusing them exits instantly (issue #6); when nothing is found a clear error tells you what to do (including the `npx install-electron` hint).
|
|
221
221
|
|
|
222
222
|
## Division of labor with the desktop shell
|
|
223
223
|
|
|
@@ -226,9 +226,10 @@ The browser's **visible view**, the **browser column layout**, and the **column-
|
|
|
226
226
|
## Requirements
|
|
227
227
|
|
|
228
228
|
- DeepSeek Harness (dsh) with the matching profile (`web` / `desktop`, etc.)
|
|
229
|
-
- **Electron runtime** (required dependency, installed automatically with the plugin):
|
|
230
|
-
-
|
|
231
|
-
- **
|
|
229
|
+
- **Electron runtime** (required dependency, installed automatically with the plugin, ≥ 40 recommended; 44+ downloads its binary on first use, needs network):
|
|
230
|
+
- `ELECTRON_PATH` can point at another binary explicitly (highest priority);
|
|
231
|
+
- **DSH Desktop**: the packaged host exe (`DSH Desktop.exe`) is **never reused** — packaged apps cannot be spawned with a script argument and misuse exits instantly (issue #6); the bundled electron is used directly, and dev-mode **bare** Electron hosts are still reusable;
|
|
232
|
+
- **plain `dsh web` self-hosted**: uses the bundled electron package directly
|
|
232
233
|
|
|
233
234
|
### Verified versions
|
|
234
235
|
|
|
@@ -237,7 +238,7 @@ The browser's **visible view**, the **browser column layout**, and the **column-
|
|
|
237
238
|
| DeepSeek Harness (dsh) | `0.1.1-rc.2` (peer range `^0.1.1-rc.2`) |
|
|
238
239
|
| Electron | `44.0.0` (≥ 40 recommended; 33.x has a compositor defect) |
|
|
239
240
|
| Node.js | `22.20.0` |
|
|
240
|
-
| dsh-builtin-browser | `0.1.
|
|
241
|
+
| dsh-builtin-browser | `0.1.20` |
|
|
241
242
|
| OS | Windows 10 (10.0.26200) |
|
|
242
243
|
|
|
243
244
|
> The plugin declares `electron >= 30`; it has **only been verified on Windows** (macOS/Linux untested, not yet promised).
|
|
@@ -254,7 +255,7 @@ The browser's **visible view**, the **browser column layout**, and the **column-
|
|
|
254
255
|
- `browser_restrict` is a **soft guardrail** against accidental actions, not a security boundary: the model can lift it itself.
|
|
255
256
|
- 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.
|
|
256
257
|
- 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.
|
|
257
|
-
- After a self-hosted child crash the browser host restarts automatically,
|
|
258
|
+
- After a self-hosted child crash (or a DSH restart that kills it) the browser host restarts automatically, and sessions opened before the crash **rebuild on their next use** — only page state is lost, no manual `browser_reset_session` needed (it still works for an explicit reset).
|
|
258
259
|
- 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.
|
|
259
260
|
- This plugin contains no browser-column UI — that is host-shell territory; do not treat "browser column" as a plugin feature.
|
|
260
261
|
|
|
@@ -294,6 +295,12 @@ Code layout:
|
|
|
294
295
|
| **0.1.17** | 2026-08-27 | **Release**: round 8 ships as **0.1.17** (build clean, 21/21 tests pass) |
|
|
295
296
|
| 9 | 2026-08-27 | **electron becomes a required dependency**: moved from optional peer into `dependencies`, so installing the plugin brings the electron package automatically (44+ downloads its binary lazily on first use); DSH Desktop still reuses the host binary; docs and error message updated |
|
|
296
297
|
| **0.1.18** | 2026-08-27 | **Release**: round 9 (electron as a required dependency) ships as **0.1.18** (build clean, 21/21 tests pass) |
|
|
298
|
+
| 10 | 2026-08-27 | **DSH-Store compatibility declaration**: added `dsh.compatibility.dshReleases` (rc.2/rc.1=compatible, rc.8=unknown) plus profiles/dsh range, clearing the store's auto-unlisting (HOLD) |
|
|
299
|
+
| **0.1.19** | 2026-08-27 | **Release**: round 10 (DSH-Store compatibility declaration) ships as **0.1.19** (build clean, 21/21 tests pass) |
|
|
300
|
+
| 11 | 2026-08-27 | **Self-hosted session self-healing after host death** (issue #5): after the host dies (DSH restart / checkpoint restore / crash), already-open sessions rebuild the host and retry on their **next call** — no more "browser host is not running", no more half-dead state; host-gone logging + a fake-child regression test added |
|
|
301
|
+
| 12 | 2026-08-27 | **resolveElectronPath excludes packaged apps** (issue #6): added `isBareElectron` (a sibling `app.asar` means packaged — never reused, all platforms incl. macOS bundle layout); bundled-electron filesystem probe goes first; `ELECTRON_PATH` override wins first; missing dist errors clearly (`npx install-electron` hint) |
|
|
302
|
+
| Hardening | 2026-08-27 | **Three review passes hardened**: concurrent-recovery double-rebuild race (child `createView` made idempotent), macOS bundle-path detection, `dispose()` vs `start()` zombie-child race triple-guard, pendingSocket leak, fully unit-tested lookup order (24→25 tests) |
|
|
303
|
+
| **0.1.20** | 2026-08-27 | **Release**: rounds 11/12 + hardening ship as **0.1.20** (build clean, 25/25 tests pass) |
|
|
297
304
|
|
|
298
305
|
## Acknowledgements
|
|
299
306
|
|
|
@@ -301,6 +308,12 @@ Special thanks to the [DeepSeek Harness repository](https://github.com/deepseek-
|
|
|
301
308
|
|
|
302
309
|
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.
|
|
303
310
|
|
|
311
|
+
## A Note from the Author
|
|
312
|
+
|
|
313
|
+
Have feedback about this plugin, or an idea for another plugin you'd like built? Feel free to reach out on WeChat:
|
|
314
|
+
|
|
315
|
+
**wx: `hui13866591135`** (please mention this project when sending the friend request)
|
|
316
|
+
|
|
304
317
|
## License
|
|
305
318
|
|
|
306
319
|
MIT License, see [LICENSE](LICENSE).
|
package/README.md
CHANGED
|
@@ -213,11 +213,11 @@ agent (browser_* 工具)
|
|
|
213
213
|
- **provider 层**(`browser-electron` 行)通过 `ElectronBrowserViewHost` 接缝操作视图(创建/销毁/显示/`sendCommand`),由真实外壳用 Electron 对象实现;
|
|
214
214
|
- **工具层**(`tool-browser` 行)提供模型侧的 33 个 `browser_*` 工具,按调用方任务(DSH 会话)维护独立的浏览器会话。
|
|
215
215
|
|
|
216
|
-
**自托管模式**:没有桌面外壳时,插件自己拉起一个 Electron 子进程(`host-main.js`),通过本机 TCP JSON-RPC 驱动。RPC 带随机 token 认证,token 经 **stdin + 环境变量双通道**传递——Windows 上 Electron 是 GUI 子系统进程、收不到 piped stdin
|
|
216
|
+
**自托管模式**:没有桌面外壳时,插件自己拉起一个 Electron 子进程(`host-main.js`),通过本机 TCP JSON-RPC 驱动。RPC 带随机 token 认证,token 经 **stdin + 环境变量双通道**传递——Windows 上 Electron 是 GUI 子系统进程、收不到 piped stdin,环境变量兜底保证握手稳定。子进程崩溃会自动重启;优先使用随插件安装的 electron 包(**打包应用如 DSH Desktop.exe 不会被误当作可复用二进制**,避免 spawn 秒退);截图优先走 Electron 原生 `capturePage`(CDP 截图在多视图下会挂起),并自动选择环境中**最新版本**的 Electron(33.x 有合成器缺陷,建议 ≥ 40;44+ 首次使用自动下载二进制,需联网)。
|
|
217
217
|
|
|
218
218
|
**自托管浏览器就是一台真正的浏览器**:每个任务(DSH 会话)拥有**独立的浏览器窗口**,窗口自带完整工具栏——地址栏、后退/前进/刷新按钮、标签条(新建/切换/关闭标签)。人可以直接像用 Chrome 一样使用它:在地址栏输入网址(自动补 `https://`)、点标签切换页面、开新标签;键盘焦点跟随点击——**点地址栏即可输入、点页面即可操作**(Windows 焦点路由,修复了点击不转移焦点导致地址栏无法输入的问题)。agent 与人的操作都汇入**同一个会话模型**(同一套标签、历史与导航),窗口标题实时显示当前任务标识与页面标题/URL,窗口缩放时视图自动跟随。任务结束后窗口随会话自动关闭。
|
|
219
219
|
|
|
220
|
-
**Electron 定位顺序**:①
|
|
220
|
+
**Electron 定位顺序**:① `ELECTRON_PATH`(显式覆盖,用户显式意图最优先)→ ② 随插件安装的 electron 包(纯文件系统探测,不触发 44+ 懒下载;覆盖 node_modules 与 pnpm store 两种布局)→ ③ DSH 安装锚点与 pnpm 虚拟仓库中**版本最新**者 → ④ 当前进程为**裸** Electron 时复用宿主二进制(开发模式)→ ⑤ 进程祖先树中的**裸** Electron 宿主(Windows 走 PowerShell CIM,仅最后手段)。**打包应用(如 `DSH Desktop.exe`)一律不复用**——它们不能按脚本参数拉起,误用会导致 spawn 秒退(issue #6);找不到时工具会报清晰的错误提示(含 `npx install-electron` 指引)。
|
|
221
221
|
|
|
222
222
|
## 与桌面外壳的分工
|
|
223
223
|
|
|
@@ -226,9 +226,10 @@ agent (browser_* 工具)
|
|
|
226
226
|
## 环境要求
|
|
227
227
|
|
|
228
228
|
- DeepSeek Harness(dsh),已安装对应 profile(`web` / `desktop` 等)
|
|
229
|
-
- **Electron 运行时**(
|
|
230
|
-
-
|
|
231
|
-
-
|
|
229
|
+
- **Electron 运行时**(必装依赖,随插件自动安装,建议 ≥ 40;44+ 首次使用自动下载二进制,需网络):
|
|
230
|
+
- `ELECTRON_PATH` 可显式指定其他二进制(最优先);
|
|
231
|
+
- **DSH Desktop**:打包宿主 exe(`DSH Desktop.exe`)**不复用**——打包应用无法按脚本参数拉起,误用会秒退(issue #6);直接使用随包 electron,开发模式的**裸** Electron 宿主仍可复用;
|
|
232
|
+
- **纯 `dsh web` 自托管**:直接使用随插件安装的 electron 包
|
|
232
233
|
|
|
233
234
|
### 验证过的版本
|
|
234
235
|
|
|
@@ -237,7 +238,7 @@ agent (browser_* 工具)
|
|
|
237
238
|
| DeepSeek Harness(dsh) | `0.1.1-rc.2`(peer 声明 `^0.1.1-rc.2`) |
|
|
238
239
|
| Electron | `44.0.0`(推荐 ≥ 40;33.x 存在合成器缺陷) |
|
|
239
240
|
| Node.js | `22.20.0` |
|
|
240
|
-
| dsh-builtin-browser | `0.1.
|
|
241
|
+
| dsh-builtin-browser | `0.1.20` |
|
|
241
242
|
| 操作系统 | Windows 10 (10.0.26200) |
|
|
242
243
|
|
|
243
244
|
> 插件声明 `electron >= 30`;**当前仅在 Windows 环境实测**(macOS/Linux 未验证,暂不承诺)。
|
|
@@ -254,7 +255,7 @@ agent (browser_* 工具)
|
|
|
254
255
|
- `browser_restrict` 是防误操作的**软护栏**,不是安全边界:模型可以自行解除白名单。
|
|
255
256
|
- 页面弹窗(`window.open` / `target=_blank`)会被重定向到当前标签页内打开,不创建独立窗口,以免破坏标签/会话模型。
|
|
256
257
|
- `browser_auth` 的 cookie 往返不保留 `hostOnly`/`sameSite` 字段(host-only cookie 恢复后变成 domain cookie);仅自托管浏览器可用。
|
|
257
|
-
-
|
|
258
|
+
- 自托管浏览器子进程崩溃(或宿主 DSH 重启)后会自动重启;崩溃前已打开的会话在**下一次调用时自动重建**——仅页面状态丢失,无需手动 `browser_reset_session`。`browser_reset_session` 仍可用于主动重置。
|
|
258
259
|
- electron 随插件安装;Electron 44+ 首次打开浏览器窗口时自动下载二进制(约 100MB,需网络),之后不再需要。若探测时网络不可用,可预装 `ELECTRON_PATH` 指定的二进制。
|
|
259
260
|
- 本插件不含浏览器列 UI——那是宿主外壳的配套,别把"浏览器列"当成插件能力。
|
|
260
261
|
|
|
@@ -294,6 +295,12 @@ npm run build
|
|
|
294
295
|
| **0.1.17** | 2026-08-27 | **发布**:第八轮修复随 **0.1.17** 发布(构建零错误、21 项测试全绿) |
|
|
295
296
|
| 第九轮 | 2026-08-27 | **electron 改为必装依赖**:从 optional peer 移入 `dependencies`,安装插件即自动带上 electron 包(44+ 二进制首次使用懒下载);DSH Desktop 依旧复用宿主二进制;文档与报错同步 |
|
|
296
297
|
| **0.1.18** | 2026-08-27 | **发布**:第九轮「electron 改为必装依赖」随 **0.1.18** 发布(构建零错误、21 项测试全绿) |
|
|
298
|
+
| 第十轮 | 2026-08-27 | **DSH-Store 兼容性声明**:新增 `dsh.compatibility.dshReleases`(rc.2/rc.1=compatible、rc.8=unknown)与 profiles/dsh 范围,解除商店自动下架(HOLD) |
|
|
299
|
+
| **0.1.19** | 2026-08-27 | **发布**:第十轮「DSH-Store 兼容性声明」随 **0.1.19** 发布(构建零错误、21 项测试全绿) |
|
|
300
|
+
| 第十一轮 | 2026-08-27 | **自托管宿主崩溃后的会话自愈**(issue #5):宿主死亡(DSH 重启 / checkpoint 恢复 / 崩溃)后,已打开的会话在**下一次调用时自动重建宿主并重试**——不再报 "browser host is not running",半死态消除;新增 host-gone 日志与假子进程回归测试 |
|
|
301
|
+
| 第十二轮 | 2026-08-27 | **resolveElectronPath 排除打包应用**(issue #6):新增 `isBareElectron`(旁有 `app.asar` 即打包应用,一律不复用,全平台含 macOS bundle 布局);bundled electron 纯文件系统探测置最优先;`ELECTRON_PATH` 显式覆盖最优先;dist 缺失时明确报错(`npx install-electron` 指引) |
|
|
302
|
+
| 全面复审加固 | 2026-08-27 | **三轮审查加固**:并发恢复双重建竞态(child `createView` 幂等化)、macOS bundle 路径判定、`dispose()` vs `start()` 僵尸 child 竞态三道闸、pendingSocket 泄漏、选路顺序全量单测(24→25 项测试) |
|
|
303
|
+
| **0.1.20** | 2026-08-27 | **发布**:第十一/十二轮 + 全面复审加固随 **0.1.20** 发布(构建零错误、25 项测试全绿) |
|
|
297
304
|
|
|
298
305
|
## 特别感谢
|
|
299
306
|
|
|
@@ -301,6 +308,12 @@ npm run build
|
|
|
301
308
|
|
|
302
309
|
同时感谢 [Cordis](https://github.com/cordiverse/cordis) 提供的插件化基础,以及所有参与讨论、测试、反馈和插件开发的社区成员。
|
|
303
310
|
|
|
311
|
+
## 作者的话
|
|
312
|
+
|
|
313
|
+
对插件本身有意见或者有想要制作的其他插件,欢迎加我微信来讨论:
|
|
314
|
+
|
|
315
|
+
**wx:`hui13866591135`**(请在申请好友时注明)
|
|
316
|
+
|
|
304
317
|
## License
|
|
305
318
|
|
|
306
319
|
本项目遵循 [MIT License](LICENSE)。
|
package/docs/architecture.md
CHANGED
|
@@ -60,8 +60,8 @@ RemoteElectronViewHost ──TCP JSON-RPC──▶ host-main.js
|
|
|
60
60
|
|
|
61
61
|
- **协议**:本机 loopback TCP,每行一个 JSON(`{ id, op, ... }` ↔ `{ id, ok, result|err }`);
|
|
62
62
|
- **认证**:每次 spawn 生成随机 token(经 `--rpc-token` 传入),子进程首条消息必须回传该 token(`hello`);服务端只接受**一个**连接,其余连接直接断开——本机其他进程无法伪冒子进程或注入回复;
|
|
63
|
-
- **Electron 定位**:①
|
|
64
|
-
- **稳健性**:子进程/套接字都有 `error` 监听(否则未捕获事件会炸掉整个 DSH 进程)
|
|
63
|
+
- **Electron 定位**:① `ELECTRON_PATH`(显式覆盖,优先于一切自动发现)→ ② 随插件安装的 electron 包(纯文件系统探测,含 pnpm store 布局,不触发 44+ 懒下载)→ ③ 锚点与 pnpm store 中**版本最新**者(33.x 有合成器缺陷,建议 ≥ 40)→ ④ 当前进程是**裸** Electron(dev 模式)时复用宿主二进制(`process.execPath`)→ ⑤ 进程祖先树中的裸 Electron 二进制(Windows 用 PowerShell CIM 查询,仅在其它路径全部落空时才执行)。**打包应用不参与复用**:旁有 `resources/app.asar` 的可执行文件(如 DSH Desktop.exe)不能按脚本参数拉起——spawn 会启动应用本体并秒退(单实例锁,即 "browser host exited (code=0)"),一律跳过;
|
|
64
|
+
- **稳健性**:子进程/套接字都有 `error` 监听(否则未捕获事件会炸掉整个 DSH 进程);子进程退出自动重启,已物化的视图句柄在下次调用时**自动重建并重试一次**(会话跨崩溃存活,仅页面状态丢失,不再出现 "browser host is not running" 僵尸态);物化失败可重试;下载仅限 HTTP(S)、`savePath` 必须绝对路径(默认限定 `~/Downloads`,可配置 `downloadDir` 覆盖)、流式限流 + Content-Length 提前拒绝、256MB 上限与 60s 超时,文件由**子进程直接落盘**(临时文件 + rename,不再经 RPC 传 base64);cookie 导出/恢复有 30s 超时;
|
|
65
65
|
- **视图可见性**:多标签/多会话时,`showView` 隐藏其他视图并把目标视图置顶(remove+re-add),确保用户看到的是活动标签;目标是当前可见视图时**跳过** remove/re-add(否则每次操作都闪烁);窗口标题实时显示当前可见会话的任务标识 + 页面标题/URL(`showView` 携带会话 label,子进程读 `getTitle`/`getURL`);窗口 resize 时视图 bounds 自动跟随;
|
|
66
66
|
- **孤儿防护**:父进程断开时子进程自动退出,不留僵尸窗口;
|
|
67
67
|
- **cookie 落盘**:子进程使用独立 userData 目录(`<DSH_HOME>/dsh-builtin-browser-host`),登录态跨重启保留(另有 `browser_auth` 手动导出/恢复)。
|
package/docs/user-guide.md
CHANGED
|
@@ -74,15 +74,15 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
74
74
|
能。插件自托管:自己拉起 Electron 窗口,无需桌面外壳。
|
|
75
75
|
|
|
76
76
|
**Q:找不到 Electron?**
|
|
77
|
-
插件按顺序自动定位:①
|
|
77
|
+
插件按顺序自动定位:① `ELECTRON_PATH` 环境变量(显式覆盖,优先于一切自动发现)→ ② 随插件安装的 electron 包(纯文件系统探测,不触发 44+ 懒下载)→ ③ DSH 锚点(profile / 全局 prefix 中单独安装的 electron)中版本最新者 → ④ 当前进程就是**裸** Electron(dev 模式)时复用宿主二进制 → ⑤ 进程祖先树中的裸 Electron 二进制。**打包应用不参与复用**:旁有 `resources/app.asar` 的可执行文件(如 DSH Desktop.exe)无法按脚本参数拉起,spawn 会启动应用本体并秒退(单实例锁)——一律跳过。
|
|
78
78
|
|
|
79
|
-
DSH Desktop
|
|
79
|
+
DSH Desktop 上①命中即可用(0.1.18+ 插件自带 electron 包,44+ 二进制首次使用自动下载);dev 模式宿主走④复用,亦零安装。全部落空时,报错会给出指引:electron 已随插件安装,44+ 二进制缺失时先 `npx install-electron`(需网络);必要时可设置 `ELECTRON_PATH`。
|
|
80
80
|
|
|
81
81
|
**Q:截图失败或挂起?**
|
|
82
82
|
确保 Electron ≥ 40(33.x 有合成器缺陷)。自托管截图优先走原生 `capturePage`,多视图/窗口未激活时自动兜底到 CDP。
|
|
83
83
|
|
|
84
84
|
**Q:浏览器窗口不见了?**
|
|
85
|
-
窗口标题为 `dsh-browser`(自托管)
|
|
85
|
+
窗口标题为 `dsh-browser`(自托管)。若子进程崩溃(或宿主 DSH 重启)会自动重启;崩溃前已打开的会话在**下一次调用时自动重建**——仅页面状态丢失,无需手动 `browser_reset_session`。`browser_reset_session` 仍可用于主动重置。
|
|
86
86
|
|
|
87
87
|
**Q:下载报 CORS 错误?**
|
|
88
88
|
`browser_download` 在页面上下文内 `fetch`,受同源/CORS 约束;跨域文件请先在同源页面内操作,或直接请求用户提供。仅支持 HTTP(S) URL;`savePath` 必须为绝对路径(配置 `downloadDir` 后限定在该目录内)。
|
|
@@ -497,6 +497,14 @@ async function handle(op, msg) {
|
|
|
497
497
|
const viewId = msg.viewId;
|
|
498
498
|
if (viewId === undefined)
|
|
499
499
|
throw new Error('createView missing viewId');
|
|
500
|
+
// Idempotent against a duplicate createView for the same id (e.g. two
|
|
501
|
+
// concurrent parent-side recoveries after a host death): re-creating
|
|
502
|
+
// would stack a second WebContentsView in the window and leak the
|
|
503
|
+
// first — the duplicate call simply confirms the existing view.
|
|
504
|
+
if (windowOfView(viewId) !== undefined) {
|
|
505
|
+
reply(msg.id, { ok: true });
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
500
508
|
const assignment = assignments.get(viewId);
|
|
501
509
|
const win = windowFor(assignment?.windowId);
|
|
502
510
|
const view = new WebContentsView();
|
|
@@ -25,6 +25,64 @@
|
|
|
25
25
|
* @module dsh-browser/browser-electron/remote-host
|
|
26
26
|
*/
|
|
27
27
|
import type { BrowserUserAction, ElectronBrowserViewHost, ElectronViewHandle } from './provider.js';
|
|
28
|
+
/**
|
|
29
|
+
* Locate a SPAWNABLE Electron binary — one that runs a script given as an
|
|
30
|
+
* argument, i.e. a BARE electron, never a packaged app executable:
|
|
31
|
+
* 0. ELECTRON_PATH (explicit override — user intent beats auto-discovery),
|
|
32
|
+
* 1. the plugin's own electron package (a real dependency since 0.1.18),
|
|
33
|
+
* found by a pure filesystem walk — never require(), whose semantics
|
|
34
|
+
* differ inside an Electron main process (there it is the built-in API
|
|
35
|
+
* module, not the npm package) and which would trigger electron 44+'s
|
|
36
|
+
* lazy binary download;
|
|
37
|
+
* 2. every DSH install anchor (electron installed separately, e.g.
|
|
38
|
+
* `dsh plugin add electron` into the profile or a global prefix),
|
|
39
|
+
* choosing the NEWEST version found. Older Electron releases (e.g.
|
|
40
|
+
* 33.x) have a compositor defect that intermittently breaks page
|
|
41
|
+
* capture, so prefer the newest binary available in the environment,
|
|
42
|
+
* 3. the current process, when it IS a bare Electron (dev hosts, e.g.
|
|
43
|
+
* `electron .`): reuse the host binary. Packaged app executables
|
|
44
|
+
* (resources/app.asar beside the exe) are never reused — they ignore
|
|
45
|
+
* the script argument and launch the app itself, typically exiting
|
|
46
|
+
* immediately via the single-instance lock, which is exactly the
|
|
47
|
+
* "browser host exited (code=0)" failure on DSH Desktop;
|
|
48
|
+
* 4. last resort: the process ancestry, for hosts that run this plugin in a
|
|
49
|
+
* child Node process of their own bare-Electron main process.
|
|
50
|
+
* @returns the path to the Electron executable.
|
|
51
|
+
*/
|
|
52
|
+
/** The discovery inputs {@link resolveElectronPathImpl} selects over, injectable for tests. */
|
|
53
|
+
interface ElectronPathInputs {
|
|
54
|
+
/** ELECTRON_PATH (may be unset, empty, or pointing at a missing file). */
|
|
55
|
+
readonly override: string | undefined;
|
|
56
|
+
/** True when running inside an Electron main process. */
|
|
57
|
+
readonly inElectron: boolean;
|
|
58
|
+
/** process.execPath (candidate for in-process host reuse). */
|
|
59
|
+
readonly execPath: string;
|
|
60
|
+
/** The plugin's own electron package probe (bundled). */
|
|
61
|
+
readonly bundled: () => string | undefined;
|
|
62
|
+
/** The DSH install-anchor probe. */
|
|
63
|
+
readonly anchored: () => string | undefined;
|
|
64
|
+
/** The process-ancestry probe (last resort). */
|
|
65
|
+
readonly ancestry: () => string | undefined;
|
|
66
|
+
}
|
|
67
|
+
declare function resolveElectronPath(): string;
|
|
68
|
+
/**
|
|
69
|
+
* Pure selection over the discovery probes, in order:
|
|
70
|
+
* 0. override (user intent) → 1. bundled package → 2. anchors (newest) →
|
|
71
|
+
* 3. in-process BARE host → 4. process ancestry → throw.
|
|
72
|
+
* Packaged app executables are never reused (steps 3/4 skip them).
|
|
73
|
+
*/
|
|
74
|
+
declare function resolveElectronPathImpl(inputs: ElectronPathInputs): string;
|
|
75
|
+
/**
|
|
76
|
+
* True when the executable is a BARE (unpackaged) Electron that can be
|
|
77
|
+
* spawned with a script argument (`exe script.js --rpc-port N`). Packaged
|
|
78
|
+
* apps carry their code inside a resources dir (`app.asar`, or an unpacked
|
|
79
|
+
* `app` dir) and are NOT spawnable as bare electron: they ignore the script
|
|
80
|
+
* argument and launch the app itself, typically exiting immediately via the
|
|
81
|
+
* single-instance lock — spawning e.g. DSH Desktop.exe is exactly the
|
|
82
|
+
* "browser host exited (code=0)" failure. A portable single-file build (no
|
|
83
|
+
* resources dir at all) likewise cannot run a script argument.
|
|
84
|
+
*/
|
|
85
|
+
declare function isBareElectron(exe: string): boolean;
|
|
28
86
|
/**
|
|
29
87
|
* Self-hosted view host: spawns the plugin's Electron child on first use and
|
|
30
88
|
* keeps it alive until dispose(). Fallback when no desktop shell provides
|
|
@@ -32,6 +90,9 @@ import type { BrowserUserAction, ElectronBrowserViewHost, ElectronViewHandle } f
|
|
|
32
90
|
*/
|
|
33
91
|
export declare class RemoteElectronViewHost implements ElectronBrowserViewHost {
|
|
34
92
|
private readonly hostMainPath;
|
|
93
|
+
/** Test seam: the executable to spawn instead of the resolved Electron
|
|
94
|
+
* binary. Absent -> resolveElectronPath() (production behavior). */
|
|
95
|
+
private readonly spawnExecutable?;
|
|
35
96
|
private client;
|
|
36
97
|
private server;
|
|
37
98
|
private pendingSocket;
|
|
@@ -45,7 +106,10 @@ export declare class RemoteElectronViewHost implements ElectronBrowserViewHost {
|
|
|
45
106
|
private readonly groups;
|
|
46
107
|
/** The provider's user-action handler; routes toolbar actions into sessions. */
|
|
47
108
|
private userActionHandler;
|
|
48
|
-
constructor(hostMainPath: string
|
|
109
|
+
constructor(hostMainPath: string,
|
|
110
|
+
/** Test seam: the executable to spawn instead of the resolved Electron
|
|
111
|
+
* binary. Absent -> resolveElectronPath() (production behavior). */
|
|
112
|
+
spawnExecutable?: string | undefined);
|
|
49
113
|
/**
|
|
50
114
|
* Cheap usability probe: can we find an Electron binary to spawn? The scan
|
|
51
115
|
* is filesystem-only (no network), per the seam's contract, and the result
|
|
@@ -74,3 +138,14 @@ export declare class RemoteElectronViewHost implements ElectronBrowserViewHost {
|
|
|
74
138
|
}
|
|
75
139
|
/** Default host-main path relative to this module's build output. */
|
|
76
140
|
export declare function defaultHostMainPath(): string;
|
|
141
|
+
/**
|
|
142
|
+
* Test/diagnostic hooks (mirrors tool-browser's `internals` convention).
|
|
143
|
+
* `isBareElectron` is the packaged-app discriminator behind the host-reuse
|
|
144
|
+
* steps; `resolveElectronPath` is the full resolution order.
|
|
145
|
+
*/
|
|
146
|
+
export declare const internals: {
|
|
147
|
+
isBareElectron: typeof isBareElectron;
|
|
148
|
+
resolveElectronPath: typeof resolveElectronPath;
|
|
149
|
+
resolveElectronPathImpl: typeof resolveElectronPathImpl;
|
|
150
|
+
};
|
|
151
|
+
export {};
|