@link-assistant/hive-mind 2.15.0 â 2.15.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/CHANGELOG.md +40 -0
- package/package.json +1 -1
- package/src/git-auth-transport.lib.mjs +309 -0
- package/src/github-merge.lib.mjs +24 -28
- package/src/lib.mjs +7 -0
- package/src/merge-error-classification.lib.mjs +134 -0
- package/src/option-suggestions.lib.mjs +1 -0
- package/src/pr-draft-state.lib.mjs +96 -0
- package/src/review.mjs +6 -0
- package/src/solve.auto-merge-attempt.lib.mjs +42 -3
- package/src/solve.auto-merge-guards.lib.mjs +152 -0
- package/src/solve.auto-merge-helpers.lib.mjs +20 -1
- package/src/solve.auto-merge-preflight.lib.mjs +122 -0
- package/src/solve.auto-merge.lib.mjs +70 -84
- package/src/solve.config.lib.mjs +8 -0
- package/src/solve.interrupt.lib.mjs +18 -1
- package/src/solve.mjs +19 -0
- package/src/solve.repo-setup.lib.mjs +10 -0
- package/src/solve.repository.lib.mjs +26 -0
- package/src/solve.restart-shared.lib.mjs +302 -278
- package/src/solve.results.lib.mjs +6 -12
- package/src/solve.session.lib.mjs +15 -4
- package/src/telegram-merge-queue.lib.mjs +3 -1
- package/src/telegram-merge-wait.lib.mjs +7 -0
- package/src/transient-errors.lib.mjs +34 -3
|
@@ -39,7 +39,7 @@ const { ensureAiToolScratchIgnored, filterAiToolScratchFromStatus } = await impo
|
|
|
39
39
|
const { RESOURCE_PHASE_RESTART_AFTER, RESOURCE_PHASE_RESTART_BEFORE, recordResourceSnapshot } = await import('./solve.resource-diagnostics.lib.mjs');
|
|
40
40
|
const { classifyFormalAiToolResult } = await import('./formal-ai.lib.mjs');
|
|
41
41
|
// Issue #2123: shared draft/ready transitions for working sessions.
|
|
42
|
-
const { ensurePullRequestIsDraft } = await import('./pr-draft-state.lib.mjs');
|
|
42
|
+
const { ensurePullRequestIsDraft, ensurePullRequestIsReady } = await import('./pr-draft-state.lib.mjs');
|
|
43
43
|
|
|
44
44
|
// Import Sentry integration
|
|
45
45
|
const sentryLib = await import('./sentry.lib.mjs');
|
|
@@ -219,251 +219,211 @@ export const executeToolIteration = async params => {
|
|
|
219
219
|
const { cascadePlaywrightMcpDisable } = await import('./playwright-mcp.lib.mjs');
|
|
220
220
|
await cascadePlaywrightMcpDisable(argv, log);
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
// Issue #2182: the ready conversion below lives in `finally` on purpose. When the AI
|
|
223
|
+
// tool throws (crash, API error, aborted process) the iteration is still over, and a
|
|
224
|
+
// pull request left in draft can never be merged by --auto-merge.
|
|
225
|
+
try {
|
|
226
|
+
let toolResult;
|
|
227
|
+
if (argv.useAgentCommander) {
|
|
228
|
+
const agentCommanderLib = await import('./agent-commander.lib.mjs');
|
|
229
|
+
await agentCommanderLib.resolvePlaywrightMcpForAgentCommander({ argv, log, tool: argv.tool || 'claude' });
|
|
230
|
+
|
|
231
|
+
toolResult = await agentCommanderLib.executeWithAgentCommander({
|
|
232
|
+
issueUrl,
|
|
233
|
+
issueNumber,
|
|
234
|
+
prNumber,
|
|
235
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
236
|
+
branchName,
|
|
237
|
+
tempDir,
|
|
238
|
+
workspaceTmpDir: params.workspaceTmpDir,
|
|
239
|
+
isContinueMode: true,
|
|
240
|
+
mergeStateStatus,
|
|
241
|
+
forkedRepo: argv.fork,
|
|
242
|
+
feedbackLines,
|
|
243
|
+
forkActionsUrl: null,
|
|
244
|
+
owner,
|
|
245
|
+
repo,
|
|
246
|
+
argv,
|
|
247
|
+
log,
|
|
248
|
+
formatAligned,
|
|
249
|
+
getResourceSnapshot,
|
|
250
|
+
setLogFile,
|
|
251
|
+
getLogFile,
|
|
252
|
+
$,
|
|
253
|
+
});
|
|
254
|
+
} else if (argv.tool === 'opencode') {
|
|
255
|
+
// Use OpenCode
|
|
256
|
+
const opencodeExecLib = await import('./opencode.lib.mjs');
|
|
257
|
+
const { executeOpenCode, checkPlaywrightMcpAvailability } = opencodeExecLib;
|
|
258
|
+
const opencodePath = argv.opencodePath || 'opencode';
|
|
226
259
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
isContinueMode: true,
|
|
236
|
-
mergeStateStatus,
|
|
237
|
-
forkedRepo: argv.fork,
|
|
238
|
-
feedbackLines,
|
|
239
|
-
forkActionsUrl: null,
|
|
240
|
-
owner,
|
|
241
|
-
repo,
|
|
242
|
-
argv,
|
|
243
|
-
log,
|
|
244
|
-
formatAligned,
|
|
245
|
-
getResourceSnapshot,
|
|
246
|
-
setLogFile,
|
|
247
|
-
getLogFile,
|
|
248
|
-
$,
|
|
249
|
-
});
|
|
250
|
-
} else if (argv.tool === 'opencode') {
|
|
251
|
-
// Use OpenCode
|
|
252
|
-
const opencodeExecLib = await import('./opencode.lib.mjs');
|
|
253
|
-
const { executeOpenCode, checkPlaywrightMcpAvailability } = opencodeExecLib;
|
|
254
|
-
const opencodePath = argv.opencodePath || 'opencode';
|
|
255
|
-
|
|
256
|
-
if (argv.promptPlaywrightMcp) {
|
|
257
|
-
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
258
|
-
if (playwrightMcpAvailable) {
|
|
259
|
-
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
260
|
+
if (argv.promptPlaywrightMcp) {
|
|
261
|
+
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
262
|
+
if (playwrightMcpAvailable) {
|
|
263
|
+
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
264
|
+
} else {
|
|
265
|
+
await log('âšī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
|
|
266
|
+
argv.promptPlaywrightMcp = false;
|
|
267
|
+
}
|
|
260
268
|
} else {
|
|
261
|
-
await log('âšī¸ Playwright MCP
|
|
262
|
-
argv.promptPlaywrightMcp = false;
|
|
269
|
+
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
263
270
|
}
|
|
264
|
-
} else {
|
|
265
|
-
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
266
|
-
}
|
|
267
271
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (argv.promptPlaywrightMcp) {
|
|
298
|
-
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
299
|
-
if (playwrightMcpAvailable) {
|
|
300
|
-
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
301
|
-
} else {
|
|
302
|
-
await log('âšī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
|
|
303
|
-
argv.promptPlaywrightMcp = false;
|
|
304
|
-
}
|
|
305
|
-
} else {
|
|
306
|
-
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
307
|
-
}
|
|
272
|
+
toolResult = await executeOpenCode({
|
|
273
|
+
issueUrl,
|
|
274
|
+
issueNumber,
|
|
275
|
+
prNumber,
|
|
276
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
277
|
+
branchName,
|
|
278
|
+
tempDir,
|
|
279
|
+
workspaceTmpDir,
|
|
280
|
+
isContinueMode: true,
|
|
281
|
+
mergeStateStatus,
|
|
282
|
+
forkedRepo: argv.fork,
|
|
283
|
+
feedbackLines,
|
|
284
|
+
owner,
|
|
285
|
+
repo,
|
|
286
|
+
argv,
|
|
287
|
+
log,
|
|
288
|
+
formatAligned,
|
|
289
|
+
getResourceSnapshot,
|
|
290
|
+
setLogFile,
|
|
291
|
+
getLogFile,
|
|
292
|
+
opencodePath,
|
|
293
|
+
$,
|
|
294
|
+
});
|
|
295
|
+
} else if (argv.tool === 'codex') {
|
|
296
|
+
// Use Codex
|
|
297
|
+
const codexExecLib = await import('./codex.lib.mjs');
|
|
298
|
+
const { executeCodex, checkPlaywrightMcpAvailability } = codexExecLib;
|
|
299
|
+
const codexPath = argv.codexPath || 'codex';
|
|
308
300
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
isContinueMode: true,
|
|
318
|
-
mergeStateStatus,
|
|
319
|
-
forkedRepo: argv.fork,
|
|
320
|
-
feedbackLines,
|
|
321
|
-
forkActionsUrl: null,
|
|
322
|
-
owner,
|
|
323
|
-
repo,
|
|
324
|
-
argv,
|
|
325
|
-
log,
|
|
326
|
-
setLogFile,
|
|
327
|
-
getLogFile,
|
|
328
|
-
formatAligned,
|
|
329
|
-
getResourceSnapshot,
|
|
330
|
-
codexPath,
|
|
331
|
-
$,
|
|
332
|
-
});
|
|
333
|
-
} else if (argv.tool === 'agent') {
|
|
334
|
-
// Use Agent
|
|
335
|
-
const agentExecLib = await import('./agent.lib.mjs');
|
|
336
|
-
const { executeAgent, checkPlaywrightMcpAvailability } = agentExecLib;
|
|
337
|
-
const agentPath = argv.agentPath || 'agent';
|
|
338
|
-
|
|
339
|
-
if (argv.promptPlaywrightMcp) {
|
|
340
|
-
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
341
|
-
if (playwrightMcpAvailable) {
|
|
342
|
-
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
301
|
+
if (argv.promptPlaywrightMcp) {
|
|
302
|
+
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
303
|
+
if (playwrightMcpAvailable) {
|
|
304
|
+
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
305
|
+
} else {
|
|
306
|
+
await log('âšī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
|
|
307
|
+
argv.promptPlaywrightMcp = false;
|
|
308
|
+
}
|
|
343
309
|
} else {
|
|
344
|
-
await log('âšī¸ Playwright MCP
|
|
345
|
-
argv.promptPlaywrightMcp = false;
|
|
310
|
+
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
346
311
|
}
|
|
347
|
-
} else {
|
|
348
|
-
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
349
|
-
}
|
|
350
312
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
313
|
+
toolResult = await executeCodex({
|
|
314
|
+
issueUrl,
|
|
315
|
+
issueNumber,
|
|
316
|
+
prNumber,
|
|
317
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
318
|
+
branchName,
|
|
319
|
+
tempDir,
|
|
320
|
+
workspaceTmpDir,
|
|
321
|
+
isContinueMode: true,
|
|
322
|
+
mergeStateStatus,
|
|
323
|
+
forkedRepo: argv.fork,
|
|
324
|
+
feedbackLines,
|
|
325
|
+
forkActionsUrl: null,
|
|
326
|
+
owner,
|
|
327
|
+
repo,
|
|
328
|
+
argv,
|
|
329
|
+
log,
|
|
330
|
+
setLogFile,
|
|
331
|
+
getLogFile,
|
|
332
|
+
formatAligned,
|
|
333
|
+
getResourceSnapshot,
|
|
334
|
+
codexPath,
|
|
335
|
+
$,
|
|
336
|
+
});
|
|
337
|
+
} else if (argv.tool === 'agent') {
|
|
338
|
+
// Use Agent
|
|
339
|
+
const agentExecLib = await import('./agent.lib.mjs');
|
|
340
|
+
const { executeAgent, checkPlaywrightMcpAvailability } = agentExecLib;
|
|
341
|
+
const agentPath = argv.agentPath || 'agent';
|
|
342
|
+
|
|
343
|
+
if (argv.promptPlaywrightMcp) {
|
|
344
|
+
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
345
|
+
if (playwrightMcpAvailable) {
|
|
346
|
+
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
347
|
+
} else {
|
|
348
|
+
await log('âšī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
|
|
349
|
+
argv.promptPlaywrightMcp = false;
|
|
350
|
+
}
|
|
385
351
|
} else {
|
|
386
|
-
await log('âšī¸ Playwright MCP
|
|
387
|
-
argv.promptPlaywrightMcp = false;
|
|
352
|
+
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
388
353
|
}
|
|
389
|
-
} else {
|
|
390
|
-
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
391
|
-
}
|
|
392
354
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
355
|
+
toolResult = await executeAgent({
|
|
356
|
+
issueUrl,
|
|
357
|
+
issueNumber,
|
|
358
|
+
prNumber,
|
|
359
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
360
|
+
branchName,
|
|
361
|
+
tempDir,
|
|
362
|
+
workspaceTmpDir,
|
|
363
|
+
isContinueMode: true,
|
|
364
|
+
mergeStateStatus,
|
|
365
|
+
forkedRepo: argv.fork,
|
|
366
|
+
feedbackLines,
|
|
367
|
+
forkActionsUrl: null,
|
|
368
|
+
owner,
|
|
369
|
+
repo,
|
|
370
|
+
argv,
|
|
371
|
+
log,
|
|
372
|
+
formatAligned,
|
|
373
|
+
getResourceSnapshot,
|
|
374
|
+
setLogFile,
|
|
375
|
+
getLogFile,
|
|
376
|
+
agentPath,
|
|
377
|
+
$,
|
|
378
|
+
});
|
|
379
|
+
} else if (argv.tool === 'gemini') {
|
|
380
|
+
// Use Gemini
|
|
381
|
+
const geminiExecLib = await import('./gemini.lib.mjs');
|
|
382
|
+
const { executeGemini, checkPlaywrightMcpAvailability } = geminiExecLib;
|
|
383
|
+
const geminiPath = argv.geminiPath || 'gemini';
|
|
384
|
+
|
|
385
|
+
if (argv.promptPlaywrightMcp) {
|
|
386
|
+
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
387
|
+
if (playwrightMcpAvailable) {
|
|
388
|
+
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
389
|
+
} else {
|
|
390
|
+
await log('âšī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
|
|
391
|
+
argv.promptPlaywrightMcp = false;
|
|
392
|
+
}
|
|
427
393
|
} else {
|
|
428
|
-
await log('âšī¸ Playwright MCP
|
|
429
|
-
argv.promptPlaywrightMcp = false;
|
|
394
|
+
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
430
395
|
}
|
|
431
|
-
} else {
|
|
432
|
-
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
433
|
-
}
|
|
434
396
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
// Check for Playwright MCP availability if using Claude tool
|
|
466
|
-
if (argv.tool === 'claude' || !argv.tool) {
|
|
397
|
+
toolResult = await executeGemini({
|
|
398
|
+
issueUrl,
|
|
399
|
+
issueNumber,
|
|
400
|
+
prNumber,
|
|
401
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
402
|
+
branchName,
|
|
403
|
+
tempDir,
|
|
404
|
+
workspaceTmpDir,
|
|
405
|
+
isContinueMode: true,
|
|
406
|
+
mergeStateStatus,
|
|
407
|
+
forkedRepo: argv.fork,
|
|
408
|
+
feedbackLines,
|
|
409
|
+
forkActionsUrl: null,
|
|
410
|
+
owner,
|
|
411
|
+
repo,
|
|
412
|
+
argv,
|
|
413
|
+
log,
|
|
414
|
+
setLogFile,
|
|
415
|
+
getLogFile,
|
|
416
|
+
formatAligned,
|
|
417
|
+
getResourceSnapshot,
|
|
418
|
+
geminiPath,
|
|
419
|
+
$,
|
|
420
|
+
});
|
|
421
|
+
} else if (argv.tool === 'qwen') {
|
|
422
|
+
// Use Qwen Code
|
|
423
|
+
const qwenExecLib = await import('./qwen.lib.mjs');
|
|
424
|
+
const { executeQwen, checkPlaywrightMcpAvailability } = qwenExecLib;
|
|
425
|
+
const qwenPath = argv.qwenPath || 'qwen';
|
|
426
|
+
|
|
467
427
|
if (argv.promptPlaywrightMcp) {
|
|
468
428
|
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
469
429
|
if (playwrightMcpAvailable) {
|
|
@@ -475,58 +435,122 @@ export const executeToolIteration = async params => {
|
|
|
475
435
|
} else {
|
|
476
436
|
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
477
437
|
}
|
|
438
|
+
|
|
439
|
+
toolResult = await executeQwen({
|
|
440
|
+
issueUrl,
|
|
441
|
+
issueNumber,
|
|
442
|
+
prNumber,
|
|
443
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
444
|
+
branchName,
|
|
445
|
+
tempDir,
|
|
446
|
+
workspaceTmpDir,
|
|
447
|
+
isContinueMode: true,
|
|
448
|
+
mergeStateStatus,
|
|
449
|
+
forkedRepo: argv.fork,
|
|
450
|
+
feedbackLines,
|
|
451
|
+
forkActionsUrl: null,
|
|
452
|
+
owner,
|
|
453
|
+
repo,
|
|
454
|
+
argv,
|
|
455
|
+
log,
|
|
456
|
+
setLogFile,
|
|
457
|
+
getLogFile,
|
|
458
|
+
formatAligned,
|
|
459
|
+
getResourceSnapshot,
|
|
460
|
+
qwenPath,
|
|
461
|
+
$,
|
|
462
|
+
});
|
|
463
|
+
} else {
|
|
464
|
+
// Use Claude (default)
|
|
465
|
+
const claudeExecLib = await import('./claude.lib.mjs');
|
|
466
|
+
const { executeClaude, checkPlaywrightMcpAvailability } = claudeExecLib;
|
|
467
|
+
const claudePath = argv.claudePath || 'claude';
|
|
468
|
+
|
|
469
|
+
// Check for Playwright MCP availability if using Claude tool
|
|
470
|
+
if (argv.tool === 'claude' || !argv.tool) {
|
|
471
|
+
if (argv.promptPlaywrightMcp) {
|
|
472
|
+
const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
|
|
473
|
+
if (playwrightMcpAvailable) {
|
|
474
|
+
await log('đ Playwright MCP detected - enabling browser automation hints', { verbose: true });
|
|
475
|
+
} else {
|
|
476
|
+
await log('âšī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
|
|
477
|
+
argv.promptPlaywrightMcp = false;
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
await log('âšī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
toolResult = await executeClaude({
|
|
485
|
+
issueUrl,
|
|
486
|
+
issueNumber,
|
|
487
|
+
prNumber,
|
|
488
|
+
prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
|
|
489
|
+
branchName,
|
|
490
|
+
tempDir,
|
|
491
|
+
workspaceTmpDir,
|
|
492
|
+
isContinueMode: true,
|
|
493
|
+
mergeStateStatus,
|
|
494
|
+
forkedRepo: argv.fork,
|
|
495
|
+
feedbackLines,
|
|
496
|
+
owner,
|
|
497
|
+
repo,
|
|
498
|
+
argv,
|
|
499
|
+
log,
|
|
500
|
+
formatAligned,
|
|
501
|
+
getResourceSnapshot,
|
|
502
|
+
setLogFile,
|
|
503
|
+
getLogFile,
|
|
504
|
+
claudePath,
|
|
505
|
+
$,
|
|
506
|
+
});
|
|
478
507
|
}
|
|
479
508
|
|
|
480
|
-
toolResult =
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
isContinueMode: true,
|
|
489
|
-
mergeStateStatus,
|
|
490
|
-
forkedRepo: argv.fork,
|
|
491
|
-
feedbackLines,
|
|
492
|
-
owner,
|
|
493
|
-
repo,
|
|
494
|
-
argv,
|
|
509
|
+
toolResult = classifyFormalAiToolResult({ model: argv.model, toolResult });
|
|
510
|
+
if (toolResult?.formalAiNonExecution) {
|
|
511
|
+
await log(`â ${toolResult.errorInfo.message}`, { level: 'error' });
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
await ensurePullRequestBaseBranch({ owner, repo, prNumber, argv, log, formatAligned, $ });
|
|
515
|
+
await recordResourceSnapshot({
|
|
516
|
+
phase: RESOURCE_PHASE_RESTART_AFTER,
|
|
495
517
|
log,
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
setLogFile,
|
|
499
|
-
getLogFile,
|
|
500
|
-
claudePath,
|
|
501
|
-
$,
|
|
518
|
+
diskPath: '/',
|
|
519
|
+
label: 'after AI restart iteration',
|
|
502
520
|
});
|
|
503
|
-
}
|
|
504
521
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
522
|
+
// Issue #2090: every restart iteration starts a brand new tool session with
|
|
523
|
+
// its own session UUID. Collect its development log here â this is the single
|
|
524
|
+
// chokepoint shared by watch mode, auto-restart-until-mergeable,
|
|
525
|
+
// keep-working, escalation and auto-ensure â otherwise only the very first
|
|
526
|
+
// session of the process ever reached the pull request.
|
|
527
|
+
// When the tool did not report a session id there is nothing to key a new
|
|
528
|
+
// directory on, so extend the previously collected session instead of losing
|
|
529
|
+
// this iteration's part of the log.
|
|
530
|
+
const { finalizeActiveDevelopmentLog } = await import('./development-log.finalize.lib.mjs');
|
|
531
|
+
await (toolResult?.sessionId ? finalizeActiveDevelopmentLog({ sessionId: toolResult.sessionId }) : finalizeActiveDevelopmentLog({ force: true }));
|
|
532
|
+
|
|
533
|
+
return toolResult;
|
|
534
|
+
} finally {
|
|
535
|
+
// Issue #2182: the iteration drafted the pull request above, so it must also
|
|
536
|
+
// undo that when the AI session finishes â exactly like endWorkSession() does
|
|
537
|
+
// for the primary session. Without this the pull request stayed a draft after
|
|
538
|
+
// the last restart iteration and --auto-merge retried `gh pr merge` every
|
|
539
|
+
// 120 seconds for 4d 12h ("Pull Request is still a draft"), because a draft
|
|
540
|
+
// PR still reports mergeable=MERGEABLE / mergeStateStatus=CLEAN.
|
|
541
|
+
if (prNumber) {
|
|
542
|
+
await ensurePullRequestIsReady({
|
|
543
|
+
owner,
|
|
544
|
+
repo,
|
|
545
|
+
prNumber,
|
|
546
|
+
$,
|
|
547
|
+
log,
|
|
548
|
+
formatAligned,
|
|
549
|
+
reason: 'restart iteration finished',
|
|
550
|
+
reportError,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
508
553
|
}
|
|
509
|
-
|
|
510
|
-
await ensurePullRequestBaseBranch({ owner, repo, prNumber, argv, log, formatAligned, $ });
|
|
511
|
-
await recordResourceSnapshot({
|
|
512
|
-
phase: RESOURCE_PHASE_RESTART_AFTER,
|
|
513
|
-
log,
|
|
514
|
-
diskPath: '/',
|
|
515
|
-
label: 'after AI restart iteration',
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
// Issue #2090: every restart iteration starts a brand new tool session with
|
|
519
|
-
// its own session UUID. Collect its development log here â this is the single
|
|
520
|
-
// chokepoint shared by watch mode, auto-restart-until-mergeable,
|
|
521
|
-
// keep-working, escalation and auto-ensure â otherwise only the very first
|
|
522
|
-
// session of the process ever reached the pull request.
|
|
523
|
-
// When the tool did not report a session id there is nothing to key a new
|
|
524
|
-
// directory on, so extend the previously collected session instead of losing
|
|
525
|
-
// this iteration's part of the log.
|
|
526
|
-
const { finalizeActiveDevelopmentLog } = await import('./development-log.finalize.lib.mjs');
|
|
527
|
-
await (toolResult?.sessionId ? finalizeActiveDevelopmentLog({ sessionId: toolResult.sessionId }) : finalizeActiveDevelopmentLog({ force: true }));
|
|
528
|
-
|
|
529
|
-
return toolResult;
|
|
530
554
|
};
|
|
531
555
|
|
|
532
556
|
/**
|
|
@@ -802,18 +802,12 @@ Fixes ${issueRef}
|
|
|
802
802
|
await log(` â ī¸ Error updating PR description: ${descError.message}`);
|
|
803
803
|
}
|
|
804
804
|
}
|
|
805
|
-
// Check if PR is ready for review (convert from draft if necessary)
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
} else {
|
|
812
|
-
await log(` â ī¸ Could not convert PR to ready (${readyResult.stderr ? readyResult.stderr.toString().trim() : 'unknown error'})`);
|
|
813
|
-
}
|
|
814
|
-
} else {
|
|
815
|
-
await log(' â
PR is already ready for review', { verbose: true });
|
|
816
|
-
}
|
|
805
|
+
// Check if PR is ready for review (convert from draft if necessary).
|
|
806
|
+
// Issue #2182: this used to be an inline `gh pr ready` that bypassed
|
|
807
|
+
// pr-draft-state.lib.mjs, so it neither skipped merged/closed PRs nor cleared the
|
|
808
|
+
// session draft registry that guarantees the ready transition on every exit path.
|
|
809
|
+
const { ensurePullRequestIsReady } = await import('./pr-draft-state.lib.mjs');
|
|
810
|
+
await ensurePullRequestIsReady({ owner, repo, prNumber: pr.number, $, log, reason: 'solution draft verified' });
|
|
817
811
|
}
|
|
818
812
|
|
|
819
813
|
// Upload log file to PR if requested
|