claude-coder 1.7.0 → 1.8.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.
Files changed (52) hide show
  1. package/README.md +177 -125
  2. package/bin/cli.js +159 -161
  3. package/package.json +52 -47
  4. package/src/commands/auth.js +294 -0
  5. package/src/commands/setup-modules/helpers.js +105 -0
  6. package/src/commands/setup-modules/index.js +26 -0
  7. package/src/commands/setup-modules/mcp.js +95 -0
  8. package/src/commands/setup-modules/provider.js +261 -0
  9. package/src/commands/setup-modules/safety.js +62 -0
  10. package/src/commands/setup-modules/simplify.js +53 -0
  11. package/src/commands/setup.js +172 -0
  12. package/src/common/assets.js +192 -0
  13. package/src/{config.js → common/config.js} +138 -201
  14. package/src/common/constants.js +57 -0
  15. package/src/{indicator.js → common/indicator.js} +222 -217
  16. package/src/common/interaction.js +170 -0
  17. package/src/common/logging.js +77 -0
  18. package/src/common/sdk.js +51 -0
  19. package/src/{tasks.js → common/tasks.js} +157 -172
  20. package/src/common/utils.js +147 -0
  21. package/src/core/base.js +54 -0
  22. package/src/core/coding.js +55 -0
  23. package/src/core/context.js +132 -0
  24. package/src/core/hooks.js +529 -0
  25. package/src/{init.js → core/init.js} +163 -144
  26. package/src/core/plan.js +318 -0
  27. package/src/core/prompts.js +253 -0
  28. package/src/core/query.js +48 -0
  29. package/src/core/repair.js +58 -0
  30. package/src/{runner.js → core/runner.js} +352 -420
  31. package/src/core/scan.js +89 -0
  32. package/src/core/simplify.js +59 -0
  33. package/src/core/validator.js +138 -0
  34. package/{prompts/ADD_GUIDE.md → templates/addGuide.md} +98 -98
  35. package/templates/addUser.md +26 -0
  36. package/{prompts/CLAUDE.md → templates/agentProtocol.md} +195 -199
  37. package/templates/bash-process.md +5 -0
  38. package/{prompts/coding_user.md → templates/codingUser.md} +31 -23
  39. package/templates/guidance.json +35 -0
  40. package/templates/playwright.md +17 -0
  41. package/templates/requirements.example.md +56 -56
  42. package/{prompts/SCAN_PROTOCOL.md → templates/scanProtocol.md} +118 -118
  43. package/{prompts/scan_user.md → templates/scanUser.md} +17 -17
  44. package/templates/test_rule.md +194 -194
  45. package/prompts/add_user.md +0 -24
  46. package/src/auth.js +0 -245
  47. package/src/hooks.js +0 -160
  48. package/src/prompts.js +0 -295
  49. package/src/scanner.js +0 -62
  50. package/src/session.js +0 -352
  51. package/src/setup.js +0 -579
  52. package/src/validator.js +0 -181
