dsh-browser-plus 0.5.0 → 0.5.1
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/CHANGELOG.md +131 -144
- package/README.en.md +27 -8
- package/README.md +27 -8
- package/client/index.js +185 -0
- package/cordis.patch.yml +24 -0
- package/docs/README.md +1 -1
- package/docs/SOAK-CHECKLIST.md +1 -1
- package/docs/tool-reference.md +5 -3
- package/docs/user-guide.md +20 -4
- package/lib/browser/runtime.d.ts +14 -1
- package/lib/browser/runtime.js +28 -0
- package/lib/browser/types.d.ts +96 -6
- package/lib/browser-electron/chrome-state.d.ts +24 -0
- package/lib/browser-electron/entry.d.ts +12 -5
- package/lib/browser-electron/entry.js +5 -2
- package/lib/browser-electron/host-main.d.ts +2 -1
- package/lib/browser-electron/host-main.js +205 -8
- package/lib/browser-electron/page-chrome.js +249 -14
- package/lib/browser-electron/provider.d.ts +60 -2
- package/lib/browser-electron/provider.js +300 -50
- package/lib/browser-electron/remote-host.d.ts +3 -1
- package/lib/browser-electron/remote-host.js +42 -1
- package/lib/client.js +185 -0
- package/lib/command-browser/index.d.ts +20 -0
- package/lib/command-browser/index.js +35 -0
- package/lib/http-browser/index.d.ts +28 -0
- package/lib/http-browser/index.js +110 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +11 -0
- package/lib/task-todos/index.d.ts +25 -0
- package/lib/task-todos/index.js +100 -0
- package/lib/tool-browser/index.js +190 -95
- package/package.json +27 -2
- package/scripts/build-client.mjs +20 -0
- package/scripts/smoke-browser-tools.mjs +84 -1
- package/scripts/smoke-chrome-world.mjs +6 -4
- package/scripts/test-orb-drag.mjs +83 -0
- package/src/browser/runtime.ts +36 -0
- package/src/browser/types.ts +98 -6
- package/src/browser-electron/chrome-state.ts +18 -0
- package/src/browser-electron/entry.ts +17 -7
- package/src/browser-electron/host-main.ts +207 -11
- package/src/browser-electron/page-chrome.ts +249 -14
- package/src/browser-electron/provider.ts +328 -50
- package/src/browser-electron/remote-host.ts +49 -2
- package/src/command-browser/index.ts +61 -0
- package/src/http-browser/index.ts +139 -0
- package/src/index.ts +13 -0
- package/src/task-todos/index.ts +114 -0
- package/src/tool-browser/index.ts +193 -96
package/CHANGELOG.md
CHANGED
|
@@ -1,166 +1,153 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v0.5.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- **`
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
## v0.5.1 (2026-10-04)
|
|
4
|
+
### 新功能
|
|
5
|
+
- **网页右下角的悬浮球:Agent 在浏览器里干什么,一眼看得见** —— 半透明、可拖动(位置存在宿主),干活时转圈、角标是 todo 进度,悬停弹出清单与「现在执行」的动作。
|
|
6
|
+
- **人和 Agent 都能开窗了** —— `/browser` 斜杠命令(不产生模型消息)+ 右侧栏「DSH-Browser-Plus」面板,不再只能等 Agent 第一次调用工具。
|
|
7
|
+
- **`browser_snapshot` 能看进 iframe** —— 同源框架递归遍历,元素带 `frame` 序号且坐标已加偏移(ref 照样能点);跨源明确标 `readable: false`。
|
|
8
|
+
- **新增 `browser_highlight`** —— 用 DevTools 那套高亮框标出元素(走 CDP `Overlay`,完全不碰页面 DOM)。
|
|
9
|
+
- **新增 `browser_pdf`** —— 打印当前标签页;Electron 的 debugger 没有 CDP `Page.printToPDF`,改走宿主 `webContents.printToPDF`。
|
|
10
|
+
- **`browser_wait_for` 能等文字、也能等东西消失** —— 新增 `text` 与 `state`(`attached` / `hidden` / `detached`)。
|
|
11
|
+
### 优化
|
|
12
|
+
- **等不了的情况直接报错** —— 既没选择器也没文字、或要等消失却没给选择器 → `BROWSER_WAIT_INVALID`,不空等到超时。
|
|
13
|
+
### 修复
|
|
14
|
+
- **页面脚本能读到 Agent 的计划** —— 注入的 chrome 改跑**隔离世界**(`chromeWorld: 'isolated'`),页面对 `__dsh*` 全局一律 `undefined`;DOM、事件与补丁通道不变,显式配 `main` 可回到旧行为。
|
|
15
|
+
- **面板的两个 HTTP 路由能被别的网站调用** —— 要求 `Origin` 与 `Host` 一致;同源面板与 curl 不受影响。
|
|
16
|
+
- **任务面板里点另一条任务没反应** —— 点击读的 `dataset.dshTaskKey` 全文件没有任何地方写过(列表用 `dshKey` 建行),三处统一。
|
|
17
|
+
- **任务面板里只有当前任务有缩略图** —— 图像只发给可见表面;现在面板打开与切任务时把手里已有的图重放一次。
|
|
18
|
+
- **书签栏会压住网页内容** —— 改成和顶栏一样占视图高度(帧 84 → 118px),页面不再靠 `padding-top` 让位。
|
|
19
|
+
> 每条改动的背景、真机证据与踩过的坑,见对应提交信息。
|
|
12
20
|
|
|
21
|
+
## v0.5.0 (2026-10-03)
|
|
22
|
+
### 新功能
|
|
23
|
+
- **`browser_dialog`** —— 查看/引导 `alert`/`confirm`/`prompt`。
|
|
24
|
+
- **`browser_console` / `browser_network`** —— 读控制台报错、未捕获异常与网络请求(每个视图各 200 条环形缓冲)。
|
|
25
|
+
- **`browser_emulate`** —— 视口(可带移动端行为与 DPR)、自定义 UA、`prefers-color-scheme`。
|
|
13
26
|
- **`browser_execute` 现在也收语句体**(自动判别:先试表达式,再试脚本体,语句体用 `return` 返回值)。
|
|
14
27
|
- **`browser_snapshot` 新增 `query` 与 `limit`** —— 按 kind+label 过滤,且**过滤发生在计上限之前**(否则默认上限 60 之外的元素永远搜不到)。
|
|
28
|
+
### 优化
|
|
15
29
|
- **坐标点击落在视口外时明确报错**,并报出那个点上实际是什么元素(坐标点击**不会自动滚动**,以前是静默丢弃)。
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **页面缩放 ≠ 100% 时,二级菜单弹层不贴按钮** —— 实测 160% 下偏 330px(`left` 311 → 502)。根因是 chrome 内部 px 与页面 px 差一个缩放倍数。
|
|
30
|
+
### 修复
|
|
31
|
+
- **页面缩放 ≠ 100% 时,二级菜单弹层不贴按钮** —— 实测 160% 下偏 330px(`left` 311 → 502)。
|
|
20
32
|
- **`browser_dialog` 的 `inspect` 看不到刚触发的对话框** —— 它没有自己排空宿主里的对话框。
|
|
21
|
-
|
|
22
33
|
> 每条改动的背景、真机证据与踩过的坑,见对应提交信息。
|
|
23
34
|
|
|
24
35
|
## v0.4.3 (2026-09-30)
|
|
25
|
-
|
|
36
|
+
### 新功能
|
|
37
|
+
- **标签栏显示 favicon**(Chrome 的标签几乎由 favicon 主导,这是「像不像」最显眼的一块)。
|
|
38
|
+
- **注入式 chrome 新增 Chrome 风格标签栏**(渲染层已完成并真机验证)。
|
|
39
|
+
- **新增 `browser_drag`(工具数 36 → 37)**:`from` 按下 → 中间移动 → `to` 释放。
|
|
40
|
+
- **指针工具支持右键与修饰键**:`browser_click`/`browser_double_click` 新增 `button`(left/right/middle)与 `modifiers`(alt/ctrl/meta/shif…。
|
|
41
|
+
- **`DSH_BROWSER_PLUS_USER_DATA` 可覆盖宿主 profile**:Chromium 对 profile 加单例锁,此前无法并存两个宿主(验证脚本会与运行中的 DSH 冲突)。
|
|
42
|
+
- **指针工具支持选择器/文字寻址**:`browser_click`/`browser_double_click`/`browser_hover` 此前**只能给坐标**,想点一个按钮必须先 `browser_snapshot` 拿 `…。
|
|
43
|
+
- **`browser_scrape` 支持并发**:新增 `concurrency`(默认 1,上限 8),每个 worker 占一个自己的标签页,从共享队列取 URL。
|
|
44
|
+
- **新增 `browser_scrape`:批量抓取,结果直接落盘**:后台批量访问 URL,每页把一行 JSON 追加到文件,**结果完全不经过模型**——一千条与一条的 token 成本相同。
|
|
45
|
+
- **`browser_auth` 支持从文件导入登录状态**:新增 `file` 参数(`action=restore`),从 JSON 文件读取 cookie 列表 —— 真实导出动辄几百条,内联经模型传递不现实。
|
|
46
|
+
- **新增深色空状态页,并修复空白视图上所有操作超时**:新建的 `WebContentsView` 在首次导航前**没有提交任何文档** —— 既按默认白底渲染(和整套深色 UI 格格不入),又让 CDP **没有 frame 可 ev…。
|
|
47
|
+
- **可选:把注入 chrome 移进隔离世界**(`browser-electron.chromeWorld: isolated`,**默认仍是 main**)。
|
|
48
|
+
- **`browser_press_key` 支持标点**:此前只认字母数字与功能键,`Ctrl+-`、`Ctrl+/`、`,`、`.`、`[`、`]` 等一律抛 `BROWSER_KEY_UNKNOWN`,而工具描述却写「single …。
|
|
49
|
+
- **写入路径白名单**:`browser_screenshot` 与 `browser_download` 只能写入 `browser-electron.writeRoots`(默认工作目录 + 系统临时目录)之内的路径。
|
|
50
|
+
### 优化
|
|
26
51
|
- **取消抽屉设计 + 页面不再被顶栏遮挡**(用户要求「取消抽屉的设计,同时为了不遮挡,像谷歌浏览器那样处理」)。
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
- **`
|
|
72
|
-
-
|
|
73
|
-
- **`
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
- **`
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
- **`browser_scroll` 描述与实现对齐**:实际是「约一屏(视口高度的 80%,最少 480px)」,描述原写「one viewport」。
|
|
92
|
-
- **新增 CI**:`.github/workflows/ci.yml` 在 push/PR 上跑 `npm ci --omit=optional` + `npm test`,并额外用 `git diff --exit-code -- lib` 校验**已提交的 `lib/`** 与 `src/` 一致——这正是 `pretest` 会掩盖的那类漂移(改了 src、本地重建了 lib,却没提交重建结果)。
|
|
93
|
-
- **新增 ESLint 最小集**:只启用类型感知的 `no-floating-promises` / `no-misused-promises` 与两条一致性规则,不引入格式化以免搅动现有风格。首次运行即发现一处真实缺陷:`setWindowOpenHandler` 里的 `loadURL()` 未被 await 也未挂 rejection handler,失败时会产生未处理拒绝。
|
|
94
|
-
- **`CHANGELOG.md` 现在会进 npm tarball**(此前 `files` 未列)。
|
|
95
|
-
- **缩略图捕获加超时**:`capturePage()` 在合成器卡住时可能永不 settle,而 `finally` 不会执行 → 单飞标志永远为 true,此后缩略图静默停更。现在 5s 超时按失败处理。
|
|
96
|
-
- **减少跨进程 IPC**:`syncVisibleTaskVisibility` 此前对**每个** view(含其它任务的隐藏页与后台标签)各发一次 `executeJavaScript`;现在只对 active 状态真正变化的 view 发送。
|
|
97
|
-
- **`installPageChrome` 的 active 判定改用 viewId**:此前只比 taskKey,导致可见任务的**后台标签页**导航时被当成「正在显示」,会启动其页面定时器并顶掉真正可见视图的 chrome epoch。
|
|
98
|
-
- **`restoreAuth` 逐条隔离**:此前任一条 cookie 非法即整批 reject、已写入不可回滚、调用方也拿不到计数;现在逐条 try/catch 并回报 `{restored, failed}`。
|
|
99
|
-
- **会话丢失会自动重开**:工具层按任务缓存 session id;若 provider 被重载(实例换了、不再认识旧 id),此前该任务之后**每次**调用都报 `BROWSER_SESSION_UNKNOWN`,只能靠人想到调 `browser_reset_session`。现在检测到该错误会丢弃缓存并重开一次(仅此一种错误会重试)。
|
|
100
|
-
- **`browser_close_tab` 如实返回**:此前无条件 `{closed:true}`,render 里「Tab not found.」是死代码;未知 tabId 与成功无法区分。现在 provider 返回布尔值,工具层如实回填。
|
|
101
|
-
- **`browser_handoff` 纳入白名单**:它不是只读工具(会改任务控制状态),此前不受 `browser_restrict` 约束。
|
|
102
|
-
- **`browser_screenshot` 仅在写盘时受白名单约束**:不带 `savePath` 的截图仍是只读,保持「只读工具永不拦截」的承诺;带 `savePath` 时按写盘工具守卫。
|
|
103
|
-
- **`browser_reset_session` 纳入每任务 FIFO**:此前直接 close,可能把并发排队操作正在使用的会话/视图拆掉。
|
|
104
|
-
- **`browser_restrict` 校验名字是否存在**:此前只校验 `browser_` 前缀,拼错(如 `browser_snapsho`)会被接受并静默拒绝该任务所有受守卫动作。
|
|
105
|
-
- **输入派发补上超时兜底**:`click`/`clickRef`/`doubleClick`/`hover`/`type`/`pressKey` 的 8 处 `Input.*` 派发此前是裸 `await`,页面主线程被同步 JS 阻塞时会一直挂到工具预算耗尽;现在与其它 CDP 调用一样有 15s 上限并响应调用方 signal。
|
|
106
|
-
- **超时错误带稳定 code**:`withTimeout` 现在抛 `BROWSER_OPERATION_TIMEOUT`(保留 `TimeoutError` 名称),此前只有 `execute`/`waitForElement` 两处归一化,其余超时是裸 Error,无法按 code 分支。
|
|
107
|
-
- **快照重试有总预算且尊重取消**:空清单重试此前最多 5 次、每次可等满求值超时(理论上约 182s,远超 60s 工具预算),且 `.catch(() => undefined)` 会吞掉 abort 继续重试。现在整段重试有 3s 预算,abort 会立即中止并上抛。
|
|
108
|
-
- **`browser_fill` 不再静默假成功**:checkbox/radio 点击后回读 `checked`,未变更(disabled 或被处理器取消)报 `ok:false`;input/textarea 在请求了非空值却得到空值时报错;`submit` 改为锚定**实际填入成功**的最后一个字段所在表单(此前取第一个能解析到的字段),并在 `requestSubmit()` 因 HTML5 约束校验不通过而**不提交**时如实返回 `submitted:false`(此前一律报 true)。
|
|
109
|
-
- **`browser_content format=json` 不再恒返回 `{}`**:DOM 元素没有自有可枚举属性,`JSON.stringify(document.body)` 永远是 `{}`。现在返回有界的结构视图(标签/id/class/子节点/叶子文本),若文本本身就是 JSON 则原样透传。
|
|
110
|
-
- **`browser_press_key` 支持标点**:此前只认字母数字与功能键,`Ctrl+-`、`Ctrl+/`、`,`、`.`、`[`、`]` 等一律抛 `BROWSER_KEY_UNKNOWN`,而工具描述却写「single characters」。现在按 US 布局补全可打印 ASCII。
|
|
111
|
-
- **`browser_wait_for` 非法选择器快速失败**:此前会每 250ms 重试直到超时(默认 15s)再报一个误导性的 `BROWSER_WAIT_TIMEOUT`,现在立即抛 `BROWSER_SELECTOR_INVALID`。
|
|
112
|
-
- **工具栏不再吞掉代理点击**:注入 chrome 的顶部中央 280×56 感应区在捕获阶段 `preventDefault` + `stopImmediatePropagation`,且从不检查 Agent 输入抑制窗口,导致落在该带的 CDP 点击到不了页面、`browser_click` 却报成功;抽屉打开后无自动关闭,死区还会扩大到约 940×42。现在感应与触发都会在 Agent 输入期间让路。
|
|
113
|
-
- **缩略图失败不再 5Hz 重试**:抓取失败(空图/编码失败/抛错)时 dirty 标记未清除,`finally` 每 200ms 重排一次,任务面板打开期间会以 5 次/秒无限抓屏。失败路径现在清除标记,只在有新动作时才重试。
|
|
114
|
-
- **下载上限改为流式判定**:此前先 `arrayBuffer()` 读完整包再比 64MiB,超大响应会先撑爆渲染进程,上限形同虚设;现在先看 `content-length`,再边读边累计并在超限时 `cancel()` 流,同时给页内 fetch 加了超时。
|
|
115
|
-
- **`browser_upload_file` 加读白名单**:此前只有写有白名单,上传可把任意本地文件交给页面(绕过 DSH 文件策略)。现在 `filePath` 必须存在且落在 `browser-electron.readRoots`(默认同 `writeRoots`)之内,校验在触碰 DOM 之前完成,越界抛 `BROWSER_READ_PATH_DENIED`。
|
|
116
|
-
- **任务摘要不再下发缩略图**:`window.__dshTasks` 走页面主世界,此前携带可见任务的 288px JPEG,任意页面可据此读走其他任务的屏幕内容。摘要只保留 `thumbnailVersion`,图片仅经定向的 `task.thumbnail` 补丁下发。写盘拒绝消息也不再回显允许根路径。
|
|
117
|
-
- **`browser_restrict` 改为按任务隔离**:此前白名单是模块级全局状态,一个任务设置后会把**所有**并行任务的浏览器工具一起限制。现在规则按调用任务存储,插件级 `tool-browser.allowedActions` 作为默认值,单个任务可用空列表只为解除自己。
|
|
118
|
-
- **页面可见轨迹脱敏**:注入页面的 `window.__dshChromeBootstrap.trail` 只保留展示所需字段——`type` 折叠为字符数、`execute` 丢弃脚本、URL 折叠为 origin、路径折叠为 basename。此前被访问页面可用一行 JS 读走同任务中早前站点输入的文本(含密码)与执行过的脚本。
|
|
119
|
-
- **页面→宿主控制通道加每视图 token**:`__dshBrowserTaskAction` 的 payload 必须携带 `createView` 生成的随机 token。此前任意页面脚本可伪造 `set-control-owner=human` 冻结该任务的 Agent 自动化。残留风险:页面若在 chrome 注入前 hook `JSON.stringify` 仍可能窃取 token,彻底解法是 isolated world 注入(后续工作)。
|
|
120
|
-
- **读操作纳入每任务 FIFO**:`snapshot`/`content`/`screenshot`/`list_tabs`/`history`/`session`/`space(list)` 现在会等待在飞写操作,修复并发 `browser_open` + `browser_snapshot` 读到导航前页面的竞态;同 readKey 的 in-flight 去重保留,`operationTails` 改为队列空闲即回收。
|
|
121
|
-
- **主机自愈改用稳定错误码**:新增 `BROWSER_HOST_DEAD` 与 `isBrowserHostDead()`;子进程在**调用中途**崩溃(exit / spawn error / socket close / 缓冲溢出 / RPC 超时)现在与"先崩再调"一样自愈一次,不再依赖错误文案匹配。disposed 之后不再重启子进程。
|
|
122
|
-
- **`available()` 实检**:`ElectronBrowserViewHost` 新增可选 `isAvailable?()`;自托管 host 落地实现(带缓存),Electron 缺失时如实上报不可用,seam 的 provider 选择错误码得以真正生效。
|
|
123
|
-
- **markdown 抓取修复**:`browser_content format=markdown` 的 walker 现在递归块级容器,标题/链接/列表在常见 `div` 嵌套下不再退化成纯文本。
|
|
124
|
-
- **下载内存**:子进程下载上限 256MiB → 64MiB,父进程 RPC 缓冲 512MiB → 128MiB(按 base64 推导保留 1.5× 余量)。
|
|
125
|
-
- **`browser_upload_file`**:补 30s 超时与 Agent 输入抑制标记,与其它输入工具一致。
|
|
126
|
-
- **`internals`**:标注 `@internal`;因 `lib/tool-browser/index.d.ts` 仍会导出,未真正移出公共 API 面(后续)。
|
|
127
|
-
- **写入路径白名单**:`browser_screenshot` 与 `browser_download` 只能写入 `browser-electron.writeRoots`(默认工作目录 + 系统临时目录)之内的路径;越界抛出 `BROWSER_WRITE_PATH_DENIED` 且不落盘。路径解析会处理最深已存在祖先的真实路径,防 `..` 与符号链接逃逸。
|
|
128
|
-
- **下载共用导航准入**:`browser_download` 与 `browser_navigate` 走同一套 URL 准入(仅 HTTP(S),拒绝 URL 内嵌凭据),不再绕过 `httpOnly`。
|
|
129
|
-
- **测试可信度**:`npm test` 现在先执行 `tsc`(`pretest`),不再对可能过期的构建产物 `lib/` 做假绿测试;快速迭代可用 `npm run test:only`。
|
|
130
|
-
## v0.4.2 (2026-09-17)
|
|
52
|
+
- **chrome 改成 Chrome 那样的「窗框」,而不是浮动小部件**。
|
|
53
|
+
- **注入式 chrome 改成 Chrome 式常驻顶栏**。
|
|
54
|
+
- **用 DSH 自己的校验器验证全部 37 个工具的 schema**。
|
|
55
|
+
- **补上 JS 侧指纹的断言(冒烟共 33 项),并确认现有指纹是自洽的**。
|
|
56
|
+
- **交互效果断言补全到 10 项(冒烟共 31 项)**:新增 **`click_ref`**(文档里的主要交互方式,此前只验证过「调用返回了」,从未验证过「页面收到了」)、双击、滚动、`fill` 选 select 四条**效果断言*…。
|
|
57
|
+
- **集成冒烟扩到 21 项,覆盖工具层与并行**:新增 ① **真实工具层跑在真实 provider 上**(`browser_open`/`browser_content`/`browser_click`/`browser_snaps…。
|
|
58
|
+
- **新增真实集成冒烟 `npm run smoke:browser-tools`**:用**真实 Electron 宿主 + 真实 Chromium** 驱动**真实 provider**,覆盖 12 项(含 click 三种寻址、sc…。
|
|
59
|
+
- **`browser_scrape` 改用独立标签页**:此前批次调用的是作用于「会话当前激活标签页」的 `navigate`/`execute`,于是 ① 批次运行期间任何工具调用都会和它**抢同一个标签页**,抽取可能拿到错误的页面…。
|
|
60
|
+
- **后台批次跳过 250ms 绘制等待**:`waitForDocumentReady` 在 `document.readyState === complete` 后会**固定再等 250ms**,目的是让截图/快照不抓到空白渲染——但…。
|
|
61
|
+
- **对齐请求指纹,减少被判定为机器人**:实测服务端收到的请求里有三处明显破绽 —— ① `User-Agent` 里带着 `Electron/42.9.3`。
|
|
62
|
+
- **下载改由子进程直接落盘**:此前子进程把整包 base64 塞进一行 JSON 回传,父进程再解码写盘——64MiB 的下载在 host→parent→disk 路径上要复制约 8 份(含 RPC 行缓冲)。
|
|
63
|
+
- **测试 seam 移出声明的 API 面**:`tsconfig` 打开 `stripInternal`,`internals` 与 `DeferredRemoteView` 不再出现在 `lib/*.d.ts` 里(运行时导出保留,…。
|
|
64
|
+
- **chrome 重装改由宿主执行**:provider 在导航后注入的是**无 token** 的 `PAGE_CHROME_SCRIPT`,而只有宿主持有每视图 token——一旦宿主自身的注入失败,退化的那份会让工具栏按钮静默失效…。
|
|
65
|
+
- **历史记录不再全量深拷贝**:`browser_history` 此前对每条 entry 做 `JSON.parse(JSON.stringify(params))`,把完整脚本与输入文本逐条复制一遍。
|
|
66
|
+
- **单条历史有存储上限**:`execute` 的脚本与 `type` 的文本超过 32KiB 时会被截断并打标。
|
|
67
|
+
- **补上两处零覆盖**:① `entry.ts` 的组合入口(外部 viewHost 优先 / 缺省自托管 / 销毁时只 dispose 自托管 host / 配置透传)此前没有任何测试。
|
|
68
|
+
- **新增 CI**:`.github/workflows/ci.yml` 在 push/PR 上跑 `npm ci --omit=optional` + `npm test`,并额外用 `git diff --exit-code -- …。
|
|
69
|
+
- **新增 ESLint 最小集**:只启用类型感知的 `no-floating-promises` / `no-misused-promises` 与两条一致性规则,不引入格式化以免搅动现有风格。
|
|
70
|
+
- **减少跨进程 IPC**:`syncVisibleTaskVisibility` 此前对**每个** view(含其它任务的隐藏页与后台标签)各发一次 `executeJavaScript`。
|
|
71
|
+
- **`browser_screenshot` 仅在写盘时受白名单约束**:不带 `savePath` 的截图仍是只读,保持「只读工具永不拦截」的承诺。
|
|
72
|
+
- **超时错误带稳定 code**:`withTimeout` 现在抛 `BROWSER_OPERATION_TIMEOUT`(保留 `TimeoutError` 名称),此前只有 `execute`/`waitForElement` 两…。
|
|
73
|
+
- **主机自愈改用稳定错误码**:新增 `BROWSER_HOST_DEAD` 与 `isBrowserHostDead()`。
|
|
74
|
+
- **`available()` 实检**:`ElectronBrowserViewHost` 新增可选 `isAvailable?()`。
|
|
75
|
+
- **下载内存**:子进程下载上限 256MiB → 64MiB,父进程 RPC 缓冲 512MiB → 128MiB(按 base64 推导保留 1.5× 余量)。
|
|
76
|
+
- **`internals`**:标注 `@internal`。
|
|
77
|
+
- **测试可信度**:`npm test` 现在先执行 `tsc`(`pretest`),不再对可能过期的构建产物 `lib/` 做假绿测试。
|
|
78
|
+
### 修复
|
|
79
|
+
- **修复:窗口从最小化恢复后,视图不会被重新布局(一直是 0×0)**。
|
|
80
|
+
- **修复 `showView` 与 `createView` 的竞态 —— 新标签的视图永远不会被显示**。
|
|
81
|
+
- **修复:浏览器直接导出的 cookie 文件会被整份拒绝**。
|
|
82
|
+
- **键盘输入此前也在空转(由第 9 轮的修复一并治好,本轮补上断言)**:实测运行中的旧代码,`browser_press_key` 派发后页面收到的 `keydown` 列表**为空** —— Enter/Tab/Escape/方…。
|
|
83
|
+
- **修复:点击在真实网站上完全不生效**。
|
|
84
|
+
- **修 `text` 寻址在「逐字符 span」页面上匹配失败(真实集成测试抓到的真 bug)**:文字匹配此前枚举候选标签(`a, button, input, span, div, li, td…`),**漏了 `p` 等大量承载正…。
|
|
85
|
+
- **修复写盘白名单默认值从未生效**:`entry.ts` 的 `writeRoots`/`readRoots` 声明为 `z.array(z.string())` 而没有默认值,而 schemastery 会把**缺省键物化成 `[]…。
|
|
86
|
+
- **每次调用的 `timeoutMs` 被夹在工具预算之下**:`browser_wait_for`/`browser_content` 此前把调用方给的值原样下传,所以 `timeoutMs: 90000` 实际会在 60s 被运行时…。
|
|
87
|
+
- **自愈不再在空白页上重放输入**:主机崩溃后重建的视图是 `about:blank`,而 `Input.*` 在空白文档上会「什么都不做但正常 resolve」,于是 `browser_click`/`browser_type` 会在…。
|
|
88
|
+
- **快照 `truncated` 语义修正**:此前用 `out.length >= cap` 判断,页面恰好有 cap 个可见候选时会误报截断。
|
|
89
|
+
- **`browser_scroll` 描述与实现对齐**:实际是「约一屏(视口高度的 80%,最少 480px)」,描述原写「one viewport」。
|
|
90
|
+
- **`CHANGELOG.md` 现在会进 npm tarball**(此前 `files` 未列)。
|
|
91
|
+
- **缩略图捕获加超时**:`capturePage()` 在合成器卡住时可能永不 settle,而 `finally` 不会执行 → 单飞标志永远为 true,此后缩略图静默停更。
|
|
92
|
+
- **`installPageChrome` 的 active 判定改用 viewId**:此前只比 taskKey,导致可见任务的**后台标签页**导航时被当成「正在显示」,会启动其页面定时器并顶掉真正可见视图的 chrome epoc…。
|
|
93
|
+
- **`restoreAuth` 逐条隔离**:此前任一条 cookie 非法即整批 reject、已写入不可回滚、调用方也拿不到计数。
|
|
94
|
+
- **会话丢失会自动重开**:工具层按任务缓存 session id。
|
|
95
|
+
- **`browser_close_tab` 如实返回**:此前无条件 `{closed:true}`,render 里「Tab not found.」是死代码。
|
|
96
|
+
- **`browser_handoff` 纳入白名单**:它不是只读工具(会改任务控制状态),此前不受 `browser_restrict` 约束。
|
|
97
|
+
- **`browser_reset_session` 纳入每任务 FIFO**:此前直接 close,可能把并发排队操作正在使用的会话/视图拆掉。
|
|
98
|
+
- **`browser_restrict` 校验名字是否存在**:此前只校验 `browser_` 前缀,拼错(如 `browser_snapsho`)会被接受并静默拒绝该任务所有受守卫动作。
|
|
99
|
+
- **输入派发补上超时兜底**:`click`/`clickRef`/`doubleClick`/`hover`/`type`/`pressKey` 的 8 处 `Input.*` 派发此前是裸 `await`,页面主线程被同步 JS 阻…。
|
|
100
|
+
- **快照重试有总预算且尊重取消**:空清单重试此前最多 5 次、每次可等满求值超时(理论上约 182s,远超 60s 工具预算),且 `.catch(() => undefined)` 会吞掉 abort 继续重试。
|
|
101
|
+
- **`browser_fill` 不再静默假成功**:checkbox/radio 点击后回读 `checked`,未变更(disabled 或被处理器取消)报 `ok:false`。
|
|
102
|
+
- **`browser_content format=json` 不再恒返回 `{}`**:DOM 元素没有自有可枚举属性,`JSON.stringify(document.body)` 永远是 `{}`。
|
|
103
|
+
- **`browser_wait_for` 非法选择器快速失败**:此前会每 250ms 重试直到超时(默认 15s)再报一个误导性的 `BROWSER_WAIT_TIMEOUT`,现在立即抛 `BROWSER_SELECTOR_INVA…。
|
|
104
|
+
- **工具栏不再吞掉代理点击**:注入 chrome 的顶部中央 280×56 感应区在捕获阶段 `preventDefault` + `stopImmediatePropagation`,且从不检查 Agent 输入抑制窗口,导致落在该…。
|
|
105
|
+
- **缩略图失败不再 5Hz 重试**:抓取失败(空图/编码失败/抛错)时 dirty 标记未清除,`finally` 每 200ms 重排一次,任务面板打开期间会以 5 次/秒无限抓屏。
|
|
106
|
+
- **下载上限改为流式判定**:此前先 `arrayBuffer()` 读完整包再比 64MiB,超大响应会先撑爆渲染进程,上限形同虚设。
|
|
107
|
+
- **`browser_upload_file` 加读白名单**:此前只有写有白名单,上传可把任意本地文件交给页面(绕过 DSH 文件策略)。
|
|
108
|
+
- **任务摘要不再下发缩略图**:`window.__dshTasks` 走页面主世界,此前携带可见任务的 288px JPEG,任意页面可据此读走其他任务的屏幕内容。
|
|
109
|
+
- **`browser_restrict` 改为按任务隔离**:此前白名单是模块级全局状态,一个任务设置后会把**所有**并行任务的浏览器工具一起限制。
|
|
110
|
+
- **页面可见轨迹脱敏**:注入页面的 `window.__dshChromeBootstrap.trail` 只保留展示所需字段——`type` 折叠为字符数、`execute` 丢弃脚本、URL 折叠为 origin、路径折叠为 ba…。
|
|
111
|
+
- **页面→宿主控制通道加每视图 token**:`__dshBrowserTaskAction` 的 payload 必须携带 `createView` 生成的随机 token。
|
|
112
|
+
- **读操作纳入每任务 FIFO**:`snapshot`/`content`/`screenshot`/`list_tabs`/`history`/`session`/`space(list)` 现在会等待在飞写操作,修复并发 `bro…。
|
|
113
|
+
- **markdown 抓取修复**:`browser_content format=markdown` 的 walker 现在递归块级容器,标题/链接/列表在常见 `div` 嵌套下不再退化成纯文本。
|
|
114
|
+
- **`browser_upload_file`**:补 30s 超时与 Agent 输入抑制标记,与其它输入工具一致。
|
|
115
|
+
- **下载共用导航准入**:`browser_download` 与 `browser_navigate` 走同一套 URL 准入(仅 HTTP(S),拒绝 URL 内嵌凭据),不再绕过 `httpOnly`。
|
|
131
116
|
|
|
132
|
-
|
|
117
|
+
## v0.4.2 (2026-09-17)
|
|
118
|
+
### 新功能
|
|
119
|
+
- **按站点清理 Cookie**:`browser_auth action="clear"` 支持按 `domain`(含子域)与/或 `name` 精确删除 Cookie。
|
|
133
120
|
|
|
134
121
|
## v0.4.1 (2026-08-26)
|
|
135
|
-
|
|
136
|
-
-
|
|
122
|
+
### 新功能
|
|
123
|
+
- **多标签会话恢复**:keyed browser sessions are recovered when the tool-layer session cache is lost, so the first direct switc…。
|
|
137
124
|
|
|
138
125
|
## v0.4.0 (2026-08-26)
|
|
139
|
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
|
|
144
|
-
-
|
|
126
|
+
### 新功能
|
|
127
|
+
- **显式人机交接**:任务卡显示运行、等待用户、用户接管、失败和空闲状态。
|
|
128
|
+
- **语义浏览控制**:新增后退、前进、刷新、停止、滚动,以及由 `snapshotId` 和元素 ref 驱动的精确点击/滚动到元素工具。
|
|
129
|
+
- **低干扰工具栏**:工具栏默认隐入页面上方,顶部中间悬停出现圆形下箭头。
|
|
130
|
+
### 优化
|
|
131
|
+
- **轻量工作区同步**:Host 改为 bootstrap + versioned patch。
|
|
132
|
+
- **资源预算**:任务缩略图仅在任务面板打开时按需单飞捕获,带 2 秒节流和 32 项缓存。
|
|
145
133
|
|
|
146
134
|
## v0.3.1 (2026-08-23)
|
|
147
|
-
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
- **Browser Flow
|
|
135
|
+
### 新功能
|
|
136
|
+
- **单窗口任务管理器**:所有 DSH 任务共享一个可见浏览器窗口,同时保留隔离的任务视图、标签和历史。
|
|
137
|
+
- **任务标签**:`browser_space` 命名或列出浏览器任务,不再表示原生窗口。
|
|
138
|
+
- **可视工作区**:任务与操作轨迹可同时打开,切换任务同步轨迹,并显示可见页面的实时缩略图。
|
|
139
|
+
- **Browser Flow 图标**:新增 SVG 主源、PNG/ICO 衍生资源及 Electron 窗口图标接入。
|
|
152
140
|
|
|
153
141
|
## v0.3.0 (2026-08-21)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
- **质量**:32/32 测试(FakeHost 行为测试 12 条 + 源码断言/页面 chrome 断言);SDD 全流程评审(每任务 implement->review->fix 循环 + 整支 final review)。
|
|
142
|
+
### 新功能
|
|
143
|
+
- **JS 对话框**:宿主自动 accept(页面永不卡死),草案以 `drainDialog` 读回并写入 `browser_history`(`dialog` 记录)。
|
|
144
|
+
- **输入工具**:`browser_press_key`(CDP keyDown/keyUp,修饰键位掩码)、`browser_double_click`(clickCount 2)、`browser_hover`(mouseMoved…。
|
|
145
|
+
- **等待与定位**:`browser_wait_for`(250ms 有界轮询,`BROWSER_WAIT_TIMEOUT`)。
|
|
146
|
+
- **每任务窗口**:每个 DSH 任务一个独立 `BrowserWindow`(createView key)。
|
|
147
|
+
### 优化
|
|
148
|
+
- **稳定性**:Electron 锁定 42.9.3(43.4.1 组合器故障)。
|
|
149
|
+
- **质量**:32/32 测试(FakeHost 行为测试 12 条 + 源码断言/页面 chrome 断言)。
|
|
163
150
|
|
|
164
151
|
## v0.2.0 (2026-08-21)
|
|
165
|
-
|
|
166
|
-
首版 `dsh-browser-plus
|
|
152
|
+
### 新功能
|
|
153
|
+
- 首版 `dsh-browser-plus`:共享可见浏览器、ego 风格页面内工具栏、操作轨迹(trail)面板、用户控制检测、稳定单视图合成。
|
package/README.en.md
CHANGED
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
dsh-browser-plus is developed on top of the MIT-licensed `dsh-browser` codebase and independently maintained by ParticleLight.
|
|
6
6
|
|
|
7
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
8
|
+
[](https://awesome-dsh-plugin.com)
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
10
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
11
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/stargazers)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/actions/workflows/ci.yml)
|
|
14
|
+
[](#install)
|
|
15
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/releases)
|
|
15
16
|
|
|
16
17
|
## Why it exists
|
|
17
18
|
|
|
@@ -30,6 +31,14 @@ Browser automation should not disappear into a process the user cannot inspect.
|
|
|
30
31
|
|
|
31
32
|
## Install
|
|
32
33
|
|
|
34
|
+
From npm (recommended):
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
dsh plugin --profile web add dsh-browser-plus
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or straight from the repository:
|
|
41
|
+
|
|
33
42
|
```sh
|
|
34
43
|
dsh plugin --profile web add github:ParticleLight/dsh-browser-plus
|
|
35
44
|
```
|
|
@@ -41,6 +50,7 @@ If another browser bundle is already installed, read the [migration guide](docs/
|
|
|
41
50
|
| Scenario | Tools |
|
|
42
51
|
| --- | --- |
|
|
43
52
|
| Open and inspect | `browser_open`, `browser_snapshot`, `browser_content`, `browser_screenshot` |
|
|
53
|
+
| Print and highlight | `browser_pdf`, `browser_highlight` |
|
|
44
54
|
| Native navigation | `browser_back`, `browser_forward`, `browser_reload`, `browser_stop`, `browser_scroll` |
|
|
45
55
|
| Snapshot references | `browser_click_ref`, `browser_scroll_into_view` |
|
|
46
56
|
| Page interaction | `browser_click`, `browser_press_key`, `browser_double_click`, `browser_hover`, `browser_type` |
|
|
@@ -61,6 +71,15 @@ If another browser bundle is already installed, read the [migration guide](docs/
|
|
|
61
71
|
|
|
62
72
|
Snapshots expose a short-lived `snapshotId` plus element references. Prefer reference tools and take a fresh snapshot after the page changes; page-level scripts automatically ignore the browser's own chrome.
|
|
63
73
|
|
|
74
|
+
## Opening the browser window
|
|
75
|
+
|
|
76
|
+
The window normally appears the first time the agent calls a browser tool. A human can open it too, two ways:
|
|
77
|
+
|
|
78
|
+
- **The `/browser` command** — type `/` in the composer (or click `+`) and pick it; the window opens or is raised, and **no model message is produced**.
|
|
79
|
+
- **The DSH-Browser-Plus tab in the right sidebar** (its own name and icon, so it never collides with the product's own browser tab) — pick it from the rightbar's add list: the window comes up as the panel opens, and the panel keeps a button for raising it again plus the current task count.
|
|
80
|
+
|
|
81
|
+
> The product's own browser tab is a different thing: DSH's sandboxed iframe browser, unrelated to this self-hosted window.
|
|
82
|
+
|
|
64
83
|
## How it works
|
|
65
84
|
|
|
66
85
|
```text
|
package/README.md
CHANGED
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
基于 MIT 许可的 `dsh-browser` 代码基础持续开发,并由 ParticleLight 独立维护。
|
|
6
6
|
|
|
7
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
8
|
+
[](https://awesome-dsh-plugin.com)
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
10
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
11
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/stargazers)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/actions/workflows/ci.yml)
|
|
14
|
+
[](#安装)
|
|
15
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/releases)
|
|
15
16
|
|
|
16
17
|
## 为何使用它
|
|
17
18
|
|
|
@@ -30,6 +31,14 @@
|
|
|
30
31
|
|
|
31
32
|
## 安装
|
|
32
33
|
|
|
34
|
+
从 npm 安装(推荐):
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
dsh plugin --profile web add dsh-browser-plus
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
或直接从仓库安装:
|
|
41
|
+
|
|
33
42
|
```sh
|
|
34
43
|
dsh plugin --profile web add github:ParticleLight/dsh-browser-plus
|
|
35
44
|
```
|
|
@@ -41,6 +50,7 @@ dsh plugin --profile web add github:ParticleLight/dsh-browser-plus
|
|
|
41
50
|
| 场景 | 工具 |
|
|
42
51
|
| --- | --- |
|
|
43
52
|
| 打开与读取 | `browser_open`、`browser_snapshot`、`browser_content`、`browser_screenshot` |
|
|
53
|
+
| 打印与高亮 | `browser_pdf`、`browser_highlight` |
|
|
44
54
|
| 语义导航 | `browser_back`、`browser_forward`、`browser_reload`、`browser_stop`、`browser_scroll` |
|
|
45
55
|
| 快照引用 | `browser_click_ref`、`browser_scroll_into_view` |
|
|
46
56
|
| 页面交互 | `browser_click`、`browser_press_key`、`browser_double_click`、`browser_hover`、`browser_type` |
|
|
@@ -61,6 +71,15 @@ dsh plugin --profile web add github:ParticleLight/dsh-browser-plus
|
|
|
61
71
|
|
|
62
72
|
快照返回短生命周期的 `snapshotId` 与元素引用;优先用 `browser_click_ref` 或 `browser_scroll_into_view` 操作,页面变化后重新快照。页面级脚本会自动过滤浏览器自身 chrome。
|
|
63
73
|
|
|
74
|
+
## 打开浏览器窗口
|
|
75
|
+
|
|
76
|
+
窗口默认只在 Agent 第一次调用浏览器工具时出现。人也可以自己打开它,有两个入口:
|
|
77
|
+
|
|
78
|
+
- **`/browser` 命令** —— 在输入框敲 `/`(或点 `+`)选「浏览器」,回车即打开或前置窗口。它**不产生模型消息**,只是把窗口带到眼前。
|
|
79
|
+
- **右侧栏「DSH-Browser-Plus」** —— 在右侧栏的「添加」列表里选它(名字和图标都是这个插件自己的,避免和 DSH 自带的「浏览器」撞名),面板打开的同时窗口就被带出来了;面板里还有一个按钮可以随时再前置一次,并显示当前有几个浏览器任务。
|
|
80
|
+
|
|
81
|
+
> 右侧栏里 DSH 自带的「浏览器」是另一个东西:那是 DSH 自己的沙箱 iframe 浏览器,与这个自托管窗口无关。
|
|
82
|
+
|
|
64
83
|
## 工作方式
|
|
65
84
|
|
|
66
85
|
```text
|