opencode-magi 0.5.0 → 0.6.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/dist/config/resolve.js +3 -3
- package/dist/config/validate.js +31 -18
- package/dist/config/worktree.js +6 -0
- package/dist/github/commands.js +153 -45
- package/dist/index.js +29 -3
- package/dist/orchestrator/ci.js +21 -14
- package/dist/orchestrator/findings.js +29 -7
- package/dist/orchestrator/majority.js +1 -1
- package/dist/orchestrator/merge.js +31 -10
- package/dist/orchestrator/model.js +23 -9
- package/dist/orchestrator/review.js +162 -36
- package/dist/orchestrator/run-manager.js +171 -146
- package/dist/orchestrator/triage.js +243 -201
- package/dist/prompts/compose.js +2 -10
- package/dist/prompts/contracts.js +6 -20
- package/dist/prompts/output.js +6 -16
- package/package.json +1 -1
- package/schema.json +3 -3
- package/dist/prompts/templates/triage/action.md +0 -5
|
@@ -15,7 +15,6 @@ const DEFAULT_CLEAR_OPTIONS = {
|
|
|
15
15
|
session: true,
|
|
16
16
|
worktree: true,
|
|
17
17
|
};
|
|
18
|
-
const SYNC_RUN_TIMEOUT_MS = 600_000;
|
|
19
18
|
function createRunId() {
|
|
20
19
|
return `run-${Date.now().toString(36)}-${randomUUID().slice(0, 8)}`;
|
|
21
20
|
}
|
|
@@ -152,6 +151,12 @@ function ciReportText(input) {
|
|
|
152
151
|
const scopeInside = input.report.scopeInside.length;
|
|
153
152
|
return `CI report for ${input.pr}: ${failed} failed, ${scopeInside} scope-in, ${rerun} rerun, ${recovered} recovered, ${unresolved} unresolved.`;
|
|
154
153
|
}
|
|
154
|
+
function ciClassifierCompletedText(input) {
|
|
155
|
+
const summary = input.checks
|
|
156
|
+
.map((check) => `${check.name}: ${check.classification} - ${check.reason}`)
|
|
157
|
+
.join("; ");
|
|
158
|
+
return `**CI classifier ${input.reviewer}** completed for ${input.pr}: ${summary}`;
|
|
159
|
+
}
|
|
155
160
|
function closeReconsiderationText(input) {
|
|
156
161
|
if (input.to === "MERGE") {
|
|
157
162
|
return `**Reviewer ${input.reviewer}** changed their close request to approval for ${input.pr}.`;
|
|
@@ -404,6 +409,8 @@ function extractQuestionRequest(properties) {
|
|
|
404
409
|
export class MagiRunManager {
|
|
405
410
|
input;
|
|
406
411
|
active = new Map();
|
|
412
|
+
activePrRuns = 0;
|
|
413
|
+
activeTriageRuns = 0;
|
|
407
414
|
countedToolParts = new Map();
|
|
408
415
|
controllers = new Map();
|
|
409
416
|
eventLastUpdates = new Map();
|
|
@@ -411,6 +418,8 @@ export class MagiRunManager {
|
|
|
411
418
|
runPaths = new Map();
|
|
412
419
|
outputDirs = new Set();
|
|
413
420
|
sessionToRun = new Map();
|
|
421
|
+
prQueue = [];
|
|
422
|
+
triageQueue = [];
|
|
414
423
|
constructor(input) {
|
|
415
424
|
this.input = input;
|
|
416
425
|
}
|
|
@@ -460,10 +469,13 @@ export class MagiRunManager {
|
|
|
460
469
|
signal: controller.signal,
|
|
461
470
|
});
|
|
462
471
|
if (input.sync)
|
|
463
|
-
return this.executeSync(state, controller, execute);
|
|
464
|
-
|
|
465
|
-
|
|
472
|
+
return this.executeSync(state, controller, execute, input.timeoutMs);
|
|
473
|
+
this.prQueue.push({
|
|
474
|
+
execute,
|
|
475
|
+
repository: input.repository,
|
|
476
|
+
runId,
|
|
466
477
|
});
|
|
478
|
+
this.drainPrQueue();
|
|
467
479
|
return state;
|
|
468
480
|
}
|
|
469
481
|
async startMerge(input) {
|
|
@@ -521,10 +533,13 @@ export class MagiRunManager {
|
|
|
521
533
|
signal: controller.signal,
|
|
522
534
|
});
|
|
523
535
|
if (input.sync)
|
|
524
|
-
return this.executeSync(state, controller, execute);
|
|
525
|
-
|
|
526
|
-
|
|
536
|
+
return this.executeSync(state, controller, execute, input.timeoutMs);
|
|
537
|
+
this.prQueue.push({
|
|
538
|
+
execute,
|
|
539
|
+
repository: input.repository,
|
|
540
|
+
runId,
|
|
527
541
|
});
|
|
542
|
+
this.drainPrQueue();
|
|
528
543
|
return state;
|
|
529
544
|
}
|
|
530
545
|
async startTriage(input) {
|
|
@@ -581,14 +596,64 @@ export class MagiRunManager {
|
|
|
581
596
|
signal: controller.signal,
|
|
582
597
|
});
|
|
583
598
|
if (input.sync)
|
|
584
|
-
return this.executeSync(state, controller, execute);
|
|
585
|
-
|
|
586
|
-
|
|
599
|
+
return this.executeSync(state, controller, execute, input.timeoutMs);
|
|
600
|
+
this.triageQueue.push({
|
|
601
|
+
execute,
|
|
602
|
+
repository: input.repository,
|
|
603
|
+
runId,
|
|
587
604
|
});
|
|
605
|
+
this.drainTriageQueue();
|
|
588
606
|
return state;
|
|
589
607
|
}
|
|
608
|
+
drainPrQueue() {
|
|
609
|
+
while (this.prQueue.length) {
|
|
610
|
+
const next = this.prQueue[0];
|
|
611
|
+
if (!next)
|
|
612
|
+
return;
|
|
613
|
+
if (this.activePrRuns >= next.repository.concurrency.runs)
|
|
614
|
+
return;
|
|
615
|
+
this.prQueue.shift();
|
|
616
|
+
const state = this.active.get(next.runId);
|
|
617
|
+
if (!state || state.status === "cancelled")
|
|
618
|
+
continue;
|
|
619
|
+
this.activePrRuns += 1;
|
|
620
|
+
void next
|
|
621
|
+
.execute()
|
|
622
|
+
.catch(async (error) => {
|
|
623
|
+
await this.failRun(next.runId, error);
|
|
624
|
+
})
|
|
625
|
+
.finally(() => {
|
|
626
|
+
this.activePrRuns -= 1;
|
|
627
|
+
this.drainPrQueue();
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
drainTriageQueue() {
|
|
632
|
+
while (this.triageQueue.length) {
|
|
633
|
+
const next = this.triageQueue[0];
|
|
634
|
+
if (!next)
|
|
635
|
+
return;
|
|
636
|
+
const limit = next.repository.triage?.concurrency.runs ?? 1;
|
|
637
|
+
if (this.activeTriageRuns >= limit)
|
|
638
|
+
return;
|
|
639
|
+
this.triageQueue.shift();
|
|
640
|
+
const state = this.active.get(next.runId);
|
|
641
|
+
if (!state || state.status === "cancelled")
|
|
642
|
+
continue;
|
|
643
|
+
this.activeTriageRuns += 1;
|
|
644
|
+
void next
|
|
645
|
+
.execute()
|
|
646
|
+
.catch(async (error) => {
|
|
647
|
+
await this.failRun(next.runId, error);
|
|
648
|
+
})
|
|
649
|
+
.finally(() => {
|
|
650
|
+
this.activeTriageRuns -= 1;
|
|
651
|
+
this.drainTriageQueue();
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
}
|
|
590
655
|
async status(input = {}) {
|
|
591
|
-
const timeoutMs =
|
|
656
|
+
const timeoutMs = input.timeoutMs;
|
|
592
657
|
const startedAt = Date.now();
|
|
593
658
|
while (input.block) {
|
|
594
659
|
const states = await this.filteredStates(input);
|
|
@@ -596,7 +661,7 @@ export class MagiRunManager {
|
|
|
596
661
|
hasAllRequestedPrStates(states, input.pr) &&
|
|
597
662
|
states.every((state) => !isActiveStatus(state.status)))
|
|
598
663
|
return states;
|
|
599
|
-
if (Date.now() - startedAt >= timeoutMs)
|
|
664
|
+
if (timeoutMs != null && Date.now() - startedAt >= timeoutMs)
|
|
600
665
|
return states;
|
|
601
666
|
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
602
667
|
}
|
|
@@ -648,53 +713,7 @@ export class MagiRunManager {
|
|
|
648
713
|
state.status = "cancelled";
|
|
649
714
|
state.phase = "cancelled";
|
|
650
715
|
state.completedAt = now();
|
|
651
|
-
|
|
652
|
-
state.editor?.status === "running" ||
|
|
653
|
-
state.editor?.status === "repairing") {
|
|
654
|
-
state.editor.status = "cancelled";
|
|
655
|
-
}
|
|
656
|
-
if (state.editor?.sessionId) {
|
|
657
|
-
await this.input.client.session
|
|
658
|
-
.abort?.({ path: { id: state.editor.sessionId } })
|
|
659
|
-
.catch(() => undefined);
|
|
660
|
-
}
|
|
661
|
-
if (state.triageCreator?.status === "pending" ||
|
|
662
|
-
state.triageCreator?.status === "running" ||
|
|
663
|
-
state.triageCreator?.status === "repairing" ||
|
|
664
|
-
state.triageCreator?.status === "blocked") {
|
|
665
|
-
state.triageCreator.status = "cancelled";
|
|
666
|
-
}
|
|
667
|
-
if (state.triageCreator?.sessionId) {
|
|
668
|
-
await this.input.client.session
|
|
669
|
-
.abort?.({ path: { id: state.triageCreator.sessionId } })
|
|
670
|
-
.catch(() => undefined);
|
|
671
|
-
}
|
|
672
|
-
for (const reviewer of Object.values(state.reviewers)) {
|
|
673
|
-
if (reviewer.status === "pending" ||
|
|
674
|
-
reviewer.status === "running" ||
|
|
675
|
-
reviewer.status === "repairing" ||
|
|
676
|
-
reviewer.status === "blocked") {
|
|
677
|
-
reviewer.status = "cancelled";
|
|
678
|
-
}
|
|
679
|
-
if (reviewer.sessionId) {
|
|
680
|
-
await this.input.client.session
|
|
681
|
-
.abort?.({ path: { id: reviewer.sessionId } })
|
|
682
|
-
.catch(() => undefined);
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
for (const classifier of Object.values(state.ciClassifiers ?? {})) {
|
|
686
|
-
if (classifier.status === "pending" ||
|
|
687
|
-
classifier.status === "running" ||
|
|
688
|
-
classifier.status === "repairing" ||
|
|
689
|
-
classifier.status === "blocked") {
|
|
690
|
-
classifier.status = "cancelled";
|
|
691
|
-
}
|
|
692
|
-
if (classifier.sessionId) {
|
|
693
|
-
await this.input.client.session
|
|
694
|
-
.abort?.({ path: { id: classifier.sessionId } })
|
|
695
|
-
.catch(() => undefined);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
716
|
+
await this.finishActiveAgents(state, "cancelled");
|
|
698
717
|
if (state.worktreePath) {
|
|
699
718
|
await removeWorktree(this.input.exec, state.worktreePath).catch(() => undefined);
|
|
700
719
|
}
|
|
@@ -1195,6 +1214,26 @@ export class MagiRunManager {
|
|
|
1195
1214
|
...Object.entries(state.reviewers),
|
|
1196
1215
|
];
|
|
1197
1216
|
}
|
|
1217
|
+
isActiveAgent(agent) {
|
|
1218
|
+
return (agent.status === "pending" ||
|
|
1219
|
+
agent.status === "running" ||
|
|
1220
|
+
agent.status === "repairing" ||
|
|
1221
|
+
agent.status === "blocked");
|
|
1222
|
+
}
|
|
1223
|
+
async finishActiveAgents(state, status, error) {
|
|
1224
|
+
for (const [, agent] of this.agentEntries(state)) {
|
|
1225
|
+
if (this.isActiveAgent(agent)) {
|
|
1226
|
+
agent.status = status;
|
|
1227
|
+
if (error != null)
|
|
1228
|
+
agent.error = error;
|
|
1229
|
+
}
|
|
1230
|
+
if (agent.sessionId) {
|
|
1231
|
+
await this.input.client.session
|
|
1232
|
+
.abort?.({ path: { id: agent.sessionId } })
|
|
1233
|
+
.catch(() => undefined);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1198
1237
|
selectPendingAgent(state, kind, key, requestId) {
|
|
1199
1238
|
const entries = key
|
|
1200
1239
|
? this.agentState(state, key)
|
|
@@ -1220,19 +1259,24 @@ export class MagiRunManager {
|
|
|
1220
1259
|
hasBlockedAgents(state) {
|
|
1221
1260
|
return this.agentEntries(state).some(([, agent]) => agent.status === "blocked");
|
|
1222
1261
|
}
|
|
1223
|
-
async executeSync(state, controller, execute) {
|
|
1262
|
+
async executeSync(state, controller, execute, timeoutMs) {
|
|
1224
1263
|
let timeout;
|
|
1225
|
-
const timeoutPromise =
|
|
1226
|
-
|
|
1227
|
-
|
|
1264
|
+
const timeoutPromise = timeoutMs == null
|
|
1265
|
+
? undefined
|
|
1266
|
+
: new Promise((resolve) => {
|
|
1267
|
+
timeout = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
1268
|
+
});
|
|
1228
1269
|
try {
|
|
1229
|
-
const result = await
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1270
|
+
const result = await (timeoutPromise
|
|
1271
|
+
? Promise.race([
|
|
1272
|
+
execute().then(() => "completed"),
|
|
1273
|
+
timeoutPromise,
|
|
1274
|
+
])
|
|
1275
|
+
: execute().then(() => "completed"));
|
|
1233
1276
|
if (result === "timeout") {
|
|
1277
|
+
const timeoutSeconds = (timeoutMs ?? 0) / 1_000;
|
|
1234
1278
|
controller.abort();
|
|
1235
|
-
await this.failRun(state.runId, new Error(
|
|
1279
|
+
await this.failRun(state.runId, new Error(`Magi sync run timed out after ${timeoutSeconds} seconds.`));
|
|
1236
1280
|
}
|
|
1237
1281
|
}
|
|
1238
1282
|
catch (error) {
|
|
@@ -1259,6 +1303,7 @@ export class MagiRunManager {
|
|
|
1259
1303
|
dryRun: input.dryRun,
|
|
1260
1304
|
exec: withGitHubApiRetry(this.input.exec, input.config.github?.apiRetryAttempts ?? 3),
|
|
1261
1305
|
onProgress: (progress) => this.applyReviewProgress(input.runId, progress),
|
|
1306
|
+
parentSessionId: input.parentSessionId,
|
|
1262
1307
|
pr: input.pr,
|
|
1263
1308
|
repository: input.repository,
|
|
1264
1309
|
runId: input.runId,
|
|
@@ -1314,6 +1359,7 @@ export class MagiRunManager {
|
|
|
1314
1359
|
dryRun: input.dryRun,
|
|
1315
1360
|
exec: withGitHubApiRetry(this.input.exec, input.config.github?.apiRetryAttempts ?? 3),
|
|
1316
1361
|
onProgress: (progress) => this.applyMergeProgress(input.runId, progress),
|
|
1362
|
+
parentSessionId: input.parentSessionId,
|
|
1317
1363
|
pr: input.pr,
|
|
1318
1364
|
repository: input.repository,
|
|
1319
1365
|
runId: input.runId,
|
|
@@ -1355,6 +1401,7 @@ export class MagiRunManager {
|
|
|
1355
1401
|
exec: withGitHubApiRetry(this.input.exec, input.config.github?.apiRetryAttempts ?? 3),
|
|
1356
1402
|
issue: input.issue,
|
|
1357
1403
|
onProgress: (progress) => this.applyTriageProgress(input.runId, progress),
|
|
1404
|
+
parentSessionId: input.parentSessionId,
|
|
1358
1405
|
repository: input.repository,
|
|
1359
1406
|
runId: input.runId,
|
|
1360
1407
|
signal: input.signal,
|
|
@@ -1395,6 +1442,7 @@ export class MagiRunManager {
|
|
|
1395
1442
|
repository: input.repository,
|
|
1396
1443
|
signal: input.signal,
|
|
1397
1444
|
sync: input.sync,
|
|
1445
|
+
timeoutMs: input.timeoutMs,
|
|
1398
1446
|
});
|
|
1399
1447
|
if (input.sync)
|
|
1400
1448
|
this.assertSuccessfulSyncFollowUp(followUp);
|
|
@@ -1408,6 +1456,7 @@ export class MagiRunManager {
|
|
|
1408
1456
|
repository: input.repository,
|
|
1409
1457
|
signal: input.signal,
|
|
1410
1458
|
sync: input.sync,
|
|
1459
|
+
timeoutMs: input.timeoutMs,
|
|
1411
1460
|
});
|
|
1412
1461
|
if (input.sync)
|
|
1413
1462
|
this.assertSuccessfulSyncFollowUp(followUp);
|
|
@@ -1451,57 +1500,69 @@ export class MagiRunManager {
|
|
|
1451
1500
|
state.worktreePath = progress.worktreePath;
|
|
1452
1501
|
state.worktreeBranch = progress.branch;
|
|
1453
1502
|
}
|
|
1503
|
+
if (progress.type === "triage_session") {
|
|
1504
|
+
if (progress.options)
|
|
1505
|
+
this.input.setSessionOptions?.(progress.sessionId, progress.options);
|
|
1506
|
+
state.sessionIds = {
|
|
1507
|
+
...state.sessionIds,
|
|
1508
|
+
[progress.key]: progress.sessionId,
|
|
1509
|
+
};
|
|
1510
|
+
this.sessionToRun.set(progress.sessionId, {
|
|
1511
|
+
agent: progress.agent,
|
|
1512
|
+
runId,
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1454
1515
|
if (progress.type === "triage_agent_started") {
|
|
1455
|
-
const
|
|
1456
|
-
if (
|
|
1457
|
-
|
|
1516
|
+
const voter = state.reviewers[progress.voter];
|
|
1517
|
+
if (voter)
|
|
1518
|
+
voter.status = "running";
|
|
1458
1519
|
}
|
|
1459
1520
|
if (progress.type === "triage_agent_session") {
|
|
1460
|
-
const
|
|
1461
|
-
if (
|
|
1521
|
+
const voter = state.reviewers[progress.voter];
|
|
1522
|
+
if (voter) {
|
|
1462
1523
|
if (progress.options)
|
|
1463
1524
|
this.input.setSessionOptions?.(progress.sessionId, progress.options);
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1525
|
+
voter.sessionId = progress.sessionId;
|
|
1526
|
+
voter.status = "running";
|
|
1527
|
+
voter.lastUpdate = now();
|
|
1467
1528
|
this.sessionToRun.set(progress.sessionId, {
|
|
1468
|
-
agent: progress.
|
|
1529
|
+
agent: progress.voter,
|
|
1469
1530
|
runId,
|
|
1470
1531
|
});
|
|
1471
1532
|
}
|
|
1472
1533
|
}
|
|
1473
1534
|
if (progress.type === "triage_agent_repair") {
|
|
1474
|
-
const
|
|
1475
|
-
if (
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1535
|
+
const voter = state.reviewers[progress.voter];
|
|
1536
|
+
if (voter) {
|
|
1537
|
+
voter.status = "repairing";
|
|
1538
|
+
voter.repairAttempts += 1;
|
|
1539
|
+
voter.lastUpdate = now();
|
|
1479
1540
|
}
|
|
1480
1541
|
}
|
|
1481
1542
|
if (progress.type === "triage_agent_response") {
|
|
1482
|
-
const
|
|
1483
|
-
if (
|
|
1484
|
-
|
|
1485
|
-
|
|
1543
|
+
const voter = state.reviewers[progress.voter];
|
|
1544
|
+
if (voter) {
|
|
1545
|
+
voter.sessionId = progress.sessionId;
|
|
1546
|
+
voter.lastUpdate = now();
|
|
1486
1547
|
}
|
|
1487
1548
|
}
|
|
1488
1549
|
if (progress.type === "triage_agent_completed") {
|
|
1489
|
-
const
|
|
1490
|
-
if (
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1550
|
+
const voter = state.reviewers[progress.voter];
|
|
1551
|
+
if (voter) {
|
|
1552
|
+
voter.sessionId = progress.sessionId;
|
|
1553
|
+
voter.status = "completed";
|
|
1554
|
+
voter.verdict = progress.vote;
|
|
1555
|
+
voter.rawPath = join(state.outputDir, `${progress.voter}.${progress.phase}.raw.txt`);
|
|
1556
|
+
voter.parsedPath = join(state.outputDir, `${progress.voter}.${progress.phase}.json`);
|
|
1557
|
+
voter.lastUpdate = now();
|
|
1497
1558
|
}
|
|
1498
1559
|
}
|
|
1499
1560
|
if (progress.type === "triage_agent_failed") {
|
|
1500
|
-
const
|
|
1501
|
-
if (
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1561
|
+
const voter = state.reviewers[progress.voter];
|
|
1562
|
+
if (voter) {
|
|
1563
|
+
voter.status = "failed";
|
|
1564
|
+
voter.error = redactSecrets(progress.error);
|
|
1565
|
+
voter.lastUpdate = now();
|
|
1505
1566
|
}
|
|
1506
1567
|
}
|
|
1507
1568
|
if (progress.type === "triage_creator_started") {
|
|
@@ -1555,16 +1616,16 @@ export class MagiRunManager {
|
|
|
1555
1616
|
}));
|
|
1556
1617
|
}
|
|
1557
1618
|
if (progress.type === "triage_agent_started") {
|
|
1558
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1619
|
+
await this.notify(state, `**Triage agent ${progress.voter}** started ${progress.phase} for ${issue}.`);
|
|
1559
1620
|
}
|
|
1560
1621
|
if (progress.type === "triage_agent_repair") {
|
|
1561
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1622
|
+
await this.notify(state, `**Triage agent ${progress.voter}** started JSON regeneration for ${issue}.`);
|
|
1562
1623
|
}
|
|
1563
1624
|
if (progress.type === "triage_agent_completed") {
|
|
1564
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1625
|
+
await this.notify(state, `**Triage agent ${progress.voter}** completed ${progress.phase} for ${issue}: ${progress.vote}.`);
|
|
1565
1626
|
}
|
|
1566
1627
|
if (progress.type === "triage_agent_failed") {
|
|
1567
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1628
|
+
await this.notify(state, `**Triage agent ${progress.voter}** failed ${progress.phase} for ${issue}: ${redactSecrets(progress.error)}`);
|
|
1568
1629
|
}
|
|
1569
1630
|
if (progress.type === "comment_posting") {
|
|
1570
1631
|
await this.notify(state, `Posting triage comment for ${issue}.`);
|
|
@@ -1649,9 +1710,8 @@ export class MagiRunManager {
|
|
|
1649
1710
|
if (progress.type === "ci_classifier_completed") {
|
|
1650
1711
|
const classifier = state.ciClassifiers?.[progress.reviewer];
|
|
1651
1712
|
if (classifier) {
|
|
1652
|
-
classifier.
|
|
1713
|
+
classifier.checks = progress.checks;
|
|
1653
1714
|
classifier.rawPath = progress.rawPath;
|
|
1654
|
-
classifier.reason = progress.reason;
|
|
1655
1715
|
classifier.sessionId = progress.sessionId;
|
|
1656
1716
|
classifier.status = "completed";
|
|
1657
1717
|
classifier.lastUpdate = now();
|
|
@@ -1759,7 +1819,11 @@ export class MagiRunManager {
|
|
|
1759
1819
|
await this.notify(state, `**CI classifier ${progress.reviewer}** started JSON regeneration for ${prMarkdownLink(state)}.`);
|
|
1760
1820
|
}
|
|
1761
1821
|
if (progress.type === "ci_classifier_completed") {
|
|
1762
|
-
await this.notify(state,
|
|
1822
|
+
await this.notify(state, ciClassifierCompletedText({
|
|
1823
|
+
checks: progress.checks,
|
|
1824
|
+
pr: prMarkdownLink(state),
|
|
1825
|
+
reviewer: progress.reviewer,
|
|
1826
|
+
}));
|
|
1763
1827
|
}
|
|
1764
1828
|
if (progress.type === "ci_classifier_failed") {
|
|
1765
1829
|
await this.notify(state, `**CI classifier ${progress.reviewer}** failed for ${prMarkdownLink(state)}: ${redactSecrets(progress.error)}`);
|
|
@@ -1928,46 +1992,7 @@ export class MagiRunManager {
|
|
|
1928
1992
|
state.phase = "failed";
|
|
1929
1993
|
state.completedAt = now();
|
|
1930
1994
|
state.error = errorMessage(error);
|
|
1931
|
-
|
|
1932
|
-
state.editor?.status === "running" ||
|
|
1933
|
-
state.editor?.status === "repairing" ||
|
|
1934
|
-
state.editor?.status === "blocked") {
|
|
1935
|
-
state.editor.status = "failed";
|
|
1936
|
-
state.editor.error = state.error;
|
|
1937
|
-
}
|
|
1938
|
-
if (state.editor?.sessionId) {
|
|
1939
|
-
await this.input.client.session
|
|
1940
|
-
.abort?.({ path: { id: state.editor.sessionId } })
|
|
1941
|
-
.catch(() => undefined);
|
|
1942
|
-
}
|
|
1943
|
-
for (const reviewer of Object.values(state.reviewers)) {
|
|
1944
|
-
if (reviewer.status === "pending" ||
|
|
1945
|
-
reviewer.status === "running" ||
|
|
1946
|
-
reviewer.status === "repairing" ||
|
|
1947
|
-
reviewer.status === "blocked") {
|
|
1948
|
-
reviewer.status = "failed";
|
|
1949
|
-
reviewer.error = state.error;
|
|
1950
|
-
}
|
|
1951
|
-
if (reviewer.sessionId) {
|
|
1952
|
-
await this.input.client.session
|
|
1953
|
-
.abort?.({ path: { id: reviewer.sessionId } })
|
|
1954
|
-
.catch(() => undefined);
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
for (const classifier of Object.values(state.ciClassifiers ?? {})) {
|
|
1958
|
-
if (classifier.status === "pending" ||
|
|
1959
|
-
classifier.status === "running" ||
|
|
1960
|
-
classifier.status === "repairing" ||
|
|
1961
|
-
classifier.status === "blocked") {
|
|
1962
|
-
classifier.status = "failed";
|
|
1963
|
-
classifier.error = state.error;
|
|
1964
|
-
}
|
|
1965
|
-
if (classifier.sessionId) {
|
|
1966
|
-
await this.input.client.session
|
|
1967
|
-
.abort?.({ path: { id: classifier.sessionId } })
|
|
1968
|
-
.catch(() => undefined);
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1995
|
+
await this.finishActiveAgents(state, "failed", state.error);
|
|
1971
1996
|
await this.persist(state);
|
|
1972
1997
|
await this.notify(state, `Magi ${state.command} failed for ${runLabel(state)}: ${state.error}`, { reply: true });
|
|
1973
1998
|
this.active.delete(runId);
|