miqian-nomad/dsh-browser-playwright-codex ↗★ 0

dsh-browser-playwright

基于Playwright的浏览器交互与截图插件 适合需要让AI进行网页自动化操作和视觉分析的用户。

包名
dsh-browser-playwright
兼容性
待验证
Harness 依赖范围
^0.1.0-rc.2 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.3-0 || ^0.1.5-0 || ^0.1.6-0
Cordis 依赖范围
^4.0.1
版本
0.2.0
许可证
MIT
最近更新
2026年9月26日

同名包的其他仓库

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:miqian-nomad/dsh-browser-playwright-codex

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 upstream dsh-browser-playwright v0.1.1, and only the compiled product survived.

本仓库只有编译产物(lib/*.js + lib/*.d.ts),这套构建的 TypeScript 源码在任何地方都不存在。 它是把 Codex 风格的浏览器功能整合进上游 dsh-browser-playwright v0.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 / 状态
1Minimized 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)
2Minimized 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
3Minimized 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
4Clicking 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 / 求助

  1. Upstream fix / 上游修复 — patches/upstream-window-activation.patch applies cleanly to upstream main (61 insertions, 5 deletions in src/playwright.ts). It adds isWindowMinimized() + createBackgroundPage() and gates bringToFront. It has not been run against upstream's test suite — review and run it. / 补丁能干净地应用到上游 main,但没有跑过上游测试套件。
  2. Cause 3 / 第三条根因 — reproduce (or refute) "a long-lived browser instance raises a minimized window on a post-op context.storageState()". Our minimal harness says storageState() is safe; the live instance said otherwise. A reliable reproduction would settle it. / 长存活实例上"操作后导出登录态会顶起最小化窗口",最小复现里 storageState() 是安全的——需要有人做出稳定复现或证伪。
  3. 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 (rewriting target via addInitScript, hooking window.open, or intercepting at the Target.targetCreated level) each have real costs; see the "Remaining" section of the analysis. / 在不改网页原意的前提下拦住 target="_blank" / window.open() 恢复最小化窗口。
  4. 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:

PartLicenceCommercial use
lib/, scripts/, patches/, cordis.patch.yml, package.jsonMIT (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 usersallowed
Documentation: this README, docs/**CC BY-NC-SA 4.0 (LICENSE-DOCS) — share and adapt with attribution and share-alike, non-commercial onlynot 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。