claude-coder 1.8.4 → 1.9.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
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### 亮点
8
8
 
9
- - **Harness 生命周期管理**:统一的 Harness 类封装环境准备、任务调度、校验、回滚、推送全生命周期,含 AI 驱动的 JSON 自愈修复
9
+ - **Session 生命周期管理**:Session 类封装 SDK 管理、query 执行、hooks、indicator 全生命周期,runner 编排循环含 AI 驱动的 JSON 自愈修复
10
10
  - **Hook 提示注入**:通过 JSON 配置在工具调用时向模型注入上下文引导,零代码修改即可扩展规则([机制详解](design/hook-mechanism.md))
11
11
  - **长时间自循环编码**:多 session 编排 + 倒计时活跃度监控 + git 回滚重试,Agent 可持续编码数小时不中断([守护机制](design/session-guard.md))
12
12
  - **配置驱动**:支持 Claude 官方、Coding Plan 多模型路由、DeepSeek 等任意 Anthropic 兼容 API
@@ -41,6 +41,7 @@ claude-coder run "实现用户注册和登录功能"
41
41
  |------|------|
42
42
  | `claude-coder setup` | 交互式配置(模型、MCP、安全限制、自动审查) |
43
43
  | `claude-coder init` | 初始化项目环境(扫描技术栈、生成 profile) |
44
+ | `claude-coder init --deploy-templates` | 部署模板和食谱到项目目录(可自定义) |
44
45
  | `claude-coder plan "需求"` | 生成计划方案 |
45
46
  | `claude-coder plan -r [file]` | 从需求文件生成计划 |
46
47
  | `claude-coder plan --planOnly` | 仅生成计划文档,不分解任务 |
@@ -52,7 +53,7 @@ claude-coder run "实现用户注册和登录功能"
52
53
  | `claude-coder run --max 1` | 单次执行 |
53
54
  | `claude-coder run --dry-run` | 预览模式(查看任务队列) |
54
55
  | `claude-coder simplify [focus]` | 代码审查和简化 |
55
- | `claude-coder auth [url]` | 导出 Playwright 登录状态 |
56
+ | `claude-coder auth [url]` | 配置浏览器测试工具 / 导出登录状态 |
56
57
  | `claude-coder status` | 查看进度和成本 |
57
58
 
58
59
  **选项**:`--max N` 限制 session 数(默认 50),`--pause N` 每 N 个 session 暂停确认,`--model M` 指定模型。
@@ -68,26 +69,26 @@ claude-coder run "实现用户注册和登录功能"
68
69
  │ 3 步流程 │
69
70
  └──────┬──────┘
70
71
 
71
- Harness 校验
72
+ runner 校验
72
73
  (含 AI 自愈)
73
74
 
74
75
  通过 → simplify? → push → 下一个任务
75
76
  失败 → git 回滚 + 重试
