@anweat/dsh-browser 0.1.13-alpha.1 → 0.1.14-alpha.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/README.md CHANGED
@@ -1,382 +1,393 @@
1
- # dsh-browser
2
-
3
- 自包含的浏览器运行时插件 for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)。
4
-
5
- 把 **Playwright / Patchright(可选 Chromium 驱动)** 与 **OpenCLI** 作为插件自身的 npm 依赖打包(优先插件本地,缺省回退全局复用),对外提供一个 `browser` 服务 + 一组交互式浏览器工具。`dsh-web-search-pro` 通过 `inject: ['browser']` 注入该服务,驱动它的浏览器 / OpenCLI 后端——**不再依赖全局 CLI**。
6
-
7
- ## 兼容与发布通道
8
-
9
- | 插件发布通道 | DSH 基线 | 兼容承诺 |
10
- |---|---|---|
11
- | npm `latest`(`0.1.12`) | `dsh-v0.1.1-rc.2` 至 `dsh-v0.1.2-rc.1` | 已验证维护基线 |
12
- | npm `next` 候选(`0.1.13-alpha.1`) | `dsh-v0.1.5-alpha.1` | 精确依赖与真实 profile 验收目标 |
13
-
14
- `0.1.13-alpha.1` 使用 DSH 新客户端分包:状态存储来自
15
- `dsh-client-store`,设置契约来自 `dsh-client-ui-settings`,客户端 Context
16
- 来自 Cordis。该候选不会覆盖 npm `latest`。
17
-
18
- ## 安装
19
-
20
- ```bash
21
- dsh plugin --profile web add @anweat/dsh-browser
22
- # 或本地目录 / tarball:
23
- dsh plugin --profile web add ./dsh-browser
24
- # 重启(web profile 关闭了 HMR):
25
- dsh --profile web
26
- ```
27
-
28
- > npm `latest` 延续现有维护基线;本开发分支精确适配 `dsh-v0.1.5-alpha.1`。
29
- > 若你的 harness 是包含未发布提交的本地源码 checkout,版本号可能有出入——用
30
- > `dsh plugin --profile web add ./<path>` 并在 profile 的 `pnpm-workspace.yaml`
31
- > 里对齐版本后重装即可。
32
-
33
- ## 从旧版本升级
34
-
35
- Web Search Pro 与浏览器插件应同步升级;`dsh-web-search-pro >= 0.1.8` 需要 `@anweat/dsh-browser >= 0.1.8`。面向 `dsh-v0.1.5-alpha.1` 联调时,使用 browser 与 Web Search Pro 的 npm `next` 候选并完整重启 profile。0.1.11 移除了对旧版 `dsh-settings` 的运行时 `settingsNamespace` 导入;0.1.10 修复工具描述被 DSH 误解析为 prompt 变量。
36
-
37
- ```bash
38
- dsh plugin --profile web add @anweat/dsh-browser@next dsh-web-search-pro@next
39
- ```
40
-
41
- 升级后完整停止并重启 Web profile,再调用 `browser_status`、`browser_opencli_status` 和 `web_backend_status`;仅刷新网页不会重新加载插件服务或 Web Search Pro 配置面板。尤其不要只升级 Web Search Pro:新的工具目录、Patchright 运行时和调用缓冲都来自浏览器插件。
42
-
43
- ## 快速使用与适用情形
44
-
45
- 安装并重启后,可先让模型调用 `browser_status`,再按任务选择工具。默认
46
- `automationMode: standard`:读取直接执行,点击、输入、悬停、文件上传及页面写操作走 DSH 原生一次性审批。页面脚本和本地文件上传在 `autonomous` 下仍需审批,只有 `unrestricted` 会跳过确认。
47
-
48
- | 情形 | 推荐方式 | 关键边界 |
49
- |---|---|---|
50
- | 公开网页读取、截图 | `browser_open` → `browser_read` / `browser_screenshot` | 不需要登录态 |
51
- | 表单、分页、懒加载 | `browser_click` / `browser_type` / `browser_scroll` | `standard` 下审批;`autonomous` 下可直接执行 |
52
- | 悬停菜单与提示 | `browser_hover` | 与直接页面交互使用相同审批策略 |
53
- | 文件上传 | `browser_set_files` | 只接受现有绝对文件路径;最多 20 个、合计 512 MiB;除 `unrestricted` 外审批会显示路径 |
54
- | 页面脚本表达式 | `browser_evaluate` | 使用当前页面来源和登录态;可访问 DOM、非 HttpOnly Cookie、Web Storage 和浏览器允许的网络 API |
55
- | 登录后站点 | `authProfile` | 必须配置 `allowedDomains`;默认不回写 Cookie |
56
- | 固定站点增强 | `rulePack` | 只允许有界步骤;本地 init script 必须 SHA-256 固定且 ≤64KB |
57
- | 模型生成的多步操作 | `browser_recipe_run` | 声明式步骤;审批策略由 `automationMode` 决定 |
58
- | 默认只读脚本 | `browser_script_catalog` → `browser_script_run_builtin` | 内置 article/links/JSON-LD/forms,不执行外来代码 |
59
- | 外部模型生成 UserScript | `browser_script_validate` → `browser_userscript_run` | 必须 `@match` + `@grant none`;除 `unrestricted` 外执行前审批 |
60
- | 有限站点遍历 | `browser_crawl` | 页数、深度、并发、突发与退避始终受 `usagePolicy` 约束 |
61
- | Reddit/小红书等 OpenCLI 平台 | `browser_opencli_status` → `browser_opencli_catalog` → `browser_opencli_run` | 先发现精确 adapter;通用调用除 `unrestricted` 外需审批 |
62
- | 普通站点兼容性不佳 | `browserRuntime: patchright` | Chromium-only;建议专用 Chrome profile,不与指纹注入库叠加 |
63
-
64
- DSH 会话示例:
65
-
66
- ```text
67
- 先调用 browser_status;然后用 browser_open 打开目标页。
68
- 若页面需要登录,使用 authProfile=forum;不要把 Cookie 放进工具参数。
69
- ```
70
-
71
- ## 内核与依赖的"打包 vs 复用"
72
-
73
- | 层 | 实际是什么 | 打包还是复用 |
74
- |---|---|---|
75
- | **chromium 内核** | 共享缓存 `%LOCALAPPDATA%\ms-playwright`(约 400MB) | **永远复用共享缓存**,不塞进插件、不重复下载;缺失时 `browser_install` 一键补 |
76
- | **playwright 驱动**(JS 包) | `playwright` npm 依赖 | 插件本地 node_modules 优先,缺省回退全局 npm |
77
- | **patchright 驱动**(可选) | 与 Playwright 同版本的 Chromium 兼容驱动 | 插件内置;配置 `browserRuntime: patchright` 才启用 |
78
- | **opencli**(纯 Node CLI) | `@jackwener/opencli` npm 依赖 | 同上,本地优先 / 全局复用 |
79
-
80
- ## 服务:`browser`
81
-
82
- `dsh-browser` 在 `apply()` 里 `ctx.provide('browser', service)`。任何插件声明
83
- `inject: ['browser']` 即可消费:
84
-
85
- ```ts
86
- export const inject = ['tools', 'browser']
87
- export function apply(ctx: Context) {
88
- const browser = ctx.get('browser') as BrowserService
89
- // browser.render / snapshot / searchResults / opencli / recipe /
90
- // runBuiltinScript / runUserscript / open / click / type / scroll / read / screenshot / close
91
- }
92
- ```
93
-
94
- 服务接口(结构性,无需共享类型包)见 `src/browser-service.ts`。
95
-
96
- ## 自动化自由度
97
-
98
- `automationMode` 控制模型可见的工具集合和执行审批。建议从 `standard` 开始,仅在完全只读任务或受控自动化环境中切换:
99
-
100
- | 模式 | 浏览器与 Web Search Pro 写操作 | 仍需审批或拒绝 | 不可取消的安全底线 |
101
- |---|---|---|---|
102
- | `read-only` | 只读工具与只读 Recipe;缓存清理、规则写入和安装拒绝 | 页面交互、写 Recipe、UserScript、OpenCLI run 均隐藏或拒绝 | 只能读取、校验、截图及运行只读脚本/Recipe |
103
- | `standard`(默认) | 页面交互、写 Recipe、缓存清理和规则写入均需一次性审批 | UserScript、通用 OpenCLI、浏览器/后端安装也需审批 | 所有安全校验持续启用 |
104
- | `autonomous` | 页面交互、写 Recipe、缓存清理和规则写入可直接执行 | 外部 UserScript、通用 OpenCLI、浏览器/后端安装仍强制审批 | 所有安全校验持续启用 |
105
- | `unrestricted` | 所有上述工具均不触发审批,适合隔离环境中的无人值守测试 | 无审批提示 | 仍执行域名、元数据、参数、大小和步骤数校验 |
106
-
107
- `unrestricted` 会允许模型直接运行外部脚本、通用 CLI 和安装命令,只应在隔离的测试 profile 或明确授权的自动化环境中使用;日常 profile 保持 `standard`。它只取消人工确认,**不会取消 `usagePolicy` 的并发、突发、页数、深度、重试与冷却保护**。模式改变后需要重启 DSH profile,工具目录才会按新配置重新注册。
108
-
109
- ## 工具(最多 24 个)
110
-
111
- | 工具 | 作用 |
112
- |---|---|
113
- | `browser_open` | 打开 URL,返回标题/可读文本/全页截图路径(持久页会话) |
114
- | `browser_click` | 按 CSS 选择器点击 |
115
- | `browser_type` | 向 input/textarea 输入 |
116
- | `browser_hover` | 悬停 CSS 选择器并返回页面状态与截图 |
117
- | `browser_set_files` | 把现有本地文件设置到 `input[type=file]`;绝对路径、数量和总大小受限 |
118
- | `browser_evaluate` | 在当前页执行最长 20,000 字符的 JavaScript 表达式,返回最多 100,000 字符 JSON |
119
- | `browser_scroll` | 纵向滚动(触发懒加载) |
120
- | `browser_read` | 读当前页 URL/标题/文本(不截图) |
121
- | `browser_screenshot` | 当前页全页截图 |
122
- | `browser_close` | 关闭当前页(下次 open 全新) |
123
- | `browser_status` | 运行时状态(含 automationMode、已暴露工具及各类审批策略) |
124
- | `browser_install` | 安装 playwright chromium(`browser_status` 报缺失时执行一次) |
125
- | `browser_script_catalog` | 列出内置只读脚本及其 SHA-256 |
126
- | `browser_script_validate` | 解析外部 UserScript 的元数据、域名、grant、能力与哈希,不执行 |
127
- | `browser_script_run_builtin` | 在独立 Playwright context 中运行内置只读脚本 |
128
- | `browser_userscript_run` | 运行外部 UserScript;强制域名匹配,审批策略由模式决定 |
129
- | `browser_recipe_run` | 最多 25 步 Playwright Recipe;支持等待、定位、表单、键盘、提取、断言和截图 |
130
- | `browser_automation_search` | 只有显式关键词调用才检索;可限定 active/draft/all、域名和类型,最多返回 `retrievalTopK` 条摘要 |
131
- | `browser_automation_develop` | 按确切 ID 读取源码,或显式保存、静态校验、真实回放草稿;永远不能激活资产 |
132
- | `browser_automation_run` | 按 ID 运行已激活资产;再次执行限域和输入大小校验,审批由 `automationMode` 决定 |
133
- | `browser_opencli_status` | 实际运行 OpenCLI doctor,报告 daemon/extension/profile 连通性 |
134
- | `browser_opencli_catalog` | 对 OpenCLI 大目录按 query/site/access/strategy 过滤,单次最多返回 100 条 |
135
- | `browser_opencli_run` | 通用 OpenCLI argv 网关;除 `unrestricted` 外触发 DSH 原生一次性审批 |
136
- | `browser_crawl` | 匿名、有限广度遍历;默认同源,强制使用全局调用缓冲和单次页数/深度预算 |
137
-
138
- ## 可复用自动化资产(实验性)
139
-
140
- > **Experimental:** Recipe/UserScript 的积累、模型开发、检索和复用接口仍可能调整。建议先在隔离 profile 中启用,审阅草稿并完成真实浏览器回放后再手动激活;不要把它作为无人监管的生产写操作入口。
141
-
142
- 自动化执行自由度与资产持久化是两套独立开关。`automationMode: unrestricted` 只影响执行审批,不会让 Agent 自动保存脚本;默认 `automationAssets.persistenceMode: suggest` 仅对成功的 `browser_recipe_run` 记录脱敏语义步骤。具体输入会替换为 `{{input}}` / `{{secret}}`,会话 ID 只保存短哈希,不保存页面正文、cookie、token、密码或聊天记录。
143
-
144
- 默认在 14 天窗口内,同一域名和步骤指纹至少成功 3 次、来自至少 2 个会话且成功率达到 80%,面板才出现“是否总结”候选。每天最多提示 2 次;候选、草稿和已激活资产均有数量上限。推荐流程是:
145
-
146
- 1. 候选达到阈值后,在“浏览器自动化 → 可复用自动化资产”选择“总结为草稿”或“暂不总结”。
147
- 2. 在脚本列表点选草稿;只有此时前端才按 ID 读取完整 recipe / UserScript。编辑器支持 recipe 和带 `@match`、`@grant none` 的 UserScript。UserScript 可从只读对象 `__DSH_INPUTS__` 读取 `inputNames` 声明的运行时输入,输入不会写入资产文件。
148
- 3. 保存后先做静态校验,再填写测试 URL/输入执行真实浏览器回放。只有真实回放成功才可手动激活;已激活版本不可原地编辑,避免后台行为静默漂移。
149
- 4. Agent 用 `browser_automation_search` 获取有界摘要,再用 `browser_automation_run` 按 ID 调用。检索默认 top 5、目录预算约 800 tokens,源码不会进入模型上下文。
150
-
151
- `persistenceMode` 可选 `off | manual | suggest | auto-draft`。日常使用建议 `suggest`;`auto-draft` 只适合隔离测试 profile,并且仍不会自动激活。`activationMode` 当前默认并推荐 `manual`;`auto-tested` 作为后续真实沙箱回放策略的保留配置,不会把一次静态校验当成生产激活依据。
152
-
153
- ### 模型显式开发 recipe / UserScript
154
-
155
- 模型目录不会预载任何 recipe 或源码。需要批量索引等强指向自动化时,模型按以下顺序显式访问:
156
-
157
- 1. 调用 `browser_automation_search(query="batch-index issues", status="draft|active", kind="recipe")`,仅得到 ID、名称、标签、域名、输入名和运行统计。
158
- 2. 确认要修改某项后,调用 `browser_automation_develop(action="get", id="...")`;只有这一步会把单个资产的完整 recipe/源码带入当前上下文。
159
- 3. `action="save"` 可直接声明新的 recipe,或保存带 `@match` / `@grant none` 的 UserScript;只能生成/更新 draft。默认每个模型会话最多写 3 次,仍受全局 `maxDrafts` 限制。
160
- 4. `action="validate"` 只做结构与 UserScript 元数据校验,不提供激活资格;`action="test"` 必须给 URL 和声明输入,执行真实 Playwright 回放,成功后才标记 `passed`。
161
- 5. 激活、归档和回滚只在可视化面板完成,模型开发工具没有对应动作。
162
-
163
- recipe 建议把检索意图固化在 `name`、`description` 和 `tags`,例如 `batch-index`、`issues`、`community-search`。检索采用小规模确定性关键词评分和 token 预算,不自动把整个资产库升级成模型工具,也不使用隐藏的全量 prompt 注入。
164
-
165
- `modelDevelopmentEnabled: false` 会在重启后直接从模型工具目录移除开发入口;`standard` 保存草稿和真实回放均需审批,`autonomous` 可直接保存草稿但真实回放仍需审批,只有 `unrestricted` 才会跳过回放审批。所有模式仍执行域名、UserScript 元数据、输入、源码大小和使用频率限制。
166
-
167
- ## 使用策略:防止过度调用的缓冲
168
-
169
- `usagePolicy` 是资源与站点压力保护,不是审批系统。所有模式共用同一个进程内 Governor:
170
-
171
- - `maxConcurrency` 限制同时发起的导航,超出后排队;`burst` + `minDelayMs` 限制单站点短时突发。
172
- - OpenCLI adapter / Browser Bridge 调度也占用同一全局并发与 burst 缓冲,不会因绕过 Playwright 而失去节流。
173
- - 站点返回 429、502、503、504 时,按 `Retry-After` 或指数退避进入站点级冷却,最多重试 `retryLimit` 次。
174
- - `browser_crawl` 还受 `maxPagesPerRun` 和 `maxDepth` 硬上限约束;调用参数只能收紧,不能突破配置。
175
- - 泛爬取默认使用匿名 context,不继承全局 `storageStatePath` 或 `defaultAuthProfile`;登录后读取仍使用显式限域的单页/Recipe 工具。
176
- - `browser_status` 显示累计运行、排队、等待和 backoff 次数,便于判断是否调用过密。
177
- - 泛爬取能力本身不隐藏,但调用方仍应遵守目标站点条款、robots 指令、版权、隐私和适用法律;工具每次返回该警告。
178
-
179
- ## 外部模型脚本:推荐流程
180
-
181
- 外部模型可以输出 Tampermonkey/UserScript 格式源码,但不要直接执行。让当前 DSH Agent 先调用
182
- `browser_script_validate`,展示名称、`@match`、SHA-256 和能力,再调用
183
- `browser_userscript_run`。除 `unrestricted` 外,执行调用会进入 Harness 的
184
- `tools/pre-execute → approval` 原生流程;用户拒绝、没有 approval 服务或调用不属于 Agent 时都不会运行。
185
-
186
- 最小脚本示例:
187
-
188
- ```js
189
- // ==UserScript==
190
- // @name Read Search Cards
191
- // @match https://example.com/search*
192
- // @grant none
193
- // ==/UserScript==
194
- return [...document.querySelectorAll('.result')].slice(0, 20).map(card => ({
195
- title: card.querySelector('h2')?.textContent?.trim() || '',
196
- url: card.querySelector('a')?.href || '',
197
- }))
198
- ```
199
-
200
- 当前兼容的是 UserScript 元数据和页面脚本执行模型,不模拟完整 Tampermonkey:
201
-
202
- - 只支持 `@grant none`;`GM_cookie`、`GM_xmlhttpRequest`、`unsafeWindow` 等不提供。
203
- - 不支持 `@require`,避免审批过的源码在运行时再拉取未审查代码。
204
- - 源码 ≤64KB、结果 ≤100,000 字符、单次运行最长 30 秒。
205
- - 使用显式 URL,新建独立 Playwright context;需要登录态时只能选已限域的 `authProfile`。
206
- - 审批代表允许该脚本以当前站点登录身份操作页面;静态能力报告只用于解释,不是沙箱。
207
-
208
- `browser_evaluate` 是面向当前持久页的短表达式入口,不使用 UserScript 元数据。它能调用页面已有 JavaScript、读取或修改 DOM、访问非 HttpOnly Cookie 和 Web Storage,也能通过 `fetch` 等浏览器 API 发起页面来源允许的请求。插件会明确报告这些能力,但不会判断具体网站是否允许该访问;调用方应根据目标网站规则及适用要求使用并承担相应责任,插件只执行被批准的浏览器操作。表达式没有 Node.js 全局对象或直接主机文件系统权限,结果必须可 JSON 序列化,超时会关闭当前页以终止执行。需要可复用、可审阅的脚本时仍使用 UserScript 资产流程。
209
-
210
- ## Cookie 与文件落盘
211
-
212
- - `authProfile` 从配置的 `storageStatePath` 载入 Cookie、localStorage 等登录态。只有 `persistState: true` 才在 context 关闭时原子回写该文件;全局兼容路径默认不会被交互会话改写。
213
- - `browser_evaluate` 可读取 `document.cookie`,因此能看到当前来源的非 HttpOnly Cookie;浏览器不会向页面 JavaScript 暴露 HttpOnly Cookie。除 `unrestricted` 外,每次执行都需要确认。
214
- - `browser_set_files` 只读取调用中列出的绝对路径并交给当前页面上传控件,不修改源文件,也不会遍历目录。除 `unrestricted` 外,即使在 `autonomous` 模式也需要确认。
215
- - `browser_screenshot` 和 `snapshot` 只向 `snapshotDir` 写入截图或 HTML;持久登录态只写配置的状态文件。`browser_evaluate` 触发的浏览器下载不会由该工具保存或返回,下载落盘需要后续单独设计显式目录和文件名规则。
216
-
217
- 常见读取任务优先用内置脚本:`article-clean`、`links`、`jsonld`、`forms`。它们不返回表单当前值,
218
- 也不触发点击或网络写操作。
219
-
220
- ## Playwright Recipe
221
-
222
- Recipe 适合让模型生成可审计、可复现的多步操作,不必生成 JavaScript:
223
-
224
- ```json
225
- {
226
- "url": "https://example.com/search",
227
- "steps": [
228
- { "type": "wait", "condition": "selector", "value": "#query" },
229
- { "type": "fill", "selector": "#query", "value": "DeepSeek Harness" },
230
- { "type": "press", "selector": "#query", "key": "Enter" },
231
- { "type": "wait", "condition": "load" },
232
- { "type": "extract", "selector": "main", "mode": "links", "limit": 30 },
233
- { "type": "screenshot" }
234
- ]
235
- }
236
- ```
237
-
238
- 支持的步骤为:`wait`、`click`、`fill`、`type`、`press`、`select`、`check`、`hover`、
239
- `scroll`、`extract`、`assert`、`screenshot`。纯读取步骤直接执行;出现点击、输入、键盘、选择、
240
- 勾选、悬停或滚动时,`standard` 下整个 Recipe 只询问一次审批,批准后顺序执行;
241
- `autonomous` / `unrestricted` 下直接执行,`read-only` 下拒绝。
242
-
243
- ## 配置(cordis.yml / patch config)
244
-
245
- ```yaml
246
- - insert:
247
- - id: browser
248
- name: '@anweat/dsh-browser'
249
- config:
250
- automationMode: standard # read-only | standard | autonomous | unrestricted
251
- browserRuntime: playwright # playwright | patchright
252
- channel: chromium # 'chromium'(打包内核)| 'msedge'(系统 Edge)
253
- headless: true
254
- opencliEnabled: true
255
- usagePolicy: # 所有模式都生效;无审批模式也不会绕过
256
- minDelayMs: 750
257
- maxConcurrency: 2
258
- burst: 3
259
- maxPagesPerRun: 20
260
- maxDepth: 2
261
- retryLimit: 2
262
- backoffBaseMs: 1000
263
- cooldownMs: 30000
264
- automationAssets:
265
- enabled: true
266
- persistenceMode: suggest # off | manual | suggest | auto-draft
267
- activationMode: manual # 当前推荐值;不会因静态校验自动激活
268
- minSuccessfulRuns: 3
269
- minDistinctSessions: 2
270
- successWindowDays: 14
271
- minSuccessRate: 0.8
272
- maxCandidates: 20
273
- candidateTtlDays: 14
274
- maxSuggestionsPerDay: 2
275
- maxDrafts: 10
276
- maxActiveAssets: 50
277
- retrievalTopK: 5
278
- catalogTokenBudget: 800
279
- modelDevelopmentEnabled: true
280
- maxModelDraftWritesPerSession: 3
281
- storageStatePath: '' # Playwright 登录态 JSON(复用已登录会话)
282
- authProfiles:
283
- forum:
284
- storageStatePath: 'D:/secrets/forum.json'
285
- allowedDomains: [example.com]
286
- persistState: false # 默认只读;true 才会原子回写刷新后的状态
287
- rulePacks:
288
- forum-enhanced:
289
- matches: [example.com]
290
- initScriptPath: 'D:/dsh/rules/forum.js'
291
- initScriptSha256: '<64位sha256>'
292
- steps:
293
- - { type: waitFor, selector: '#results', timeoutMs: 10000 }
294
- - { type: scroll, deltaY: 1600, repeat: 2, waitMs: 300 }
295
- autoInstall: false # 缺内核时是否自动 install chromium
296
- verbose: false
297
- ```
298
-
299
- 这些字段同时进入 Host settings 命名空间和专用可视化卡片:打开 `设置 → 插件 → 插件配置 → 浏览器自动化`,可调整工具自由度、Playwright/Patchright、OpenCLI、`usagePolicy`、自动化资产策略与限域登录态;同一卡片包含候选提示、脚本列表、JSON 编辑器、测试、激活和归档操作。保存运行时配置后需要重启 profile;资产 CRUD 通过 loopback-only Host RPC 即时落盘。若没有看到卡片,先确认浏览器插件已同步升级并完整重启,而不是只刷新 Web Search Pro 页面。
300
-
301
- ### Patchright 可选内核
302
-
303
- Patchright 是 Playwright-compatible 的 Chromium 驱动,适合普通 Playwright 在搜索页遇到自动化检测时显式启用:
304
-
305
- ```yaml
306
- browserRuntime: patchright
307
- channel: chrome
308
- headless: false
309
- ```
310
-
311
- `channel: chrome + headless: false` 是更贴近其推荐的兼容配置;CI/无人值守也可使用 headless,但 `browser_status.runtimeWarnings` 会如实提示差异。Patchright 会禁用 Playwright console API,因此依赖控制台监听的 Recipe/脚本不应切换到它。不要再叠加自定义 User-Agent、额外请求头或指纹注入器;这类组合更容易形成自相矛盾的指纹。
312
-
313
- Camoufox 当前没有硬集成:截至本版,其 JS 包要求 Node 22 且 peer 约束为 `playwright-core <1.61`,与本插件验证的 Playwright/Patchright 1.62.1 不兼容,并需要独立下载 Firefox 内核。后续等版本边界对齐后再作为第三 provider 接入,避免安装后才发生依赖漂移。
314
-
315
- ## 登录态复用
316
-
317
- - `channel: chromium` + `storageStatePath` 指向一份 storageState JSON,即可用你已登录的身份抓受限页面。
318
- - 新配置优先使用 `authProfiles`:按名称复用全局登录态,但必须用 `allowedDomains` 限域;默认只读,避免一次搜索意外改写 Cookie Vault。
319
- - `browser_open` 和 web-search-pro 的平台搜索可选择 `authProfile` / `rulePack`。`browser_status` 只显示 profile 名称、域名和回写状态,不显示文件路径或 Cookie。
320
- - RulePack 仍只允许有界动作;init script 必须是本地、SHA-256 固定且不超过 64KB。外部模型 JavaScript 使用独立的 UserScript 工具,不能冒充 RulePack;除 `unrestricted` 外需一次性审批。
321
- - 生成登录态:`npx playwright codegen --save-storage=storageState.json`(或复用 `dsh-web-search-pro` 的 `scripts/save-login.mjs`),把产物路径填进 `storageStatePath`。
322
- - opencli 的社交平台后端(小红书/推特/Reddit/IG/FB)仍需浏览器扩展 + 登录态在线,即使 opencli 已打包为依赖也绕不开扩展。
323
-
324
- ### OpenCLI 连接检查
325
-
326
- 插件运行时优先使用自己依赖的 OpenCLI。需要在终端排查 Browser Bridge 时,可全局安装同一 CLI 并检查:
327
-
328
- ```bash
329
- npm i -g @jackwener/opencli
330
- opencli daemon status
331
- opencli doctor
332
- ```
333
-
334
- 健康状态应同时包含 daemon running、extension connected 和一个 connected Chrome profile。仅安装 npm 包不等于 Browser Bridge 可用;Chrome 扩展断开时,OpenCLI 社区搜索会明确失败,而普通 Playwright 浏览器工具不受影响。
335
-
336
- 插件内先调用 `browser_opencli_status`,不要只看 `browser_status.opencliEnabled`。后者表示配置开关,
337
- 前者才是真实连接。通用调用以 argv 数组传入,不经过 shell,也不会自行拼接引号:
338
-
339
- ```json
340
- {
341
- "profile": "chrome",
342
- "args": ["reddit", "search", "DeepSeek Harness", "-f", "json"]
343
- }
344
- ```
345
-
346
- 不确定命令时先查目录,避免让模型猜 adapter:
347
-
348
- ```json
349
- { "query": "search", "site": "reddit", "access": "read", "limit": 10 }
350
- ```
351
-
352
- `browser_opencli_catalog` 从 `opencli list -f json` 读取并缓存目录,只暴露过滤后的最多 100 条;它不执行站点命令,也不读取站点登录数据。
353
-
354
- 优先级建议:已有站点 adapter(`opencli <site> <command>`)→ `opencli web read` / `extract` →
355
- `browser network` → DOM state/find/action → 最后才是只读 `eval`。`opencli browser` 必须包含显式 session:
356
-
357
- ```text
358
- ["browser", "research", "open", "https://example.com"]
359
- ["browser", "research", "state"]
360
- ["browser", "research", "network", "--filter", "title,url"]
361
- ["browser", "research", "extract", "--selector", "main"]
362
- ["browser", "research", "close"]
363
- ```
364
-
365
- `browser_opencli_run` 是通用高级入口,可能调用发布、删除、发帖等 adapter,因此无论命令看起来是否只读,
366
- 除 `unrestricted` 外都要求原生一次性审批。常规搜索仍优先走 `dsh-web-search-pro` 的只读工具。
367
-
368
- ## 发布 / 构建
369
-
370
- ```bash
371
- pnpm install # 装依赖(playwright / patchright / opencli / @deepseek-ai/*)
372
- pnpm test
373
- pnpm run build # tsc → lib/
374
- pnpm run verify # typecheck → build → real-browser tests → client bundle check
375
- node scripts/install-browser.mjs # 安装 chromium 内核(发布前验证,可选)
376
- ```
377
-
378
- ## 与 dsh-web-search-pro 的关系
379
-
380
- `dsh-web-search-pro` 现在 `inject: ['browser']`,其 `web_snapshot` / `web_fetch_pro`(playwright 后端) /
381
- `web_platform_search`(中文社区 playwright + 社交平台 opencli) 全部走本插件的 `browser` 服务。
382
- 两者可独立安装,但 web-search-pro 的浏览器类能力依赖 dsh-browser 先行提供 `browser` 服务(Cordis `inject` 自动排序,无需手动控制挂载顺序)。
1
+ # dsh-browser
2
+
3
+ 自包含的浏览器运行时插件 for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)。
4
+
5
+ 把 **Playwright / Patchright(可选 Chromium 驱动)** 与 **OpenCLI** 作为插件自身的 npm 依赖打包(优先插件本地,缺省回退全局复用),对外提供一个 `browser` 服务 + 一组交互式浏览器工具。`dsh-web-search-pro` 通过 `inject: ['browser']` 注入该服务,驱动它的浏览器 / OpenCLI 后端——**不再依赖全局 CLI**。
6
+
7
+ ## 兼容与发布通道
8
+
9
+ | 插件发布通道 | DSH 基线 | 兼容承诺 |
10
+ |---|---|---|
11
+ | npm `latest`(`0.1.12`) | `dsh-v0.1.1-rc.2` 至 `dsh-v0.1.2-rc.1` | 已验证维护基线 |
12
+ | npm `next` 候选(`0.1.13-alpha.1`) | `dsh-v0.1.5-alpha.1` | 精确依赖与真实 profile 验收目标 |
13
+
14
+ `0.1.13-alpha.1` 使用 DSH 新客户端分包:状态存储来自
15
+ `dsh-client-store`,设置契约来自 `dsh-client-ui-settings`,客户端 Context
16
+ 来自 Cordis。该候选不会覆盖 npm `latest`。
17
+
18
+ ## 安装
19
+
20
+ ```bash
21
+ dsh plugin --profile web add @anweat/dsh-browser
22
+ # 或本地目录 / tarball:
23
+ dsh plugin --profile web add ./dsh-browser
24
+ # 重启(web profile 关闭了 HMR):
25
+ dsh --profile web
26
+ ```
27
+
28
+ > npm `latest` 延续现有维护基线;本开发分支精确适配 `dsh-v0.1.5-alpha.1`。
29
+ > 若你的 harness 是包含未发布提交的本地源码 checkout,版本号可能有出入——用
30
+ > `dsh plugin --profile web add ./<path>` 并在 profile 的 `pnpm-workspace.yaml`
31
+ > 里对齐版本后重装即可。
32
+
33
+ ## 从旧版本升级
34
+
35
+ Web Search Pro 与浏览器插件应同步升级;`dsh-web-search-pro >= 0.1.8` 需要 `@anweat/dsh-browser >= 0.1.8`。面向 `dsh-v0.1.5-alpha.1` 联调时,使用 browser 与 Web Search Pro 的 npm `next` 候选并完整重启 profile。0.1.11 移除了对旧版 `dsh-settings` 的运行时 `settingsNamespace` 导入;0.1.10 修复工具描述被 DSH 误解析为 prompt 变量。
36
+
37
+ ```bash
38
+ dsh plugin --profile web add @anweat/dsh-browser@next dsh-web-search-pro@next
39
+ ```
40
+
41
+ 升级后完整停止并重启 Web profile,再调用 `browser_status`、`browser_opencli_status` 和 `web_backend_status`;仅刷新网页不会重新加载插件服务或 Web Search Pro 配置面板。尤其不要只升级 Web Search Pro:新的工具目录、Patchright 运行时和调用缓冲都来自浏览器插件。
42
+
43
+ ## 快速使用与适用情形
44
+
45
+ 安装并重启后,可先让模型调用 `browser_status`,再按任务选择工具。默认
46
+ `automationMode: standard`:读取直接执行,点击、输入、按键、选择、勾选、悬停、文件上传及页面写操作走 DSH 原生一次性审批。页面脚本和本地文件上传在 `autonomous` 下仍需审批,只有 `unrestricted` 会跳过确认。
47
+
48
+ | 情形 | 推荐方式 | 关键边界 |
49
+ |---|---|---|
50
+ | 公开网页读取、截图 | `browser_open` → `browser_read` / `browser_screenshot` | 不需要登录态 |
51
+ | 表单、分页、懒加载 | `browser_click` / `browser_type` / `browser_press` / `browser_select` / `browser_check` / `browser_scroll` | CSS 或 role/text/label 语义定位;`standard` 下审批 |
52
+ | SPA 条件等待 | `browser_wait` | 支持 locator、URL glob、networkidle 或最多 10 秒固定等待 |
53
+ | 悬停菜单与提示 | `browser_hover` | 与直接页面交互使用相同审批策略 |
54
+ | 文件上传 | `browser_set_files` | 只接受现有绝对文件路径;最多 20 个、合计 512 MiB;除 `unrestricted` 外审批会显示路径 |
55
+ | 页面脚本表达式 | `browser_evaluate` | 使用当前页面来源和登录态;可访问 DOM、非 HttpOnly Cookie、Web Storage 和浏览器允许的网络 API |
56
+ | 页面故障排查 | `browser_open(capture=[console,network])` → `browser_console` / `browser_requests` | 只在内存保留最多 200 条;网络仅记录失败及 4xx/5xx,不记录 body/header |
57
+ | 登录后站点 | `authProfile` | 必须配置 `allowedDomains`;默认不回写 Cookie |
58
+ | 固定站点增强 | `rulePack` | 只允许有界步骤;本地 init script 必须 SHA-256 固定且 ≤64KB |
59
+ | 模型生成的多步操作 | `browser_recipe_run` | 声明式步骤;审批策略由 `automationMode` 决定 |
60
+ | 默认只读脚本 | `browser_script_catalog` → `browser_script_run_builtin` | 内置 article/links/JSON-LD/forms,不执行外来代码 |
61
+ | 外部模型生成 UserScript | `browser_script_validate` → `browser_userscript_run` | 必须 `@match` + `@grant none`;除 `unrestricted` 外执行前审批 |
62
+ | 有限站点遍历 | `browser_crawl` | 页数、深度、并发、突发与退避始终受 `usagePolicy` 约束 |
63
+ | Reddit/小红书等 OpenCLI 平台 | `browser_opencli_status` → `browser_opencli_catalog` → `browser_opencli_run` | 先发现精确 adapter;通用调用除 `unrestricted` 外需审批 |
64
+ | 普通站点兼容性不佳 | `browserRuntime: patchright` | Chromium-only;建议专用 Chrome profile,不与指纹注入库叠加 |
65
+
66
+ 所有网页访问、交互、脚本、Cookie 使用、上传和下载都必须由调用方或操作者根据目标网站规则及适用要求判断并使用。插件只执行被请求或批准的浏览器操作,不判断具体用途是否获得网站授权,也不承担调用方的合规责任。限流、审批、域名和文件边界用于约束执行面,不能替代目标网站规则。
67
+
68
+ DSH 会话示例:
69
+
70
+ ```text
71
+ 先调用 browser_status;然后用 browser_open 打开目标页。
72
+ 若页面需要登录,使用 authProfile=forum;不要把 Cookie 放进工具参数。
73
+ ```
74
+
75
+ ## 内核与依赖的"打包 vs 复用"
76
+
77
+ | 层 | 实际是什么 | 打包还是复用 |
78
+ |---|---|---|
79
+ | **chromium 内核** | 共享缓存 `%LOCALAPPDATA%\ms-playwright`(约 400MB) | **永远复用共享缓存**,不塞进插件、不重复下载;缺失时 `browser_install` 一键补 |
80
+ | **playwright 驱动**(JS 包) | `playwright` npm 依赖 | 插件本地 node_modules 优先,缺省回退全局 npm |
81
+ | **patchright 驱动**(可选) | 与 Playwright 同版本的 Chromium 兼容驱动 | 插件内置;配置 `browserRuntime: patchright` 才启用 |
82
+ | **opencli**(纯 Node CLI) | `@jackwener/opencli` npm 依赖 | 同上,本地优先 / 全局复用 |
83
+
84
+ ## 服务:`browser`
85
+
86
+ `dsh-browser` 在 `apply()` 里 `ctx.provide('browser', service)`。任何插件声明
87
+ `inject: ['browser']` 即可消费:
88
+
89
+ ```ts
90
+ export const inject = ['tools', 'browser']
91
+ export function apply(ctx: Context) {
92
+ const browser = ctx.get('browser') as BrowserService
93
+ // browser.render / snapshot / searchResults / opencli / recipe /
94
+ // runBuiltinScript / runUserscript / open / click / type / scroll / read / screenshot / close
95
+ }
96
+ ```
97
+
98
+ 服务接口(结构性,无需共享类型包)见 `src/browser-service.ts`。
99
+
100
+ ## 自动化自由度
101
+
102
+ `automationMode` 控制模型可见的工具集合和执行审批。建议从 `standard` 开始,仅在完全只读任务或受控自动化环境中切换:
103
+
104
+ | 模式 | 浏览器与 Web Search Pro 写操作 | 仍需审批或拒绝 | 不可取消的安全底线 |
105
+ |---|---|---|---|
106
+ | `read-only` | 只读工具与只读 Recipe;缓存清理、规则写入和安装拒绝 | 页面交互、写 Recipe、UserScript、OpenCLI run 均隐藏或拒绝 | 只能读取、校验、截图及运行只读脚本/Recipe |
107
+ | `standard`(默认) | 页面交互、写 Recipe、缓存清理和规则写入均需一次性审批 | UserScript、通用 OpenCLI、浏览器/后端安装也需审批 | 所有安全校验持续启用 |
108
+ | `autonomous` | 页面交互、写 Recipe、缓存清理和规则写入可直接执行 | 外部 UserScript、通用 OpenCLI、浏览器/后端安装仍强制审批 | 所有安全校验持续启用 |
109
+ | `unrestricted` | 所有上述工具均不触发审批,适合隔离环境中的无人值守测试 | 无审批提示 | 仍执行域名、元数据、参数、大小和步骤数校验 |
110
+
111
+ `unrestricted` 会允许模型直接运行外部脚本、通用 CLI 和安装命令,只应在隔离的测试 profile 或明确授权的自动化环境中使用;日常 profile 保持 `standard`。它只取消人工确认,**不会取消 `usagePolicy` 的并发、突发、页数、深度、重试与冷却保护**。模式改变后需要重启 DSH profile,工具目录才会按新配置重新注册。
112
+
113
+ ## 工具(最多 30 个)
114
+
115
+ | 工具 | 作用 |
116
+ |---|---|
117
+ | `browser_open` | 打开 URL,返回标题/可读文本/全页截图路径;可显式启用 console/network 内存捕获 |
118
+ | `browser_click` | 按 CSS 或结构化 Playwright locator 点击 |
119
+ | `browser_type` | 向 CSS 或语义定位的 input/textarea 输入 |
120
+ | `browser_wait` | 等待 locator 状态、URL glob、networkidle 或固定时间 |
121
+ | `browser_press` | 对 locator 或全局键盘发送按键 |
122
+ | `browser_select` | 按 locator 选择一个或多个 option value |
123
+ | `browser_check` | 按 locator 勾选或取消勾选控件 |
124
+ | `browser_hover` | 悬停 CSS 或语义 locator 并返回页面状态与截图 |
125
+ | `browser_set_files` | 把现有本地文件设置到 `input[type=file]`;绝对路径、数量和总大小受限 |
126
+ | `browser_evaluate` | 在当前页执行最长 20,000 字符的 JavaScript 表达式,返回最多 100,000 字符 JSON |
127
+ | `browser_console` | 读取本次显式捕获的脱敏 console 记录 |
128
+ | `browser_requests` | 读取本次显式捕获的失败及 HTTP 4xx/5xx 请求;无 body/header |
129
+ | `browser_scroll` | 纵向滚动(触发懒加载) |
130
+ | `browser_read` | 读当前页 URL/标题/文本(不截图) |
131
+ | `browser_screenshot` | 当前页、locator 或区域截图;普通文件名固定落在 `snapshotDir` |
132
+ | `browser_close` | 关闭当前页(下次 open 全新) |
133
+ | `browser_status` | 运行时状态(含 automationMode、已暴露工具及各类审批策略) |
134
+ | `browser_install` | 安装 playwright chromium(`browser_status` 报缺失时执行一次) |
135
+ | `browser_script_catalog` | 列出内置只读脚本及其 SHA-256 |
136
+ | `browser_script_validate` | 解析外部 UserScript 的元数据、域名、grant、能力与哈希,不执行 |
137
+ | `browser_script_run_builtin` | 在独立 Playwright context 中运行内置只读脚本 |
138
+ | `browser_userscript_run` | 运行外部 UserScript;强制域名匹配,审批策略由模式决定 |
139
+ | `browser_recipe_run` | 最多 25 步 Playwright Recipe;支持等待、定位、表单、键盘、提取、断言和截图 |
140
+ | `browser_automation_search` | 只有显式关键词调用才检索;可限定 active/draft/all、域名和类型,最多返回 `retrievalTopK` 条摘要 |
141
+ | `browser_automation_develop` | 按确切 ID 读取源码,或显式保存、静态校验、真实回放草稿;永远不能激活资产 |
142
+ | `browser_automation_run` | 按 ID 运行已激活资产;再次执行限域和输入大小校验,审批由 `automationMode` 决定 |
143
+ | `browser_opencli_status` | 实际运行 OpenCLI doctor,报告 daemon/extension/profile 连通性 |
144
+ | `browser_opencli_catalog` | 对 OpenCLI 大目录按 query/site/access/strategy 过滤,单次最多返回 100 条 |
145
+ | `browser_opencli_run` | 通用 OpenCLI argv 网关;除 `unrestricted` 外触发 DSH 原生一次性审批 |
146
+ | `browser_crawl` | 匿名、有限广度遍历;默认同源,强制使用全局调用缓冲和单次页数/深度预算 |
147
+
148
+ ## 可复用自动化资产(实验性)
149
+
150
+ > **Experimental:** Recipe/UserScript 的积累、模型开发、检索和复用接口仍可能调整。建议先在隔离 profile 中启用,审阅草稿并完成真实浏览器回放后再手动激活;不要把它作为无人监管的生产写操作入口。
151
+
152
+ 自动化执行自由度与资产持久化是两套独立开关。`automationMode: unrestricted` 只影响执行审批,不会让 Agent 自动保存脚本;默认 `automationAssets.persistenceMode: suggest` 仅对成功的 `browser_recipe_run` 记录脱敏语义步骤。具体输入会替换为 `{{input}}` / `{{secret}}`,会话 ID 只保存短哈希,不保存页面正文、cookie、token、密码或聊天记录。
153
+
154
+ 默认在 14 天窗口内,同一域名和步骤指纹至少成功 3 次、来自至少 2 个会话且成功率达到 80%,面板才出现“是否总结”候选。每天最多提示 2 次;候选、草稿和已激活资产均有数量上限。推荐流程是:
155
+
156
+ 1. 候选达到阈值后,在“浏览器自动化 → 可复用自动化资产”选择“总结为草稿”或“暂不总结”。
157
+ 2. 在脚本列表点选草稿;只有此时前端才按 ID 读取完整 recipe / UserScript。编辑器支持 recipe 和带 `@match`、`@grant none` 的 UserScript。UserScript 可从只读对象 `__DSH_INPUTS__` 读取 `inputNames` 声明的运行时输入,输入不会写入资产文件。
158
+ 3. 保存后先做静态校验,再填写测试 URL/输入执行真实浏览器回放。只有真实回放成功才可手动激活;已激活版本不可原地编辑,避免后台行为静默漂移。
159
+ 4. Agent 用 `browser_automation_search` 获取有界摘要,再用 `browser_automation_run` 按 ID 调用。检索默认 top 5、目录预算约 800 tokens,源码不会进入模型上下文。
160
+
161
+ `persistenceMode` 可选 `off | manual | suggest | auto-draft`。日常使用建议 `suggest`;`auto-draft` 只适合隔离测试 profile,并且仍不会自动激活。`activationMode` 当前默认并推荐 `manual`;`auto-tested` 作为后续真实沙箱回放策略的保留配置,不会把一次静态校验当成生产激活依据。
162
+
163
+ ### 模型显式开发 recipe / UserScript
164
+
165
+ 模型目录不会预载任何 recipe 或源码。需要批量索引等强指向自动化时,模型按以下顺序显式访问:
166
+
167
+ 1. 调用 `browser_automation_search(query="batch-index issues", status="draft|active", kind="recipe")`,仅得到 ID、名称、标签、域名、输入名和运行统计。
168
+ 2. 确认要修改某项后,调用 `browser_automation_develop(action="get", id="...")`;只有这一步会把单个资产的完整 recipe/源码带入当前上下文。
169
+ 3. `action="save"` 可直接声明新的 recipe,或保存带 `@match` / `@grant none` 的 UserScript;只能生成/更新 draft。默认每个模型会话最多写 3 次,仍受全局 `maxDrafts` 限制。
170
+ 4. `action="validate"` 只做结构与 UserScript 元数据校验,不提供激活资格;`action="test"` 必须给 URL 和声明输入,执行真实 Playwright 回放,成功后才标记 `passed`。
171
+ 5. 激活、归档和回滚只在可视化面板完成,模型开发工具没有对应动作。
172
+
173
+ recipe 建议把检索意图固化在 `name`、`description` 和 `tags`,例如 `batch-index`、`issues`、`community-search`。检索采用小规模确定性关键词评分和 token 预算,不自动把整个资产库升级成模型工具,也不使用隐藏的全量 prompt 注入。
174
+
175
+ `modelDevelopmentEnabled: false` 会在重启后直接从模型工具目录移除开发入口;`standard` 保存草稿和真实回放均需审批,`autonomous` 可直接保存草稿但真实回放仍需审批,只有 `unrestricted` 才会跳过回放审批。所有模式仍执行域名、UserScript 元数据、输入、源码大小和使用频率限制。
176
+
177
+ ## 使用策略:防止过度调用的缓冲
178
+
179
+ `usagePolicy` 是资源与站点压力保护,不是审批系统。所有模式共用同一个进程内 Governor:
180
+
181
+ - `maxConcurrency` 限制同时发起的导航,超出后排队;`burst` + `minDelayMs` 限制单站点短时突发。
182
+ - OpenCLI adapter / Browser Bridge 调度也占用同一全局并发与 burst 缓冲,不会因绕过 Playwright 而失去节流。
183
+ - 站点返回 429、502、503、504 时,按 `Retry-After` 或指数退避进入站点级冷却,最多重试 `retryLimit` 次。
184
+ - `browser_crawl` 还受 `maxPagesPerRun` 和 `maxDepth` 硬上限约束;调用参数只能收紧,不能突破配置。
185
+ - 泛爬取默认使用匿名 context,不继承全局 `storageStatePath` 或 `defaultAuthProfile`;登录后读取仍使用显式限域的单页/Recipe 工具。
186
+ - `browser_status` 显示累计运行、排队、等待和 backoff 次数,便于判断是否调用过密。
187
+ - 泛爬取能力本身不隐藏,但调用方仍应遵守目标站点条款、robots 指令、版权、隐私和适用法律;工具每次返回该警告。
188
+
189
+ ## 外部模型脚本:推荐流程
190
+
191
+ 外部模型可以输出 Tampermonkey/UserScript 格式源码,但不要直接执行。让当前 DSH Agent 先调用
192
+ `browser_script_validate`,展示名称、`@match`、SHA-256 和能力,再调用
193
+ `browser_userscript_run`。除 `unrestricted` 外,执行调用会进入 Harness 的
194
+ `tools/pre-execute → approval` 原生流程;用户拒绝、没有 approval 服务或调用不属于 Agent 时都不会运行。
195
+
196
+ 最小脚本示例:
197
+
198
+ ```js
199
+ // ==UserScript==
200
+ // @name Read Search Cards
201
+ // @match https://example.com/search*
202
+ // @grant none
203
+ // ==/UserScript==
204
+ return [...document.querySelectorAll('.result')].slice(0, 20).map(card => ({
205
+ title: card.querySelector('h2')?.textContent?.trim() || '',
206
+ url: card.querySelector('a')?.href || '',
207
+ }))
208
+ ```
209
+
210
+ 当前兼容的是 UserScript 元数据和页面脚本执行模型,不模拟完整 Tampermonkey:
211
+
212
+ - 只支持 `@grant none`;`GM_cookie`、`GM_xmlhttpRequest`、`unsafeWindow` 等不提供。
213
+ - 不支持 `@require`,避免审批过的源码在运行时再拉取未审查代码。
214
+ - 源码 ≤64KB、结果 ≤100,000 字符、单次运行最长 30 秒。
215
+ - 使用显式 URL,新建独立 Playwright context;需要登录态时只能选已限域的 `authProfile`。
216
+ - 审批代表允许该脚本以当前站点登录身份操作页面;静态能力报告只用于解释,不是沙箱。
217
+
218
+ `browser_evaluate` 是面向当前持久页的短表达式入口,不使用 UserScript 元数据。它能调用页面已有 JavaScript、读取或修改 DOM、访问非 HttpOnly Cookie 和 Web Storage,也能通过 `fetch` 等浏览器 API 发起页面来源允许的请求。插件会明确报告这些能力,但不会判断具体网站是否允许该访问;调用方应根据目标网站规则及适用要求使用并承担相应责任,插件只执行被批准的浏览器操作。表达式没有 Node.js 全局对象或直接主机文件系统权限,结果必须可 JSON 序列化;超时会通过 Chromium DevTools 终止页面 JavaScript,保留当前 page/context 供后续读取或导航。需要可复用、可审阅的脚本时仍使用 UserScript 资产流程。
219
+
220
+ ## Cookie 与文件落盘
221
+
222
+ - `authProfile` 从配置的 `storageStatePath` 载入 Cookie、localStorage 等登录态。只有 `persistState: true` 才在 context 关闭时原子回写该文件;全局兼容路径默认不会被交互会话改写。
223
+ - `browser_evaluate` 可读取 `document.cookie`,因此能看到当前来源的非 HttpOnly Cookie;浏览器不会向页面 JavaScript 暴露 HttpOnly Cookie。除 `unrestricted` 外,每次执行都需要确认。
224
+ - `browser_set_files` 只读取调用中列出的绝对路径并交给当前页面上传控件,不修改源文件,也不会遍历目录。除 `unrestricted` 外,即使在 `autonomous` 模式也需要确认。
225
+ - `browser_screenshot` 和 `snapshot` 只向 `snapshotDir` 写入截图或 HTML;自定义截图名只允许普通文件名,拒绝绝对路径、目录分隔符和 `..`。持久登录态只写配置的状态文件。`browser_evaluate` 触发的浏览器下载不会由该工具保存或返回,下载落盘需要后续单独设计显式目录和文件名规则。
226
+ - console/network 捕获必须由 `browser_open.capture` 显式启用,只在内存保留最多 200 条;记录文本和 URL 查询中的常见 token/cookie/password 字段会脱敏,网络只保留方法、URL、失败原因或 4xx/5xx 状态,不保存 header/body。
227
+
228
+ 常见读取任务优先用内置脚本:`article-clean`、`links`、`jsonld`、`forms`。它们不返回表单当前值,
229
+ 也不触发点击或网络写操作。
230
+
231
+ ## Playwright Recipe
232
+
233
+ Recipe 适合让模型生成可审计、可复现的多步操作,不必生成 JavaScript:
234
+
235
+ ```json
236
+ {
237
+ "url": "https://example.com/search",
238
+ "steps": [
239
+ { "type": "wait", "condition": "selector", "value": "#query" },
240
+ { "type": "fill", "selector": "#query", "value": "DeepSeek Harness" },
241
+ { "type": "press", "selector": "#query", "key": "Enter" },
242
+ { "type": "wait", "condition": "load" },
243
+ { "type": "extract", "selector": "main", "mode": "links", "limit": 30 },
244
+ { "type": "screenshot" }
245
+ ]
246
+ }
247
+ ```
248
+
249
+ 支持的步骤为:`wait`、`click`、`fill`、`type`、`press`、`select`、`check`、`hover`、
250
+ `scroll`、`extract`、`assert`、`screenshot`。纯读取步骤直接执行;出现点击、输入、键盘、选择、
251
+ 勾选、悬停或滚动时,`standard` 下整个 Recipe 只询问一次审批,批准后顺序执行;
252
+ `autonomous` / `unrestricted` 下直接执行,`read-only` 下拒绝。
253
+
254
+ ## 配置(cordis.yml / patch config)
255
+
256
+ ```yaml
257
+ - insert:
258
+ - id: browser
259
+ name: '@anweat/dsh-browser'
260
+ config:
261
+ automationMode: standard # read-only | standard | autonomous | unrestricted
262
+ browserRuntime: playwright # playwright | patchright
263
+ channel: chromium # 'chromium'(打包内核)| 'msedge'(系统 Edge)
264
+ headless: true
265
+ opencliEnabled: true
266
+ usagePolicy: # 所有模式都生效;无审批模式也不会绕过
267
+ minDelayMs: 750
268
+ maxConcurrency: 2
269
+ burst: 3
270
+ maxPagesPerRun: 20
271
+ maxDepth: 2
272
+ retryLimit: 2
273
+ backoffBaseMs: 1000
274
+ cooldownMs: 30000
275
+ automationAssets:
276
+ enabled: true
277
+ persistenceMode: suggest # off | manual | suggest | auto-draft
278
+ activationMode: manual # 当前推荐值;不会因静态校验自动激活
279
+ minSuccessfulRuns: 3
280
+ minDistinctSessions: 2
281
+ successWindowDays: 14
282
+ minSuccessRate: 0.8
283
+ maxCandidates: 20
284
+ candidateTtlDays: 14
285
+ maxSuggestionsPerDay: 2
286
+ maxDrafts: 10
287
+ maxActiveAssets: 50
288
+ retrievalTopK: 5
289
+ catalogTokenBudget: 800
290
+ modelDevelopmentEnabled: true
291
+ maxModelDraftWritesPerSession: 3
292
+ storageStatePath: '' # Playwright 登录态 JSON(复用已登录会话)
293
+ authProfiles:
294
+ forum:
295
+ storageStatePath: 'D:/secrets/forum.json'
296
+ allowedDomains: [example.com]
297
+ persistState: false # 默认只读;true 才会原子回写刷新后的状态
298
+ rulePacks:
299
+ forum-enhanced:
300
+ matches: [example.com]
301
+ initScriptPath: 'D:/dsh/rules/forum.js'
302
+ initScriptSha256: '<64位sha256>'
303
+ steps:
304
+ - { type: waitFor, selector: '#results', timeoutMs: 10000 }
305
+ - { type: scroll, deltaY: 1600, repeat: 2, waitMs: 300 }
306
+ autoInstall: false # 缺内核时是否自动 install chromium
307
+ verbose: false
308
+ ```
309
+
310
+ 这些字段同时进入 Host settings 命名空间和专用可视化卡片:打开 `设置 → 插件 → 插件配置 → 浏览器自动化`,可调整工具自由度、Playwright/Patchright、OpenCLI、`usagePolicy`、自动化资产策略与限域登录态;同一卡片包含候选提示、脚本列表、JSON 编辑器、测试、激活和归档操作。保存运行时配置后需要重启 profile;资产 CRUD 通过 loopback-only Host RPC 即时落盘。若没有看到卡片,先确认浏览器插件已同步升级并完整重启,而不是只刷新 Web Search Pro 页面。
311
+
312
+ ### Patchright 可选内核
313
+
314
+ Patchright 是 Playwright-compatible 的 Chromium 驱动,适合普通 Playwright 在搜索页遇到自动化检测时显式启用:
315
+
316
+ ```yaml
317
+ browserRuntime: patchright
318
+ channel: chrome
319
+ headless: false
320
+ ```
321
+
322
+ `channel: chrome + headless: false` 是更贴近其推荐的兼容配置;CI/无人值守也可使用 headless,但 `browser_status.runtimeWarnings` 会如实提示差异。Patchright 会禁用 Playwright console API,因此依赖控制台监听的 Recipe/脚本不应切换到它。不要再叠加自定义 User-Agent、额外请求头或指纹注入器;这类组合更容易形成自相矛盾的指纹。
323
+
324
+ Camoufox 当前没有硬集成:截至本版,其 JS 包要求 Node 22 且 peer 约束为 `playwright-core <1.61`,与本插件验证的 Playwright/Patchright 1.62.1 不兼容,并需要独立下载 Firefox 内核。后续等版本边界对齐后再作为第三 provider 接入,避免安装后才发生依赖漂移。
325
+
326
+ ## 登录态复用
327
+
328
+ - `channel: chromium` + `storageStatePath` 指向一份 storageState JSON,即可用你已登录的身份抓受限页面。
329
+ - 新配置优先使用 `authProfiles`:按名称复用全局登录态,但必须用 `allowedDomains` 限域;默认只读,避免一次搜索意外改写 Cookie Vault。
330
+ - `browser_open` 和 web-search-pro 的平台搜索可选择 `authProfile` / `rulePack`。`browser_status` 只显示 profile 名称、域名和回写状态,不显示文件路径或 Cookie。
331
+ - RulePack 仍只允许有界动作;init script 必须是本地、SHA-256 固定且不超过 64KB。外部模型 JavaScript 使用独立的 UserScript 工具,不能冒充 RulePack;除 `unrestricted` 外需一次性审批。
332
+ - 生成登录态:`npx playwright codegen --save-storage=storageState.json`(或复用 `dsh-web-search-pro` 的 `scripts/save-login.mjs`),把产物路径填进 `storageStatePath`。
333
+ - opencli 的社交平台后端(小红书/推特/Reddit/IG/FB)仍需浏览器扩展 + 登录态在线,即使 opencli 已打包为依赖也绕不开扩展。
334
+
335
+ ### OpenCLI 连接检查
336
+
337
+ 插件运行时优先使用自己依赖的 OpenCLI。需要在终端排查 Browser Bridge 时,可全局安装同一 CLI 并检查:
338
+
339
+ ```bash
340
+ npm i -g @jackwener/opencli
341
+ opencli daemon status
342
+ opencli doctor
343
+ ```
344
+
345
+ 健康状态应同时包含 daemon running、extension connected 和一个 connected Chrome profile。仅安装 npm 包不等于 Browser Bridge 可用;Chrome 扩展断开时,OpenCLI 社区搜索会明确失败,而普通 Playwright 浏览器工具不受影响。
346
+
347
+ 插件内先调用 `browser_opencli_status`,不要只看 `browser_status.opencliEnabled`。后者表示配置开关,
348
+ 前者才是真实连接。通用调用以 argv 数组传入,不经过 shell,也不会自行拼接引号:
349
+
350
+ ```json
351
+ {
352
+ "profile": "chrome",
353
+ "args": ["reddit", "search", "DeepSeek Harness", "-f", "json"]
354
+ }
355
+ ```
356
+
357
+ 不确定命令时先查目录,避免让模型猜 adapter:
358
+
359
+ ```json
360
+ { "query": "search", "site": "reddit", "access": "read", "limit": 10 }
361
+ ```
362
+
363
+ `browser_opencli_catalog` 从 `opencli list -f json` 读取并缓存目录,只暴露过滤后的最多 100 条;它不执行站点命令,也不读取站点登录数据。
364
+
365
+ 优先级建议:已有站点 adapter(`opencli <site> <command>`)→ `opencli web read` / `extract` →
366
+ `browser network` → DOM state/find/action → 最后才是只读 `eval`。`opencli browser` 必须包含显式 session:
367
+
368
+ ```text
369
+ ["browser", "research", "open", "https://example.com"]
370
+ ["browser", "research", "state"]
371
+ ["browser", "research", "network", "--filter", "title,url"]
372
+ ["browser", "research", "extract", "--selector", "main"]
373
+ ["browser", "research", "close"]
374
+ ```
375
+
376
+ `browser_opencli_run` 是通用高级入口,可能调用发布、删除、发帖等 adapter,因此无论命令看起来是否只读,
377
+ 除 `unrestricted` 外都要求原生一次性审批。常规搜索仍优先走 `dsh-web-search-pro` 的只读工具。
378
+
379
+ ## 发布 / 构建
380
+
381
+ ```bash
382
+ pnpm install # 装依赖(playwright / patchright / opencli / @deepseek-ai/*)
383
+ pnpm test
384
+ pnpm run build # tsc → lib/
385
+ pnpm run verify # typecheck → build → real-browser tests → client bundle check
386
+ node scripts/install-browser.mjs # 安装 chromium 内核(发布前验证,可选)
387
+ ```
388
+
389
+ ## 与 dsh-web-search-pro 的关系
390
+
391
+ `dsh-web-search-pro` 现在 `inject: ['browser']`,其 `web_snapshot` / `web_fetch_pro`(playwright 后端) /
392
+ `web_platform_search`(中文社区 playwright + 社交平台 opencli) 全部走本插件的 `browser` 服务。
393
+ 两者可独立安装,但 web-search-pro 的浏览器类能力依赖 dsh-browser 先行提供 `browser` 服务(Cordis `inject` 自动排序,无需手动控制挂载顺序)。