@@ -1,195 +1,195 @@
1
- # Playwright 自动化测试通用规则 v0.0.1
2
-
3
- ## 一、四条铁律
4
-
5
- 1. **真实操作** — 必须通过 Playwright MCP 产生浏览器交互,代码审查不等于测试
6
- 2. **测试业务** — 断言基于用户可见结果(页面文本、按钮状态),非内部变量
7
- 3. **独立可重复** — 每个场景不依赖其他测试结果
8
- 4. **先调查再修复** — 失败先分析根因,不要修改测试让它通过
9
-
10
- ## 二、三步测试方法论
11
-
12
- 任何 Web 项目的端到端测试遵循三步走:
13
-
14
- ### Step 1: 功能验证(Happy Path)
15
-
16
- 核心用户流程能走通,每个步骤对应一个 Playwright MCP 工具调用:
17
-
18
- ```
19
- 1. browser_navigate → [页面URL]
20
- 2. browser_snapshot → 确认页面加载,定位关键元素 ref
21
- 3. browser_fill_form / browser_type → 输入测试数据
22
- 4. browser_click → 提交操作
23
- 5. browser_wait_for → 等待结果出现
24
- 6. browser_snapshot → 验证预期结果
25
- ```
26
-
27
- ### Step 2: 错误场景(Unhappy Path)
28
-
29
- | 类别 | 典型场景 |
30
- |------|---------|
31
- | 输入验证 | 空提交、超长输入、特殊字符、非法格式 |
32
- | 认证权限 | 未登录访问、过期凭证、无效 API Key |
33
- | 网络服务 | 后端宕机、慢响应、API 500 |
34
- | 状态边界 | 空数据、大数据量、重复提交、浏览器后退 |
35
-
36
- ### Step 3: 探索性测试
37
-
38
- 以目标用户角色自由使用系统,关注可发现性、可理解性、响应速度、错误恢复、视觉一致性。
39
-
40
- ## 三、Playwright MCP 工具速查
41
-
42
- ### 导航与观察
43
-
44
- | 工具 | 用途 | 关键参数 |
45
- |------|------|---------|
46
- | `browser_navigate` | 打开页面 | `url` |
47
- | `browser_snapshot` | 获取页面可访问性快照 | 无 |
48
- | `browser_console_messages` | 检查控制台 | `level` |
49
- | `browser_network_requests` | 网络请求日志 | 无 |
50
-
51
- ### 交互操作
52
-
53
- | 工具 | 用途 | 关键参数 |
54
- |------|------|---------|
55
- | `browser_click` | 点击元素 | `ref`, `element` |
56
- | `browser_type` | 逐字符输入 | `ref`, `text`, `submit` |
57
- | `browser_fill_form` | 批量填写表单 | `fields[]` |
58
- | `browser_select_option` | 选择下拉项 | `ref`, `values[]` |
59
- | `browser_press_key` | 按键 | `key` |
60
- | `browser_file_upload` | 上传文件 | `paths[]` |
61
- | `browser_handle_dialog` | 处理弹窗 | `accept` |
62
-
63
- ### 等待与控制
64
-
65
- | 工具 | 用途 | 关键参数 |
66
- |------|------|---------|
67
- | `browser_wait_for` | 等待元素/文本出现 | `text`, `ref`, `timeout` |
68
- | `browser_evaluate` | 执行 JS | `function` |
69
- | `browser_close` | 关闭页面 | 无 |
70
-
71
- ## 四、Smart Snapshot 策略(节省 40-60% Token)
72
-
73
- 每次 `browser_snapshot` 消耗 3,000-8,000 tokens。分级控制:
74
-
75
- | 级别 | 何时 snapshot | 示例 |
76
- |------|-------------|------|
77
- | **必须** | 首次加载页面 | navigate 后确认页面正确 |
78
- | **必须** | 关键断言点 | 验证操作结果出现 |
79
- | **必须** | 操作失败时 | 调查页面状态 |
80
- | **可选** | 中间操作后 | fill 后确认文字填入 |
81
- | **跳过** | 连续同类操作间 | 连续选择多个下拉框 |
82
- | **跳过** | 等待循环中 | 改用 `browser_wait_for` |
83
-
84
- **高效模式**:navigate → snapshot → fill → select → click → wait_for → snapshot(**2 次**)
85
- **低效模式**:navigate → snapshot → fill → snapshot → select → snapshot → click → snapshot(**4 次**)
86
-
87
- ## 五、等待策略
88
-
89
- ### 按操作类型选择
90
-
91
- | 操作类型 | 策略 | Token 消耗 |
92
- |---------|------|-----------|
93
- | 瞬时(导航、点击) | 直接操作,不等待 | 极低 |
94
- | 短等(表单提交) | `browser_wait_for text="成功" timeout=10000` | ~5K |
95
- | 长等(AI 生成、文件处理) | `browser_wait_for` + 合理 timeout | ~5K |
96
- | 超长等(批量处理) | Shell 端 API 检查 + 最终 1 次 snapshot | ~5.5K |
97
-
98
- ### SSE / 流式生成任务的等待策略
99
-
100
- 当操作涉及 AI 生成、文件转换、SSE 流式处理等需要较长时间的场景时,优先使用 `browser_wait_for` 而非轮询 snapshot:
101
-
102
- | 步骤 | 工具 | 说明 |
103
- |------|------|------|
104
- | 触发操作 | `browser_click` | 点击"生成"/"提交"按钮 |
105
- | 等待完成 | `browser_wait_for` | 等待完成标志文本出现,设置合理 timeout |
106
- | 验证结果 | `browser_snapshot` | 确认结果/下载链接出现 |
107
-
108
- **`browser_wait_for` 参数**:
109
- - `text`:完成标志文本(如"下载"、"完成"、"预览")
110
- - `timeout`:根据操作实际预估耗时设置(如表单提交 10s、AI 生成 60-180s、批量处理更长)
111
- - 相比轮询 snapshot,Token 消耗从 ~60K+ 降至 ~5K
112
-
113
- ### 常见反模式
114
-
115
- - 每步 snapshot → 合并 2-3 操作后再 snapshot
116
- - 轮询 snapshot 等待长操作 → 改用 `browser_wait_for`
117
- - MCP 做 20+ 步 → 长流程用 Playwright CLI
118
- - 反复 navigate 同一页面 → 在同一页面完成
119
- - 失败后盲目重试 → 先 `browser_console_messages` 分析
120
-
121
- ### 优先级映射
122
-
123
- P0(核心流程)必测 → P1(错误处理)必测 → P2(次要功能)按需 → P3 低优先
124
-
125
- 预算 >200K: P0+P1+P2 | 100-200K: P0+P1 | <100K: 仅 P0
126
-
127
- ## 六、凭证管理
128
-
129
- `.mcp.json` 由 `claude-coder auth` 自动生成,根据配置模式使用不同参数:
130
- - persistent(默认):`--user-data-dir=<path>`,登录态自动保持
131
- - isolated:`--isolated --storage-state=<path>`,每次从快照加载
132
- - extension:`--extension`,连接真实浏览器
133
-
134
- 凭证失效时:不修改 auth 文件,报告中标注,提示用户运行 `claude-coder auth [URL]`。
135
-
136
- ## 七、失败处理
137
-
138
- **阻断性**(立即停止): 服务未启动、500 错误、凭证缺失、页面空白
139
-
140
- **非阻断性**(记录继续): 样式异常、console warning、慢响应
141
-
142
- 失败时: snapshot(记录状态)→ console_messages(错误日志)→ 停止该场景 → 继续下一个
143
-
144
- ## 八、tasks.json 测试步骤模板
145
-
146
- 推荐使用结构化标签前缀(`【规则】【环境】【P0】` 等)组织步骤。研究表明,结构化标记可提升 LLM 的指令遵循度和步骤完成率,帮助 Agent 理解每步的目的和优先级。
147
-
148
- ### 基础模板
149
-
150
- ```json
151
- {
152
- "steps": [
153
- "【规则】阅读 .claude-coder/test_rule.md",
154
- "【环境】curl [后端]/health && curl [前端](失败则停止)",
155
- "【P0】Playwright MCP 执行核心 Happy Path(Smart Snapshot)",
156
- "【P1】错误场景:空输入、无效凭证",
157
- "【记录】结果写入 record/",
158
- "【预算】消耗 >80% 时跳过低优先级,记录 session_result.json"
159
- ]
160
- }
161
- ```
162
-
163
- ### 含长等待操作的模板(SSE / AI 生成 / 文件转换)
164
-
165
- ```json
166
- {
167
- "steps": [
168
- "【规则】阅读 .claude-coder/test_rule.md",
169
- "【环境】curl http://localhost:8000/health 确认后端服务正常",
170
- "【P0】Playwright MCP 访问目标页面,snapshot 确认页面加载",
171
- "【P0】填写表单数据,snapshot 确认输入成功",
172
- "【P0】点击提交,使用 browser_wait_for 等待结果出现(根据操作耗时设置合理 timeout)",
173
- "【P0】验证结果正确(下载链接有效 / 预览内容匹配)",
174
- "【记录】测试结果写入 record/(使用 test_rule.md 报告模板)",
175
- "【预算】Smart Snapshot 策略:导航→填写→点击→等待→验证,共 3-4 次 snapshot"
176
- ]
177
- }
178
- ```
179
-
180
- ## 九、测试报告格式
181
-
182
- ```markdown
183
- # E2E 测试报告
184
- **日期**: YYYY-MM-DD | **环境**: 前端 [URL] / 后端 [URL]
185
-
186
- | 场景 | 结果 | 备注 |
187
- |------|------|------|
188
- | [名称] | PASS/FAIL | [简要] |
189
-
190
- ## 发现的问题
191
- ### [P0/P1/P2] 标题
192
- - **复现**: [Playwright 动作序列]
193
- - **预期/实际**: ...
194
- - **根因**: [代码分析]
1
+ # Playwright 自动化测试通用规则 v0.0.1
2
+
3
+ ## 一、四条铁律
4
+
5
+ 1. **真实操作** — 必须通过 Playwright MCP 产生浏览器交互,代码审查不等于测试
6
+ 2. **测试业务** — 断言基于用户可见结果(页面文本、按钮状态),非内部变量
7
+ 3. **独立可重复** — 每个场景不依赖其他测试结果
8
+ 4. **先调查再修复** — 失败先分析根因,不要修改测试让它通过
9
+
10
+ ## 二、三步测试方法论
11
+
12
+ 任何 Web 项目的端到端测试遵循三步走:
13
+
14
+ ### Step 1: 功能验证(Happy Path)
15
+
16
+ 核心用户流程能走通,每个步骤对应一个 Playwright MCP 工具调用:
17
+
18
+ ```
19
+ 1. browser_navigate → [页面URL]
20
+ 2. browser_snapshot → 确认页面加载,定位关键元素 ref
21
+ 3. browser_fill_form / browser_type → 输入测试数据
22
+ 4. browser_click → 提交操作
23
+ 5. browser_wait_for → 等待结果出现
24
+ 6. browser_snapshot → 验证预期结果
25
+ ```
26
+
27
+ ### Step 2: 错误场景(Unhappy Path)
28
+
29
+ | 类别 | 典型场景 |
30
+ |------|---------|
31
+ | 输入验证 | 空提交、超长输入、特殊字符、非法格式 |
32
+ | 认证权限 | 未登录访问、过期凭证、无效 API Key |
33
+ | 网络服务 | 后端宕机、慢响应、API 500 |
34
+ | 状态边界 | 空数据、大数据量、重复提交、浏览器后退 |
35
+
36
+ ### Step 3: 探索性测试
37
+
38
+ 以目标用户角色自由使用系统,关注可发现性、可理解性、响应速度、错误恢复、视觉一致性。
39
+
40
+ ## 三、Playwright MCP 工具速查
41
+
42
+ ### 导航与观察
43
+
44
+ | 工具 | 用途 | 关键参数 |
45
+ |------|------|---------|
46
+ | `browser_navigate` | 打开页面 | `url` |
47
+ | `browser_snapshot` | 获取页面可访问性快照 | 无 |
48
+ | `browser_console_messages` | 检查控制台 | `level` |
49
+ | `browser_network_requests` | 网络请求日志 | 无 |
50
+
51
+ ### 交互操作
52
+
53
+ | 工具 | 用途 | 关键参数 |
54
+ |------|------|---------|
55
+ | `browser_click` | 点击元素 | `ref`, `element` |
56
+ | `browser_type` | 逐字符输入 | `ref`, `text`, `submit` |
57
+ | `browser_fill_form` | 批量填写表单 | `fields[]` |
58
+ | `browser_select_option` | 选择下拉项 | `ref`, `values[]` |
59
+ | `browser_press_key` | 按键 | `key` |
60
+ | `browser_file_upload` | 上传文件 | `paths[]` |
61
+ | `browser_handle_dialog` | 处理弹窗 | `accept` |
62
+
63
+ ### 等待与控制
64
+
65
+ | 工具 | 用途 | 关键参数 |
66
+ |------|------|---------|
67
+ | `browser_wait_for` | 等待元素/文本出现 | `text`, `ref`, `timeout` |
68
+ | `browser_evaluate` | 执行 JS | `function` |
69
+ | `browser_close` | 关闭页面 | 无 |
70
+
71
+ ## 四、Smart Snapshot 策略(节省 40-60% Token)
72
+
73
+ 每次 `browser_snapshot` 消耗 3,000-8,000 tokens。分级控制:
74
+
75
+ | 级别 | 何时 snapshot | 示例 |
76
+ |------|-------------|------|
77
+ | **必须** | 首次加载页面 | navigate 后确认页面正确 |
78
+ | **必须** | 关键断言点 | 验证操作结果出现 |
79
+ | **必须** | 操作失败时 | 调查页面状态 |
80
+ | **可选** | 中间操作后 | fill 后确认文字填入 |
81
+ | **跳过** | 连续同类操作间 | 连续选择多个下拉框 |
82
+ | **跳过** | 等待循环中 | 改用 `browser_wait_for` |
83
+
84
+ **高效模式**:navigate → snapshot → fill → select → click → wait_for → snapshot(**2 次**)
85
+ **低效模式**:navigate → snapshot → fill → snapshot → select → snapshot → click → snapshot(**4 次**)
86
+
87
+ ## 五、等待策略
88
+
89
+ ### 按操作类型选择
90
+
91
+ | 操作类型 | 策略 | Token 消耗 |
92
+ |---------|------|-----------|
93
+ | 瞬时(导航、点击) | 直接操作,不等待 | 极低 |
94
+ | 短等(表单提交) | `browser_wait_for text="成功" timeout=10000` | ~5K |
95
+ | 长等(AI 生成、文件处理) | `browser_wait_for` + 合理 timeout | ~5K |
96
+ | 超长等(批量处理) | Shell 端 API 检查 + 最终 1 次 snapshot | ~5.5K |
97
+
98
+ ### SSE / 流式生成任务的等待策略
99
+
100
+ 当操作涉及 AI 生成、文件转换、SSE 流式处理等需要较长时间的场景时,优先使用 `browser_wait_for` 而非轮询 snapshot:
101
+
102
+ | 步骤 | 工具 | 说明 |
103
+ |------|------|------|
104
+ | 触发操作 | `browser_click` | 点击"生成"/"提交"按钮 |
105
+ | 等待完成 | `browser_wait_for` | 等待完成标志文本出现,设置合理 timeout |
106
+ | 验证结果 | `browser_snapshot` | 确认结果/下载链接出现 |
107
+
108
+ **`browser_wait_for` 参数**:
109
+ - `text`:完成标志文本(如"下载"、"完成"、"预览")
110
+ - `timeout`:根据操作实际预估耗时设置(如表单提交 10s、AI 生成 60-180s、批量处理更长)
111
+ - 相比轮询 snapshot,Token 消耗从 ~60K+ 降至 ~5K
112
+
113
+ ### 常见反模式
114
+
115
+ - 每步 snapshot → 合并 2-3 操作后再 snapshot
116
+ - 轮询 snapshot 等待长操作 → 改用 `browser_wait_for`
117
+ - MCP 做 20+ 步 → 长流程用 Playwright CLI
118
+ - 反复 navigate 同一页面 → 在同一页面完成
119
+ - 失败后盲目重试 → 先 `browser_console_messages` 分析
120
+
121
+ ### 优先级映射
122
+
123
+ P0(核心流程)必测 → P1(错误处理)必测 → P2(次要功能)按需 → P3 低优先
124
+
125
+ 预算 >200K: P0+P1+P2 | 100-200K: P0+P1 | <100K: 仅 P0
126
+
127
+ ## 六、凭证管理
128
+
129
+ `.mcp.json` 由 `claude-coder auth` 自动生成,根据配置模式使用不同参数:
130
+ - persistent(默认):`--user-data-dir=<path>`,登录态自动保持
131
+ - isolated:`--isolated --storage-state=<path>`,每次从快照加载
132
+ - extension:`--extension`,连接真实浏览器
133
+
134
+ 凭证失效时:不修改 auth 文件,报告中标注,提示用户运行 `claude-coder auth [URL]`。
135
+
136
+ ## 七、失败处理
137
+
138
+ **阻断性**(立即停止): 服务未启动、500 错误、凭证缺失、页面空白
139
+
140
+ **非阻断性**(记录继续): 样式异常、console warning、慢响应
141
+
142
+ 失败时: snapshot(记录状态)→ console_messages(错误日志)→ 停止该场景 → 继续下一个
143
+
144
+ ## 八、tasks.json 测试步骤模板
145
+
146
+ 推荐使用结构化标签前缀(`【规则】【环境】【P0】` 等)组织步骤。研究表明,结构化标记可提升 LLM 的指令遵循度和步骤完成率,帮助 Agent 理解每步的目的和优先级。
147
+
148
+ ### 基础模板
149
+
150
+ ```json
151
+ {
152
+ "steps": [
153
+ "【规则】阅读 .claude-coder/test_rule.md",
154
+ "【环境】curl [后端]/health && curl [前端](失败则停止)",
155
+ "【P0】Playwright MCP 执行核心 Happy Path(Smart Snapshot)",
156
+ "【P1】错误场景:空输入、无效凭证",
157
+ "【记录】结果写入 record/",
158
+ "【预算】消耗 >80% 时跳过低优先级,记录 session_result.json"
159
+ ]
160
+ }
161
+ ```
162
+
163
+ ### 含长等待操作的模板(SSE / AI 生成 / 文件转换)
164
+
165
+ ```json
166
+ {
167
+ "steps": [
168
+ "【规则】阅读 .claude-coder/test_rule.md",
169
+ "【环境】curl http://localhost:8000/health 确认后端服务正常",
170
+ "【P0】Playwright MCP 访问目标页面,snapshot 确认页面加载",
171
+ "【P0】填写表单数据,snapshot 确认输入成功",
172
+ "【P0】点击提交,使用 browser_wait_for 等待结果出现(根据操作耗时设置合理 timeout)",
173
+ "【P0】验证结果正确(下载链接有效 / 预览内容匹配)",
174
+ "【记录】测试结果写入 record/(使用 test_rule.md 报告模板)",
175
+ "【预算】Smart Snapshot 策略:导航→填写→点击→等待→验证,共 3-4 次 snapshot"
176
+ ]
177
+ }
178
+ ```
179
+
180
+ ## 九、测试报告格式
181
+
182
+ ```markdown
183
+ # E2E 测试报告
184
+ **日期**: YYYY-MM-DD | **环境**: 前端 [URL] / 后端 [URL]
185
+
186
+ | 场景 | 结果 | 备注 |
187
+ |------|------|------|
188
+ | [名称] | PASS/FAIL | [简要] |
189
+
190
+ ## 发现的问题
191
+ ### [P0/P1/P2] 标题
192
+ - **复现**: [Playwright 动作序列]
193
+ - **预期/实际**: ...
194
+ - **根因**: [代码分析]
195
195
  ```
@@ -1,24 +0,0 @@
1
- 你是资深需求分析师,擅长将模糊需求分解为可执行的原子任务。
2
- 这是任务追加 session,不是编码 session。你只分解任务,不实现代码。
3
-
4
- {{profileContext}}
5
- {{taskContext}}
6
- {{recentExamples}}
7
- 项目绝对路径: {{projectRoot}}
8
-
9
- 执行步骤(按顺序,不可跳过):
10
- 1. 读取 .claude-coder/tasks.json 和 .claude-coder/project_profile.json,全面了解项目现状
11
- 2. 分析用户指令:识别核心功能点,判断是单任务还是需要拆分为多任务
12
- 3. 检查重复:对比已有任务,避免功能重叠
13
- 4. 确定依赖:新任务的 depends_on 引用已有或新增任务的 id,形成 DAG
14
- 5. 分解任务:按下方任务分解指南的规则,每个任务独立可测试
15
- 6. 追加到 tasks.json,id 和 priority 从已有最大值递增,status: pending
16
- 7. git add -A && git commit -m "chore: add new tasks"
17
- 8. 写入 session_result.json(格式:{ "session_result": "success", "status_before": "N/A", "status_after": "N/A", "notes": "追加了 N 个任务:简述" })
18
-
19
- {{addGuide}}
20
-
21
- {{testRuleHint}}
22
- 不修改已有任务,不实现代码。
23
-
24
- 用户指令:{{instruction}}
package/src/auth.js DELETED
@@ -1,245 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const os = require('os');
5
- const path = require('path');
6
- const { execSync } = require('child_process');
7
- const { paths, loadConfig, log, getProjectRoot, ensureLoopDir } = require('./config');
8
-
9
- function updateGitignore(entry) {
10
- const gitignorePath = path.join(getProjectRoot(), '.gitignore');
11
- let content = '';
12
- if (fs.existsSync(gitignorePath)) {
13
- content = fs.readFileSync(gitignorePath, 'utf8');
14
- }
15
- if (content.includes(entry)) return;
16
-
17
- const suffix = content.endsWith('\n') || content === '' ? '' : '\n';
18
- fs.appendFileSync(gitignorePath, `${suffix}${entry}\n`, 'utf8');
19
- log('ok', `.gitignore 已添加: ${entry}`);
20
- }
21
-
22
- function updateMcpConfig(p, mode) {
23
- let mcpConfig = {};
24
- if (fs.existsSync(p.mcpConfig)) {
25
- try { mcpConfig = JSON.parse(fs.readFileSync(p.mcpConfig, 'utf8')); } catch {}
26
- }
27
-
28
- if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
29
-
30
- const args = ['@playwright/mcp@latest'];
31
-
32
- switch (mode) {
33
- case 'persistent': {
34
- const relProfile = path.relative(getProjectRoot(), p.browserProfile).split(path.sep).join('/');
35
- args.push(`--user-data-dir=${relProfile}`);
36
- break;
37
- }
38
- case 'isolated': {
39
- const relAuth = path.relative(getProjectRoot(), p.playwrightAuth).split(path.sep).join('/');
40
- args.push('--isolated', `--storage-state=${relAuth}`);
41
- break;
42
- }
43
- case 'extension':
44
- args.push('--extension');
45
- break;
46
- }
47
-
48
- mcpConfig.mcpServers.playwright = { command: 'npx', args };
49
- fs.writeFileSync(p.mcpConfig, JSON.stringify(mcpConfig, null, 2) + '\n', 'utf8');
50
- log('ok', `.mcp.json 已配置 Playwright MCP (${mode} 模式)`);
51
- }
52
-
53
- function enableMcpPlaywrightEnv() {
54
- const p = paths();
55
- if (!fs.existsSync(p.envFile)) return;
56
-
57
- let content = fs.readFileSync(p.envFile, 'utf8');
58
- if (/^MCP_PLAYWRIGHT=/m.test(content)) {
59
- content = content.replace(/^MCP_PLAYWRIGHT=.*/m, 'MCP_PLAYWRIGHT=true');
60
- } else {
61
- const suffix = content.endsWith('\n') ? '' : '\n';
62
- content += `${suffix}MCP_PLAYWRIGHT=true\n`;
63
- }
64
- fs.writeFileSync(p.envFile, content, 'utf8');
65
- log('ok', '.claude-coder/.env 已设置 MCP_PLAYWRIGHT=true');
66
- }
67
-
68
- // ── persistent 模式:启动持久化浏览器让用户登录 ──
69
-
70
- async function authPersistent(url, p) {
71
- const profileDir = p.browserProfile;
72
- if (!fs.existsSync(profileDir)) fs.mkdirSync(profileDir, { recursive: true });
73
-
74
- const lockFile = path.join(profileDir, 'SingletonLock');
75
- if (fs.existsSync(lockFile)) {
76
- fs.unlinkSync(lockFile);
77
- log('warn', '已清理残留的 SingletonLock(上次浏览器未正常关闭)');
78
- }
79
-
80
- console.log('操作步骤:');
81
- console.log(' 1. 浏览器将自动打开,请手动完成登录');
82
- console.log(' 2. 登录成功后关闭浏览器窗口');
83
- console.log(' 3. 登录状态将保存在持久化配置中');
84
- console.log(' 4. MCP 后续会话自动复用此登录状态');
85
- console.log('');
86
-
87
- const scriptContent = [
88
- `let chromium;`,
89
- `try { chromium = require('playwright').chromium; } catch {`,
90
- ` try { chromium = require('@playwright/test').chromium; } catch {`,
91
- ` console.error('错误: 未找到 playwright 模块');`,
92
- ` console.error('请安装: npx playwright install chromium');`,
93
- ` process.exit(1);`,
94
- ` }`,
95
- `}`,
96
- `(async () => {`,
97
- ` const ctx = await chromium.launchPersistentContext(${JSON.stringify(profileDir)}, { headless: false });`,
98
- ` const page = ctx.pages()[0] || await ctx.newPage();`,
99
- ` try { await page.goto(${JSON.stringify(url)}); } catch {}`,
100
- ` console.log('请在浏览器中完成登录后关闭窗口...');`,
101
- ` await new Promise(r => {`,
102
- ` ctx.on('close', r);`,
103
- ` const t = setInterval(() => { try { if (!ctx.pages().length) { clearInterval(t); r(); } } catch { clearInterval(t); r(); } }, 2000);`,
104
- ` });`,
105
- ` try { await ctx.close(); } catch {}`,
106
- `})().then(() => process.exit(0)).catch(() => process.exit(0));`,
107
- ].join('\n');
108
-
109
- const tmpScript = path.join(os.tmpdir(), `pw-auth-${Date.now()}.js`);
110
- fs.writeFileSync(tmpScript, scriptContent);
111
-
112
- const helperModules = path.join(__dirname, '..', 'node_modules');
113
- const existingNodePath = process.env.NODE_PATH || '';
114
- const nodePath = existingNodePath ? `${helperModules}:${existingNodePath}` : helperModules;
115
-
116
- let scriptOk = false;
117
- try {
118
- execSync(`node "${tmpScript}"`, {
119
- stdio: 'inherit',
120
- cwd: getProjectRoot(),
121
- env: { ...process.env, NODE_PATH: nodePath },
122
- });
123
- scriptOk = true;
124
- } catch {
125
- // 浏览器关闭时可能返回非零退出码,只要 profile 目录有内容就认为成功
126
- const profileFiles = fs.readdirSync(profileDir);
127
- scriptOk = profileFiles.length > 2;
128
- if (!scriptOk) {
129
- log('error', 'Playwright 启动失败,且未检测到有效的浏览器配置');
130
- log('info', '请确保已安装 Chromium: npx playwright install chromium');
131
- try { fs.unlinkSync(tmpScript); } catch {}
132
- return;
133
- }
134
- log('warn', '浏览器退出码非零,但已检测到有效配置,继续...');
135
- }
136
-
137
- try { fs.unlinkSync(tmpScript); } catch {}
138
-
139
- log('ok', '登录状态已保存到持久化配置');
140
- updateMcpConfig(p, 'persistent');
141
- updateGitignore('.claude-coder/.runtime/browser-profile');
142
- enableMcpPlaywrightEnv();
143
-
144
- console.log('');
145
- log('ok', '配置完成!');
146
- const relProfile = path.relative(getProjectRoot(), profileDir);
147
- log('info', `MCP 使用 persistent 模式 (user-data-dir: ${relProfile})`);
148
- log('info', '如需更新登录状态,重新运行 claude-coder auth');
149
- }
150
-
151
- // ── isolated 模式:使用 codegen 录制 storage-state ──
152
-
153
- async function authIsolated(url, p) {
154
- console.log('操作步骤:');
155
- console.log(' 1. 浏览器将自动打开,请手动完成登录');
156
- console.log(' 2. 登录成功后关闭浏览器窗口');
157
- console.log(' 3. 登录状态(cookies + localStorage)将保存到 playwright-auth.json');
158
- console.log(' 4. MCP 每次会话自动从此文件加载初始状态');
159
- console.log('');
160
-
161
- try {
162
- execSync(
163
- `npx playwright codegen --save-storage="${p.playwrightAuth}" "${url}"`,
164
- { stdio: 'inherit', cwd: getProjectRoot() }
165
- );
166
- } catch (err) {
167
- if (!fs.existsSync(p.playwrightAuth)) {
168
- log('error', `Playwright 登录状态导出失败: ${err.message}`);
169
- log('info', '请确保已安装: npx playwright install chromium');
170
- return;
171
- }
172
- }
173
-
174
- if (!fs.existsSync(p.playwrightAuth)) {
175
- log('error', '未检测到导出的登录状态文件');
176
- return;
177
- }
178
-
179
- log('ok', '登录状态已保存到 playwright-auth.json');
180
- updateMcpConfig(p, 'isolated');
181
- updateGitignore('.claude-coder/playwright-auth.json');
182
- enableMcpPlaywrightEnv();
183
-
184
- console.log('');
185
- log('ok', '配置完成!');
186
- log('info', 'MCP 使用 isolated 模式 (storage-state)');
187
- log('info', 'cookies 和 localStorage 每次会话自动从 playwright-auth.json 加载');
188
- log('info', '如需更新登录状态,重新运行 claude-coder auth');
189
- }
190
-
191
- // ── extension 模式:连接真实浏览器 ──
192
-
193
- function authExtension(p) {
194
- console.log('Extension 模式说明:');
195
- console.log('');
196
- console.log(' 此模式通过 Chrome 扩展连接到您正在运行的浏览器。');
197
- console.log(' MCP 将直接使用浏览器中已有的登录态和扩展。');
198
- console.log('');
199
- console.log(' 前置条件:');
200
- console.log(' 1. 安装 "Playwright MCP Bridge" Chrome/Edge 扩展');
201
- console.log(' https://chromewebstore.google.com/detail/playwright-mcp-bridge/mmlmfjhmonkocbjadbfplnigmagldckm');
202
- console.log(' 2. 确保浏览器已启动且扩展已启用');
203
- console.log(' 3. 无需额外认证操作,您的浏览器登录态将自动可用');
204
- console.log('');
205
-
206
- updateMcpConfig(p, 'extension');
207
- enableMcpPlaywrightEnv();
208
-
209
- console.log('');
210
- log('ok', '配置完成!');
211
- log('info', 'MCP 使用 extension 模式(连接真实浏览器)');
212
- log('info', '确保 Chrome/Edge 已运行且 Playwright MCP Bridge 扩展已启用');
213
- }
214
-
215
- // ── 主入口 ──
216
-
217
- async function auth(url) {
218
- ensureLoopDir();
219
- const config = loadConfig();
220
- const p = paths();
221
- const mode = config.playwrightMode;
222
- const targetUrl = url || 'http://localhost:3000';
223
-
224
- log('info', `Playwright 模式: ${mode}`);
225
- log('info', `目标 URL: ${targetUrl}`);
226
- console.log('');
227
-
228
- switch (mode) {
229
- case 'persistent':
230
- await authPersistent(targetUrl, p);
231
- break;
232
- case 'isolated':
233
- await authIsolated(targetUrl, p);
234
- break;
235
- case 'extension':
236
- authExtension(p);
237
- break;
238
- default:
239
- log('error', `未知的 Playwright 模式: ${mode}`);
240
- log('info', '请运行 claude-coder setup 重新配置');
241
- return;
242
- }
243
- }
244
-
245
- module.exports = { auth, updateMcpConfig };