@taskless-app/swarm 0.6.26 → 0.6.27
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/cli.js +35 -22
- package/dist/overmind.js +301 -79
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -340,26 +340,6 @@ var init_timeline = __esm({
|
|
|
340
340
|
}
|
|
341
341
|
});
|
|
342
342
|
|
|
343
|
-
// ../swarm-core/src/reviewPhase.ts
|
|
344
|
-
var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
|
|
345
|
-
var init_reviewPhase = __esm({
|
|
346
|
-
"../swarm-core/src/reviewPhase.ts"() {
|
|
347
|
-
"use strict";
|
|
348
|
-
REVIEW_PHASE_TEXT = {
|
|
349
|
-
checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
|
|
350
|
-
awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
|
|
351
|
-
ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
|
|
352
|
-
in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
|
|
353
|
-
changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
|
|
354
|
-
ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
|
|
355
|
-
reviewer_dead: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u0443\u043C\u0435\u0440 \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435\u0442, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A"
|
|
356
|
-
};
|
|
357
|
-
PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
|
|
358
|
-
(a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
|
|
363
343
|
// ../swarm-core/src/verifyVerdict.ts
|
|
364
344
|
function isVerifyVerdict(v) {
|
|
365
345
|
return typeof v === "string" && VERIFY_VERDICT_SET.has(v);
|
|
@@ -428,6 +408,31 @@ var init_verifyVerdict = __esm({
|
|
|
428
408
|
}
|
|
429
409
|
});
|
|
430
410
|
|
|
411
|
+
// ../swarm-core/src/reviewPhase.ts
|
|
412
|
+
var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
|
|
413
|
+
var init_reviewPhase = __esm({
|
|
414
|
+
"../swarm-core/src/reviewPhase.ts"() {
|
|
415
|
+
"use strict";
|
|
416
|
+
init_verifyVerdict();
|
|
417
|
+
REVIEW_PHASE_TEXT = {
|
|
418
|
+
checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
|
|
419
|
+
awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
|
|
420
|
+
ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
|
|
421
|
+
in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
|
|
422
|
+
changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
|
|
423
|
+
verify_found: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0430\u0448\u0451\u043B \u2014 \u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438",
|
|
424
|
+
verify_not_reproduced: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0435 \u0432\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0451\u043B \u2014 \u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438",
|
|
425
|
+
awaiting_verify: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u043C \u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E",
|
|
426
|
+
verify_dead: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0435 \u0434\u0430\u043B \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u2014 \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A",
|
|
427
|
+
ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
|
|
428
|
+
reviewer_dead: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u0443\u043C\u0435\u0440 \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435\u0442, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A"
|
|
429
|
+
};
|
|
430
|
+
PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
|
|
431
|
+
(a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
431
436
|
// ../swarm-core/src/mergeGate.ts
|
|
432
437
|
function computeMergeGate(input) {
|
|
433
438
|
if (!input.hasRun) {
|
|
@@ -1619,6 +1624,13 @@ var init_zoneMemory = __esm({
|
|
|
1619
1624
|
}
|
|
1620
1625
|
});
|
|
1621
1626
|
|
|
1627
|
+
// ../swarm-core/src/taskPrs.ts
|
|
1628
|
+
var init_taskPrs = __esm({
|
|
1629
|
+
"../swarm-core/src/taskPrs.ts"() {
|
|
1630
|
+
"use strict";
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1622
1634
|
// ../swarm-core/src/index.ts
|
|
1623
1635
|
var init_src = __esm({
|
|
1624
1636
|
"../swarm-core/src/index.ts"() {
|
|
@@ -1653,6 +1665,7 @@ var init_src = __esm({
|
|
|
1653
1665
|
init_effort();
|
|
1654
1666
|
init_queuePlan();
|
|
1655
1667
|
init_zoneMemory();
|
|
1668
|
+
init_taskPrs();
|
|
1656
1669
|
}
|
|
1657
1670
|
});
|
|
1658
1671
|
|
|
@@ -3040,7 +3053,7 @@ var init_package = __esm({
|
|
|
3040
3053
|
"package.json"() {
|
|
3041
3054
|
package_default = {
|
|
3042
3055
|
name: "@taskless-app/swarm",
|
|
3043
|
-
version: "0.6.
|
|
3056
|
+
version: "0.6.27",
|
|
3044
3057
|
type: "module",
|
|
3045
3058
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3046
3059
|
keywords: [
|
|
@@ -3091,7 +3104,7 @@ var init_package = __esm({
|
|
|
3091
3104
|
execa: "^10.0.0",
|
|
3092
3105
|
zod: "3.25.76"
|
|
3093
3106
|
},
|
|
3094
|
-
gitHead: "
|
|
3107
|
+
gitHead: "2e1ed83014422ae577be60271adc79e291b9e2ab"
|
|
3095
3108
|
};
|
|
3096
3109
|
}
|
|
3097
3110
|
});
|
package/dist/overmind.js
CHANGED
|
@@ -309,52 +309,6 @@ var init_timeline = __esm({
|
|
|
309
309
|
}
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
-
// ../swarm-core/src/reviewPhase.ts
|
|
313
|
-
function computeReviewPhase(input) {
|
|
314
|
-
const { reviewVerdict, ciRed } = input;
|
|
315
|
-
if (reviewVerdict === "approve" && !ciRed) {
|
|
316
|
-
return { kind: "ready", label: REVIEW_PHASE_TEXT.ready, ready: true };
|
|
317
|
-
}
|
|
318
|
-
if (ciRed) {
|
|
319
|
-
const jobs = (input.ciFailing ?? []).filter((j) => j && j !== "?");
|
|
320
|
-
const label3 = jobs.length ? `${REVIEW_PHASE_TEXT.ci_fixing}: ${jobs.join(", ")}` : REVIEW_PHASE_TEXT.ci_fixing;
|
|
321
|
-
return { kind: "ci_fixing", label: label3, ready: false };
|
|
322
|
-
}
|
|
323
|
-
if (reviewVerdict === "changes") {
|
|
324
|
-
return { kind: "changes", label: REVIEW_PHASE_TEXT.changes, ready: false };
|
|
325
|
-
}
|
|
326
|
-
if (input.reviewerName) {
|
|
327
|
-
return { kind: "in_review", label: `\u041D\u0430 \u0440\u0435\u0432\u044C\u044E \u0443 ${input.reviewerName}`, ready: false };
|
|
328
|
-
}
|
|
329
|
-
if (input.reviewerDead) {
|
|
330
|
-
return { kind: "reviewer_dead", label: REVIEW_PHASE_TEXT.reviewer_dead, ready: true };
|
|
331
|
-
}
|
|
332
|
-
const p = input.ciProgress;
|
|
333
|
-
if (p && p.total > 0 && p.pass >= p.total) {
|
|
334
|
-
return { kind: "awaiting_reviewer", label: REVIEW_PHASE_TEXT.awaiting_reviewer, ready: false };
|
|
335
|
-
}
|
|
336
|
-
const label2 = p && p.total > 0 ? `${REVIEW_PHASE_TEXT.checks} \u2014 CI ${p.pass}/${p.total}` : REVIEW_PHASE_TEXT.checks;
|
|
337
|
-
return { kind: "checks", label: label2, ready: false };
|
|
338
|
-
}
|
|
339
|
-
var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
|
|
340
|
-
var init_reviewPhase = __esm({
|
|
341
|
-
"../swarm-core/src/reviewPhase.ts"() {
|
|
342
|
-
"use strict";
|
|
343
|
-
REVIEW_PHASE_TEXT = {
|
|
344
|
-
checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
|
|
345
|
-
awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
|
|
346
|
-
ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
|
|
347
|
-
in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
|
|
348
|
-
changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
|
|
349
|
-
ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
|
|
350
|
-
reviewer_dead: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u0443\u043C\u0435\u0440 \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435\u0442, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A"
|
|
351
|
-
};
|
|
352
|
-
PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
|
|
353
|
-
(a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
|
|
358
312
|
// ../swarm-core/src/verifyVerdict.ts
|
|
359
313
|
function isVerifyVerdict(v) {
|
|
360
314
|
return typeof v === "string" && VERIFY_VERDICT_SET.has(v);
|
|
@@ -402,6 +356,68 @@ var init_verifyVerdict = __esm({
|
|
|
402
356
|
}
|
|
403
357
|
});
|
|
404
358
|
|
|
359
|
+
// ../swarm-core/src/reviewPhase.ts
|
|
360
|
+
function computeReviewPhase(input) {
|
|
361
|
+
const { reviewVerdict, ciRed } = input;
|
|
362
|
+
const verifyVerdict = input.verifyVerdict ?? null;
|
|
363
|
+
if (!ciRed && isNegativeVerifyVerdict(verifyVerdict)) {
|
|
364
|
+
const kind = verifyVerdict === "found_issues" ? "verify_found" : "verify_not_reproduced";
|
|
365
|
+
return { kind, label: REVIEW_PHASE_TEXT[kind], ready: false };
|
|
366
|
+
}
|
|
367
|
+
if (reviewVerdict === "approve" && !ciRed) {
|
|
368
|
+
if (verifyVerdict === "confirmed" || input.verifyExpected === false) {
|
|
369
|
+
return { kind: "ready", label: REVIEW_PHASE_TEXT.ready, ready: true };
|
|
370
|
+
}
|
|
371
|
+
if (input.verifierDead) {
|
|
372
|
+
return { kind: "verify_dead", label: REVIEW_PHASE_TEXT.verify_dead, ready: true };
|
|
373
|
+
}
|
|
374
|
+
return { kind: "awaiting_verify", label: REVIEW_PHASE_TEXT.awaiting_verify, ready: false };
|
|
375
|
+
}
|
|
376
|
+
if (ciRed) {
|
|
377
|
+
const jobs = (input.ciFailing ?? []).filter((j) => j && j !== "?");
|
|
378
|
+
const label3 = jobs.length ? `${REVIEW_PHASE_TEXT.ci_fixing}: ${jobs.join(", ")}` : REVIEW_PHASE_TEXT.ci_fixing;
|
|
379
|
+
return { kind: "ci_fixing", label: label3, ready: false };
|
|
380
|
+
}
|
|
381
|
+
if (reviewVerdict === "changes") {
|
|
382
|
+
return { kind: "changes", label: REVIEW_PHASE_TEXT.changes, ready: false };
|
|
383
|
+
}
|
|
384
|
+
if (input.reviewerName) {
|
|
385
|
+
return { kind: "in_review", label: `\u041D\u0430 \u0440\u0435\u0432\u044C\u044E \u0443 ${input.reviewerName}`, ready: false };
|
|
386
|
+
}
|
|
387
|
+
if (input.reviewerDead) {
|
|
388
|
+
return { kind: "reviewer_dead", label: REVIEW_PHASE_TEXT.reviewer_dead, ready: true };
|
|
389
|
+
}
|
|
390
|
+
const p = input.ciProgress;
|
|
391
|
+
if (p && p.total > 0 && p.pass >= p.total) {
|
|
392
|
+
return { kind: "awaiting_reviewer", label: REVIEW_PHASE_TEXT.awaiting_reviewer, ready: false };
|
|
393
|
+
}
|
|
394
|
+
const label2 = p && p.total > 0 ? `${REVIEW_PHASE_TEXT.checks} \u2014 CI ${p.pass}/${p.total}` : REVIEW_PHASE_TEXT.checks;
|
|
395
|
+
return { kind: "checks", label: label2, ready: false };
|
|
396
|
+
}
|
|
397
|
+
var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
|
|
398
|
+
var init_reviewPhase = __esm({
|
|
399
|
+
"../swarm-core/src/reviewPhase.ts"() {
|
|
400
|
+
"use strict";
|
|
401
|
+
init_verifyVerdict();
|
|
402
|
+
REVIEW_PHASE_TEXT = {
|
|
403
|
+
checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
|
|
404
|
+
awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
|
|
405
|
+
ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
|
|
406
|
+
in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
|
|
407
|
+
changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
|
|
408
|
+
verify_found: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0430\u0448\u0451\u043B \u2014 \u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438",
|
|
409
|
+
verify_not_reproduced: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0435 \u0432\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0451\u043B \u2014 \u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438",
|
|
410
|
+
awaiting_verify: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u043C \u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E",
|
|
411
|
+
verify_dead: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0435 \u0434\u0430\u043B \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u2014 \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A",
|
|
412
|
+
ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
|
|
413
|
+
reviewer_dead: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u0443\u043C\u0435\u0440 \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435\u0442, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A"
|
|
414
|
+
};
|
|
415
|
+
PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
|
|
416
|
+
(a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
405
421
|
// ../swarm-core/src/mergeGate.ts
|
|
406
422
|
function computeMergeGate(input) {
|
|
407
423
|
if (!input.hasRun) {
|
|
@@ -1709,6 +1725,57 @@ var init_zoneMemory = __esm({
|
|
|
1709
1725
|
}
|
|
1710
1726
|
});
|
|
1711
1727
|
|
|
1728
|
+
// ../swarm-core/src/taskPrs.ts
|
|
1729
|
+
function normalizePrUrl(raw) {
|
|
1730
|
+
const s = (raw ?? "").trim();
|
|
1731
|
+
if (!s) return null;
|
|
1732
|
+
const m = s.match(/^(?:https?:\/\/)?(?:www\.)?github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/(\d+)/i);
|
|
1733
|
+
if (!m) return s.replace(/\/+$/, "").toLowerCase();
|
|
1734
|
+
return `github.com/${m[1]}/${m[2]}/pull/${m[3]}`.toLowerCase();
|
|
1735
|
+
}
|
|
1736
|
+
function samePr(a, b) {
|
|
1737
|
+
const x = normalizePrUrl(a);
|
|
1738
|
+
const y = normalizePrUrl(b);
|
|
1739
|
+
return x != null && y != null && x === y;
|
|
1740
|
+
}
|
|
1741
|
+
function prBelongsToTask(slug, pr) {
|
|
1742
|
+
const s = (slug ?? "").trim().toLowerCase();
|
|
1743
|
+
if (!s) return false;
|
|
1744
|
+
const branch = (pr.headRefName ?? "").trim().toLowerCase();
|
|
1745
|
+
if (branch === s || branch.startsWith(s) && /^[-/_.]/.test(branch.slice(s.length))) return true;
|
|
1746
|
+
const title = (pr.title ?? "").toLowerCase();
|
|
1747
|
+
if (!title.includes(s)) return false;
|
|
1748
|
+
const at = title.indexOf(s);
|
|
1749
|
+
const before = at > 0 ? title[at - 1] : "";
|
|
1750
|
+
const after = title[at + s.length] ?? "";
|
|
1751
|
+
return !/[a-z0-9]/.test(before) && !/[a-z0-9-]/.test(after);
|
|
1752
|
+
}
|
|
1753
|
+
function decideTaskWork(facts) {
|
|
1754
|
+
const candidate = (facts.mergedCandidate ?? "").trim() || null;
|
|
1755
|
+
const open = [];
|
|
1756
|
+
for (const raw of facts.openPrs ?? []) {
|
|
1757
|
+
const url = (raw ?? "").trim();
|
|
1758
|
+
if (!url) continue;
|
|
1759
|
+
if (!open.some((u) => samePr(u, url))) open.push(url);
|
|
1760
|
+
}
|
|
1761
|
+
if (open.length > 0) return { kind: "open", prs: open, candidate: candidate && !open.some((u) => samePr(u, candidate)) ? candidate : null };
|
|
1762
|
+
if (!candidate) return { kind: "unmerged" };
|
|
1763
|
+
return { kind: "merged", pr: candidate };
|
|
1764
|
+
}
|
|
1765
|
+
function formatMergedDuplicateReason(pr) {
|
|
1766
|
+
return `PR \u0437\u0430\u0434\u0430\u0447\u0438 \u0443\u0436\u0435 \u0441\u043C\u0435\u0440\u0436\u0435\u043D (${pr}) \u2014 \u043F\u0440\u043E\u0433\u043E\u043D-\u0434\u0443\u0431\u043B\u044C \u0437\u0430\u043A\u0440\u044B\u0442 \u0431\u0435\u0437 \u0441\u043F\u0430\u0432\u043D\u0430/\u0434\u043E\u0440\u0430\u0431\u043E\u0442\u043A\u0438 (TASWM-206)`;
|
|
1767
|
+
}
|
|
1768
|
+
function formatOpenPrHold(v) {
|
|
1769
|
+
const list = v.prs.join(", ");
|
|
1770
|
+
const tail2 = v.candidate ? ` (\u0441\u043C\u0435\u0440\u0436\u0435\u043D ${v.candidate}, \u043D\u043E \u044D\u0442\u043E \u043D\u0435 \u0432\u0441\u044F \u0440\u0430\u0431\u043E\u0442\u0430)` : "";
|
|
1771
|
+
return `\u0443 \u0437\u0430\u0434\u0430\u0447\u0438 \u043E\u0441\u0442\u0430\u043B\u0438\u0441\u044C \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 PR: ${list}${tail2} \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u0432\u043B\u0438\u0442\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C, \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0435\u043C \u0438 \u043F\u0440\u043E\u0433\u043E\u043D \u0434\u0443\u0431\u043B\u0435\u043C \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u043C (TASWM-515)`;
|
|
1772
|
+
}
|
|
1773
|
+
var init_taskPrs = __esm({
|
|
1774
|
+
"../swarm-core/src/taskPrs.ts"() {
|
|
1775
|
+
"use strict";
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
|
|
1712
1779
|
// ../swarm-core/src/index.ts
|
|
1713
1780
|
var init_src = __esm({
|
|
1714
1781
|
"../swarm-core/src/index.ts"() {
|
|
@@ -1743,6 +1810,7 @@ var init_src = __esm({
|
|
|
1743
1810
|
init_effort();
|
|
1744
1811
|
init_queuePlan();
|
|
1745
1812
|
init_zoneMemory();
|
|
1813
|
+
init_taskPrs();
|
|
1746
1814
|
}
|
|
1747
1815
|
});
|
|
1748
1816
|
|
|
@@ -11124,25 +11192,76 @@ var UNRETRIABLE_PARK_MARK = "\u043F\u043E\u0432\u0442\u043E\u0440 \u043D\u0435 \
|
|
|
11124
11192
|
function isUnretriableParked(run) {
|
|
11125
11193
|
return isPreStartFailure(run) && (run.stop_reason ?? "").includes(UNRETRIABLE_PARK_MARK);
|
|
11126
11194
|
}
|
|
11195
|
+
var PARK_APPLIED_MARK = "\u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u043D\u044F\u0442\u0430 \u0441 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u0440\u043E\u044F";
|
|
11196
|
+
var PARK_APPLIED_RE = new RegExp(`${PARK_APPLIED_MARK} \\(([^,)]+)(?:, \u043F\u0440\u043E\u0433\u043E\u043D\u044B \u043F\u043E #(\\d+))?\\)`);
|
|
11197
|
+
function withParkApplied(reason, at, upToRunId) {
|
|
11198
|
+
if (PARK_APPLIED_RE.test(reason)) return reason;
|
|
11199
|
+
const upTo = upToRunId != null ? `, \u043F\u0440\u043E\u0433\u043E\u043D\u044B \u043F\u043E #${upToRunId}` : "";
|
|
11200
|
+
return `${reason} \u2014 ${PARK_APPLIED_MARK} (${at}${upTo})`;
|
|
11201
|
+
}
|
|
11202
|
+
function parkApplied(run) {
|
|
11203
|
+
if (!run || !isParkApplied(run)) return null;
|
|
11204
|
+
const m = PARK_APPLIED_RE.exec(run.stop_reason ?? "");
|
|
11205
|
+
if (!m) return null;
|
|
11206
|
+
const ms = m[1] ? stampMs(m[1]) : Number.NaN;
|
|
11207
|
+
return {
|
|
11208
|
+
at: Number.isFinite(ms) ? ms : null,
|
|
11209
|
+
upToRunId: m[2] ? Number(m[2]) : null
|
|
11210
|
+
};
|
|
11211
|
+
}
|
|
11212
|
+
function lastRunIdFor(runs, taskSlug) {
|
|
11213
|
+
return ownRuns(runs, taskSlug).reduce((max, r) => Math.max(max, r.id), 0);
|
|
11214
|
+
}
|
|
11215
|
+
function isParkApplied(run) {
|
|
11216
|
+
return isPreStartFailure(run) && (run.stop_reason ?? "").includes(PARK_APPLIED_MARK);
|
|
11217
|
+
}
|
|
11218
|
+
var PARK_CAUSE_PREFIX = "\u0427\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0438\u043B\u043E: ";
|
|
11219
|
+
function parkedCause(run) {
|
|
11220
|
+
const at = (run?.stop_reason ?? "").indexOf(PARK_CAUSE_PREFIX);
|
|
11221
|
+
if (at < 0) return null;
|
|
11222
|
+
const cause = run.stop_reason.slice(at + PARK_CAUSE_PREFIX.length).replace(new RegExp(`\\s*\u2014\\s*${PARK_APPLIED_MARK} \\([^)]*\\)\\s*$`), "").trim();
|
|
11223
|
+
return cause || null;
|
|
11224
|
+
}
|
|
11127
11225
|
var SPAWN_ATTEMPT_WINDOW_MS = 60 * 6e4;
|
|
11226
|
+
function ownRuns(runs, taskSlug) {
|
|
11227
|
+
return runs.filter(
|
|
11228
|
+
(r) => r.task_slug === taskSlug && r.reviews_run_id == null && r.resolves_run_id == null && r.verifies_run_id == null
|
|
11229
|
+
);
|
|
11230
|
+
}
|
|
11231
|
+
function newestFirst(a, b) {
|
|
11232
|
+
const at = a.created_at ? stampMs(a.created_at) : Number.NaN;
|
|
11233
|
+
const bt = b.created_at ? stampMs(b.created_at) : Number.NaN;
|
|
11234
|
+
if (Number.isFinite(at) && Number.isFinite(bt) && at !== bt) return bt - at;
|
|
11235
|
+
return b.id - a.id;
|
|
11236
|
+
}
|
|
11128
11237
|
function preStartAttempts(runs, taskSlug, opts = {}) {
|
|
11129
11238
|
const windowMs = opts.windowMs ?? SPAWN_ATTEMPT_WINDOW_MS;
|
|
11130
11239
|
const now = opts.now ?? Date.now();
|
|
11131
|
-
const own = runs
|
|
11240
|
+
const own = ownRuns(runs, taskSlug).sort(newestFirst);
|
|
11132
11241
|
let n = 0;
|
|
11242
|
+
let newestCreatedAt = Number.NEGATIVE_INFINITY;
|
|
11243
|
+
let newestSeenId = Number.NEGATIVE_INFINITY;
|
|
11133
11244
|
for (const run of own) {
|
|
11245
|
+
const applied = parkApplied(run);
|
|
11246
|
+
if (applied) {
|
|
11247
|
+
const returned = applied.upToRunId != null ? newestSeenId > applied.upToRunId : applied.at != null && newestCreatedAt > applied.at;
|
|
11248
|
+
if (returned) break;
|
|
11249
|
+
}
|
|
11250
|
+
newestSeenId = Math.max(newestSeenId, run.id);
|
|
11251
|
+
const startedAt = run.created_at ? stampMs(run.created_at) : Number.NaN;
|
|
11252
|
+
if (Number.isFinite(startedAt)) newestCreatedAt = Math.max(newestCreatedAt, startedAt);
|
|
11134
11253
|
if (run.status === "queued" || run.status === "running") continue;
|
|
11135
11254
|
if (isSpawnParked(run) && run.status !== "failed") continue;
|
|
11136
11255
|
if (!isPreStartFailure(run)) break;
|
|
11137
|
-
|
|
11138
|
-
if (Number.isFinite(
|
|
11256
|
+
if (Number.isFinite(startedAt) && now - startedAt >= windowMs) break;
|
|
11257
|
+
if (opts.since != null && Number.isFinite(startedAt) && startedAt < opts.since) break;
|
|
11139
11258
|
n += 1;
|
|
11140
11259
|
if (isUnretriableParked(run)) return Math.max(n, PRE_START_ATTEMPT_LIMIT);
|
|
11141
11260
|
}
|
|
11142
11261
|
return n;
|
|
11143
11262
|
}
|
|
11144
11263
|
function lastPreStartAttempt(runs, taskSlug) {
|
|
11145
|
-
return runs.filter((r) => r.task_slug === taskSlug && isPreStartFailure(r)).sort(
|
|
11264
|
+
return runs.filter((r) => r.task_slug === taskSlug && isPreStartFailure(r)).sort(newestFirst)[0] ?? null;
|
|
11146
11265
|
}
|
|
11147
11266
|
function unresolvedRepoReason(repo, served) {
|
|
11148
11267
|
const raw = repo.trim();
|
|
@@ -11325,6 +11444,17 @@ async function mergedPrForBranch(branch, repoDir, run = realRepoRunner) {
|
|
|
11325
11444
|
return null;
|
|
11326
11445
|
}
|
|
11327
11446
|
}
|
|
11447
|
+
async function openPrsForTask(slug, repoDir, run = realRepoRunner) {
|
|
11448
|
+
if (!slug || !repoDir) return null;
|
|
11449
|
+
try {
|
|
11450
|
+
const out = await run(["pr", "list", "--state", "open", "--json", "url,headRefName,title", "--limit", "50"], repoDir);
|
|
11451
|
+
const arr = JSON.parse(out);
|
|
11452
|
+
if (!Array.isArray(arr)) return null;
|
|
11453
|
+
return arr.filter((p) => typeof p.url === "string" && prBelongsToTask(slug, { headRefName: p.headRefName, title: p.title })).map((p) => p.url);
|
|
11454
|
+
} catch {
|
|
11455
|
+
return null;
|
|
11456
|
+
}
|
|
11457
|
+
}
|
|
11328
11458
|
async function closePR(prUrl, run = realRunner) {
|
|
11329
11459
|
await run(["pr", "close", prUrl, "--comment", "\u043F\u0435\u0440\u0435\u0438\u0433\u0440\u0430\u043D \u043D\u0430 \u0434\u0440\u0443\u0433\u043E\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 (swarm)"]);
|
|
11330
11460
|
}
|
|
@@ -14074,7 +14204,7 @@ import { serve as serve2 } from "@hono/node-server";
|
|
|
14074
14204
|
// package.json
|
|
14075
14205
|
var package_default = {
|
|
14076
14206
|
name: "@taskless-app/swarm",
|
|
14077
|
-
version: "0.6.
|
|
14207
|
+
version: "0.6.27",
|
|
14078
14208
|
type: "module",
|
|
14079
14209
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
14080
14210
|
keywords: [
|
|
@@ -14125,7 +14255,7 @@ var package_default = {
|
|
|
14125
14255
|
execa: "^10.0.0",
|
|
14126
14256
|
zod: "3.25.76"
|
|
14127
14257
|
},
|
|
14128
|
-
gitHead: "
|
|
14258
|
+
gitHead: "2e1ed83014422ae577be60271adc79e291b9e2ab"
|
|
14129
14259
|
};
|
|
14130
14260
|
|
|
14131
14261
|
// src/version.ts
|
|
@@ -16625,6 +16755,7 @@ var RESPAWN_LIMIT = Number(process.env.SWARM_RESPAWN_LIMIT) || 2;
|
|
|
16625
16755
|
var RESPAWN_YOUNG_MS = Number(process.env.SWARM_RESPAWN_YOUNG_MS) || 60 * 1e3;
|
|
16626
16756
|
var EXITED_NO_DONE_REASON = "\u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u0441\u0430\u043C\u0430, done() \u043D\u0435 \u0432\u044B\u0437\u0432\u0430\u043D";
|
|
16627
16757
|
var ABORTED_STOP_REASON = "\u0441\u0435\u0441\u0441\u0438\u044F \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u0430\u0441\u044C, done() \u043D\u0435 \u0432\u044B\u0437\u0432\u0430\u043D";
|
|
16758
|
+
var SUBMITTED_EXIT_TEXT = "\u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C, \u043D\u043E \u0440\u0430\u0431\u043E\u0442\u0430 \u0443\u0436\u0435 \u0441\u0434\u0430\u043D\u0430 (PR \u043E\u0442\u043A\u0440\u044B\u0442, done() \u043F\u0440\u0438\u043D\u044F\u0442) \u2014 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u044E \u0432 \u0440\u0435\u0432\u044C\u044E, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u043D\u0435 \u043D\u0443\u0436\u0435\u043D";
|
|
16628
16759
|
var EXIT_WORK_PUSHED = "\u0432\u0435\u0442\u043A\u0430 \u0435\u0441\u0442\u044C \u043D\u0430 origin \u2014 \u0435\u0441\u0442\u044C \u0447\u0442\u043E \u0441\u043F\u0430\u0441\u0430\u0442\u044C, PR \u043D\u0435 \u043E\u0442\u043A\u0440\u044B\u0442";
|
|
16629
16760
|
var EXIT_WORK_LOST = "\u0432\u0435\u0442\u043A\u0438 \u043D\u0430 origin \u043D\u0435\u0442 \u2014 \u043D\u0435\u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u043E\u0435 \u043F\u043E\u0442\u0435\u0440\u044F\u043D\u043E";
|
|
16630
16761
|
var EXIT_WORK_UNKNOWN = "\u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C origin \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u2014 \u0446\u0435\u043B\u0430 \u043B\u0438 \u0440\u0430\u0431\u043E\u0442\u0430, \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E";
|
|
@@ -16757,7 +16888,7 @@ function lastCiCheckMs(db, runId) {
|
|
|
16757
16888
|
if (!evs.length) return null;
|
|
16758
16889
|
return Date.parse(evs[evs.length - 1].at.replace(" ", "T") + "Z");
|
|
16759
16890
|
}
|
|
16760
|
-
function reviewPhaseInputFor(deps, run) {
|
|
16891
|
+
function reviewPhaseInputFor(deps, run, projectWantsVerify = true) {
|
|
16761
16892
|
const events = deps.db.events(run.id);
|
|
16762
16893
|
let ciRed = false;
|
|
16763
16894
|
let ciFailing = [];
|
|
@@ -16782,20 +16913,35 @@ function reviewPhaseInputFor(deps, run) {
|
|
|
16782
16913
|
const attempts = deps.db.reviewerAttemptCountFor(run.id);
|
|
16783
16914
|
const lastAttempt = deps.db.lastReviewerAttemptFor(run.id);
|
|
16784
16915
|
const reviewerDead = !reviewer && run.review_verdict == null && attempts >= REVIEW_SPAWN_LIMIT && (lastAttempt?.status === "failed" || lastAttempt?.status === "stalled" || lastAttempt?.status === "stopped");
|
|
16916
|
+
const verifyExpected = deps.spawnVerifier != null && projectWantsVerify;
|
|
16917
|
+
const verifierDead = verifyExpected && run.verify_verdict == null && deps.db.verifierCountFor(run.id) === 0 && deps.db.verifierAttemptCountFor(run.id) >= VERIFY_SPAWN_LIMIT;
|
|
16785
16918
|
return {
|
|
16786
16919
|
reviewVerdict: run.review_verdict,
|
|
16787
16920
|
ciRed,
|
|
16788
16921
|
ciFailing,
|
|
16789
16922
|
ciProgress,
|
|
16790
16923
|
reviewerName: reviewer?.name ?? null,
|
|
16791
|
-
reviewerDead
|
|
16924
|
+
reviewerDead,
|
|
16925
|
+
verifyVerdict: run.verify_verdict,
|
|
16926
|
+
verifyExpected,
|
|
16927
|
+
verifierDead
|
|
16792
16928
|
};
|
|
16793
16929
|
}
|
|
16794
|
-
function refreshReviewPhases(deps) {
|
|
16795
|
-
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
16930
|
+
async function refreshReviewPhases(deps) {
|
|
16931
|
+
const runs = deps.db.listRuns("review").filter((r) => r.reviews_run_id == null && r.resolves_run_id == null && !!r.pr_url);
|
|
16932
|
+
const wantsChecks = /* @__PURE__ */ new Map();
|
|
16933
|
+
const needsAnswer = (r) => deps.spawnVerifier != null && r.review_verdict === "approve" && r.verify_verdict == null;
|
|
16934
|
+
for (const run of runs) {
|
|
16935
|
+
if (!needsAnswer(run) || wantsChecks.has(run.repo)) continue;
|
|
16936
|
+
try {
|
|
16937
|
+
wantsChecks.set(run.repo, await projectWantsChecks(deps, run));
|
|
16938
|
+
} catch (e) {
|
|
16939
|
+
console.warn(`[overmind] autoReview \u043F\u0440\u043E\u0435\u043A\u0442\u0430 (${run.repo}) \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D \u2014 \u0444\u0430\u0437\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0440\u0430\u043D\u044C\u0448\u0435:`, e);
|
|
16940
|
+
wantsChecks.set(run.repo, true);
|
|
16941
|
+
}
|
|
16942
|
+
}
|
|
16943
|
+
for (const run of runs) {
|
|
16944
|
+
const phase = computeReviewPhase(reviewPhaseInputFor(deps, run, wantsChecks.get(run.repo) ?? true));
|
|
16799
16945
|
if (run.review_phase !== phase.label) deps.db.updateRun(run.id, { review_phase: phase.label });
|
|
16800
16946
|
}
|
|
16801
16947
|
}
|
|
@@ -16897,7 +17043,14 @@ async function retireOutdatedReviewers(deps, run) {
|
|
|
16897
17043
|
narrate(deps, `${droneLabel(run)}: \u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u043F\u0440\u043E\u0448\u043B\u043E\u0433\u043E \u043A\u0440\u0443\u0433\u0430 \u0435\u0449\u0451 \u0436\u0438\u0432 \u2014 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u0435\u0433\u043E, \u0432\u0442\u043E\u0440\u043E\u0433\u043E \u043F\u043E\u0432\u0435\u0440\u0445 \u043D\u0435 \u0434\u0435\u0440\u0436\u0443.`);
|
|
16898
17044
|
}
|
|
16899
17045
|
}
|
|
16900
|
-
async function finalizeMergedReview(deps, run) {
|
|
17046
|
+
async function finalizeMergedReview(deps, run, opts) {
|
|
17047
|
+
if (!opts?.workChecked) {
|
|
17048
|
+
const work = await taskWorkState(deps, run.task_slug, run.repo || "", run.pr_url ?? null);
|
|
17049
|
+
if (work.kind === "open") {
|
|
17050
|
+
noteOpenPrHold(deps, run, work);
|
|
17051
|
+
return false;
|
|
17052
|
+
}
|
|
17053
|
+
}
|
|
16901
17054
|
await deps.finishTask(run.task_slug, run.workspace_id);
|
|
16902
17055
|
if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
|
|
16903
17056
|
});
|
|
@@ -16905,6 +17058,7 @@ async function finalizeMergedReview(deps, run) {
|
|
|
16905
17058
|
deps.db.updateRun(run.id, { status: "done" });
|
|
16906
17059
|
deps.db.addEvent(run.id, "done");
|
|
16907
17060
|
await closeReviewersOnDeadPr(deps, run.id, "PR \u0441\u043C\u0435\u0440\u0436\u0435\u043D \u0440\u0430\u043D\u044C\u0448\u0435 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u0440\u0435\u0432\u044C\u044E \u2014 \u0440\u0435\u0432\u044C\u044E \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u043D\u0443\u0436\u043D\u043E");
|
|
17061
|
+
return true;
|
|
16908
17062
|
}
|
|
16909
17063
|
async function finalizeClosedPrReview(deps, run, reason) {
|
|
16910
17064
|
await closeReviewersOnDeadPr(deps, run.id, "PR \u0437\u0430\u043A\u0440\u044B\u0442 \u0431\u0435\u0437 \u043C\u0435\u0440\u0436\u0430 \u2014 \u0440\u0435\u0432\u044C\u044E\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E");
|
|
@@ -16918,7 +17072,7 @@ async function prGateForReviewer(deps, run, prUrl, when) {
|
|
|
16918
17072
|
const st = await deps.prStatus(prUrl).catch(() => null);
|
|
16919
17073
|
switch (prLiveness(st)) {
|
|
16920
17074
|
case "merged":
|
|
16921
|
-
await finalizeMergedReview(deps, run);
|
|
17075
|
+
if (!await finalizeMergedReview(deps, run)) return { kind: "wait" };
|
|
16922
17076
|
narrate(deps, `PR ${droneLabel(run)} \u0441\u043C\u0435\u0440\u0436\u0435\u043D, ${when} \u2014 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u043F\u0440\u043E\u0433\u043E\u043D, \u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u043D\u0435 \u043D\u0443\u0436\u0435\u043D.`);
|
|
16923
17077
|
return { kind: "finalized" };
|
|
16924
17078
|
case "closed":
|
|
@@ -16949,6 +17103,16 @@ function doneMergedPrForSlug(db, slug) {
|
|
|
16949
17103
|
);
|
|
16950
17104
|
return done?.pr_url ?? null;
|
|
16951
17105
|
}
|
|
17106
|
+
var OPEN_PR_HOLD_MARK = "\u0443 \u0437\u0430\u0434\u0430\u0447\u0438 \u043E\u0441\u0442\u0430\u043B\u0438\u0441\u044C \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 PR";
|
|
17107
|
+
async function taskWorkState(deps, slug, repoDir, candidate) {
|
|
17108
|
+
const openPrs = deps.openPrsForTask ? await deps.openPrsForTask(slug, repoDir).catch(() => null) : null;
|
|
17109
|
+
return decideTaskWork({ mergedCandidate: candidate, openPrs });
|
|
17110
|
+
}
|
|
17111
|
+
function noteOpenPrHold(deps, run, v) {
|
|
17112
|
+
if (deps.db.events(run.id).some((e) => (e.text ?? "").includes(OPEN_PR_HOLD_MARK))) return;
|
|
17113
|
+
deps.db.addEvent(run.id, "step", formatOpenPrHold(v));
|
|
17114
|
+
narrate(deps, `${droneLabel(run)} \u2014 \u0443 ${run.task_slug} \u0435\u0449\u0451 \u043E\u0442\u043A\u0440\u044B\u0442 PR \u0441 \u043D\u0435\u0432\u043B\u0438\u0442\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u043E\u0439 (${v.prs.join(", ")}), \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E.`);
|
|
17115
|
+
}
|
|
16952
17116
|
async function closeDuplicateTaskRun(deps, run, mergedUrl) {
|
|
16953
17117
|
if (run.pid != null && deps.kill && deps.isAlive(run.pid)) {
|
|
16954
17118
|
try {
|
|
@@ -16958,7 +17122,7 @@ async function closeDuplicateTaskRun(deps, run, mergedUrl) {
|
|
|
16958
17122
|
}
|
|
16959
17123
|
if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
|
|
16960
17124
|
});
|
|
16961
|
-
const reason =
|
|
17125
|
+
const reason = formatMergedDuplicateReason(mergedUrl);
|
|
16962
17126
|
deps.db.updateRun(run.id, { status: "superseded", stop_reason: reason });
|
|
16963
17127
|
deps.db.addEvent(run.id, "superseded", reason);
|
|
16964
17128
|
}
|
|
@@ -16990,10 +17154,16 @@ async function closeMergedTaskRuns(deps) {
|
|
|
16990
17154
|
mergedUrl = await deps.mergedPrForBranch(slug, group[0].repo || "").catch(() => null);
|
|
16991
17155
|
}
|
|
16992
17156
|
if (!mergedUrl) continue;
|
|
17157
|
+
const work = await taskWorkState(deps, slug, group[0].repo || "", mergedUrl);
|
|
17158
|
+
if (work.kind === "open") {
|
|
17159
|
+
for (const run of nonTerminal) noteOpenPrHold(deps, run, work);
|
|
17160
|
+
continue;
|
|
17161
|
+
}
|
|
17162
|
+
if (work.kind === "merged") mergedUrl = work.pr;
|
|
16993
17163
|
const canonical = withPr && withPr.pr_url === mergedUrl && !isTerminalStatus(withPr.status) ? withPr : null;
|
|
16994
17164
|
for (const run of nonTerminal) {
|
|
16995
17165
|
if (canonical && run.id === canonical.id) {
|
|
16996
|
-
await finalizeMergedReview(deps, run);
|
|
17166
|
+
await finalizeMergedReview(deps, run, { workChecked: true });
|
|
16997
17167
|
narrate(deps, `PR ${droneLabel(run)} \u0441\u043C\u0435\u0440\u0436\u0435\u043D \u2014 ${slug} \u0437\u0430\u043A\u0440\u044B\u0442\u0430 (\u0434\u0443\u0431\u043B\u044C-\u0440\u0430\u043D\u044B \u0440\u043E\u044F, TASWM-206).`);
|
|
16998
17168
|
} else {
|
|
16999
17169
|
await closeDuplicateTaskRun(deps, run, mergedUrl);
|
|
@@ -17592,6 +17762,16 @@ async function wakeRun(deps, runId) {
|
|
|
17592
17762
|
if (!run) return { ok: false, why: `\u043F\u0440\u043E\u0433\u043E\u043D #${runId} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u0432 \u0437\u0435\u0440\u043A\u0430\u043B\u0435 \u0440\u043E\u044F` };
|
|
17593
17763
|
if (run.pid != null && deps.isAlive(run.pid)) return { ok: false, why: `\u043F\u0440\u043E\u0433\u043E\u043D #${runId} \u0443\u0436\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 (pid ${run.pid}) \u2014 \u0431\u0443\u0434\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E` };
|
|
17594
17764
|
if (isTerminalStatus(run.status)) return { ok: false, why: `\u043F\u0440\u043E\u0433\u043E\u043D #${runId} \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0435\u043D (${run.status}) \u2014 \u0431\u0443\u0434\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E` };
|
|
17765
|
+
const authorSideStopped = deps.db.events(run.id).some(
|
|
17766
|
+
(e) => [RESOLVE_ESCALATION_MARK, CI_WAKE_ESCALATION_MARK, VERIFY_ESCALATION_MARK].some(
|
|
17767
|
+
(m) => (e.text ?? "").includes(m)
|
|
17768
|
+
)
|
|
17769
|
+
);
|
|
17770
|
+
const changesEscalated = deps.db.events(run.id).some((e) => (e.text ?? "").includes(`${CHANGES_WAKE_ESCALATION_MARK} (\u043A\u0440\u0443\u0433 ${run.review_cycle ?? 0})`));
|
|
17771
|
+
const stoppedForHuman = deliberateReviewStop(deps.db, run) != null || changesEscalated || authorSideStopped;
|
|
17772
|
+
if (run.status === "review" && run.pr_url && !needsFixIteration(run) && !stoppedForHuman) {
|
|
17773
|
+
return { ok: false, why: `\u043F\u0440\u043E\u0433\u043E\u043D #${runId} \u0443\u0436\u0435 \u0441\u0434\u0430\u043D \u043D\u0430 \u0440\u0435\u0432\u044C\u044E (${run.pr_url}) \u2014 \u0431\u0443\u0434\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E; \u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442 \u0440\u043E\u0439 \u043F\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0443` };
|
|
17774
|
+
}
|
|
17595
17775
|
const worktreeExists = deps.worktreeExists ?? existsSync18;
|
|
17596
17776
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
17597
17777
|
const wt = run.worktree_path;
|
|
@@ -18194,17 +18374,31 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
18194
18374
|
// причина одна на машину — в лог уходит одной строкой, а не по строке на прогон
|
|
18195
18375
|
});
|
|
18196
18376
|
}
|
|
18197
|
-
const spentAttempts =
|
|
18377
|
+
const spentAttempts = attemptsFor(deps, run.task_slug);
|
|
18198
18378
|
if (spentAttempts >= PRE_START_ATTEMPT_LIMIT) {
|
|
18199
18379
|
const last = lastPreStartAttempt(deps.db.listRuns(), run.task_slug);
|
|
18200
|
-
const
|
|
18380
|
+
const cause = parkedCause(last);
|
|
18381
|
+
const tail2 = cause ? ` \u0427\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0438\u043B\u043E: ${cause}` : "";
|
|
18382
|
+
const why = (last && isUnretriableParked(last) ? `${SPAWN_PARK_MARK}: \u043F\u0440\u0438\u0447\u0438\u043D\u0430 \u043E\u0442\u043A\u0430\u0437\u0430 \u043F\u043E\u0432\u0442\u043E\u0440\u043E\u043C \u043D\u0435 \u043B\u0435\u0447\u0438\u0442\u0441\u044F, \u043D\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u0445\u043E\u0434\u0430 \u043D\u0435 \u0434\u0435\u043B\u0430\u044E (TASWM-485). \u0427\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C \u2014 \u0432 \u043F\u0440\u043E\u0433\u043E\u043D\u0435 #${last.id}` : `${PRE_START_MARK} ${spentAttempts} \u0440\u0430\u0437\u0430 \u043F\u043E\u0434\u0440\u044F\u0434 \u2014 ${SPAWN_PARK_MARK}, \u0447\u0435\u0442\u0432\u0451\u0440\u0442\u043E\u0433\u043E \u0437\u0430\u0445\u043E\u0434\u0430 \u043D\u0435 \u0434\u0435\u043B\u0430\u044E (TASWM-422)`) + tail2;
|
|
18201
18383
|
deps.db.updateRun(run.id, { status: "stopped", stop_reason: why });
|
|
18202
18384
|
deps.db.addEvent(run.id, "step", why);
|
|
18385
|
+
if (deps.parkTask && last && !isParkApplied(last)) {
|
|
18386
|
+
const ok = await deps.parkTask(run, last.stop_reason ?? why, { comment: false }).catch(() => false);
|
|
18387
|
+
if (ok)
|
|
18388
|
+
deps.db.updateRun(last.id, {
|
|
18389
|
+
// Водораздел включает и ЭТОТ, только что закрытый гейтом прогон: он появился до
|
|
18390
|
+
// подтверждения, и принимать его за ручной возврат нельзя (code-review PR #984).
|
|
18391
|
+
stop_reason: withParkApplied(last.stop_reason ?? why, stamp(), lastRunIdFor(deps.db.listRuns(), run.task_slug))
|
|
18392
|
+
});
|
|
18393
|
+
}
|
|
18203
18394
|
const d = noteDefer(deps.spawnDefer ??= /* @__PURE__ */ new Map(), `pre-start-exhausted:${run.task_slug}`, why, GATE_LOG_HEARTBEAT_TICKS);
|
|
18204
18395
|
if (d.log) console.error(`[overmind] ${run.task_slug}: ${why}${d.changed ? "" : ` \u2014 \u0435\u0449\u0451 \u0432\u0438\u0441\u0438\u0442, \u0442\u0438\u043A ${d.ticks}`}`);
|
|
18205
18396
|
return "closed";
|
|
18206
18397
|
}
|
|
18207
|
-
const
|
|
18398
|
+
const mergedCandidate = doneMergedPrForSlug(deps.db, run.task_slug) ?? (deps.mergedPrForBranch ? await deps.mergedPrForBranch(run.task_slug, run.repo || "").catch(() => null) : null);
|
|
18399
|
+
const work = mergedCandidate ? await taskWorkState(deps, run.task_slug, run.repo || "", mergedCandidate) : null;
|
|
18400
|
+
if (work?.kind === "open") noteOpenPrHold(deps, run, work);
|
|
18401
|
+
const mergedUrl = work?.kind === "merged" ? work.pr : null;
|
|
18208
18402
|
if (mergedUrl) {
|
|
18209
18403
|
await closeDuplicateTaskRun(deps, run, mergedUrl);
|
|
18210
18404
|
await deps.finishTask(run.task_slug, run.workspace_id).catch(() => {
|
|
@@ -18299,10 +18493,13 @@ function spawnRetryOpts(e) {
|
|
|
18299
18493
|
if (!(e instanceof TaskBodyUnavailableError)) return {};
|
|
18300
18494
|
return { retriable: TOOL_FAILURE_RETRIABLE[e.code] };
|
|
18301
18495
|
}
|
|
18496
|
+
function attemptsFor(deps, taskSlug) {
|
|
18497
|
+
return preStartAttempts(deps.db.listRuns(), taskSlug, deps.startedAt != null ? { since: deps.startedAt } : {});
|
|
18498
|
+
}
|
|
18302
18499
|
async function failBeforeStart(deps, run, reason, opts = {}) {
|
|
18303
18500
|
deps.db.updateRun(run.id, { status: "failed", stop_reason: `${PRE_START_MARK}: ${reason}` });
|
|
18304
18501
|
deps.db.addEvent(run.id, "failed", `${PRE_START_MARK} \u2014 ${reason}`);
|
|
18305
|
-
const attempts =
|
|
18502
|
+
const attempts = attemptsFor(deps, run.task_slug);
|
|
18306
18503
|
if (opts.retriable !== false && attempts < PRE_START_ATTEMPT_LIMIT) {
|
|
18307
18504
|
narrate(deps, `${droneLabel(run)} \u2014 ${PRE_START_MARK} (\u043F\u043E\u043F\u044B\u0442\u043A\u0430 ${attempts} \u0438\u0437 ${PRE_START_ATTEMPT_LIMIT}): ${reason}`);
|
|
18308
18505
|
return "failed";
|
|
@@ -18313,7 +18510,13 @@ async function failBeforeStart(deps, run, reason, opts = {}) {
|
|
|
18313
18510
|
narrate(deps, `${run.task_slug}: ${parked}`);
|
|
18314
18511
|
if (deps.parkTask) {
|
|
18315
18512
|
const ok = await deps.parkTask(run, parked).catch(() => false);
|
|
18316
|
-
if (
|
|
18513
|
+
if (ok)
|
|
18514
|
+
deps.db.updateRun(run.id, {
|
|
18515
|
+
// Водораздел (code-review PR #984) — самый большой id прогона задачи ПРЯМО СЕЙЧАС:
|
|
18516
|
+
// всё, что появится после него, заведено уже по возвращённой в очередь задаче.
|
|
18517
|
+
stop_reason: withParkApplied(parked, stamp(), lastRunIdFor(deps.db.listRuns(), run.task_slug))
|
|
18518
|
+
});
|
|
18519
|
+
else {
|
|
18317
18520
|
deps.db.addEvent(
|
|
18318
18521
|
run.id,
|
|
18319
18522
|
"step",
|
|
@@ -18983,8 +19186,7 @@ async function tickOnce(deps) {
|
|
|
18983
19186
|
const st = await deps.prStatus(prUrl);
|
|
18984
19187
|
run = syncBranchFromPr(deps.db, run, st.headBranch);
|
|
18985
19188
|
if (st.merged) {
|
|
18986
|
-
await finalizeMergedReview(deps, run);
|
|
18987
|
-
narrate(deps, `PR ${droneLabel(run)} \u0441\u043C\u0435\u0440\u0436\u0435\u043D \u2014 ${run.task_slug} \u0437\u0430\u043A\u0440\u044B\u0442\u0430, \u0441\u043B\u043E\u0442 \u0441\u0432\u043E\u0431\u043E\u0434\u0435\u043D.`);
|
|
19189
|
+
if (await finalizeMergedReview(deps, run)) narrate(deps, `PR ${droneLabel(run)} \u0441\u043C\u0435\u0440\u0436\u0435\u043D \u2014 ${run.task_slug} \u0437\u0430\u043A\u0440\u044B\u0442\u0430, \u0441\u043B\u043E\u0442 \u0441\u0432\u043E\u0431\u043E\u0434\u0435\u043D.`);
|
|
18988
19190
|
continue;
|
|
18989
19191
|
}
|
|
18990
19192
|
if (prLiveness(st) === "closed") {
|
|
@@ -19128,7 +19330,7 @@ async function tickOnce(deps) {
|
|
|
19128
19330
|
relinkUnboundReviewers(deps);
|
|
19129
19331
|
await closeOrphanedReviewers(deps);
|
|
19130
19332
|
await spawnVerifiersForOpenPrs(deps, stormActive);
|
|
19131
|
-
refreshReviewPhases(deps);
|
|
19333
|
+
await refreshReviewPhases(deps);
|
|
19132
19334
|
let liveChildPpids;
|
|
19133
19335
|
try {
|
|
19134
19336
|
liveChildPpids = deps.livePpids?.() ?? null;
|
|
@@ -19218,6 +19420,12 @@ async function tickOnce(deps) {
|
|
|
19218
19420
|
}
|
|
19219
19421
|
}
|
|
19220
19422
|
if (!alive && (outcome === "graceful" || outcome === "aborted") && run.status === "running" && run.resolves_run_id == null && run.reviews_run_id == null && run.verifies_run_id == null && run.kind !== "hero") {
|
|
19423
|
+
if (!wasAborted(outcome) && run.pr_url) {
|
|
19424
|
+
deps.db.updateRun(run.id, { status: "review", stop_reason: null });
|
|
19425
|
+
deps.db.addEvent(run.id, "step", `${SUBMITTED_EXIT_TEXT}: ${run.pr_url}`);
|
|
19426
|
+
narrate(deps, `${droneLabel(run)} \u0432\u044B\u0448\u0435\u043B, \u043D\u043E \u0440\u0430\u0431\u043E\u0442\u0430 \u0443\u0436\u0435 \u0441\u0434\u0430\u043D\u0430 (${run.pr_url}) \u2014 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u044E \u0432 \u0440\u0435\u0432\u044C\u044E, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u043D\u0435 \u043D\u0443\u0436\u0435\u043D.`);
|
|
19427
|
+
continue;
|
|
19428
|
+
}
|
|
19221
19429
|
const aborted = wasAborted(outcome);
|
|
19222
19430
|
const abort = aborted ? deps.exitAbort?.(run) ?? null : null;
|
|
19223
19431
|
const what = aborted ? abortReason(abort) : EXITED_NO_DONE_REASON;
|
|
@@ -20484,6 +20692,9 @@ async function runDaemon(opts) {
|
|
|
20484
20692
|
// Смерженный PR ветки-слага (TASWM-206) — тот же фолбэк на дефолт-репо роя, что и
|
|
20485
20693
|
// openPrsForBranch выше; реальный gh, логика закрытия дублей — в tickOnce (тестируется).
|
|
20486
20694
|
mergedPrForBranch: (branch, repoDir) => mergedPrForBranch(branch, repoDir || opts.repo),
|
|
20695
|
+
// ВСЕ открытые PR задачи (TASWM-515) — тот же фолбэк на дефолт-репо роя. Реальный gh;
|
|
20696
|
+
// и отбор «этот PR — задачи», и решение «закончена ли работа» чистые (swarm-core).
|
|
20697
|
+
openPrsForTask: (slug, repoDir) => openPrsForTask(slug, repoDir || opts.repo),
|
|
20487
20698
|
// Закрыта ли задача в Taskless (TASWM-137 п.г): death-detect гасит зомби-прогон, чья
|
|
20488
20699
|
// задача уже completed/cancelled/archived, вместо респавна. null — Taskless недоступен
|
|
20489
20700
|
// (не гасим). Без tl (нет токена) ключ не задаём — шаг инертен, старое поведение.
|
|
@@ -20499,17 +20710,22 @@ async function runDaemon(opts) {
|
|
|
20499
20710
|
// задачу), а не кодом возврата: клиент глушит отказ сервера внутрь (safeCall), и по
|
|
20500
20711
|
// возврату «отложил» было бы неотличимо от «сказал, но не доехало» — то самое молчание,
|
|
20501
20712
|
// из-за которого 17.08 круг и крутился.
|
|
20502
|
-
parkTask: async (run, reason) => {
|
|
20713
|
+
parkTask: async (run, reason, opts2) => {
|
|
20503
20714
|
const client = tlFor(run.workspace_id);
|
|
20504
20715
|
if (!client) return false;
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20716
|
+
if (opts2?.comment !== false)
|
|
20717
|
+
await client.addComment(
|
|
20718
|
+
run.task_slug,
|
|
20719
|
+
// TASWM-514: советуем ИМЕННО возврат в очередь — теперь этот рычаг работает
|
|
20720
|
+
// (возврат в «не начато» обнуляет счётчик попыток). И причина стоит в первой
|
|
20721
|
+
// строке (её несёт `reason`, см. parkReason): человек, читающий пометку через
|
|
20722
|
+
// час, должен из неё понять, ЧТО чинить, а не раскапывать записи прогонов.
|
|
20723
|
+
`${reason}
|
|
20508
20724
|
|
|
20509
|
-
\u0417\u0430\u0434\u0430\u0447\u0430 \u0441\u043D\u044F\u0442\u0430 \u0441 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u0440\u043E\u044F \u2014 \u043F\u043E\u043A\u0430 \u043F\u0440\u0438\u0447\u0438\u043D\u0430 \u043D\u0435 \u0443\u0441\u0442\u0440\u0430\u043D\u0435\u043D\u0430, \u0431\u0440\u0430\u0442\u044C \u0435\u0451 \u0441\u043D\u043E\u0432\u0430 \u0441\u043C\u044B\u0441\u043B\u0430 \u043D\u0435\u0442. \
|
|
20510
|
-
|
|
20511
|
-
|
|
20512
|
-
|
|
20725
|
+
\u0417\u0430\u0434\u0430\u0447\u0430 \u0441\u043D\u044F\u0442\u0430 \u0441 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u0440\u043E\u044F \u2014 \u043F\u043E\u043A\u0430 \u043F\u0440\u0438\u0447\u0438\u043D\u0430 \u043D\u0435 \u0443\u0441\u0442\u0440\u0430\u043D\u0435\u043D\u0430, \u0431\u0440\u0430\u0442\u044C \u0435\u0451 \u0441\u043D\u043E\u0432\u0430 \u0441\u043C\u044B\u0441\u043B\u0430 \u043D\u0435\u0442. \u0423\u0441\u0442\u0440\u0430\u043D\u0438 \u043F\u0440\u0438\u0447\u0438\u043D\u0443 \u0438 \u0432\u0435\u0440\u043D\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \xAB\u043D\u0435 \u043D\u0430\u0447\u0430\u0442\u043E\xBB \u2014 \u0440\u043E\u0439 \u043F\u043E\u0434\u0445\u0432\u0430\u0442\u0438\u0442 \u0435\u0451 \u0441\u043D\u043E\u0432\u0430.`,
|
|
20726
|
+
{ swarmKind: "report", swarmDroneName: run.name }
|
|
20727
|
+
).catch(() => {
|
|
20728
|
+
});
|
|
20513
20729
|
await client.startTask(run.task_slug).catch(() => {
|
|
20514
20730
|
});
|
|
20515
20731
|
const after = await client.getTask(run.task_slug).catch(() => null);
|
|
@@ -20723,6 +20939,9 @@ async function runDaemon(opts) {
|
|
|
20723
20939
|
nudge
|
|
20724
20940
|
),
|
|
20725
20941
|
worktreeExists: (p) => existsSync18(p),
|
|
20942
|
+
// TASWM-514: с этого момента считаем попытки спавна — счётчик живёт ровно одну жизнь
|
|
20943
|
+
// процесса демона и рестарт не переживает (см. preStartAttempts).
|
|
20944
|
+
startedAt: Date.now(),
|
|
20726
20945
|
hasTranscript: executorHasSession,
|
|
20727
20946
|
// CI-осведомлённость review-PR (TASWM-102): реальный `gh pr checks`/`gh run view --log-failed`
|
|
20728
20947
|
// (gh.ts) — решение (будить ли дрона) и гейты живут в tickOnce/handleCiRed. failureSummary
|
|
@@ -21184,6 +21403,7 @@ export {
|
|
|
21184
21403
|
GATE_LOG_HEARTBEAT_TICKS,
|
|
21185
21404
|
HEADLESS_BLOCK,
|
|
21186
21405
|
HERO_CONTINUE_NUDGE,
|
|
21406
|
+
OPEN_PR_HOLD_MARK,
|
|
21187
21407
|
OVERMIND_ENTRY,
|
|
21188
21408
|
RESOLVE_ESCALATION_MARK,
|
|
21189
21409
|
RESOLVE_LIMIT,
|
|
@@ -21201,6 +21421,8 @@ export {
|
|
|
21201
21421
|
STALL_FLOOR_MS,
|
|
21202
21422
|
STALL_MS,
|
|
21203
21423
|
STORM_DEAD_LIMIT,
|
|
21424
|
+
SUBMITTED_EXIT_TEXT,
|
|
21425
|
+
VERIFY_ESCALATION_MARK,
|
|
21204
21426
|
VERIFY_SPAWN_LIMIT,
|
|
21205
21427
|
WATCHDOG_PARK_REASON,
|
|
21206
21428
|
abortReason,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"execa": "^10.0.0",
|
|
40
40
|
"zod": "3.25.76"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "2e1ed83014422ae577be60271adc79e291b9e2ab",
|
|
43
43
|
"scripts": {
|
|
44
44
|
"overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
|
|
45
45
|
"swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",
|