claude-coder 1.9.1 → 1.9.2
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/package.json +1 -1
- package/src/commands/auth.js +83 -25
- package/src/common/config.js +1 -1
- package/src/core/runner.js +16 -3
- package/src/core/session.js +20 -11
package/package.json
CHANGED
package/src/commands/auth.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const http = require('http');
|
|
6
7
|
const { execSync } = require('child_process');
|
|
7
8
|
const { loadConfig, log } = require('../common/config');
|
|
8
9
|
const { assets } = require('../common/assets');
|
|
@@ -277,36 +278,91 @@ function authExtension() {
|
|
|
277
278
|
log('info', '确保 Chrome/Edge 已运行且 Playwright MCP Bridge 扩展已启用');
|
|
278
279
|
}
|
|
279
280
|
|
|
280
|
-
function
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
console.log(' - 调试工具: Console 消息、网络请求检查、内存快照');
|
|
297
|
-
console.log('');
|
|
298
|
-
console.log(` 注意: 单实例限制,同一时间只能连接一个 Chrome 调试会话。`);
|
|
299
|
-
console.log(` 如需多实例并行,请配置 Playwright MCP(claude-coder setup)。`);
|
|
300
|
-
console.log('');
|
|
281
|
+
function getChromeCommand() {
|
|
282
|
+
if (process.platform === 'win32') {
|
|
283
|
+
const prefixes = [
|
|
284
|
+
process.env['PROGRAMFILES(X86)'],
|
|
285
|
+
process.env.PROGRAMFILES,
|
|
286
|
+
process.env.LOCALAPPDATA,
|
|
287
|
+
].filter(Boolean);
|
|
288
|
+
for (const prefix of prefixes) {
|
|
289
|
+
const p = path.join(prefix, 'Google', 'Chrome', 'Application', 'chrome.exe');
|
|
290
|
+
if (fs.existsSync(p)) return `"${p}"`;
|
|
291
|
+
}
|
|
292
|
+
return 'start chrome';
|
|
293
|
+
}
|
|
294
|
+
if (process.platform === 'darwin') return 'open -a "Google Chrome" --args';
|
|
295
|
+
return 'google-chrome';
|
|
296
|
+
}
|
|
301
297
|
|
|
298
|
+
function checkCdpConnection(port = 9222, timeoutMs = 5000) {
|
|
299
|
+
return new Promise(resolve => {
|
|
300
|
+
const req = http.get(`http://127.0.0.1:${port}/json/version`, res => {
|
|
301
|
+
let data = '';
|
|
302
|
+
res.on('data', chunk => { data += chunk; });
|
|
303
|
+
res.on('end', () => {
|
|
304
|
+
try {
|
|
305
|
+
const info = JSON.parse(data);
|
|
306
|
+
resolve({ ok: true, browser: info.Browser || 'Chrome', wsUrl: info.webSocketDebuggerUrl || '' });
|
|
307
|
+
} catch {
|
|
308
|
+
resolve({ ok: false });
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
req.on('error', () => resolve({ ok: false }));
|
|
313
|
+
req.setTimeout(timeoutMs, () => { req.destroy(); resolve({ ok: false }); });
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function authChromeDevTools(url) {
|
|
302
318
|
const mcpPath = assets.path('mcpConfig');
|
|
303
319
|
updateMcpConfig(mcpPath, 'chrome-devtools');
|
|
304
320
|
enableWebTestEnv('chrome-devtools');
|
|
305
321
|
|
|
322
|
+
log('ok', '.mcp.json 已配置完成');
|
|
306
323
|
console.log('');
|
|
307
|
-
|
|
308
|
-
log('info', 'Chrome DevTools
|
|
309
|
-
|
|
324
|
+
|
|
325
|
+
log('info', '正在检测 Chrome DevTools 连接...');
|
|
326
|
+
let conn = await checkCdpConnection();
|
|
327
|
+
|
|
328
|
+
if (!conn.ok && url) {
|
|
329
|
+
log('info', '未检测到 Chrome 远程调试实例,尝试启动 Chrome...');
|
|
330
|
+
const chromeCmd = getChromeCommand();
|
|
331
|
+
const launchCmd = `${chromeCmd} --remote-debugging-port=9222 "${url}"`;
|
|
332
|
+
try {
|
|
333
|
+
const { spawn } = require('child_process');
|
|
334
|
+
const child = spawn(launchCmd, { shell: true, detached: true, stdio: 'ignore' });
|
|
335
|
+
child.unref();
|
|
336
|
+
} catch (err) {
|
|
337
|
+
log('warn', `Chrome 启动失败: ${err.message}`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
for (let i = 0; i < 6; i++) {
|
|
341
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
342
|
+
conn = await checkCdpConnection();
|
|
343
|
+
if (conn.ok) break;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
console.log('');
|
|
348
|
+
if (conn.ok) {
|
|
349
|
+
log('ok', `Chrome DevTools 连接成功: ${conn.browser}`);
|
|
350
|
+
if (conn.wsUrl) log('info', `WebSocket: ${conn.wsUrl}`);
|
|
351
|
+
log('ok', '配置验证通过!MCP 可以正常连接 Chrome。');
|
|
352
|
+
} else {
|
|
353
|
+
log('warn', '未检测到 Chrome 远程调试实例');
|
|
354
|
+
console.log('');
|
|
355
|
+
console.log(' 请确保:');
|
|
356
|
+
console.log(' 1. Chrome 144+ 已安装');
|
|
357
|
+
console.log(' 2. 打开 chrome://inspect/#remote-debugging 启用远程调试');
|
|
358
|
+
console.log(' 3. 允许传入调试连接');
|
|
359
|
+
console.log('');
|
|
360
|
+
console.log(' 或手动启动带远程调试的 Chrome:');
|
|
361
|
+
const chromeCmd = getChromeCommand();
|
|
362
|
+
console.log(` ${chromeCmd} --remote-debugging-port=9222`);
|
|
363
|
+
console.log('');
|
|
364
|
+
log('info', '.mcp.json 已配置,Chrome 就绪后 MCP 会自动连接 (autoConnect)');
|
|
365
|
+
}
|
|
310
366
|
}
|
|
311
367
|
|
|
312
368
|
async function auth(url) {
|
|
@@ -328,9 +384,11 @@ async function auth(url) {
|
|
|
328
384
|
log('info', '升级后重新运行此命令');
|
|
329
385
|
return;
|
|
330
386
|
}
|
|
387
|
+
const targetUrl = normalizeUrl(url) || null;
|
|
331
388
|
log('info', '浏览器工具: Chrome DevTools MCP');
|
|
389
|
+
if (targetUrl) log('info', `目标 URL: ${targetUrl}`);
|
|
332
390
|
console.log('');
|
|
333
|
-
authChromeDevTools();
|
|
391
|
+
await authChromeDevTools(targetUrl);
|
|
334
392
|
return;
|
|
335
393
|
}
|
|
336
394
|
|
package/src/common/config.js
CHANGED
|
@@ -21,7 +21,7 @@ function log(level, msg) {
|
|
|
21
21
|
warn: `${COLOR.yellow}[WARN]${COLOR.reset} `,
|
|
22
22
|
error: `${COLOR.red}[ERROR]${COLOR.reset}`,
|
|
23
23
|
};
|
|
24
|
-
console.error(`${tags[level] || ''} ${msg}`);
|
|
24
|
+
console.error(`${tags[level] || ''} ${msg} \n`);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// --------------- .env parsing ---------------
|
package/src/core/runner.js
CHANGED
|
@@ -308,8 +308,17 @@ async function onFailure(session, { headBefore, taskId, sessionResult, validateR
|
|
|
308
308
|
});
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
-
async function onStall(session, { headBefore, taskId, sessionResult, consecutiveFailures }) {
|
|
312
|
-
log('warn', `Session ${session}
|
|
311
|
+
async function onStall(session, { headBefore, taskId, sessionResult, consecutiveFailures, config }) {
|
|
312
|
+
log('warn', `Session ${session} 因停顿超时中断,尝试校验任务是否已完成...`);
|
|
313
|
+
|
|
314
|
+
const validateResult = await validate(config, headBefore, taskId);
|
|
315
|
+
|
|
316
|
+
if (!validateResult.fatal) {
|
|
317
|
+
log('ok', `停顿超时但任务已完成,按成功处理${validateResult.hasWarnings ? ' (有警告)' : ''}`);
|
|
318
|
+
return onSuccess(session, { taskId, sessionResult, validateResult });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
log('warn', '停顿超时且校验未通过,回滚重试');
|
|
313
322
|
return _handleRetryOrSkip(session, {
|
|
314
323
|
headBefore, taskId, sessionResult, consecutiveFailures,
|
|
315
324
|
result: 'stalled', reason: '停顿超时',
|
|
@@ -420,7 +429,11 @@ async function executeRun(config, opts = {}) {
|
|
|
420
429
|
});
|
|
421
430
|
|
|
422
431
|
if (sessionResult.stalled) {
|
|
423
|
-
state = await onStall(session, { headBefore, taskId, sessionResult, ...state });
|
|
432
|
+
state = await onStall(session, { headBefore, taskId, sessionResult, config, ...state });
|
|
433
|
+
if (state.consecutiveFailures === 0) {
|
|
434
|
+
if (shouldSimplify(config)) await tryRunSimplify(config);
|
|
435
|
+
tryPush(projectRoot);
|
|
436
|
+
}
|
|
424
437
|
continue;
|
|
425
438
|
}
|
|
426
439
|
|
package/src/core/session.js
CHANGED
|
@@ -164,21 +164,30 @@ class Session {
|
|
|
164
164
|
const messages = [];
|
|
165
165
|
const querySession = sdk.query({ prompt, options: queryOpts });
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
try {
|
|
168
|
+
for await (const message of querySession) {
|
|
169
|
+
if (this._isStalled()) {
|
|
170
|
+
log('warn', '停顿超时,中断消息循环');
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
messages.push(message);
|
|
174
|
+
this._logMessage(message);
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
if (opts.onMessage) {
|
|
177
|
+
const action = opts.onMessage(message, messages);
|
|
178
|
+
if (action === 'break') break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
if (this._isStalled()) {
|
|
183
|
+
log('warn', 'SDK 会话因停顿超时中断');
|
|
184
|
+
} else {
|
|
185
|
+
throw err;
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
188
|
|
|
181
189
|
const sdkResult = extractResult(messages);
|
|
190
|
+
this.logStream.write(`\n[SDK_RESULT] ${JSON.stringify(sdkResult, null, 2)}\n\n`);
|
|
182
191
|
const cost = sdkResult?.total_cost_usd || null;
|
|
183
192
|
const usage = sdkResult?.usage || null;
|
|
184
193
|
const turns = sdkResult?.num_turns || null;
|
|
@@ -196,7 +205,7 @@ class Session {
|
|
|
196
205
|
console.log('----- SESSION END -----');
|
|
197
206
|
log('info', `session 统计: ${summary}`);
|
|
198
207
|
if (this.logStream?.writable) {
|
|
199
|
-
this.logStream.write(`[
|
|
208
|
+
this.logStream.write(`[SESSION_INFO] ${summary}\n`);
|
|
200
209
|
}
|
|
201
210
|
}
|
|
202
211
|
|