dsh-browser-playwright-codex 0.6.6 → 0.7.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 CHANGED
@@ -3,6 +3,45 @@
3
3
  Bilingual by intent: the version headings and the summary of each release are given in both
4
4
  languages, the individual entries follow the language the surrounding code and docs use.
5
5
 
6
+ ## 0.7.1 — 2026-10-19
7
+
8
+ 一句话摘要:**只修文档与一处口径** —— 外部评分(8.9/10)点名的问题:CHANGELOG 的数字手写写错、对比表把五个闸门写成三个、有头模式的 viewport 仍然不生效却没标注。行为零变化。
9
+
10
+ ### Added
11
+
12
+ - **设置卡新增第三个工具开关:诊断工具**(`browser_console_messages` / `browser_network_requests`)。与 `evaluate` / `cdp` 同一套机制:`POST /api/browser-playwright/gates` 现在接受 `diagnostics`,home 补丁块的整行 config 一并写入,`tool.ts` 把**实际生效值**(而不是猜的)发布给卡片;卡片上显示"当前:N 个开着"也把这一项算进去。
13
+ - **「已登录的站点」默认折叠**:标题行直接给出「N 个域 · M 个 cookie · 点击展开」,点开才渲染说明与名单(分组仍各自折叠)。设置页不再被这份名单占掉大半屏。
14
+
15
+ ### Fixed
16
+
17
+ - **CHANGELOG 0.7.0 的数字按实测改正**:常驻是 **16 工具 / 11,179 字符**(此前手写成 11,005 字符,token 数也跟着漂),对比基线 18 工具 / 12,755 字符保持不变,字符降幅 **−1,576(−12.4%)**。这是连续第三个版本出现"主文档被守卫钉住、CHANGELOG 叙事手写漂移"——本轮起新增加一条守卫:**最新一节 CHANGELOG 不许出现手写的 `≈ N token/轮` 数字**,要写就写实测命令与结果表。
18
+ - **对比与优势.md 的闸门清单**:"五个闸门"此前只列了 `evaluate` / `cdp` / `extract` 三个名字,补上 `console_messages` / `network_requests`,并把它与全量注册的字符差从旧的 2,853 更正为实测 4,603 字符(token 换算见 README 成本表)。
19
+
20
+ ### Changed
21
+
22
+ - **有头模式的 `viewport` 标注**:`browser-lifecycle.ts:44` 用 `viewport: null` 跟随真实窗口,所以 `launch.viewport` 只在 `headless: true` 时生效;README 配置示例与 Known Limitations 现在明写这一点(此前"配了也不生效"没有任何提示,被外部评分连续四次点出)。
23
+
24
+ ## 0.7.0 — 2026-10-19
25
+
26
+ 一句话摘要:**两个插件合成一个** —— 设置卡片并入本包;加载行从三行收成一行(这是 `dsh-client-modules` 允许本包带 client 模块的前提),独立的 `dsh-browser-toggle` 退役。
27
+
28
+ ### Breaking
29
+
30
+ - **一个包一行 loader**:`cordis.patch.yml` 现在只插 `- id: browser` / `name: 'dsh-browser-playwright-codex'`,三块配置收进嵌套的 `service` / `playwright` / `tool`。旧的 `browser-playwright`、`browser-tool` 行不再被读取;loader 整体替换 config,迁移时三节都要写全(设置卡会自动重写 home 补丁层里的那一块)。
31
+ - 版本跳到 0.7.0,因为配置形状变了。
32
+
33
+ ### Added
34
+
35
+ - **设置卡随本包发布**:`dsh.client` + `./client` 导出,卡片仍在 `/api/browser-playwright/*` 上提供总开关、页面识别方式、两个强力工具闸门与已登录站点名单。
36
+ - **单 loader 行守卫**(tests/plugin-entry.test.ts):`cordis.patch.yml` 不得再出现本包的子路径行,否则卡片会重新变成非法。
37
+
38
+ ### Changed
39
+
40
+ - **两个诊断工具改为门控**:`browser_console_messages` / `browser_network_requests` 不再常驻 —— 新增 `tool.diagnostics: false`(默认关),开启后才注册。常驻成本 **18 工具 12,755 字符 ≈ 3,543 token/轮 → 16 工具 11,179 字符 ≈ 3,105 token/轮(−438,−12.4%)**;全量注册仍是 21 工具 15,782 字符 ≈ 4,384。
41
+ - **快照瘦身(运行时大头)**:无名无状态的 `generic` 包装层不再逐层输出(真实页面常把一个链接包在 7~8 层 div 里),显示用 `href` 去掉追踪参数(`utm_*` / `gclid` / `rsv_*` / `sa` 等)并截到 160 字符。百度结果页形状的样本:**6,169 → 2,557 字符(−58.6%)**,行数 108 → 24。refs 与点击行为不变 —— 省的是模型读到的东西。
42
+ - 闸门写入块改为**整行 config**(新标记 `# >>> dsh-browser:`),并兼容旧的 `dsh-browser-toggle` 标记就地替换 —— 避免同一个 id 被两段 patch 争抢。
43
+ - `scripts/shipped-gates.mjs` 按新行名读取出厂闸门;`scripts/build-client.mjs` 把 `client/client.js` 复制进 `lib/`。
44
+
6
45
  ## 0.6.6 — 2026-10-17