76
77
  ```
77
78
 
78
- 每个 session 内,Agent 自主执行 3 步:**实现**(任务上下文由 harness 注入,编码实现) → **验证**(按 category 选最轻量测试) → **收尾**(git commit + 写 session_result.json)。
79
+ 每个 session 内,Agent 自主执行 3 步:**实现**(任务上下文由 prompt 注入,编码实现) → **验证**(按 category 选最轻量测试) → **收尾**(git commit + 写 session_result.json)。
79
80
 
80
- Harness 在 session 结束后自动校验 `session_result.json` + git 进度。校验失败时 AI 自动尝试修复损坏的 JSON 文件(`repair.js`),仍失败则回滚代码并重试。
81
+ Runner 在 session 结束后自动校验 `session_result.json` + git 进度。校验失败时 AI 自动尝试修复损坏的 JSON 文件(`repair.js`),仍失败则回滚代码并重试。
81
82
 
82
83
  ## 机制文档
83
84
 
84
85
  | 文档 | 说明 |
85
86
  |------|------|
86
- | [技术架构](design/ARCHITECTURE.md) | 核心设计规则、Harness 类职责、模块关系、Prompt 注入架构 |
87
+ | [技术架构](design/ARCHITECTURE.md) | 核心设计规则、Session 类职责、模块关系、Prompt 注入架构 |
87
88
  | [Hook 注入机制](design/hook-mechanism.md) | SDK Hook 调研、GuidanceInjector 三级匹配、配置格式、副作用评估 |
88
89
  | [Session 守护机制](design/session-guard.md) | 中断策略、倒计时活跃度检测、工具运行状态追踪、防刷屏 |
89
90
  | [Go 指令流程](design/go-flow.md) | AI 驱动的需求组装、食谱系统、与 plan 衔接 |
90
- | [测试凭证方案](docs/PLAYWRIGHT_CREDENTIALS.md) | Playwright 登录态导出、API Key 持久化 |
91
+ | [浏览器测试工具](docs/PLAYWRIGHT_CREDENTIALS.md) | Playwright MCP / Chrome DevTools MCP 对比、安装、凭证管理 |
91
92
  | [SDK 使用指南](docs/CLAUDE_AGENT_SDK_GUIDE.md) | Claude Agent SDK 接口参考 |
92
93
 
93
94
  ## 使用场景
@@ -96,11 +97,57 @@ Harness 在 session 结束后自动校验 `session_result.json` + git 进度。
96
97
 
97
98
  **已有项目**:`claude-coder run "新增头像上传功能"` — 先扫描现有代码和技术栈,再增量开发。
98
99
 
99
- **需求文档驱动**:在项目根目录创建 `requirements.md`,运行 `claude-coder run`。需求变更后 `claude-coder add -r` 同步新任务。
100
+ **需求文档驱动**:在项目根目录创建 `requirements.md`,运行 `claude-coder plan -r requirements.md` 分解任务后 `claude-coder run` 执行。
100
101
 
101
102
  **AI 驱动需求组装**:`claude-coder go "用户管理页面"` — AI 扫描内置食谱库,自动组装完整需求方案,一键进入 plan 分解任务。支持对话模式 (`go`) 逐步引导非技术人员。
102
103
 
103
- **自动测试 + 凭证持久化**:`claude-coder auth http://localhost:3000` — 导出浏览器登录态,Agent 测试时自动使用。详见 [测试凭证方案](docs/PLAYWRIGHT_CREDENTIALS.md)。
104
+ **自动测试 + 凭证持久化**:`claude-coder auth http://localhost:3000` — 导出浏览器登录态,Agent 测试时自动使用。详见 [浏览器测试工具指南](docs/PLAYWRIGHT_CREDENTIALS.md)。
105
+
106
+ ## 浏览器测试工具
107
+
108
+ 支持两种 MCP 浏览器测试工具,通过 `WEB_TEST_TOOL` 环境变量切换:
109
+
110
+ | 维度 | Playwright MCP | Chrome DevTools MCP |
111
+ |------|---------------|---------------------|
112
+ | **维护方** | 微软 | Google |
113
+ | **核心优势** | 25+ 自动化工具,多实例并行 | 连接已打开 Chrome,调试能力强 |
114
+ | **多实例** | 支持 | 不支持(单实例,多开请用 Playwright) |
115
+ | **安装依赖** | `npx playwright install chromium` | Node.js v20.19+ / Chrome 144+ |
116
+ | **凭证方案** | persistent 模式复用登录态 | 直接复用已打开 Chrome 的登录态 |
117
+ | **适合场景** | CI/CD、多并行测试、需要 Chromium 隔离 | 本地开发、调试、利用已有 Chrome 环境 |
118
+
119
+ ### 安装步骤
120
+
121
+ ```bash
122
+ # Playwright MCP(推荐)
123
+ claude-coder setup # → 选择「Playwright MCP」→ 选择模式
124
+ npx playwright install chromium
125
+ claude-coder auth http://your-app.com # 导出登录态
126
+
127
+ # Chrome DevTools MCP(需 Node.js v20.19+)
128
+ claude-coder setup # → 选择「Chrome DevTools MCP」
129
+ # 打开 Chrome → chrome://inspect/#remote-debugging → 启用远程调试
130
+ claude-coder auth # 配置 .mcp.json
131
+ ```
132
+
133
+ ### 常见问题
134
+
135
+ **Q: Playwright 和 Chrome DevTools 该选哪个?**
136
+ A: 如果你需要多实例并行测试或 CI/CD 集成,选 Playwright MCP。如果你只需要本地调试、想复用已打开 Chrome 的登录态和扩展,选 Chrome DevTools MCP。
137
+
138
+ **Q: Chrome DevTools MCP 报 `chrome-devtools-mcp` 安装失败?**
139
+ A: 确保 Node.js ≥ v20.19。nvm 用户执行 `nvm alias default 22 && nvm use 22`,然后重新安装 `npm install -g @anthropic-ai/claude-code`。
140
+
141
+ **Q: Playwright 浏览器启动后白屏或超时?**
142
+ A: 运行 `npx playwright install chromium` 确保浏览器已安装。persistent 模式下检查 `.claude-coder/.runtime/browser-profile/` 目录是否存在。
143
+
144
+ **Q: 切换工具后需要重新认证吗?**
145
+ A: 不需要。`claude-coder setup` 切换时自动更新 `.env` 和 `.mcp.json`。之前的认证数据(如 browser-profile)保留,切回时直接可用。
146
+
147
+ **Q: 两个工具可以同时启用吗?**
148
+ A: 不可以。`.mcp.json` 中同时只保留一个工具的配置,切换时自动替换。
149
+
150
+ 详见 [浏览器测试工具完整文档](docs/PLAYWRIGHT_CREDENTIALS.md)。
104
151
 
