miqian-nomad/dsh-browser-playwright-codex ↗★ 0
dsh-browser-playwright
Playwright-powered browser capability for DeepSeek Harness: accessibility-snapshot interaction with stable element refs, session-scoped browser sessions, screenshots as attachments. Codex-merged 0.2.0 build (compiled only) with minimized-window focus-stealing fixes. 适合需要让AI进行网页自动化操作和视觉分析的用户。
同名パッケージの別リポジトリ
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:miqian-nomad/dsh-browser-playwright-codexドキュメント
README 全文を読む ↗dsh-browser-playwright-codex
A Codex-merged, headful build of dsh-browser-playwright for DeepSeek Harness — plus a full diagnosis of the "minimized browser window gets yanked back onto my screen" bug, and the patches that fix it.
面向 DeepSeek Harness 的浏览器插件(上游 dsh-browser-playwright + Codex 浏览器插件功能整合版)——附带"最小化窗口被自动拽回桌面"这个 bug 的完整诊断与修复补丁。
⚠️ Read this before anything else / 先读这一段
This repository contains compiled output only (
lib/*.js+lib/*.d.ts). The TypeScript source of this build does not exist anywhere. It was produced by merging Codex-style browser features into upstreamdsh-browser-playwrightv0.1.1, and only the compiled product survived.本仓库只有编译产物(
lib/*.js+lib/*.d.ts),这套构建的 TypeScript 源码在任何地方都不存在。 它是把 Codex 风格的浏览器功能整合进上游dsh-browser-playwrightv0.1.1 得到的,只剩编译产物。That is exactly why this repo is asking for help — see Help wanted / 求助. If you want to fix logic rather than patch a build artifact, the right starting point is the upstream source tree.
这正是这个仓库存在的理由——见 Help wanted / 求助。想改逻辑而不是给编译产物打补丁,请从上游源码树开始。
Status / 现状
| # | Symptom / 症状 | Root cause / 根因 | State / 状态 |
|---|---|---|---|
| 1 | Minimized window is raised when the plugin switches tabs | ||
| 切标签时最小化的窗口被弹出来 | switchTab calls page.bringToFront() unconditionally | ||
switchTab 无条件调用 page.bringToFront() | Fixed here (lib/playwright.js L1417) · Patch ready for upstream (patches/upstream-window-activation.patch) | ||
| 2 | Minimized window is raised when the plugin opens a tab | ||
| 开新标签时窗口被弹出来 | context.newPage() → CDP Target.createTarget without background, and Chromium activates the window on every tab creation | ||
context.newPage() 内部发的 Target.createTarget 不带 background,Chromium 建标签必激活窗口 | Fixed here (createBackgroundPage, L153) · Patch ready for upstream | ||
| 3 | Minimized window is raised by any tool call, even one that fails before touching the page | ||
| 任何一次工具调用都会弹窗,连"导航前就失败"的调用也弹 | Post-op login-state export (endOp → persistStateSoon → context.storageState()) in this fork's persistent-profile layer | ||
| 本 fork 持久化 profile 层里"每次操作后导出登录态" | Mitigated here (skip export while minimized, L574) — but not reproducible in a minimal harness, so the mechanism is still unknown: see docs/FOCUS-STEALING.md | ||
| 4 | Clicking a link with target="_blank" (or any page-side window.open()) still raises the window | ||
点击 target="_blank" 链接(或页面自己 window.open())仍会拽窗 | Chromium's own default: a new tab must be selected and shown, so a minimized window is restored. The plugin never issues this call — the page does | ||
| Chromium 自身默认行为:新标签要"选中并显示",于是恢复最小化的窗口。这一下不是插件发起的,是网页发起的 | Open — help wanted |
Everything else the plugin does (snapshot, evaluate, screenshot, click, fill, scroll, wheel, goto, reload, storageState, CDP session creation) was measured to leave a minimized window alone. / 插件其它操作(快照、evaluate、截图、点击、填写、滑动、滚轮、导航、刷新、storageState、建 CDP 会话)实测都不会碰最小化的窗口。
Provenance & license / 来源与许可
- Upstream: ChenyuHeee/dsh-browser-playwright v0.1.1, MIT — the accessibility-snapshot interaction engine (
injected.js,snapshot-render.js), the tool family, the URL policy, and the test suite are upstream work. Copyright (c) 2026 dsh-browser-playwright contributors. - Merged on top (Codex-inspired layer): geometric click (
browser_click_at) with landing-element reporting, the CDP policy layer (cdp-policy.js), the persistent profile + login-state export (runtime-state.js,persistState/restoreState), dialog parking (DIALOG-POLICY.md), snapshot rules (SNAPSHOT-RULES.md), safety rules (SAFETY-RULES.md), and the Codex rule set (codex-rules.md). - License: MIT, unchanged. Redistribution of the compiled upstream work keeps the upstream copyright notice — see
LICENSE. - 上游:ChenyuHeee/dsh-browser-playwright v0.1.1(MIT)。无障碍快照引擎、工具族、URL 策略、测试套件均为上游成果。叠加层(Codex 风格):几何点击、CDP 策略、持久化 profile 与登录态导出、对话框挂起策略、快照/安全规则。许可仍为 MIT,保留上游版权声明。
Install / 安装
# from a checkout / 从本地检出安装
dsh plugin --profile add link:
Config lives in the DSH profile; the browser profile directory defaults to ~/.dsh/browser-profiles/playwright. Set launch.headless: false (this build defaults to headful) for login/captcha hand-off, or launch.persistent: false for the legacy shared-browser mode. / 浏览器 profile 目录默认 ~/.dsh/browser-profiles/playwright;launch.headless: false 用于登录/验证码人工接管,launch.persistent: false 回到上游的共享浏览器模式。
Reproducing the bug in 60 seconds / 60 秒复现
No DSH needed — the mechanism is pure Playwright + Chromium:
cd scripts
set PW_MODE=launch # or: persistent
set PW_CHANNEL=chrome
set PW_CORE_PATH=
\node_modules\playwright-core
node repro-minimize.mjs
Observed output (Windows 11, playwright-core 1.62.1, Google Chrome 151, PW_MODE=launch and persistent — identical in both):
safe baseline: sleep only (3s) before=minimized after=minimized
RAISES context.newPage() before=minimized after=normal
safe CDP Target.createTarget({background:true}) before=minimized after=minimized
RAISES page.bringToFront() before=minimized after=normal
safe context.newCDPSession(anchor) before=minimized after=minimized
safe context.storageState() before=minimized after=minimized
safe anchor.goto() (same tab) before=minimized after=minimized
safe anchor.screenshot() before=minimized after=minimized
Full analysis, method and limitations: docs/FOCUS-STEALING.md.
Help wanted / 求助
- Upstream fix / 上游修复 —
patches/upstream-window-activation.patchapplies cleanly to upstreammain(61 insertions, 5 deletions insrc/playwright.ts). It addsisWindowMinimized()+createBackgroundPage()and gatesbringToFront. It has not been run against upstream's test suite — review and run it. / 补丁能干净地应用到上游main,但没有跑过上游测试套件。 - Cause 3 / 第三条根因 — reproduce (or refute) "a long-lived browser instance raises a minimized window on a post-op
context.storageState()". Our minimal harness saysstorageState()is safe; the live instance said otherwise. A reliable reproduction would settle it. / 长存活实例上"操作后导出登录态会顶起最小化窗口",最小复现里storageState()是安全的——需要有人做出稳定复现或证伪。 - Cause 4 / 第四条根因 — a clean way to stop
target="_blank"/window.open()from restoring a minimized window, without rewriting the page's semantics behind the user's back. Known approaches (rewritingtargetviaaddInitScript, hookingwindow.open, or intercepting at theTarget.targetCreatedlevel) each have real costs; see the "Remaining" section of the analysis. / 在不改网页原意的前提下拦住target="_blank"/window.open()恢复最小化窗口。 - Source recovery / 源码找回 — if you know how this Codex-merged 0.2.0 build was produced, or have its
src/, that would be worth more than any patch here. / 知道这套 0.2.0 从哪来、或手上有src/,比这里任何补丁都值钱。
Open an issue or a PR — both are welcome. / 欢迎开 issue 或直接提 PR。
Which mode should this run in? / 该用哪种模式
Short answer: the choice is not free, and "default to headless" is the option that costs the most exactly when a human is needed. Measured comparison of headless vs headful (UA, viewport, DPR, responsive breakpoints, screenshot size), what actually requires a visible window (spoiler: not native dialogs), and the measured minimize ⇄ show hand-off that avoids mode switches entirely: docs/MODE-TRADE-OFFS.md.
一句话:这个选择不是免费的,而且"默认 headless"的代价恰好都落在"需要人"的那一刻。 量化对照见 docs/MODE-TRADE-OFFS.md。
License / 许可
This repository is intentionally not under a single licence:
| Part | Licence | Commercial use |
|---|---|---|
lib/, scripts/, patches/, cordis.patch.yml, package.json | MIT (LICENSE) — required, because lib/ is a derivative of MIT-licensed upstream work and adding a non-commercial restriction to it would be an unauthorised restriction on downstream users | allowed |
Documentation: this README, docs/** | CC BY-NC-SA 4.0 (LICENSE-DOCS) — share and adapt with attribution and share-alike, non-commercial only | not allowed |
No OpenAI code is redistributed here. docs/codex-rules.md is an independently written Chinese summary of browser-automation behaviour plus a source map to the original documentation; no verbatim text from it is reproduced. Full details, including the provenance of every file: NOTICE.md.
中文:代码走 MIT(因为 lib/ 派生自 MIT 的上游,往上加"禁止商用"是越权);文档走 CC BY-NC-SA 4.0(禁止商用、需署名、相同方式共享)。仓库里不含任何 OpenAI 的代码;docs/codex-rules.md 是原创中文归纳 + 原文出处对照表。细节见 NOTICE.md。