7
46
 
8
47
  一句话摘要:**四份独立审查(文档漂移 / 代码对抗 / 发行打包 / 中性冷读)查出的问题集中修掉**——两条安全缺陷、几处"假成功/假失败"、随包自检的假承诺、发布门禁漏洞与一批文档漂移。
package/README.md CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  > [![dsh.so 安装验证 · harness 0.2.0-rc.1](https://www.dsh.so/badge/install/dsh-browser-playwright-codex@0.2.0-rc.1.svg)](https://www.dsh.so/zh/artifact/dsh-browser-playwright-codex/) [![dsh.so 风险](https://www.dsh.so/badge/dsh-browser-playwright-codex.svg)](https://www.dsh.so/zh/artifact/dsh-browser-playwright-codex/)
4
4
 
5
- **一句话**:让 AI 用你**已经登录的账号**在真实网页上干活 —— 填表、抓取列表、多标签查后台;浏览器窗口就在你桌面上、你随时看得见。原生弹框会被挂起、**绝不替你点「确定」**;验证码/登录页会被识别出来并把情况报给你、请你本人接手(识别不出来时也会停下来问人,而不是硬闯)。
5
+ **一句话**:让 AI 用你**已经登录的账号**在真实网页上干活 —— 填表、抓取列表、多标签查后台;浏览器窗口就在你桌面上、你随时看得见。原生弹框会被挂起、**绝不替你点「确定」**(机制级);验证码/挑战页会被识别出来,并以提示要求模型停下交给你(**提示不是阻断**)。登录/二次验证**没有探测器**,靠模型从快照看出来并停下;密码、一次性验证码、卡号字段 `browser_fill` **直接拒绝**——这类字由你本人在窗口里输。
6
6
 
7
7
  **In one line**: the agent drives a **visible, profile-backed browser window** with the logins you
8
8
  already have — filling in forms, scraping lists and working across tabs in real pages — through
9
9
  accessibility snapshots with stable element refs. Native dialogs are parked and reported instead of
10
- auto-accepted; a login, 2FA or challenge page is handed back to you rather than guessed at. No
10
+ auto-accepted. Challenge pages are detected and reported as a note that tells the agent to stop and hand
11
+ the page back — a note, not a block. There is **no sign-in detector**, and `browser_fill` refuses
12
+ password / one-time-code / card fields outright — you type those in the visible window. No
11
13
  CSS-selector guessing, no full-DOM dumps.
12
14
 
13
15
  ```sh
@@ -42,8 +44,8 @@ dsh plugin --profile <name> add github:miqian-nomad/dsh-browser-playwright-codex
42
44
  implementation of `browser_evaluate` (its dynamic evaluation), which this package ships switched off.
43
45
  [SECURITY.md](https://github.com/miqian-nomad/dsh-browser-playwright-codex/blob/main/SECURITY.md) says what each
44
46
  finding actually is, whether a capability gate makes it reachable (two of the warnings are not gate-controlled:
45
- the login-state write and the local test server in the acceptance script), and explains what the plugin can and
46
- cannot do with your logins (URL policy, CDP allow-list, dialog policy, no telemetry, and it never types
47
+ cannot do with your logins (URL policy, CDP allow-list, dialog policy, no telemetry, and `browser_fill`
48
+ refuses password / one-time-code / card fields). Counts move as the scanner and the code change — their own report is the
47
49
  passwords or 2FA codes). Counts move as the scanner and the code change — their own report is the
48
50
  live number.
49
51
 
@@ -88,8 +90,9 @@ Install it and ask for something that leaves a visible result — there is nothi
88
90
  > Go to my orders page on `<site>` and tell me the delivery address on the most recent order.
89
91
 
90
92
  > Fill in this contact form, but stop and show me the filled form before you submit it.
91
-
92
- What you should see: a real browser window on your desktop doing the clicking, and the page coming back to
93
+ the model as a `ref`-numbered list. The first time it meets a verification page it **reports the page back
94
+ to you** — take the window over by hand and it continues from where it left off (sign-ins have no detector:
95
+ the agent is told to stop when it sees one).
93
96
  the model as a `ref`-numbered list. The first time it meets a sign-in, a 2FA prompt or a verification page
94
97
  it **reports the page back to you** — take the window over by hand and it continues from where it left off.
95
98
  Native dialogs are the one case that is enforced at the interface: they are parked and never auto-accepted.
@@ -116,7 +119,7 @@ Or pin a binary: `launch.executablePath` / `launch.channel` in the plugin config
116
119
 
117
120
  ## Tools
118
121
 
119
- The default `toolPrefix` is `browser_`. Every action returns a fresh snapshot, so refs always come from the latest result. The registered set is capability-gated: `browser_evaluate`, `browser_cdp` and `browser_extract` appear only when their capability is switched on (their schemas are resident in the system prompt on every turn, so a tool that could only answer "disabled" would be pure prompt cost). Count the live surface with `npm run cost` — the shipped `cordis.patch.yml` keeps **both power gates off** (since 0.4.7), so a profile mounting this bundle sees **18 tools**; 19 or 20 once your deployment opts into `evaluate` / `cdp`, 21 once `extract` is configured. How to opt in: paste the snippet under Known Limitations below, or use the settings card in `dsh-browser-toggle`.
122
+ The default `toolPrefix` is `browser_`. Every action returns a fresh snapshot, so refs always come from the latest result. The registered set is capability-gated: `browser_evaluate`, `browser_cdp` and `browser_extract` appear only when their capability is switched on (their schemas are resident in the system prompt on every turn, so a tool that could only answer "disabled" would be pure prompt cost). Count the live surface with `npm run cost` — the shipped `cordis.patch.yml` keeps **both power gates off** (since 0.4.7), so a profile mounting this bundle sees **16 tools**; 17 or 18 once your deployment opts into `evaluate` / `cdp`, 19 with `diagnostics: true`, 21 once `extract` is configured. How to opt in: paste the snippet under Known Limitations below, or use the built-in Settings card.
120
123
 
121
124
  | Tool | Purpose |
122
125
  |---|---|
@@ -135,8 +138,8 @@ The default `toolPrefix` is `browser_`. Every action returns a fresh snapshot, s
135
138
  | `browser_dialog` | Answer the native dialog blocking the page: `{ accept: true }` confirms, `false` cancels; errors with `NO_DIALOG` when nothing is pending |
136
139
  | `browser_cdp` | Send one raw CDP command (DOM inspection / Input simulation allow-list only; disabled by default); **only registered when its capability is enabled** |
137
140
  | `browser_close` | Close the session's browser window; the profile keeps login state, so the next call reopens signed in |
138
- | `browser_console_messages` | Read the page console messages captured for the current page (levels, text, source) |
139
- | `browser_network_requests` | Read the network requests captured for the current page (method, URL, status, resource type) |
141
+ | `browser_console_messages` | Read the page console messages captured for the current page (levels, text, source); **only registered when `diagnostics: true`** |
142
+ | `browser_network_requests` | Read the network requests captured for the current page (method, URL, status, resource type); **only registered when `diagnostics: true`** |
140
143
 
141
144
  ### Parameter signatures
142
145
 
@@ -211,49 +214,51 @@ An actionable element with no text of its own is named from its descendants —
211
214
  All tunables are patchable through the profile's `cordis.patch.yml` (later layers win per row).
212
215
 
213
216
  ```yaml
217
+ # ONE row for the whole capability (2026-10-19). A package with a client module (the
218
+ # Settings card lives here) may only be mounted once, so the three concerns are nested.
214
219
  - id: browser
220
+ name: 'dsh-browser-playwright-codex'
215
221
  config:
216
- provider: playwright # explicit provider selection
217
-
218
- - id: browser-playwright
219
- config:
220
- launch:
221
- channel: chrome # or chromium / msedge / edge
222
- headless: false # visible window you can watch and rescue
223
- persistent: true # profile-backed window, login survives close
224
- # profileDir: ~/.dsh/browser-profiles/playwright by default
225
- viewport: { width: 1280, height: 800 }
226
- navigationTimeoutMs: 30000
227
- ignoreHTTPSErrors: false
228
- allowedDomains: [] # e.g. ['github.com'] restricts navigation
229
- idleTimeoutMs: 0 # shipped value: never auto-close (schema default 600000 = 10 min)
230
- maxSessions: 8 # LRU eviction (persistent mode: one window)
231
- snapshot:
232
- engine: legacy # 'legacy' (default) or 'aria' (Playwright ariaSnapshot, refs aligned back)
233
- maxNodes: 500 # token budget per snapshot tree
234
- maxNameLength: 120
235
- maxTextLength: 300
236
- diff: false # true = return "+/-/~" ref diffs instead of the full tree
237
-
238
- - id: browser-tool
239
- config:
240
- toolPrefix: browser_ # model-facing tool name prefix
241
- allowEvaluate: false # browser_evaluate gate
242
- allowCdp: false # browser_cdp gate (DOM inspection / Input simulation allow-list)
243
- registerDisabledTools: false # register evaluate/cdp/extract even while off (discoverability vs resident prompt cost)
244
- interactiveOnlyDefault: false # true = browser_snapshot returns actionable elements only
245
- maxWaitMs: 60000 # browser_wait bound
246
- extract:
247
- provider: deepseek-official # optional: enables browser_extract
248
- model: deepseek-v4-flash
249
- maxInputChars: 20000 # caps the page text handed to that model
250
- maxOutputTokens: 2000
222
+ service:
223
+ provider: playwright # explicit provider selection
224
+ playwright:
225
+ launch:
226
+ channel: chrome # or chromium / msedge / edge
227
+ headless: false # visible window you can watch and rescue
228
+ persistent: true # profile-backed window, login survives close
229
+ # profileDir: ~/.dsh/browser-profiles/playwright by default
230
+ viewport: { width: 1280, height: 800 } # headful: IGNORED (the window tracks the desktop; only headless: true pins it)
231
+ navigationTimeoutMs: 30000
232
+ ignoreHTTPSErrors: false
233
+ allowedDomains: [] # e.g. ['github.com'] restricts navigation
234
+ idleTimeoutMs: 0 # shipped value: never auto-close (schema default 600000 = 10 min)
235
+ maxSessions: 8 # LRU eviction (persistent mode: one window)
236
+ snapshot:
237
+ engine: legacy # 'legacy' (default) or 'aria' (Playwright ariaSnapshot, refs aligned back)
238
+ maxNodes: 500 # token budget per snapshot tree
239
+ maxNameLength: 120
240
+ maxTextLength: 300
241
+ diff: false # true = return "+/-/~" ref diffs instead of the full tree
242
+ tool:
243
+ toolPrefix: browser_ # model-facing tool name prefix
244
+ allowEvaluate: false # browser_evaluate gate
245
+ allowCdp: false # browser_cdp gate (DOM inspection / Input simulation allow-list)
246
+ registerDisabledTools: false # register gated tools even while off (discoverability vs resident prompt cost)
247
+ diagnostics: false # true = register browser_console_messages / browser_network_requests
248
+ interactiveOnlyDefault: false # true = browser_snapshot returns actionable elements only
249
+ maxWaitMs: 60000 # browser_wait bound
250
+ extract:
251
+ provider: deepseek-official # optional: enables browser_extract
252
+ model: deepseek-v4-flash
253
+ maxInputChars: 20000 # caps the page text handed to that model
254
+ maxOutputTokens: 2000
255
+ ```
251
256
  ```
252
257
 
253
258
  `snapshot.engine` picks the page-reading engine: `'legacy'` (the default) walks the injected DOM,
254
259
  `'aria'` uses Playwright's official `ariaSnapshot({ mode: 'ai' })` and aligns the result back onto the
255
260
  same `ref` ids; an aria tree that cannot be parsed falls back to legacy rather than handing the model an
256
- empty tree. It is a `snapshot` key, next to `maxNodes` / `maxNameLength` / `maxTextLength` / `diff`.
261
+ empty tree. It lives under `playwright.snapshot`, next to `maxNodes` / `maxNameLength` / `maxTextLength` / `diff`.
257
262
 
258
263
  `browser_extract` needs an auxiliary LLM route (`extract.provider` + `extract.model`); without one it fails with an actionable error. With a route configured, `extract.maxInputChars` bounds the page text in that prompt, and the prompt names the cap when it truncates. A gated tool is **not registered at all** while its capability is off, so its schema never reaches the system prompt; set `registerDisabledTools: true` to keep the whole surface discoverable (the tool then answers with the error naming the switch). The shipped layer in [`cordis.patch.yml`](https://github.com/miqian-nomad/dsh-browser-playwright-codex/blob/main/cordis.patch.yml) keeps `allowEvaluate` and `allowCdp` **off**, matching the schema defaults and this sample: that file travels inside the package, so anything it enabled would be enabled for everyone who installs it. Opt in per deployment, in that deployment's own patch layer. `browser_evaluate` executes arbitrary page JavaScript; `browser_cdp` stays off until `allowCdp: true`, and even then only the allow-list in `lib/cdp-policy.js` passes — network, storage, cookie, security and arbitrary-JS (`Runtime.evaluate`) commands are rejected with `CDP_DENIED`.
259
264
 
@@ -278,8 +283,8 @@ turning them on in a deployment that shares prompts across many users.
278
283
 
279
284
  ### Prefer a switch to editing config?
280
285
 
281
- The companion package [`dsh-browser-toggle`](https://github.com/miqian-nomad/dsh-browser-toggle) puts
282
- this on a Settings card: enable/disable the browser, pick the page-reading mode, and turn the two
286
+ The Settings card ships **inside this package** (it moved out of the companion package `dsh-browser-toggle`, which is retired) and puts
287
+ this on one card: enable/disable the browser, pick the page-reading mode, and turn the two
283
288
  power tools on or off — no restart, no YAML. The card also lists **which sites this browser looks
284
289
  signed in to**. Two things make that list trustworthy: cookies are attributed **first-party** — only
285
290
  domains this browser actually visited are candidates, because a tracker's cookie belongs to the site
@@ -363,9 +368,9 @@ Measured with ``npm run cost`` (per-turn, resident in the system prompt):
363
368
 
364
369
  | Surface | Tools | Schema characters | ≈ tokens/turn |
365
370
  |---|---|---|---|
366
- | Schema defaults (`Config({})`, no patch layer) | 18 | 12,755 | ≈ 3,543 |
367
- | Shipped bundle layer (this package's `cordis.patch.yml`: both power gates off) | 18 | 12,755 | ≈ 3,543 |
368
- | Everything registered (`registerDisabledTools: true`, plus `extract`) | 21 | 15,608 | ≈ 4,336 |
371
+ | Schema defaults (`Config({})`, no patch layer) | 16 | 11,179 | ≈ 3,105 |
372
+ | Shipped bundle layer (this package's `cordis.patch.yml`: both power gates off) | 16 | 11,179 | ≈ 3,105 |
373
+ | Everything registered (`registerDisabledTools: true`, plus `extract`) | 21 | 15,782 | ≈ 4,384 |
369
374
 
370
375
  This paragraph describes the 0.6.0 change; the table above is today's measurement. Three things changed
371
376
  there, and only one of them was about size. (1) The click family was rewritten so each rule is stated once
@@ -415,14 +420,18 @@ links below go to GitHub rather than to files inside the package:
415
420
  - **The package ships both power gates OFF, and that is deliberate** — `cordis.patch.yml` is part of the package, so anything it enables is enabled for *everyone who installs this*. It therefore sets `allowEvaluate: false` and `allowCdp: false` (the code defaults), and each deployment opts in through its **own profile patch** (`~/.dsh/profiles/<name>/cordis.patch.yml`). A package that shipped them on would be handing every installer a backdoor they never asked for. Snippet:
416
421
  ```yaml
417
422
  # dsh replaces an entry's config object wholesale — list every key you rely on.
418
- - id: browser-tool
423
+ - id: browser
419
424
  config:
420
- toolPrefix: 'browser_'
421
- allowEvaluate: true # registers browser_evaluate
422
- allowCdp: true # registers browser_cdp (needs a full DSH restart)
423
- registerDisabledTools: false
424
- maxWaitMs: 60000
425
+ service: { provider: playwright }
426
+ playwright: { launch: { headless: false, persistent: true }, idleTimeoutMs: 0, maxSessions: 8, snapshot: { diff: false } }
427
+ tool:
428
+ toolPrefix: 'browser_'
429
+ allowEvaluate: true # registers browser_evaluate
430
+ allowCdp: true # registers browser_cdp (needs a full DSH restart)
431
+ registerDisabledTools: false
432
+ maxWaitMs: 60000
425
433
  ```
434
+ - **`launch.viewport` only applies headless** — the visible window is a real window: it tracks the desktop size (`browser-lifecycle.ts` passes `viewport: null` in headful), so setting 1280×800 there changes nothing. Pin the size by running `headless: true`, or resize the window itself.
426
435
  - **Chromium family only** — Firefox/WebKit channels are not probed; providers are swappable if another engine is needed.
427
436
  - **Extract needs a dedicated model route** — it does not reuse the main request's route; misconfiguration fails loudly at call time.
428
437
  - **JS-driven navigations are not statically checkable** — `allowedDomains` covers `browser_navigate`, `browser_open_tab`, every navigating click (`browser_click`: `ref`, `text`, `precise` and raw-coordinate modes) and `browser_switch_tab`; `mode: "hover"` reveals content without activating anything, so it is not checked against the URL policy. A button whose handler runs `location.href = …` can still leave the allowed hosts, and so can a `<form>` whose `action` points at another host (pressing its submit button is a navigation this check does not statically see), and a tab that is already sitting on a disallowed host stays open (the agent simply refuses to drive it); deploy an external network guard for hard isolation.
@@ -449,9 +458,13 @@ MIT
449
458
 
450
459
  (此列表只记 **minor 里程碑**;每个补丁版本见 [CHANGELOG.md](https://github.com/miqian-nomad/dsh-browser-playwright-codex/blob/main/CHANGELOG.md)。)
451
460
 
461
+ ### 0.7.0(2026-10-19)
462
+
463
+ - **两个插件合成一个(破坏性)**:设置卡片并入本包(`dsh.client` + `./client`),`dsh-browser-toggle` 退役;`cordis.patch.yml` 从三行 loader 收成**一行** —— `- id: browser` 加嵌套的 `service` / `playwright` / `tool`。这是硬约束:`dsh-client-modules` 拒绝一个包被多个 loader 行挂载,所以带 client 的包只能有一个入口。
464
+
452
465
  ### 0.6.0(2026-10-16)
453
466
 
454
- - **工具面三合一(破坏性)**:`browser_click` / `browser_hover` / `browser_click_at` 合并成一个 `browser_click` —— `mode: "hover"` 是原来的悬停、`precise: true` 是原来的几何中点兜底、`x`+`y` 是裸坐标。常驻 prompt **净减 16.5%(约六分之一)**:现在是 **18 个工具 12,755 字符 ≈ 3,543 token/轮**,全量注册(含三个闸门工具)21 个;规则一条没丢,守卫改成"合并后的工具必须保住原来三个的全部规则"。
467
+ - **工具面三合一(破坏性)**:`browser_click` / `browser_hover` / `browser_click_at` 合并成一个 `browser_click` —— `mode: "hover"` 是原来的悬停、`precise: true` 是原来的几何中点兜底、`x`+`y` 是裸坐标。常驻 prompt **净减 16.5%(约六分之一)**(当时的值;当前成本见上面的成本表),全量注册(含三个闸门工具)21 个;规则一条没丢,守卫改成"合并后的工具必须保住原来三个的全部规则"。
455
468
  - **`browser_fill` 接受 `value` 作 `text` 的别名**:模型按语义猜参数名不再第一次就撞墙;缺值时给的是指路错误(同时点出两种写法,并说明要点可见标签该用 `browser_click`)。
456
469
  - **设置页多了一节「已登录的站点」(只读)**:按域名列出"像登录态"的 cookie —— 只列你在浏览器里**真的访问过**的域(第三方统计/广告域排除),判据用 OWASP 的会话特征(httpOnly 且会话级/值像令牌),**名字与条数不再作为依据**。不显示 cookie 的名字和值、不写磁盘、**模型看不到**;同一家公司的域折叠成一行(如 `京东系(18 个域)`),每行写明"这个域名是什么"(离线对照表 → 网页自己的标题 → 域名,认不出不编)。
457
470
  - **`GET /state` 补上防伪头**:四个路由里唯一一个没校验 `x-dsh-plugin` 的;新增的 `GET /logins` 同样强制该头(这份名单是用户的登录站点)。
package/SECURITY.md CHANGED
@@ -15,9 +15,12 @@ this package ships switched off** — it is not registered at all until a deploy
15
15
 
16
16
  **It drives your browser, as you.** The provider opens a visible, profile-backed Chromium-family
17
17
  window (`~/.dsh/browser-profiles/playwright` by default) and reuses the logins already in it. It does
18
- not have your passwords, and it never types them: when a login, a 2FA prompt or a captcha appears,
19
- the agent is supposed to stop and hand the page back to you.
20
-
18
+ window (`~/.dsh/browser-profiles/playwright` by default) and reuses the logins already in it. It does
19
+ not have your passwords, and `browser_fill` **refuses** credential fields (`type=password`,
20
+ `autocomplete=current-password` / `new-password` / `one-time-code` / `cc-*`) — typing one is a
21
+ mechanism-level no, not a promise. Challenge pages are detected and reported as a note; there is
22
+ **no sign-in detector**, so a sign-in page is handled by the agent's discipline and you complete it in
23
+ the visible window.
21
24
  **It is visible and interruptible.** The window lives on your desktop. You can watch every action,
22
25
  minimise it (the provider detects a minimised window and keeps working without raising it — see
23
26
  [FOCUS-STEALING.md](https://github.com/miqian-nomad/dsh-browser-playwright-codex/blob/main/FOCUS-STEALING.md)), or close it: login state is exported first and restored on
package/cordis.patch.yml CHANGED
@@ -1,72 +1,80 @@
1
- # dsh-browser-playwright-codex bundle layer: the browser seam, the Playwright
2
- # provider, and the model-facing tool family. Applied as one insert over the
3
- # profile's entry list; rows are patchable by id like every other plugin.
1
+ # dsh-browser-playwright-codex bundle layer — ONE row for the whole capability.
4
2
  #
5
- # The `name:` values are package specifiers resolved from the profile, so they
6
- # must track package.json#name — a rename that misses this file fails at load
7
- # with MODULE_NOT_FOUND (2026-09-30: the 0.4.0 rename to *-codex did exactly
8
- # that; verified `require.resolve('dsh-browser-playwright/service')` fails in
9
- # both profiles while the *-codex specifier resolves).
3
+ # History worth keeping: this file used to insert three rows (`browser` service,
4
+ # `browser-playwright` provider, `browser-tool` tools) because the capability has
5
+ # three configurable concerns. `dsh-client-modules` rejects distinct active Loader
6
+ # sources that resolve to one package name, so a Settings card (which needs a
7
+ # client module) could not live in such a package — it shipped as a second plugin,
8
+ # dsh-browser-toggle. 2026-10-19: one row, three nested config sections, one plugin.
9
+ #
10
+ # The `name:` value is a package specifier resolved from the profile, so it must
11
+ # track package.json#name — a rename that misses this file fails at load with
12
+ # MODULE_NOT_FOUND (the 0.4.0 rename to *-codex did exactly that).
10
13
  - insert:
11
14
  - id: browser
12
- name: 'dsh-browser-playwright-codex/service'
13
- config:
14
- provider: playwright
15
- - id: browser-playwright
16
- name: 'dsh-browser-playwright-codex/playwright'
17
- config:
18
- launch:
19
- # Visible profile-backed window (persistent mode): the agent drives a
20
- # browser the user can watch and rescue. Set true for headless
21
- # servers. profileDir defaults to ~/.dsh/browser-profiles/playwright.
22
- headless: false
23
- persistent: true
24
- viewport:
25
- width: 1280
26
- height: 800
27
- navigationTimeoutMs: 30000
28
- ignoreHTTPSErrors: false
29
- # Idle auto-close: ms of no agent activity before the window closes
30
- # itself (login state is saved first, so it reopens logged-in). 0 =
31
- # never auto-close; the window stays until the user closes it or DSH
32
- # exits. User choice: never auto-close (2026-09-04).
33
- idleTimeoutMs: 0
34
- maxSessions: 8
35
- # Response-size lever (off by default): return "+/-/~" ref diffs between
36
- # snapshots instead of the whole tree. Smaller returns on pages that
37
- # re-render often; the model then has to hold the previous tree itself.
38
- snapshot:
39
- diff: false
40
- - id: browser-tool
41
- name: 'dsh-browser-playwright-codex/tool'
15
+ name: 'dsh-browser-playwright-codex'
42
16
  config:
43
- # This file ships INSIDE the package, so it must not turn anything on for
44
- # the people who install it. It used to: an earlier revision carried the
45
- # author's own `allowEvaluate: true` / `allowCdp: true` (2026-09-04) into
46
- # every download, which is how a package ends up handing each installer a
47
- # backdoor they never asked for — and it is what a third-party scanner
48
- # reads as "dynamic code execution, critical".
49
- #
50
- # Both are OFF here (matching the code defaults in src/tool.ts, and the
51
- # README's own configuration example). Opt in per deployment, in YOUR
52
- # profile patch — never in the package:
53
- #
54
- # # ~/.dsh/profiles/<name>/cordis.patch.yml
55
- # # NOTE: dsh replaces an entry's config object wholesale, so list every
56
- # # key you rely on, not just the one you are changing.
57
- # - id: browser-tool
58
- # config:
59
- # toolPrefix: 'browser_'
60
- # allowEvaluate: true # registers browser_evaluate
61
- # allowCdp: true # registers browser_cdp (needs a DSH restart)
62
- # registerDisabledTools: false
63
- # interactiveOnlyDefault: false # true = snapshot returns actionable elements only
64
- # maxWaitMs: 60000
65
- #
66
- # browser_evaluate runs arbitrary page JavaScript: it can read anything in
67
- # the page and act on the user's logged-in sites. browser_cdp is CDP with
68
- # an allow-list — only inspection and input simulation pass
69
- # (lib/cdp-policy.js); network/storage/cookie/security commands never do.
70
- # Neither tool is registered at all while its gate is false.
71
- allowEvaluate: false
72
- allowCdp: false
17
+ # Browser seam: which registered provider to drive.
18
+ service:
19
+ provider: playwright
20
+ # Provider: window, launch, snapshot and session settings.
21
+ playwright:
22
+ launch:
23
+ # Visible profile-backed window (persistent mode): the agent drives a
24
+ # browser the user can watch and rescue. Set true for headless servers.
25
+ # profileDir defaults to ~/.dsh/browser-profiles/playwright.
26
+ headless: false
27
+ persistent: true
28
+ viewport:
29
+ width: 1280
30
+ height: 800
31
+ navigationTimeoutMs: 30000
32
+ ignoreHTTPSErrors: false
33
+ # Idle auto-close: ms of no agent activity before the window closes
34
+ # itself (login state is saved first, so it reopens logged-in). 0 =
35
+ # never auto-close. User choice: never auto-close (2026-09-04).
36
+ idleTimeoutMs: 0
37
+ maxSessions: 8
38
+ # Response-size lever (off by default): return "+/-/~" ref diffs between
39
+ # snapshots instead of the whole tree.
40
+ snapshot:
41
+ diff: false
42
+ # Model-facing tools: prefix, capability gates and wait caps.
43
+ tool:
44
+ # This file ships INSIDE the package, so it must not turn anything on for
45
+ # the people who install it. It used to: an earlier revision carried the
46
+ # author's own allowEvaluate/allowCdp true (2026-09-04) into every
47
+ # download — a backdoor each installer never asked for, and what a
48
+ # third-party scanner reads as "dynamic code execution, critical".
49
+ #
50
+ # Both are OFF here (matching the code defaults in src/tool.ts). Opt in
51
+ # per deployment, in YOUR profile or home patch — never in the package:
52
+ #
53
+ # - id: browser
54
+ # name: 'dsh-browser-playwright-codex'
55
+ # config:
56
+ # service: { provider: playwright }
57
+ # playwright: { launch: { headless: false, persistent: true }, idleTimeoutMs: 0, maxSessions: 8, snapshot: { diff: false } }
58
+ # tool:
59
+ # toolPrefix: 'browser_'
60
+ # allowEvaluate: true # registers browser_evaluate
61
+ # diagnostics: true # registers browser_console_messages / browser_network_requests
62
+ # allowCdp: true # registers browser_cdp
63
+ # registerDisabledTools: false
64
+ # interactiveOnlyDefault: false # true = snapshot returns actionable elements only
65
+ # maxWaitMs: 60000
66
+ #
67
+ # The loader replaces an entry's config object WHOLESALE, so a partial
68
+ # block resets every key you leave out. List all three sections.
69
+ #
70
+ # browser_evaluate runs arbitrary page JavaScript: it can read anything
71
+ # in the page and act on the user's logged-in sites. browser_cdp is CDP
72
+ # with an allow-list — only inspection and input simulation pass
73
+ # (lib/cdp-policy.js); network/storage/cookie/security commands never do.
74
+ # Neither tool is registered at all while its gate is false.
75
+ allowEvaluate: false
76
+ allowCdp: false
77
+ # Diagnostics tools (console messages, network requests) are OFF here:
78
+ # they debug a failed run; their schemas would otherwise sit in the
79
+ # system prompt every turn. Turn them on per deployment.
80
+ diagnostics: false