claude-coder 1.8.4 → 1.9.1
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 +214 -167
- package/bin/cli.js +155 -172
- package/package.json +55 -53
- package/recipes/_shared/roles/developer.md +11 -11
- package/recipes/_shared/roles/product.md +12 -12
- package/recipes/_shared/roles/tester.md +12 -12
- package/recipes/_shared/test/report-format.md +86 -86
- package/recipes/backend/base.md +27 -27
- package/recipes/backend/components/auth.md +18 -18
- package/recipes/backend/components/crud-api.md +18 -18
- package/recipes/backend/components/file-service.md +15 -15
- package/recipes/backend/manifest.json +20 -20
- package/recipes/backend/test/api-test.md +25 -25
- package/recipes/console/base.md +37 -37
- package/recipes/console/components/modal-form.md +20 -20
- package/recipes/console/components/pagination.md +17 -17
- package/recipes/console/components/search.md +17 -17
- package/recipes/console/components/table-list.md +18 -18
- package/recipes/console/components/tabs.md +14 -14
- package/recipes/console/components/tree.md +15 -15
- package/recipes/console/components/upload.md +15 -15
- package/recipes/console/manifest.json +24 -24
- package/recipes/console/test/crud-e2e.md +47 -47
- package/recipes/h5/base.md +26 -26
- package/recipes/h5/components/animation.md +11 -11
- package/recipes/h5/components/countdown.md +11 -11
- package/recipes/h5/components/share.md +11 -11
- package/recipes/h5/components/swiper.md +11 -11
- package/recipes/h5/manifest.json +21 -21
- package/recipes/h5/test/h5-e2e.md +20 -20
- package/src/commands/auth.js +362 -290
- package/src/commands/setup-modules/helpers.js +100 -99
- package/src/commands/setup-modules/index.js +25 -25
- package/src/commands/setup-modules/mcp.js +115 -95
- package/src/commands/setup-modules/provider.js +260 -260
- package/src/commands/setup-modules/safety.js +47 -61
- package/src/commands/setup-modules/simplify.js +52 -52
- package/src/commands/setup.js +172 -172
- package/src/common/assets.js +245 -236
- package/src/common/config.js +125 -125
- package/src/common/constants.js +55 -55
- package/src/common/indicator.js +260 -222
- package/src/common/interaction.js +170 -170
- package/src/common/logging.js +77 -77
- package/src/common/sdk.js +50 -50
- package/src/common/tasks.js +88 -88
- package/src/common/utils.js +213 -161
- package/src/core/coding.js +33 -55
- package/src/core/go.js +264 -310
- package/src/core/hooks.js +500 -533
- package/src/core/init.js +166 -171
- package/src/core/plan.js +188 -325
- package/src/core/prompts.js +247 -227
- package/src/core/repair.js +36 -46
- package/src/core/runner.js +458 -195
- package/src/core/scan.js +93 -89
- package/src/core/session.js +271 -57
- package/src/core/simplify.js +74 -53
- package/src/core/state.js +105 -0
- package/src/index.js +76 -0
- package/templates/bash-process.md +12 -12
- package/templates/codingSystem.md +65 -65
- package/templates/codingUser.md +17 -17
- package/templates/coreProtocol.md +29 -29
- package/templates/goSystem.md +130 -130
- package/templates/guidance.json +72 -53
- package/templates/planSystem.md +78 -78
- package/templates/planUser.md +8 -8
- package/templates/requirements.example.md +57 -57
- package/templates/scanSystem.md +120 -120
- package/templates/scanUser.md +10 -10
- package/templates/test_rule.md +194 -194
- package/templates/web-testing.md +17 -0
- package/types/index.d.ts +217 -0
- package/src/core/context.js +0 -117
- package/src/core/harness.js +0 -484
- package/src/core/query.js +0 -50
- package/templates/playwright.md +0 -17
|
@@ -1,99 +1,100 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const readline = require('readline');
|
|
6
|
-
const { log, COLOR, updateEnvVar } = require('../../common/config');
|
|
7
|
-
const { ensureGitignore: ensureGitignoreBase } = require('../../common/utils');
|
|
8
|
-
const { assets } = require('../../common/assets');
|
|
9
|
-
|
|
10
|
-
function createInterface() {
|
|
11
|
-
return readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function ask(rl, question) {
|
|
15
|
-
return new Promise(resolve => rl.question(question, resolve));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function askChoice(rl, prompt, min, max, defaultVal) {
|
|
19
|
-
return new Promise(async (resolve) => {
|
|
20
|
-
while (true) {
|
|
21
|
-
const raw = await ask(rl, prompt);
|
|
22
|
-
const val = raw.trim() || String(defaultVal ?? '');
|
|
23
|
-
const num = parseInt(val, 10);
|
|
24
|
-
if (num >= min && num <= max) return resolve(num);
|
|
25
|
-
console.log(`请输入 ${min}-${max}`);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function askApiKey(rl, platform, apiUrl, existingKey) {
|
|
31
|
-
if (existingKey) {
|
|
32
|
-
console.log('回车保留当前 API Key,输入新 Key 更新,输入 q 返回上层菜单:');
|
|
33
|
-
} else {
|
|
34
|
-
console.log(`请输入 ${platform} 的 API Key:`);
|
|
35
|
-
}
|
|
36
|
-
if (apiUrl) {
|
|
37
|
-
console.log(` ${COLOR.blue}获取入口: ${apiUrl}${COLOR.reset}`);
|
|
38
|
-
console.log('');
|
|
39
|
-
}
|
|
40
|
-
const key = await ask(rl, ' API Key: ');
|
|
41
|
-
const trimmed = key.trim();
|
|
42
|
-
if (trimmed.toLowerCase() === 'q') {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
if (!trimmed) {
|
|
46
|
-
if (existingKey) return existingKey;
|
|
47
|
-
console.error('API Key 不能为空');
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
return trimmed;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function writeConfig(filePath, lines) {
|
|
54
|
-
const dir = path.dirname(filePath);
|
|
55
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
56
|
-
|
|
57
|
-
if (fs.existsSync(filePath)) {
|
|
58
|
-
const ts = new Date().toISOString().replace(/[:\-T]/g, '').slice(0, 14);
|
|
59
|
-
const backup = `${filePath}.bak.${ts}`;
|
|
60
|
-
fs.copyFileSync(filePath, backup);
|
|
61
|
-
log('info', `已备份旧配置到: ${backup}`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf8');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function ensureGitignore() {
|
|
68
|
-
if (ensureGitignoreBase(assets.projectRoot)) {
|
|
69
|
-
log('info', '已更新 .gitignore');
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function showCurrentConfig(existing) {
|
|
74
|
-
console.log('');
|
|
75
|
-
console.log(`${COLOR.blue}当前配置:${COLOR.reset}`);
|
|
76
|
-
console.log(` 提供商: ${existing.MODEL_PROVIDER || '未配置'}`);
|
|
77
|
-
console.log(` BASE_URL: ${existing.ANTHROPIC_BASE_URL || '默认'}`);
|
|
78
|
-
console.log(` 模型: ${existing.ANTHROPIC_MODEL || '默认'}`);
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
console.log(`
|
|
84
|
-
console.log(`
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
console.log('');
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const { log, COLOR, updateEnvVar } = require('../../common/config');
|
|
7
|
+
const { ensureGitignore: ensureGitignoreBase } = require('../../common/utils');
|
|
8
|
+
const { assets } = require('../../common/assets');
|
|
9
|
+
|
|
10
|
+
function createInterface() {
|
|
11
|
+
return readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function ask(rl, question) {
|
|
15
|
+
return new Promise(resolve => rl.question(question, resolve));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function askChoice(rl, prompt, min, max, defaultVal) {
|
|
19
|
+
return new Promise(async (resolve) => {
|
|
20
|
+
while (true) {
|
|
21
|
+
const raw = await ask(rl, prompt);
|
|
22
|
+
const val = raw.trim() || String(defaultVal ?? '');
|
|
23
|
+
const num = parseInt(val, 10);
|
|
24
|
+
if (num >= min && num <= max) return resolve(num);
|
|
25
|
+
console.log(`请输入 ${min}-${max}`);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function askApiKey(rl, platform, apiUrl, existingKey) {
|
|
31
|
+
if (existingKey) {
|
|
32
|
+
console.log('回车保留当前 API Key,输入新 Key 更新,输入 q 返回上层菜单:');
|
|
33
|
+
} else {
|
|
34
|
+
console.log(`请输入 ${platform} 的 API Key:`);
|
|
35
|
+
}
|
|
36
|
+
if (apiUrl) {
|
|
37
|
+
console.log(` ${COLOR.blue}获取入口: ${apiUrl}${COLOR.reset}`);
|
|
38
|
+
console.log('');
|
|
39
|
+
}
|
|
40
|
+
const key = await ask(rl, ' API Key: ');
|
|
41
|
+
const trimmed = key.trim();
|
|
42
|
+
if (trimmed.toLowerCase() === 'q') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
if (!trimmed) {
|
|
46
|
+
if (existingKey) return existingKey;
|
|
47
|
+
console.error('API Key 不能为空');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
return trimmed;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function writeConfig(filePath, lines) {
|
|
54
|
+
const dir = path.dirname(filePath);
|
|
55
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
56
|
+
|
|
57
|
+
if (fs.existsSync(filePath)) {
|
|
58
|
+
const ts = new Date().toISOString().replace(/[:\-T]/g, '').slice(0, 14);
|
|
59
|
+
const backup = `${filePath}.bak.${ts}`;
|
|
60
|
+
fs.copyFileSync(filePath, backup);
|
|
61
|
+
log('info', `已备份旧配置到: ${backup}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf8');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function ensureGitignore() {
|
|
68
|
+
if (ensureGitignoreBase(assets.projectRoot)) {
|
|
69
|
+
log('info', '已更新 .gitignore');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function showCurrentConfig(existing) {
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log(`${COLOR.blue}当前配置:${COLOR.reset}`);
|
|
76
|
+
console.log(` 提供商: ${existing.MODEL_PROVIDER || '未配置'}`);
|
|
77
|
+
console.log(` BASE_URL: ${existing.ANTHROPIC_BASE_URL || '默认'}`);
|
|
78
|
+
console.log(` 模型: ${existing.ANTHROPIC_MODEL || '默认'}`);
|
|
79
|
+
const webTool = existing.WEB_TEST_TOOL;
|
|
80
|
+
const webMode = existing.WEB_TEST_MODE;
|
|
81
|
+
console.log(` 浏览器工具: ${webTool ? `${webTool}${webMode ? ` (${webMode})` : ''}` : '未启用'}`);
|
|
82
|
+
const turns = existing.SESSION_MAX_TURNS || '0';
|
|
83
|
+
console.log(` 停顿超时: ${existing.SESSION_STALL_TIMEOUT || '600'} 秒`);
|
|
84
|
+
console.log(` 完成检测: Stop hook(SDK 原生)`);
|
|
85
|
+
console.log(` 工具轮次: ${turns === '0' ? '无限制' : turns}`);
|
|
86
|
+
const simplifyInterval = existing.SIMPLIFY_INTERVAL ?? '5';
|
|
87
|
+
const simplifyCommits = existing.SIMPLIFY_COMMITS ?? '5';
|
|
88
|
+
console.log(` 自动审查: ${simplifyInterval === '0' ? '禁用' : `每 ${simplifyInterval} 个 session`}${simplifyInterval !== '0' ? `,审查 ${simplifyCommits} 个 commit` : ''}`);
|
|
89
|
+
console.log('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
createInterface,
|
|
94
|
+
ask,
|
|
95
|
+
askChoice,
|
|
96
|
+
askApiKey,
|
|
97
|
+
writeConfig,
|
|
98
|
+
ensureGitignore,
|
|
99
|
+
showCurrentConfig,
|
|
100
|
+
};
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// ── setup 子模块统一入口 ──
|
|
4
|
-
|
|
5
|
-
const helpers = require('./helpers');
|
|
6
|
-
const provider = require('./provider');
|
|
7
|
-
const mcp = require('./mcp');
|
|
8
|
-
const safety = require('./safety');
|
|
9
|
-
const simplify = require('./simplify');
|
|
10
|
-
|
|
11
|
-
module.exports = {
|
|
12
|
-
createInterface: helpers.createInterface,
|
|
13
|
-
ask: helpers.ask,
|
|
14
|
-
askChoice: helpers.askChoice,
|
|
15
|
-
askApiKey: helpers.askApiKey,
|
|
16
|
-
writeConfig: helpers.writeConfig,
|
|
17
|
-
ensureGitignore: helpers.ensureGitignore,
|
|
18
|
-
showCurrentConfig: helpers.showCurrentConfig,
|
|
19
|
-
selectProvider: provider.selectProvider,
|
|
20
|
-
updateApiKeyOnly: provider.updateApiKeyOnly,
|
|
21
|
-
configureMCP: mcp.configureMCP,
|
|
22
|
-
appendMcpConfig: mcp.appendMcpConfig,
|
|
23
|
-
updateMCPOnly: mcp.updateMCPOnly,
|
|
24
|
-
updateSafetyLimits: safety.updateSafetyLimits,
|
|
25
|
-
updateSimplifyConfig: simplify.updateSimplifyConfig,
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ── setup 子模块统一入口 ──
|
|
4
|
+
|
|
5
|
+
const helpers = require('./helpers');
|
|
6
|
+
const provider = require('./provider');
|
|
7
|
+
const mcp = require('./mcp');
|
|
8
|
+
const safety = require('./safety');
|
|
9
|
+
const simplify = require('./simplify');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
createInterface: helpers.createInterface,
|
|
13
|
+
ask: helpers.ask,
|
|
14
|
+
askChoice: helpers.askChoice,
|
|
15
|
+
askApiKey: helpers.askApiKey,
|
|
16
|
+
writeConfig: helpers.writeConfig,
|
|
17
|
+
ensureGitignore: helpers.ensureGitignore,
|
|
18
|
+
showCurrentConfig: helpers.showCurrentConfig,
|
|
19
|
+
selectProvider: provider.selectProvider,
|
|
20
|
+
updateApiKeyOnly: provider.updateApiKeyOnly,
|
|
21
|
+
configureMCP: mcp.configureMCP,
|
|
22
|
+
appendMcpConfig: mcp.appendMcpConfig,
|
|
23
|
+
updateMCPOnly: mcp.updateMCPOnly,
|
|
24
|
+
updateSafetyLimits: safety.updateSafetyLimits,
|
|
25
|
+
updateSimplifyConfig: simplify.updateSimplifyConfig,
|
|
26
26
|
};
|
|
@@ -1,95 +1,115 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
const { log, COLOR, updateEnvVar } = require('../../common/config');
|
|
5
|
-
const { assets } = require('../../common/assets');
|
|
6
|
-
|
|
7
|
-
// ── MCP 配置 ──
|
|
8
|
-
|
|
9
|
-
async function configureMCP(rl) {
|
|
10
|
-
console.log('');
|
|
11
|
-
console.log('
|
|
12
|
-
console.log('');
|
|
13
|
-
console.log(' Playwright MCP
|
|
14
|
-
console.log('
|
|
15
|
-
console.log('
|
|
16
|
-
console.log('');
|
|
17
|
-
console.log('
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
console.log('');
|
|
28
|
-
console.log('
|
|
29
|
-
console.log('');
|
|
30
|
-
console.log('
|
|
31
|
-
console.log('
|
|
32
|
-
console.log('');
|
|
33
|
-
console.log('
|
|
34
|
-
console.log('
|
|
35
|
-
console.log('');
|
|
36
|
-
console.log('
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
mcpConfig.mode
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
console.log(
|
|
48
|
-
|
|
49
|
-
console.log('');
|
|
50
|
-
console.log('
|
|
51
|
-
|
|
52
|
-
console.log('
|
|
53
|
-
console.log(
|
|
54
|
-
|
|
55
|
-
console.log('
|
|
56
|
-
console.log(
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { askChoice } = require('./helpers');
|
|
4
|
+
const { log, COLOR, updateEnvVar } = require('../../common/config');
|
|
5
|
+
const { assets } = require('../../common/assets');
|
|
6
|
+
|
|
7
|
+
// ── MCP 配置 ──
|
|
8
|
+
|
|
9
|
+
async function configureMCP(rl) {
|
|
10
|
+
console.log('');
|
|
11
|
+
console.log('是否启用浏览器测试工具?');
|
|
12
|
+
console.log('');
|
|
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 项目)');
|
|
17
|
+
console.log('');
|
|
18
|
+
|
|
19
|
+
const toolChoice = await askChoice(rl, '选择 [1-3]: ', 1, 3);
|
|
20
|
+
|
|
21
|
+
const mcpConfig = { tool: '', mode: '' };
|
|
22
|
+
|
|
23
|
+
if (toolChoice === 1) {
|
|
24
|
+
mcpConfig.tool = 'playwright';
|
|
25
|
+
console.log('');
|
|
26
|
+
console.log('请选择 Playwright MCP 浏览器模式:');
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log(' 1) persistent - 懒人模式(默认,推荐)');
|
|
29
|
+
console.log(' 登录一次永久生效,适合 Google SSO、企业内网等日常开发');
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log(' 2) isolated - 开发模式');
|
|
32
|
+
console.log(' 每次会话从快照加载,适合验证登录流程的自动化测试');
|
|
33
|
+
console.log('');
|
|
34
|
+
console.log(' 3) extension - 连接真实浏览器(实验性)');
|
|
35
|
+
console.log(' 通过 Chrome 扩展复用已有登录态和插件');
|
|
36
|
+
console.log('');
|
|
37
|
+
|
|
38
|
+
const modeChoice = await askChoice(rl, '选择 [1-3,默认 1]: ', 1, 3, 1);
|
|
39
|
+
const modeMap = { 1: 'persistent', 2: 'isolated', 3: 'extension' };
|
|
40
|
+
mcpConfig.mode = modeMap[modeChoice];
|
|
41
|
+
|
|
42
|
+
console.log('');
|
|
43
|
+
if (mcpConfig.mode === 'extension') {
|
|
44
|
+
console.log(` ${COLOR.yellow}⚠ 前置条件:安装 Playwright MCP Bridge 浏览器扩展${COLOR.reset}`);
|
|
45
|
+
console.log(` ${COLOR.blue} https://chromewebstore.google.com/detail/playwright-mcp-bridge/mmlmfjhmonkocbjadbfplnigmagldckm${COLOR.reset}`);
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(' 安装扩展后,运行 claude-coder auth 生成 .mcp.json 配置');
|
|
48
|
+
} else if (mcpConfig.mode === 'persistent') {
|
|
49
|
+
console.log(' 使用 claude-coder auth <URL> 打开浏览器完成首次登录');
|
|
50
|
+
console.log(' 登录状态将持久保存,后续 MCP 会话自动复用');
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log(' 请确保已安装 Playwright:');
|
|
53
|
+
console.log(` ${COLOR.blue}npx playwright install chromium${COLOR.reset}`);
|
|
54
|
+
} else {
|
|
55
|
+
console.log(' 使用 claude-coder auth <URL> 录制登录状态到 playwright-auth.json');
|
|
56
|
+
console.log(' MCP 每次会话从此文件加载初始 cookies/localStorage');
|
|
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');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return mcpConfig;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ── MCP 配置追加到 lines ──
|
|
83
|
+
|
|
84
|
+
function appendMcpConfig(lines, mcpConfig) {
|
|
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}`);
|
|
89
|
+
} else {
|
|
90
|
+
lines.push('WEB_TEST_TOOL=');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── 仅更新 MCP 配置 ──
|
|
95
|
+
|
|
96
|
+
async function updateMCPOnly(rl) {
|
|
97
|
+
const mcpConfig = await configureMCP(rl);
|
|
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', '');
|
|
105
|
+
const { updateMcpConfig } = require('../auth');
|
|
106
|
+
updateMcpConfig(assets.path('mcpConfig'), 'chrome-devtools');
|
|
107
|
+
}
|
|
108
|
+
log('ok', 'MCP 配置已更新');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = {
|
|
112
|
+
configureMCP,
|
|
113
|
+
appendMcpConfig,
|
|
114
|
+
updateMCPOnly,
|
|
115
|
+
};
|