105
152
  ## 模型支持
106
153
 
@@ -142,9 +189,9 @@ your-project/
142
189
  progress.json # 会话历史 + 成本
143
190
  test.env # 测试凭证(可选)
144
191
  go/ # go 指令输出的方案文件
145
- recipes/ # 食谱库(init 时从内置模板部署)
192
+ recipes/ # 食谱库(--deploy-templates 时从内置模板部署,可选)
146
193
  .runtime/
147
- harness_state.json # Harness 状态(session 计数等)
194
+ harness_state.json # 运行状态(session 计数等)
148
195
  logs/ # 每 session 独立日志
149
196
  ```
150
197
 
@@ -154,7 +201,7 @@ your-project/
154
201
 
155
202
  **中断恢复**:直接重新运行 `claude-coder run`,从上次中断处继续。
156
203
 
157
- **长时间无响应**:模型处理复杂任务时可能出现长思考间隔(indicator 显示黄色"工具执行中"或红色"无响应"),这是正常行为。超过阈值后 harness 自动中断并重试。通过 `claude-coder setup` 的安全限制配置或 `.env` 中 `SESSION_STALL_TIMEOUT=秒数` 调整。
204
+ **长时间无响应**:模型处理复杂任务时可能出现长思考间隔(indicator 显示黄色"工具执行中"或红色"无响应"),这是正常行为。超过阈值后自动中断并重试。通过 `claude-coder setup` 的安全限制配置或 `.env` 中 `SESSION_STALL_TIMEOUT=秒数` 调整。
158
205
 
159
206
  **跳过任务**:将 `.claude-coder/tasks.json` 中该任务的 `status` 改为 `done`。
160
207
 
package/bin/cli.js CHANGED
@@ -6,7 +6,7 @@ const pkg = require('../package.json');
6
6
  const COMMANDS = {
7
7
  run: { desc: '自动编码循环', usage: 'claude-coder run [--max N] [--pause N] [--dry-run]' },
8
8
  setup: { desc: '交互式模型配置', usage: 'claude-coder setup' },
9
- init: { desc: '初始化项目环境', usage: 'claude-coder init' },
9
+ init: { desc: '初始化项目环境', usage: 'claude-coder init [--deploy-templates]' },
10
10
  plan: { desc: '生成计划方案', usage: 'claude-coder plan "需求" | plan -r requirements.md [--planOnly] [-i]' },
11
11
  simplify: { desc: '代码审查和简化', usage: 'claude-coder simplify [focus]' },
12
12
  auth: { desc: '导出 Playwright 登录状态', usage: 'claude-coder auth [url]' },
@@ -31,6 +31,7 @@ function showHelp() {
31
31
  console.log(' claude-coder run --max 1 单次执行');
32
32
  console.log(' claude-coder run --max 5 --pause 5 每 5 个 session 暂停确认');
33
33
  console.log(' claude-coder run --dry-run 预览模式');
34
+ console.log(' claude-coder init --deploy-templates 部署模板和食谱到项目目录(可自定义)');
34
35
  console.log(' claude-coder simplify 代码审查和简化');
35
36
  console.log(' claude-coder simplify "内存效率" 聚焦特定领域审查');
36
37
  console.log(' claude-coder go 对话式需求收集和方案组装');
@@ -50,6 +51,11 @@ function parseArgs(argv) {
50
51
  const positional = [];
51
52
 
52
53
  for (let i = 1; i < args.length; i++) {
54
+ // support --key=value syntax
55
+ if (args[i].startsWith('--') && args[i].includes('=')) {
56
+ const eq = args[i].indexOf('=');
57
+ args.splice(i, 1, args[i].slice(0, eq), args[i].slice(eq + 1));
58
+ }
53
59
  switch (args[i]) {
54
60
  case '--max':
55
61
  opts.max = parseInt(args[++i], 10) || 50;
@@ -87,6 +93,9 @@ function parseArgs(argv) {
87
93
  case '--interactive':
88
94
  opts.interactive = true;
89
95
  break;
96
+ case '--deploy-templates':
97
+ opts.deployTemplates = true;
98
+ break;
90
99
  case '--help':
91
100
  case '-h':
92
101
  showHelp();
@@ -103,7 +112,7 @@ function parseArgs(argv) {
103
112
  return { command, positional, opts };
104
113
  }
105
114
 
106
- async function main() {
115
+ async function cliMain() {
107
116
  const { command, positional, opts } = parseArgs(process.argv);
108
117
 
109
118
  if (!command || command === '--help' || command === '-h') {
@@ -117,56 +126,30 @@ async function main() {
117
126
  }
118
127
 
119
128
  switch (command) {
120
- case 'run': {
121
- const runner = require('../src/core/runner');
122
- await runner.run(opts);
123
- break;
124
- }
125
129
  case 'setup': {
126
130
  const setup = require('../src/commands/setup');
127
131
  await setup.setup();
128
- break;
129
- }
130
- case 'init': {
131
- const { init } = require('../src/core/init');
132
- await init();
133
- break;
134
- }
135
- case 'plan': {
136
- const { run: planRun } = require('../src/core/plan');
137
- const input = positional[0] || '';
138
- await planRun(input, opts);
139
- break;
140
- }
141
- case 'simplify': {
142
- const { simplify } = require('../src/core/simplify');
143
- await simplify(positional[0] || null, { n: opts.n });
144
- break;
132
+ return;
145
133
  }
146
134
  case 'auth': {
147
135
  const { auth } = require('../src/commands/auth');
148
136
  await auth(positional[0] || null);
149
- break;
150
- }
151
- case 'go': {
152
- const { run: goRun } = require('../src/core/go');
153
- await goRun(positional[0] || '', opts);
154
- break;
137
+ return;
155
138
  }
156
139
  case 'status': {
157
140
  const tasks = require('../src/common/tasks');
158
141
  tasks.showStatus();
159
- break;
142
+ return;
160
143
  }
161
- default:
162
- console.error(`未知命令: ${command}`);
163
- showHelp();
164
- process.exit(1);
165
144
  }
145
+
146
+ const { main } = require('../src');
147
+ await main(command, positional[0] || '', opts);
166
148
  }
167
149
 
168
- main().catch(err => {
169
- console.error(`\n错误: ${err.message}`);
150
+ cliMain().catch(err => {
151
+ const { log } = require('../src/common/config');
152
+ log('error', err.message);
170
153
  if (process.env.DEBUG) console.error(err.stack);
171
154
  process.exit(1);
172
155
  });
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "claude-coder",
3
- "version": "1.8.4",
3
+ "version": "1.9.0",
4
4
  "description": "Claude Coder — Autonomous coding agent harness powered by Claude Code SDK. Scan, plan, code, validate, git-commit in a loop.",
5
5
  "bin": {
6
6
  "claude-coder": "bin/cli.js"
7
7
  },
8
+ "types": "types/index.d.ts",
8
9
  "files": [
9
10
  "bin/",
10
11
  "src/",
12
+ "types/",
11
13
  "recipes/",
12
14
  "templates/"
13
15
  ],
@@ -41,7 +41,11 @@ function updateGitignore(entry) {
41
41
  }
42
42
  }
43
43
 
44
- function updateMcpConfig(mcpPath, mode) {
44
+ // ─────────────────────────────────────────────────────────────
45
+ // .mcp.json 配置(Playwright / Chrome DevTools 共用)
46
+ // ─────────────────────────────────────────────────────────────
47
+
48
+ function updateMcpConfig(mcpPath, tool, mode) {
45
49
  let mcpConfig = {};
46
50
  if (fs.existsSync(mcpPath)) {
47
51
  try { mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf8')); } catch {}
@@ -49,6 +53,19 @@ function updateMcpConfig(mcpPath, mode) {
49
53
 
50
54
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
51
55
 
56
+ if (tool === 'chrome-devtools') {
57
+ delete mcpConfig.mcpServers.playwright;
58
+ mcpConfig.mcpServers['chrome-devtools'] = {
59
+ command: 'npx',
60
+ args: ['-y', 'chrome-devtools-mcp@latest', '--autoConnect'],
61
+ };
62
+ fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2) + '\n', 'utf8');
63
+ log('ok', '.mcp.json 已配置 Chrome DevTools MCP (autoConnect)');
64
+ return;
65
+ }
66
+
67
+ // Playwright MCP
68
+ delete mcpConfig.mcpServers['chrome-devtools'];
52
69
  const args = ['@playwright/mcp@latest'];
53
70
  const projectRoot = assets.projectRoot;
54
71
 
@@ -75,23 +92,23 @@ function updateMcpConfig(mcpPath, mode) {
75
92
  log('ok', `.mcp.json 已配置 Playwright MCP (${mode} 模式)`);
76
93
  }
77
94
 
78
- function enableMcpPlaywrightEnv() {
95
+ function enableWebTestEnv(tool) {
79
96
  const envPath = assets.path('env');
80
97
  if (!envPath || !fs.existsSync(envPath)) return;
81
98
 
82
99
  let content = fs.readFileSync(envPath, 'utf8');
83
- if (/^MCP_PLAYWRIGHT=/m.test(content)) {
84
- content = content.replace(/^MCP_PLAYWRIGHT=.*/m, 'MCP_PLAYWRIGHT=true');
100
+ if (/^WEB_TEST_TOOL=/m.test(content)) {
101
+ content = content.replace(/^WEB_TEST_TOOL=.*/m, `WEB_TEST_TOOL=${tool}`);
85
102
  } else {
86
103
  const suffix = content.endsWith('\n') ? '' : '\n';
87
- content += `${suffix}MCP_PLAYWRIGHT=true\n`;
104
+ content += `${suffix}WEB_TEST_TOOL=${tool}\n`;
88
105
  }
89
106
  fs.writeFileSync(envPath, content, 'utf8');
90
- log('ok', '.claude-coder/.env 已设置 MCP_PLAYWRIGHT=true');
107
+ log('ok', `.claude-coder/.env 已设置 WEB_TEST_TOOL=${tool}`);
91
108
  }
92
109
 
93
110
  // ─────────────────────────────────────────────────────────────
94
- // 浏览器脚本(session cookie 自动持久化)
111
+ // 浏览器脚本(Playwright persistent 模式用)
95
112
  // ─────────────────────────────────────────────────────────────
96
113
 
97
114
  function buildBrowserScript(playwrightDir, profileDir, url) {
@@ -185,9 +202,9 @@ async function authPersistent(url) {
185
202
 
186
203
  const mcpPath = assets.path('mcpConfig');
187
204
  log('ok', '登录状态已保存到持久化配置');
188
- updateMcpConfig(mcpPath, 'persistent');
205
+ updateMcpConfig(mcpPath, 'playwright', 'persistent');
189
206
  updateGitignore('.claude-coder/.runtime/browser-profile');
190
- enableMcpPlaywrightEnv();
207
+ enableWebTestEnv('playwright');
191
208
 
192
209
  console.log('');
193
210
  log('ok', '配置完成!');
@@ -227,9 +244,9 @@ async function authIsolated(url) {
227
244
 
228
245
  const mcpPath = assets.path('mcpConfig');
229
246
  log('ok', '登录状态已保存到 playwright-auth.json');
230
- updateMcpConfig(mcpPath, 'isolated');
247
+ updateMcpConfig(mcpPath, 'playwright', 'isolated');
231
248
  updateGitignore('.claude-coder/playwright-auth.json');
232
- enableMcpPlaywrightEnv();
249
+ enableWebTestEnv('playwright');
233
250
 
234
251
  console.log('');
235
252
  log('ok', '配置完成!');
@@ -251,8 +268,8 @@ function authExtension() {
251
268
  console.log('');
252
269
 
253
270
  const mcpPath = assets.path('mcpConfig');
254
- updateMcpConfig(mcpPath, 'extension');
255
- enableMcpPlaywrightEnv();
271
+ updateMcpConfig(mcpPath, 'playwright', 'extension');
272
+ enableWebTestEnv('playwright');
256
273
 
257
274
  console.log('');
258
275
  log('ok', '配置完成!');
@@ -260,13 +277,68 @@ function authExtension() {
260
277
  log('info', '确保 Chrome/Edge 已运行且 Playwright MCP Bridge 扩展已启用');
261
278
  }
262
279
 
280
+ function authChromeDevTools() {
281
+ console.log('Chrome DevTools MCP 配置:');
282
+ console.log('');
283
+ console.log(' 此模式通过 Chrome DevTools Protocol 连接到已打开的 Chrome 浏览器。');
284
+ console.log(' 直接复用浏览器中已有的登录态、扩展和 DevTools 调试能力。');
285
+ console.log('');
286
+ console.log(' 前置条件:');
287
+ console.log(' 1. Node.js v20.19+(npx 自动下载 chrome-devtools-mcp 包)');
288
+ console.log(' 2. Chrome 144+ 版本');
289
+ console.log(' 3. 打开 chrome://inspect/#remote-debugging 启用远程调试');
290
+ console.log(' 4. 允许传入调试连接');
291
+ console.log('');
292
+ console.log(' 功能:');
293
+ console.log(' - 输入自动化: 点击、输入、表单填写');
294
+ console.log(' - 页面导航: 多页面管理、截图');
295
+ console.log(' - 性能分析: Trace 录制、Core Web Vitals、Lighthouse 审计');
296
+ console.log(' - 调试工具: Console 消息、网络请求检查、内存快照');
297
+ console.log('');
298
+ console.log(` 注意: 单实例限制,同一时间只能连接一个 Chrome 调试会话。`);
299
+ console.log(` 如需多实例并行,请配置 Playwright MCP(claude-coder setup)。`);
300
+ console.log('');
301
+
302
+ const mcpPath = assets.path('mcpConfig');
303
+ updateMcpConfig(mcpPath, 'chrome-devtools');
304
+ enableWebTestEnv('chrome-devtools');
305
+
306
+ console.log('');
307
+ log('ok', '配置完成!');
308
+ log('info', 'Chrome DevTools MCP 使用 autoConnect 模式');
309
+ log('info', '确保 Chrome 已启动且已在 chrome://inspect 中启用远程调试');
310
+ }
311
+
263
312
  async function auth(url) {
264
313
  assets.ensureDirs();
265
314
  const config = loadConfig();
266
- const mode = config.playwrightMode;
315
+ const tool = config.webTestTool;
316
+
317
+ if (!tool) {
318
+ log('error', '未配置浏览器测试工具');
319
+ log('info', '请先运行 claude-coder setup 选择 Playwright MCP 或 Chrome DevTools MCP');
320
+ return;
321
+ }
322
+
323
+ if (tool === 'chrome-devtools') {
324
+ const [major, minor] = process.versions.node.split('.').map(Number);
325
+ if (major < 20 || (major === 20 && minor < 19)) {
326
+ log('warn', `当前 Node.js 版本 v${process.versions.node},Chrome DevTools MCP 要求 v20.19+`);
327
+ log('info', 'nvm 用户请执行: nvm alias default 22 && nvm use 22');
328
+ log('info', '升级后重新运行此命令');
329
+ return;
330
+ }
331
+ log('info', '浏览器工具: Chrome DevTools MCP');
332
+ console.log('');
333
+ authChromeDevTools();
334
+ return;
335
+ }
336
+
337
+ // Playwright MCP
338
+ const mode = config.webTestMode;
267
339
  const targetUrl = normalizeUrl(url) || 'http://localhost:3000';
268
340
 
269
- log('info', `Playwright 模式: ${mode}`);
341
+ log('info', `浏览器工具: Playwright MCP (${mode} 模式)`);
270
342
  log('info', `目标 URL: ${targetUrl}`);
271
343
  console.log('');
272
344
 
@@ -76,11 +76,12 @@ function showCurrentConfig(existing) {
76
76
  console.log(` 提供商: ${existing.MODEL_PROVIDER || '未配置'}`);
77
77
  console.log(` BASE_URL: ${existing.ANTHROPIC_BASE_URL || '默认'}`);
78
78
  console.log(` 模型: ${existing.ANTHROPIC_MODEL || '默认'}`);
79
- console.log(` MCP: ${existing.MCP_PLAYWRIGHT === 'true' ? `已启用 (${existing.MCP_PLAYWRIGHT_MODE || 'persistent'})` : '未启用'}`);
80
- const compTimeout = existing.SESSION_COMPLETION_TIMEOUT || '300';
79
+ const webTool = existing.WEB_TEST_TOOL;
80
+ const webMode = existing.WEB_TEST_MODE;
81
+ console.log(` 浏览器工具: ${webTool ? `${webTool}${webMode ? ` (${webMode})` : ''}` : '未启用'}`);
81
82
  const turns = existing.SESSION_MAX_TURNS || '0';
82
83
  console.log(` 停顿超时: ${existing.SESSION_STALL_TIMEOUT || '600'} 秒`);
83
- console.log(` 完成检测: ${compTimeout} 秒`);
84
+ console.log(` 完成检测: Stop hook(SDK 原生)`);
84
85
  console.log(` 工具轮次: ${turns === '0' ? '无限制' : turns}`);
85
86
  const simplifyInterval = existing.SIMPLIFY_INTERVAL ?? '5';
86
87
  const simplifyCommits = existing.SIMPLIFY_COMMITS ?? '5';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { ask, askChoice } = require('./helpers');
3
+ const { askChoice } = require('./helpers');
4
4
  const { log, COLOR, updateEnvVar } = require('../../common/config');
5
5
  const { assets } = require('../../common/assets');
6
6
 
@@ -8,34 +8,31 @@ const { assets } = require('../../common/assets');
8
8
 
9
9
  async function configureMCP(rl) {
10
10
  console.log('');
11
- console.log('是否启用 Playwright MCP(浏览器自动化测试)?');
11
+ console.log('是否启用浏览器测试工具?');
12
12
  console.log('');
13
- console.log(' Playwright MCP 由微软官方维护 (github.com/microsoft/playwright-mcp)');
14
- console.log(' 提供 browser_click、browser_snapshot 25+ 浏览器自动化工具');
15
- console.log(' 适用于有 Web 前端的项目,Agent 可用它做端到端测试');
16
- console.log('');
17
- console.log(' 1) 是 - 启用 Playwright MCP(项目有 Web 前端)');
18
- console.log(' 2) 否 - 跳过(纯后端 / CLI 项目)');
13
+ console.log(' 1) Playwright MCP 微软官方,25+ 浏览器自动化工具,支持多实例并行');
14
+ console.log(' 2) Chrome DevTools MCP — Google 官方,连接已打开的 Chrome,调试能力更强');
15
+ console.log(' (单实例限制,多开请配置 Playwright MCP)');
16
+ console.log(' 3) 跳过(纯后端 / CLI 项目)');
19
17
  console.log('');
20
18
 
21
- const mcpChoice = await askChoice(rl, '选择 [1-2]: ', 1, 2);
19
+ const toolChoice = await askChoice(rl, '选择 [1-3]: ', 1, 3);
22
20
 
23
- const mcpConfig = { enabled: false, mode: null };
21
+ const mcpConfig = { tool: '', mode: '' };
24
22
 
25
- if (mcpChoice === 1) {
26
- mcpConfig.enabled = true;
23
+ if (toolChoice === 1) {
24
+ mcpConfig.tool = 'playwright';
27
25
  console.log('');
28
26
  console.log('请选择 Playwright MCP 浏览器模式:');
29
27
  console.log('');
30
28
  console.log(' 1) persistent - 懒人模式(默认,推荐)');
31
- console.log(' 登录一次永久生效,适合 Google SSO、企业内网 API 拉取等日常开发');
29
+ console.log(' 登录一次永久生效,适合 Google SSO、企业内网等日常开发');
32
30
  console.log('');
33
31
  console.log(' 2) isolated - 开发模式');
34
32
  console.log(' 每次会话从快照加载,适合验证登录流程的自动化测试');
35
33
  console.log('');
36
34
  console.log(' 3) extension - 连接真实浏览器(实验性)');
37
35
  console.log(' 通过 Chrome 扩展复用已有登录态和插件');
38
- console.log(' 需要安装 "Playwright MCP Bridge" 扩展');
39
36
  console.log('');
40
37
 
41
38
  const modeChoice = await askChoice(rl, '选择 [1-3,默认 1]: ', 1, 3, 1);
@@ -58,6 +55,25 @@ async function configureMCP(rl) {
58
55
  console.log(' 使用 claude-coder auth <URL> 录制登录状态到 playwright-auth.json');
59
56
  console.log(' MCP 每次会话从此文件加载初始 cookies/localStorage');
60
57
  }
58
+ } else if (toolChoice === 2) {
59
+ mcpConfig.tool = 'chrome-devtools';
60
+
61
+ const [major, minor] = process.versions.node.split('.').map(Number);
62
+ if (major < 20 || (major === 20 && minor < 19)) {
63
+ console.log('');
64
+ console.log(` ${COLOR.yellow}⚠ 当前 Node.js v${process.versions.node},Chrome DevTools MCP 要求 v20.19+${COLOR.reset}`);
65
+ console.log(` ${COLOR.blue} nvm 用户: nvm alias default 22 && nvm use 22${COLOR.reset}`);
66
+ }
67
+
68
+ console.log('');
69
+ console.log(' Chrome DevTools MCP 将连接已打开的 Chrome 浏览器。');
70
+ console.log('');
71
+ console.log(' 前置条件:');
72
+ console.log(' 1. Node.js v20.19+(npx 自动下载 chrome-devtools-mcp 包)');
73
+ console.log(' 2. Chrome 144+');
74
+ console.log(' 3. 打开 chrome://inspect/#remote-debugging 启用远程调试');
75
+ console.log('');
76
+ console.log(' 运行 claude-coder auth 自动配置 .mcp.json');
61
77
  }
62
78
 
63
79
  return mcpConfig;
@@ -66,12 +82,12 @@ async function configureMCP(rl) {
66
82
  // ── MCP 配置追加到 lines ──
67
83
 
68
84
  function appendMcpConfig(lines, mcpConfig) {
69
- lines.push('', '# MCP 工具配置');
70
- if (mcpConfig.enabled) {
71
- lines.push('MCP_PLAYWRIGHT=true');
72
- if (mcpConfig.mode) lines.push(`MCP_PLAYWRIGHT_MODE=${mcpConfig.mode}`);
85
+ lines.push('', '# 浏览器测试工具配置');
86
+ if (mcpConfig.tool) {
87
+ lines.push(`WEB_TEST_TOOL=${mcpConfig.tool}`);
88
+ if (mcpConfig.mode) lines.push(`WEB_TEST_MODE=${mcpConfig.mode}`);
73
89
  } else {
74
- lines.push('MCP_PLAYWRIGHT=false');
90
+ lines.push('WEB_TEST_TOOL=');
75
91
  }
76
92
  }
77
93
 
@@ -79,11 +95,15 @@ function appendMcpConfig(lines, mcpConfig) {
79
95
 
80
96
  async function updateMCPOnly(rl) {
81
97
  const mcpConfig = await configureMCP(rl);
82
- updateEnvVar('MCP_PLAYWRIGHT', mcpConfig.enabled ? 'true' : 'false');
83
- if (mcpConfig.enabled && mcpConfig.mode) {
84
- updateEnvVar('MCP_PLAYWRIGHT_MODE', mcpConfig.mode);
98
+ updateEnvVar('WEB_TEST_TOOL', mcpConfig.tool);
99
+ if (mcpConfig.tool === 'playwright' && mcpConfig.mode) {
100
+ updateEnvVar('WEB_TEST_MODE', mcpConfig.mode);
101
+ const { updateMcpConfig } = require('../auth');
102
+ updateMcpConfig(assets.path('mcpConfig'), 'playwright', mcpConfig.mode);
103
+ } else if (mcpConfig.tool === 'chrome-devtools') {
104
+ updateEnvVar('WEB_TEST_MODE', '');
85
105
  const { updateMcpConfig } = require('../auth');
86
- updateMcpConfig(assets.path('mcpConfig'), mcpConfig.mode);
106
+ updateMcpConfig(assets.path('mcpConfig'), 'chrome-devtools');
87
107
  }
88
108
  log('ok', 'MCP 配置已更新');
89
109
  }
@@ -92,4 +112,4 @@ module.exports = {
92
112
  configureMCP,
93
113
  appendMcpConfig,
94
114
  updateMCPOnly,
95
- };
115
+ };
@@ -7,16 +7,14 @@ const { log, COLOR, updateEnvVar } = require('../../common/config');
7
7
 
8
8
  async function updateSafetyLimits(rl, existing) {
9
9
  const currentStall = existing.SESSION_STALL_TIMEOUT || '600';
10
- const currentCompletion = existing.SESSION_COMPLETION_TIMEOUT || '300';
11
10
  const currentTurns = existing.SESSION_MAX_TURNS || '0';
12
11
 
13
12
  console.log(`${COLOR.blue}当前安全限制:${COLOR.reset}`);
14
13
  console.log(` 停顿超时: ${currentStall} 秒 (${Math.floor(parseInt(currentStall) / 60)} 分钟)`);
15
- console.log(` 完成检测超时: ${currentCompletion} 秒 (${Math.ceil(parseInt(currentCompletion) / 60)} 分钟)`);
16
14
  console.log(` 最大工具轮次: ${currentTurns === '0' ? '无限制' : currentTurns}`);
17
15
  console.log('');
18
16
  console.log(`${COLOR.yellow}说明:${COLOR.reset}`);
19
- console.log(' 完成检测 — 模型写入 session_result.json 后缩短等待,解决"完成但不退出"');
17
+ console.log(' 完成检测 — 通过 SDK Stop hook 感知模型结束,无需额外超时');
20
18
  console.log(' 停顿超时 — 长时间无工具调用时自动中断(通用兜底)');
21
19
  console.log(' 最大轮次 — 限制总轮次,仅 CI 推荐(默认 0 = 无限制)');
22
20
  console.log('');
@@ -32,18 +30,6 @@ async function updateSafetyLimits(rl, existing) {
32
30
  }
33
31
  }
34
32
 
35
- console.log('');
36
- const compInput = await ask(rl, `完成检测超时秒数(回车保留 ${currentCompletion}): `);
37
- if (compInput.trim()) {
38
- const seconds = parseInt(compInput.trim(), 10);
39
- if (isNaN(seconds) || seconds < 30) {
40
- log('warn', '完成检测超时需 >= 30 秒,跳过');
41
- } else {
42
- updateEnvVar('SESSION_COMPLETION_TIMEOUT', String(seconds));
43
- log('ok', `完成检测超时已设置为 ${seconds} 秒`);
44
- }
45
- }
46
-
47
33
  console.log('');
48
34
  const turnsInput = await ask(rl, `最大工具轮次(回车保留 ${currentTurns === '0' ? '无限制' : currentTurns},输入 0 = 无限制): `);
49
35
  if (turnsInput.trim()) {