@taole/dd-playwright 0.0.0-stage → 0.1.0

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,3 +1,99 @@
1
- # Temporary Holding Version
1
+ # dd-playwright (dd-pw)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 增强型 stdio MCP 服务与 CLI 工具:Playwright 浏览器自动化 + 隔离 whistle 代理 + 点点账号 storageState 免登注入。
4
+ 可挂载到任意 AI 客户端(omp / Cursor / Claude Desktop / Codex 等)使用,不依赖任何特定宿主项目。
5
+
6
+ ## 能力
7
+
8
+ | 工具 | 说明 |
9
+ |---|---|
10
+ | `browser_navigate` | 访问 URL。支持显式指定 `uid` 选择绑定账号(默认使用当前默认账号);支持通过 `anonymous: true` 模拟未登录游客状态访问 |
11
+ | `browser_screenshot` | 页面/元素截图,落盘到数据目录并返回路径 |
12
+ | `browser_get_console_errors` | 收集 console.error 与未捕获异常 |
13
+ | `browser_click_element` | 按选择器模拟用户点击元素 |
14
+ | `browser_fill_text` | 向指定选择器的输入框/文本域填入文本,触发 input 与 change 事件 |
15
+ | `browser_press_key` | 模拟键盘按键(Enter, Tab, Escape, Backspace, 快捷键组合等) |
16
+ | `browser_hover` | 悬停在指定元素上触发 hover 菜单或 Tooltip 浮层 |
17
+ | `browser_scroll` | 页面视口滚动或滚动指定元素进入视图 |
18
+ | `browser_wait_for` | 等待整页状态或等待特定 DOM 元素出现/隐藏/移除 |
19
+ | `browser_get_dom` | 提取当前页面的结构化可交互 DOM 树(按钮/链接/输入框及其选择器),免去盲猜 |
20
+ | `browser_eval_js` | 页面上下文执行 JS |
21
+ | `browser_set_proxy_rule` | 声明「本地 dev server → 干净 `*.tuwan.com` 域名」映射,隔离 whistle 代理自动托管 |
22
+ | `browser_status` | 查询登录态挂载情况、当前 UID、代理状态、数据目录,排查免登问题先调它 |
23
+
24
+ ## 安装与挂载
25
+
26
+ 需要 Node.js >=22.13(使用内置 `node:sqlite`)。在本仓库目录执行:
27
+
28
+ ```bash
29
+ npm install
30
+ npx playwright install chromium
31
+ ```
32
+
33
+ MCP 客户端配置(以 omp / Cursor / Claude 为例):
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "dd-playwright": {
39
+ "command": "dd-playwright-mcp"
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ 或者直接指向本地入口:`node D:/tools/dd-browser-mcp/bin/mcp-server.mjs`
46
+
47
+ ## 数据与配置
48
+
49
+ - **数据目录**:默认自动固定为 `~/.dd-browser-mcp`(账号库 `runtime.db` 与截图目录),无需手动设置环境变量。
50
+ - **无头模式 (Headless)**:默认为 `true`(静默后台运行),可在 Web 控制台(`http://127.0.0.1:12309`)的「全局运行配置」中一键开关切换为可见窗口。
51
+ - **域名白名单**:默认为 `tuwan.com`,可通过 `BROWSER_MCP_DOMAIN_SUFFIX` 按需调整。
52
+
53
+ 登录态来源优先级:`BROWSER_MCP_STORAGE_STATE` 文件 > `~/.dd-browser-mcp/runtime.db` 中激活的账号 > 无登录态。
54
+
55
+ 服务启动时读取一次 storageState;更新绑定或切换账号后需重启 MCP 进程。`browser_status.storageStateLoaded` 只表示状态已加载,不代表 Cookie 仍有效。未提供状态时按未登录浏览器运行。
56
+
57
+ 当前包尚未发布到 npm,请使用上面的本地路径配置。每个客户端启动一个独立 stdio 进程,不共享页面、代理规则或浏览器实例。
58
+
59
+ 仅向受信任的本地 AI 客户端开放:`browser_eval_js` 能执行任意页面脚本,浏览器持有登录凭据。storageState、数据库及截图可能包含敏感信息,不要提交到版本库。Cookie 按浏览器原生 domain/path/secure 规则发送,不做域名重写。
60
+
61
+ ## 登录与账号管理(Web 控制台扫码绑定)
62
+
63
+ 提供独立的 Web 管理服务,无需经过 MCP 协议,通过浏览器即可直观扫码绑定与管理点点账号:
64
+
65
+ ```bash
66
+ # 后台静默启动(推荐,终端立即返回,不占控制台):
67
+ dd-pw startweb
68
+
69
+ # 查看后台服务运行状态、PID 与监听端口:
70
+ dd-pw statusweb
71
+
72
+ # 停止后台运行的服务:
73
+ dd-pw stopweb
74
+
75
+ # (可选)前台阻塞运行(Ctrl+C 退出):
76
+ dd-pw serve [--port 12309]
77
+ ```
78
+
79
+ 1. 启动后在浏览器打开 `http://127.0.0.1:12309`。
80
+ 2. 点击右上角 **「+ 添加绑定账号」**,后台会以独立的 Playwright 实例拉起扫码页并渲染二维码。
81
+ 3. 使用微信或点点 App 扫码登录,完成后会自动捕获 Cookie 与 `storageState`,提取点点账号 UID、昵称与头像,并落库至 `$BROWSER_MCP_DATA_DIR/runtime.db`。
82
+ 4. 支持多账号管理、一键设为当前激活账号或解绑账号。
83
+ 5. MCP 服务启动时会自动加载该激活账号的 `storageState`,完成免登。
84
+
85
+ ## 代理说明
86
+
87
+ - 每个 MCP 进程在进程内启动 Whistle,并在首次加载 Whistle 模块前将 `WHISTLE_PATH` 设置为本进程独立的临时目录,不改 hosts,隔离配置、规则、证书和临时文件,不读写用户本机的 `~/.WhistleAppData`。
88
+ - 域名后缀仅限制可声明的转发规则,不是浏览器访问控制。启用代理后浏览器流量经过该代理,未匹配流量按 Whistle 默认行为转发。
89
+ - `browser_set_proxy_rule` 后浏览器自动重启加载规则;HTTPS 场景自动忽略自签证书错误。
90
+ - `protocol` 指本地上游协议;返回访问 URL 使用相同协议。每次设置会替换当前单条规则,重启浏览器会丢失当前页面的未保存状态。
91
+
92
+ ## 目录结构
93
+
94
+ ```
95
+ bin/mcp-server.mjs # stdio 入口 + 工具注册
96
+ src/config.mjs # 环境变量解析、域名白名单正则
97
+ src/browser-manager.mjs # Playwright 浏览器生命周期、storageState 注入
98
+ src/whistle-proxy.mjs # 隔离 whistle 实例托管
99
+ ```
package/SKILL.md ADDED
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: dd-playwright
3
+ description: >-
4
+ 使用 dd-playwright (别名: dd-pw, dd-browser) 进行点点前端业务页面与 H5 活动的自动化测试、免登导航、页面截图、表单填写、键盘按键、DOM 提取、JS 评估与 Whistle 代理规则调试。
5
+ 支持多账号免登与游客匿名态模拟,通过本地扫码控制台绑定点点账号。
6
+ 当用户提到点点页面测试、免登访问、浏览器截图、控制台报错排查、本地 dev server 代理映射、dd-playwright、dd-pw、dd-browser 时使用。
7
+ ---
8
+
9
+ # dd-playwright (dd-pw)
10
+
11
+ 增强型 Playwright 浏览器自动化 MCP 服务与扫码控制台,专为点点业务前端调试和 AI Agent 设计。
12
+
13
+ ## 核心特性
14
+
15
+ 1. **自动免登注入**:访问 `*.tuwan.com` 时自动注入扫码绑定的点点测试账号凭据(`Tuwan_Passport` 等 Cookie)。
16
+ 2. **多账号与匿名切换**:
17
+ - 默认使用控制台设为「默认账号」的凭据。
18
+ - `browser_navigate` 支持显式指定 `uid: "12345"` 切换不同测试身份。
19
+ - 支持 `anonymous: true` 模拟未登录的游客态访问,测试未登录拦截与导流逻辑。
20
+ 3. **独立 Whistle 代理托管**:
21
+ - `browser_set_proxy_rule` 可声明 `本地端口 -> 干净 *.tuwan.com 域名` 的代理规则。
22
+ - 进程内完全隔离临时 Whistle 配置,绝不污染系统或用户目录 `~/.WhistleAppData`。
23
+ 4. **一键 Web 扫码绑定**:
24
+ - 内置 Web 控制台(默认监听 `12309` 端口),手机扫码即刻完成账号绑定并同步至 MCP。
25
+
26
+ ---
27
+
28
+ ## 快速配置 MCP 客户端
29
+
30
+ 在你的 AI 客户端(如 **omp**, **Cursor**, **Claude Desktop** 等)的 MCP 配置文件中添加:
31
+
32
+ ### 1. 全局命令方式(推荐)
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "dd-playwright": {
37
+ "command": "dd-playwright-mcp"
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ### 2. 源码路径方式(本地调试)
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "dd-playwright": {
48
+ "command": "node",
49
+ "args": ["D:/tools/dd-browser-mcp/bin/mcp-server.mjs"]
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 工具集 (Tools) 契约
58
+
59
+ | 工具名称 | 关键参数 | 说明 |
60
+ |---|---|---|
61
+ | `browser_navigate` | `url` (必填)<br>`uid` (可选): 指定点点账号 UID<br>`anonymous` (可选): `true` 模拟游客态<br>`waitFor` (可选): 等待的 DOM 选择器<br>`timeout` (可选, 默认 15000ms) | 访问目标页面,返回 HTTP 状态码、页面标题与控制台报错统计。自动注入点点 storageState。不同身份调用自动隔离上下文。 |
62
+ | `browser_screenshot` | `selector` (可选): 指定元素选择器<br>`fullPage` (可选, 默认 false): 整页滚动截图 | 截取页面或特定元素,落盘到数据目录,返回本地图片路径。 |
63
+ | `browser_get_console_errors` | 无 | 收集当前页面自导航以来的 console.error 与未捕获异常。 |
64
+ | `browser_click_element` | `selector` (必填)<br>`timeout` (可选, 默认 10000ms) | 模拟用户点击指定 DOM 元素(按钮、选项卡等)。 |
65
+ | `browser_fill_text` | `selector` (必填)<br>`text` (必填)<br>`timeout` (可选) | 向目标输入框/文本域填入文本,原生触发 input 与 change 事件。 |
66
+ | `browser_press_key` | `key` (必填, 如 "Enter", "Tab", "Escape")<br>`selector` (可选): 目标聚焦元素 | 模拟键盘单键或组合键按下。 |
67
+ | `browser_hover` | `selector` (必填)<br>`timeout` (可选) | 鼠标悬停在指定 DOM 元素上,触发 hover 样式或 Tooltip 浮层。 |
68
+ | `browser_scroll` | `direction` ("down" 或 "up")<br>`deltaY` (可选数值)<br>`selector` (可选): 指定滚动元素 | 滚动视口或将指定元素滚动至可视区域。 |
69
+ | `browser_wait_for` | `selector` (可选)<br>`state` ("visible", "hidden", "attached", "detached")<br>`timeout` (可选) | 等待页面加载状态或特定 DOM 元素出现/隐藏。 |
70
+ | `browser_get_dom` | `interactiveOnly` (可选, 默认 true)<br>`maxDepth` (可选, 默认 10) | 结构化提取页面可见交互元素清单(含文本与选择器),免去盲猜或截大图。 |
71
+ | `browser_eval_js` | `script` (必填): JS 代码字符串 | 在当前浏览器页面上下文中执行任意 JavaScript 脚本并返回结果。 |
72
+ | `browser_set_proxy_rule` | `domain` (必填, 需匹配 `*.tuwan.com`)<br>`port` (必填, 本地服务端口)<br>`protocol` (可选, "http" 或 "https") | 声明本地 dev server 代理映射,使本地开发服务可通过合法的点点域名访问并正常携带登录 Cookie。 |
73
+ | `browser_status` | 无 | 查询当前服务版本、激活点点账号、代理状态与数据目录。 |
74
+
75
+ ---
76
+
77
+ ## Web 账号控制台 (扫码绑定)
78
+
79
+ 在终端运行以下命令启动管理控制台:
80
+
81
+ ```bash
82
+ # 后台静默启动(推荐,不占控制台终端):
83
+ dd-pw startweb
84
+
85
+ # 查看后台运行状态与 PID:
86
+ dd-pw statusweb
87
+
88
+ # 停止后台服务:
89
+ dd-pw stopweb
90
+
91
+ # 前台阻塞运行(Ctrl+C 退出):
92
+ dd-pw serve
93
+ ```
94
+
95
+ - 打开浏览器访问:`http://127.0.0.1:12309`
96
+ - 点击 **「+ 添加绑定账号」**,使用微信或点点 App 扫描二维码即可。
97
+ - 控制台支持多账号查看、设为默认账号或解绑账号。
98
+
99
+ ---
100
+
101
+ ## Agent 使用最佳实践
102
+
103
+ 1. **先排查状态**:在执行复杂的业务排查或测试前,先调用 `browser_status` 确认是否已加载登录态或默认账号 UID。
104
+ 2. **测试登录态与未登录态对比**:
105
+ - 先调用 `browser_navigate({ url, anonymous: true })` 查看游客视角行为(如是否弹出登录拦截、展示游客文案)。
106
+ - 再调用 `browser_navigate({ url })` 查看默认登录用户视角;或 `browser_navigate({ url, uid: "..." })` 验证特定业务角色。
107
+ 3. **本地 dev 调试**:
108
+ - 本地前端开发服务启动后(例如 `127.0.0.1:9527`),先调用 `browser_set_proxy_rule({ domain: "act-dev.tuwan.com", port: 9527 })`。
109
+ - 随后调用 `browser_navigate({ url: "http://act-dev.tuwan.com/..." })`,不仅不改 hosts,且浏览器能正常携带点点线上 Cookie。
package/bin/cli.mjs ADDED
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env node
2
+ import { resolveConfig } from "../src/config.mjs";
3
+ import { startWebServer } from "../src/server/web-server.mjs";
4
+ import {
5
+ startWebDaemon,
6
+ stopWebDaemon,
7
+ getWebDaemonStatus,
8
+ } from "../src/server/daemon.mjs";
9
+
10
+ const args = process.argv.slice(2);
11
+ const command = args[0];
12
+
13
+ function printHelp() {
14
+ console.log(`
15
+ dd-playwright (别名: dd-pw) CLI
16
+
17
+ 用法:
18
+ dd-pw startweb [--port 12309] 后台静默启动 Web 控制台(不占用控制台)
19
+ dd-pw stopweb 停止后台运行的 Web 控制台
20
+ dd-pw statusweb 查看后台 Web 控制台运行状态与端口
21
+ dd-pw serve [--port 12309] 前台阻塞启动 Web 控制台(按 Ctrl+C 退出)
22
+ dd-pw mcp 以 stdio 模式启动 MCP 浏览器服务
23
+ dd-pw --help, -h 查看帮助信息
24
+
25
+ 说明:
26
+ - startweb 启动后服务将在系统后台持续运行,终端可立即继续其他操作。
27
+ - 控制台默认监听 http://127.0.0.1:12309,可在此扫码绑定账号与切换无头模式。
28
+ `);
29
+ }
30
+
31
+ async function main() {
32
+ if (!command || command === "--help" || command === "-h") {
33
+ printHelp();
34
+ process.exit(0);
35
+ }
36
+
37
+ if (command === "startweb") {
38
+ let port = 12309;
39
+ const portIdx = args.indexOf("--port");
40
+ if (portIdx !== -1 && args[portIdx + 1]) {
41
+ port = parseInt(args[portIdx + 1], 10) || 12309;
42
+ }
43
+
44
+ const config = resolveConfig();
45
+ console.log(`[dd-playwright] 正在后台启动 Web 服务...`);
46
+
47
+ try {
48
+ const res = await startWebDaemon({
49
+ port,
50
+ dataDir: config.dataDir,
51
+ pidFile: config.webPidFile,
52
+ logFile: config.webLogFile,
53
+ });
54
+
55
+ if (res.alreadyRunning) {
56
+ console.log(`[dd-playwright] Web 服务已在后台运行中 (PID: ${res.pid})`);
57
+ console.log(`访问地址: ${res.url}`);
58
+ process.exit(0);
59
+ }
60
+
61
+ if (res.started) {
62
+ console.log(`
63
+ ==================================================
64
+ dd-playwright Web 服务已在后台启动成功!
65
+ PID: ${res.pid}
66
+ 请在浏览器访问: ${res.url}
67
+ 运行日志落盘至: ${res.logFile}
68
+ 如需停止服务请运行: dd-pw stopweb
69
+ ==================================================
70
+ `);
71
+ } else {
72
+ console.error(`[dd-playwright] 后台启动超时,请检查日志: ${res.logFile}`);
73
+ process.exit(1);
74
+ }
75
+ } catch (err) {
76
+ console.error(`[dd-playwright] 启动异常:`, err);
77
+ process.exit(1);
78
+ }
79
+ } else if (command === "stopweb") {
80
+ const config = resolveConfig();
81
+ console.log(`[dd-playwright] 正在停止后台 Web 服务...`);
82
+ try {
83
+ const res = await stopWebDaemon(config.webPidFile);
84
+ if (res.stopped) {
85
+ console.log(`[dd-playwright] 后台 Web 服务已成功停止 (PID: ${res.pid})`);
86
+ } else {
87
+ console.log(`[dd-playwright] ${res.message}`);
88
+ }
89
+ } catch (err) {
90
+ console.error(`[dd-playwright] 停止失败:`, err);
91
+ process.exit(1);
92
+ }
93
+ } else if (command === "statusweb") {
94
+ const config = resolveConfig();
95
+ try {
96
+ const status = await getWebDaemonStatus(config.webPidFile);
97
+ if (status.running) {
98
+ console.log(`
99
+ [dd-playwright] 后台 Web 服务状态:
100
+ - 运行状态: 正在运行
101
+ - 进程 PID: ${status.pid}
102
+ - 监听端口: ${status.port}
103
+ - HTTP 响应: ${status.responding ? "正常 (200 OK)" : "未响应/启动中"}
104
+ - 访问地址: ${status.url}
105
+ - 日志文件: ${config.webLogFile}
106
+ `);
107
+ } else {
108
+ console.log(`[dd-playwright] 后台 Web 服务当前未运行。使用 "dd-pw startweb" 启动服务。`);
109
+ }
110
+ } catch (err) {
111
+ console.error(`[dd-playwright] 查询状态失败:`, err);
112
+ process.exit(1);
113
+ }
114
+ } else if (command === "serve" || command === "serve-daemon") {
115
+ const isDaemon = command === "serve-daemon";
116
+ let port = 12309;
117
+ const portIdx = args.indexOf("--port");
118
+ if (portIdx !== -1 && args[portIdx + 1]) {
119
+ port = parseInt(args[portIdx + 1], 10) || 12309;
120
+ }
121
+
122
+ const config = resolveConfig();
123
+ if (!isDaemon) {
124
+ console.log(`[dd-playwright] 正在启动 Web 控制台...`);
125
+ console.log(`[dd-playwright] 账号数据文件: ${config.dbPath}`);
126
+ }
127
+
128
+ try {
129
+ const web = await startWebServer({
130
+ port,
131
+ dbPath: config.dbPath,
132
+ dataDir: config.dataDir,
133
+ });
134
+
135
+ if (!isDaemon) {
136
+ console.log(`
137
+ ==================================================
138
+ dd-playwright 账号控制台已启动!
139
+ 请在浏览器访问: http://127.0.0.1:${port}
140
+ 在此页面可扫码绑定点点账号,并自动同步至 MCP 服务。
141
+ (若希望后台静默运行不占用终端,可使用: dd-pw startweb)
142
+ ==================================================
143
+ `);
144
+ }
145
+
146
+ const shutdown = async () => {
147
+ if (!isDaemon) {
148
+ console.log(`\n[dd-playwright] 正在停止服务...`);
149
+ }
150
+ await web.close();
151
+ process.exit(0);
152
+ };
153
+
154
+ process.on("SIGINT", shutdown);
155
+ process.on("SIGTERM", shutdown);
156
+ } catch (err) {
157
+ console.error(`[dd-playwright] 启动失败:`, err);
158
+ process.exit(1);
159
+ }
160
+ } else if (command === "mcp") {
161
+ // 转发至 mcp-server.mjs
162
+ await import("./mcp-server.mjs");
163
+ } else {
164
+ console.error(`未知命令: ${command}`);
165
+ printHelp();
166
+ process.exit(1);
167
+ }
168
+ }
169
+
170
+ main().catch((err) => {
171
+ console.error("CLI 执行异常:", err);
172
+ process.exit(1);
173
+ });